SQLite

Check-in [0b434ca7aa]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add support for the CONCAT() and CONCAT_WS() SQL functions, modeled after the PostgreSQL behavior.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0b434ca7aa19eff4ad134a8c6f88f6a7ccab88864faa55e93579a2462d8ac3bc
User & Date: drh 2023-08-29 15:24:41.645
Context
2023-08-29
15:38
Change the version number to 3.44.0 to begin the next development cycle. (Should have done this a few check-ins ago.) (check-in: 253fe4a45d user: drh tags: trunk)
15:24
Add support for the CONCAT() and CONCAT_WS() SQL functions, modeled after the PostgreSQL behavior. (check-in: 0b434ca7aa user: drh tags: trunk)
10:50
Change a variable from "int" to "i64" to make it easier to prove that it cannot overflow. (check-in: 00a8b3a263 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/func.c.
1546
1547
1548
1549
1550
1551
1552











































































1553
1554
1555
1556
1557
1558
1559
    if( zCharSet ){
      sqlite3_free(azChar);
    }
  }
  sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}













































































#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "sqlite3" command-line shell is built using this functionality,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
    if( zCharSet ){
      sqlite3_free(azChar);
    }
  }
  sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}

/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
** functions.
**
** Return a string value that is the concatenation of all non-null
** entries in argv[].  Use zSep as the separator.
*/
static void concatFuncCore(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv,
  int nSep,
  const char *zSep
){
  i64 j, k, n = 0;
  int i;
  char *z;
  for(i=0; i<argc; i++){
    n += sqlite3_value_bytes(argv[i]);
  }
  n += (argc-1)*nSep;
  z = sqlite3_malloc64(n+1);
  if( z==0 ){
    sqlite3_result_error_nomem(context);
    return;
  }
  j = 0;
  for(i=0; i<argc; i++){
    k = sqlite3_value_bytes(argv[i]);
    if( k>0 ){
      const char *v = (const char*)sqlite3_value_text(argv[i]);
      if( ALWAYS(v!=0) ){
        if( j>0 && nSep>0 ){
          memcpy(&z[j], zSep, nSep);
          j += nSep;
        }
        memcpy(&z[j], v, k);
        j += k;
      }
    }
  }
  z[j] = 0;
  assert( j<=n );
  sqlite3_result_text64(context, z, n, sqlite3_free, SQLITE_UTF8);
}

/*
** The CONCAT(...) function.  Generate a string result that is the
** concatentation of all non-null arguments.
*/
static void concatFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  concatFuncCore(context, argc, argv, 0, "");
}

/*
** The CONCAT_WS(separator, ...) function.
**
** Generate a string that is the concatenation of 2nd through the Nth
** argument.  Use the first argument (which must be non-NULL) as the
** separator.
*/
static void concatwsFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int nSep = sqlite3_value_bytes(argv[0]);
  const char *zSep = (const char*)sqlite3_value_text(argv[0]);
  if( zSep==0 ) return;
  concatFuncCore(context, argc-1, argv+1, nSep, zSep);
}


#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "sqlite3" command-line shell is built using this functionality,
2555
2556
2557
2558
2559
2560
2561





2562
2563
2564
2565
2566
2567
2568
    FUNCTION(round,              2, 0, 0, roundFunc        ),
#endif
    FUNCTION(upper,              1, 0, 0, upperFunc        ),
    FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    FUNCTION(hex,                1, 0, 0, hexFunc          ),
    FUNCTION(unhex,              1, 0, 0, unhexFunc        ),
    FUNCTION(unhex,              2, 0, 0, unhexFunc        ),





    INLINE_FUNC(ifnull,          2, INLINEFUNC_coalesce, 0 ),
    VFUNCTION(random,            0, 0, 0, randomFunc       ),
    VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
    FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
    DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),







>
>
>
>
>







2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
    FUNCTION(round,              2, 0, 0, roundFunc        ),
#endif
    FUNCTION(upper,              1, 0, 0, upperFunc        ),
    FUNCTION(lower,              1, 0, 0, lowerFunc        ),
    FUNCTION(hex,                1, 0, 0, hexFunc          ),
    FUNCTION(unhex,              1, 0, 0, unhexFunc        ),
    FUNCTION(unhex,              2, 0, 0, unhexFunc        ),
    FUNCTION(concat,            -1, 0, 0, concatFunc       ),
    FUNCTION(concat,             0, 0, 0, 0                ),
    FUNCTION(concat_ws,         -1, 0, 0, concatwsFunc     ),
    FUNCTION(concat_ws,          0, 0, 0, 0                ),
    FUNCTION(concat_ws,          1, 0, 0, 0                ),
    INLINE_FUNC(ifnull,          2, INLINEFUNC_coalesce, 0 ),
    VFUNCTION(random,            0, 0, 0, randomFunc       ),
    VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
    FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
    DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
    DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
    FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
Added test/func9.test.
















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 2023-08-29
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#*************************************************************************
#
# Test cases for SQL newer functions
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test func9-100 {
  SELECT concat('abc',123,null,'xyz');
} {abc123xyz}
do_execsql_test func9-110 {
  SELECT typeof(concat(null));
} {text}
do_catchsql_test func9-120 {
  SELECT concat();
} {1 {wrong number of arguments to function concat()}}
do_execsql_test func9-130 {
  SELECT concat_ws(',',1,2,3,4,5,6,7,8,NULL,9,10,11,12);
} {1,2,3,4,5,6,7,8,9,10,11,12}
do_execsql_test func9-140 {
  SELECT concat_ws(NULL,1,2,3,4,5,6,7,8,NULL,9,10,11,12);
} {{}}
do_catchsql_test func9-150 {
  SELECT concat_ws();
} {1 {wrong number of arguments to function concat_ws()}}
do_catchsql_test func9-160 {
  SELECT concat_ws(',');
} {1 {wrong number of arguments to function concat_ws()}}


finish_test