1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-23 21:49:02 +03:00

Merge all the latest trunk enhancements and fixes into the temp-trigger-refs

branch.

FossilOrigin-Name: 8e8a27c77aa0ea5891968231e13a8caeade48b817419bbf6eda18ad217f1df63
This commit is contained in:
drh
2025-12-04 11:20:01 +00:00
21 changed files with 989 additions and 152 deletions

14
ext/qrf/dev-notes.md Normal file
View File

@@ -0,0 +1,14 @@
# Developer Notes
## Measuring Test Coverage On Linux
On Mint Linux, as of 2025-12-02:
> ~~~
./configure --dev CFLAGS='-O0 -g -fprofile-arcs -ftest-coverage'
make clean testfixture
./testfixture test/qrf*.test
gcov -b -c testfixture-tclsqlite-ex.c
~~~
View results in tclsqlite-ex.c.gcov

View File

@@ -537,13 +537,20 @@ static int qrfIsVt100(const unsigned char *z){
/*
** Return the length of a string in display characters.
** Multibyte UTF8 characters count as a single character
** for single-width characters, or as two characters for
** double-width characters.
**
** Most characters of the input string count as 1, including
** multi-byte UTF8 characters. However, zero-width unicode
** characters and VT100 escape sequences count as zero, and
** double-width characters count as two.
**
** The definition of "zero-width" and "double-width" characters
** is not precise. It depends on the output device, to some extent,
** and it varies according to the Unicode version. This routine
** makes the best guess that it can.
*/
static int qrfDisplayLength(const char *zIn){
size_t sqlite3_qrf_wcswidth(const char *zIn){
const unsigned char *z = (const unsigned char*)zIn;
int n = 0;
size_t n = 0;
while( *z ){
if( z[0]<' ' ){
int k;
@@ -2198,7 +2205,7 @@ static void qrfExplain(Qrf *p){
int len;
if( i==nArg-1 ) w = 0;
if( zVal==0 ) zVal = "";
len = qrfDisplayLength(zVal);
len = (int)sqlite3_qrf_wcswidth(zVal);
if( len>w ){
w = len;
zSep = " ";
@@ -2388,7 +2395,7 @@ static void qrfOneSimpleRow(Qrf *p){
int sz;
p->u.sLine.azCol[i] = sqlite3_column_name(p->pStmt, i);
if( p->u.sLine.azCol[i]==0 ) p->u.sLine.azCol[i] = "unknown";
sz = qrfDisplayLength(p->u.sLine.azCol[i]);
sz = (int)sqlite3_qrf_wcswidth(p->u.sLine.azCol[i]);
if( sz > p->u.sLine.mxColWth ) p->u.sLine.mxColWth = sz;
}
}

View File

@@ -176,13 +176,21 @@ int sqlite3_format_query_result(
** character c. For normal characters, the answer is always 1. But the
** estimate might be 0 or 2 for zero-width and double-width characters.
**
** Different display devices display unicode using different widths. So
** Different devices display unicode using different widths. So
** it is impossible to know that true display width with 100% accuracy.
** Inaccuracies in the width estimates might cause columns to be misaligned.
** Unfortunately, there is nothing we can do about that.
*/
int sqlite3_qrf_wcwidth(int c);
/*
** Return an estimate of the number of display columns used by the
** string in the argument. The width of individual characters is
** determined as for sqlite3_qrf_wcwidth(). VT100 escape code sequences
** are assigned a width of zero.
*/
size_t sqlite3_qrf_wcswidth(const char*);
#ifdef __cplusplus
}

View File

@@ -1107,11 +1107,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
sqlite3.config.warn("DB.exec() is propagating exception",opt,e);
throw e;
}*/finally{
wasm.scopedAllocPop(stack);
if(stmt){
__execLock.delete(stmt);
stmt.finalize();
}
wasm.scopedAllocPop(stack);
}
return arg.returnVal();
}/*exec()*/,

View File

@@ -1,5 +1,5 @@
C Fix\sa\smemory\sleak\sthat\scould\sfollow\san\sOOM\son\sthis\sbranch.
D 2025-12-01T18:11:08.093
C Merge\sall\sthe\slatest\strunk\senhancements\sand\sfixes\sinto\sthe\stemp-trigger-refs\nbranch.
D 2025-12-04T11:20:01.398
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -417,8 +417,9 @@ F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6
F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
F ext/qrf/README.md 86fc5c3c5e3eddbe54fc1235cbdc52b8c2c0732791d224345c3014cd45c4c0e7
F ext/qrf/qrf.c 425d02cffcc5b5fe9ff5817794bf751b1fdd6912f570c354272429ce1262b866
F ext/qrf/qrf.h 322d48537a5aa39c206c2ec0764a7938ea7662a8c25be1c4e9d742789609ba1e
F ext/qrf/dev-notes.md e68a6d91ce4c7eb296ef2daadc2bb79c95c317ad15b9fafe40850c67b29c2430
F ext/qrf/qrf.c c50368ea2be3ab67bd6698d8b34bf70210d3fbf6b3659ed328543e5ec8d69eff
F ext/qrf/qrf.h 2cd7bd43579c522d3ae5c16034c7fdf41085684189811ae8e18ebc932a1cc79f
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
F ext/rbu/rbu10.test 7c22caa32c2ff26983ca8320779a31495a6555737684af7aba3daaf762ef3363
@@ -594,7 +595,7 @@ F ext/wasm/api/post-js-footer.js a50c1a2c4d008aede7b2aa1f18891a7ee71437c2f415b8a
F ext/wasm/api/post-js-header.js d24bd0d065f3489c8b78ddf3ead6321e5d047187a162cd503c41700e03dd1f06
F ext/wasm/api/pre-js.c-pp.js d73088472f91856a27837c0588ac355516cea441ff67d2990effc2ca0627bf21
F ext/wasm/api/sqlite3-api-glue.c-pp.js 9b33e3ee467791dec4fd1b444b12a8545dfbb6c8b28ac651c7bdc7661a3b5a5c
F ext/wasm/api/sqlite3-api-oo1.c-pp.js 7a6c85b260082d72a5c355caf37876763d8770a29d9e0587751e584c31bf2777
F ext/wasm/api/sqlite3-api-oo1.c-pp.js b2fa08dc02a0d852d88c59ce4a77cce3af033982f7eb41eeb81f1ba80f5f1b10
F ext/wasm/api/sqlite3-api-prologue.js fd836265adefbe4ed8a978326e0273bafcfb7d42f754b69a5d131a9031428c9f
F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667430f9d45167569633ffc7567938
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
@@ -668,7 +669,7 @@ F mptest/multiwrite01.test dab5c5f8f9534971efce679152c5146da265222d
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366
F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398
F src/alter.c 06a27ab1cc064f5c6647e7fadfb12c8d7cafd35de1751f12419e1f2b28037540
F src/alter.c 6c7791c7d95f66df7c510ed006bd8b0a58badfd7106ad2aa97f2d10ae3c3e06d
F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d
F src/attach.c 7cf07d4fa42b9fc8662237c60c40b730326c30aa90ae5fffc0b18b2d726ebf61
F src/auth.c 54ab9c6c5803b47c0d45b76ce27eff22a03b4b1f767c5945a3a4eb13aa4c78dc
@@ -686,7 +687,7 @@ F src/date.c e19e0cfff9a41bfdd884c655755f6f00bca4c1a22272b56e0dd6667b7ea893a2
F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f
F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c
F src/delete.c 03a77ba20e54f0f42ebd8eddf15411ed6bdb06a2c472ac4b6b336521bf7cea42
F src/expr.c 17b0cbe08e004c1653030f5de9b6b050e84feaa112239f7f576af2dc5e53a5fb
F src/expr.c b4530f3e23d8ea38c7de4c7b55af52d43156c79128c042a580e670776f59a9bc
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c c065da737307a29e4d240ac727758dbf4102cb3218a1f651eb689b6a6fa12531
F src/func.c 0b802107498048d3dcac0b757720bcb8506507ce02159e213ab8161458eb293b
@@ -725,7 +726,7 @@ F src/os_win.c a89b501fc195085c7d6c9eec7f5bd782625e94bb2a96b000f4d009703df1083f
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
F src/parse.y e31046636c50ba4a1cf4d12c7a6112a31b11975b1ade84a45f2109a30e8f358d
F src/parse.y 015375decff21fa3be5688189d58988458db8e3ccb821041b0fb7de4cd2fcf30
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
@@ -733,18 +734,18 @@ F src/pragma.c ecec75795c1821520266e4f93fa8840cce48979af532db06f085e36a7813860f
F src/prepare.c f6a6e28a281bd1d1da12f47d370a81af46159b40f73bf7fa0b276b664f9c8b7d
F src/printf.c b1b29b5e58e1530d5daeee5963d3c318d8ab2d7e38437580e28755753e0c1ded
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
F src/resolve.c 8d53771eb51a4ab5f970150c3a70969d8db79cd04a8774c2d296bbcf471a0dd0
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 6a509cddd815d64f6141e539fff633a518a393772a44dffb4490f7fc3f0d83a9
F src/shell.c.in 8ec8bf61a3322c5e29c286d4aecbc82e25157df9244cb1a1a1c4e2c49de8b64d
F src/select.c 344518c1bba9c4636bf651b7642304abd2e7075ba35feb4bae42a51e5efe991f
F src/shell.c.in 62b286951404fd72c116bb3b96b5ee9330de4dc4c8753ca33967ca1a47b3b972
F src/sqlite.h.in 706cacea5308b0244fb6cec92e08310fb427a125375c64137cc1f878ae4cf5c0
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
F src/sqliteInt.h f8b6a6bdb92aaeeedd768d27650a39f543c4b7cc66534c564e2ec249ed80e210
F src/sqliteInt.h af67bc95fa6b66cd3c7f3d18d2d040ad386e4cbb02965ee318cc721ee9d5fa45
F src/sqliteLimit.h 0a5516b4ec192a205c541e05f67009028a9451dc6678aae4cf8e68596903c246
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c ec2ad3fbf5390c3d4307bc9d1f2a37a9c5d726b5309769dc770ab37f6812152d
F src/tclsqlite.c 4b6f6b142b951a8a127e0cbd2e37284fc71f8e6a391ec8c6188fb831b51ec0b8
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
@@ -820,8 +821,8 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
F src/where.c 1b554a868134cbc9ca2192385403c0b63e5073ff01a6cdd600a846c09f843165
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5
F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc
F src/window.c 538195bbc75bb924e18e368fbd4ed731a3fe3f901351b44f6466ec486f53affe
F src/whereexpr.c 5f412da6616e26b8000dd736a5ce5da0018dff0933cd656bbb25f407db16bf93
F src/window.c c0a38cd32473e8e8e7bc435039f914a36ca42465506dc491c65870c01ddac9fb
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d
F test/affinity3.test 9b7d1133e11d5edd7805573c4ab6f3ba73b0b74a1f280d5b130d4bf3506a93ff
@@ -851,7 +852,7 @@ F test/altermalloc3.test 8040e486368403f2fdd6fc3998258b499bd4cc2f3ddbb5f8f874cd4
F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
F test/altertab2.test 0889ba0700cc1cdb7bc7d25975aa61fece34f621de963d0886e2395716b38576
F test/altertab3.test 471b8898d10bbc6488db9c23dc76811f405de6707d2d342b1b8b6fd1f13cd3c8
F test/altertab3.test 575e771e2f02b13eb98798dc92eabacd187d6dbcf596e70f11d699b0b6b5d0b2
F test/altertrig.test b1590647076add5a47aea0f2236c609ca0bc8a7a2462463edd3e5882c7894802
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
@@ -1514,6 +1515,8 @@ F test/qrf01.test 48c86e90f606739e67b73937babb662ef0edf1ede06954489c588815fa17b5
F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
F test/qrf03.test ad7fa339fb46b26b08625f3a77a4827bdee9f0dad402d8ddc1fcb8f05aa64a54
F test/qrf04.test 0894692c998d2401dcc33449c02051b503ecce0c94217be54fb007c82d2d1379
F test/qrf05.test 8ade5bfa7ef0b448e531687203fa8ae9ef41f1d7e4c11d5ba0c4846af75b13d5
F test/qrf06.test 3907f81c79fd884802cc7552d4a07fd8d73c381ade9d5108e6d7f56fd962b99b
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
F test/quickcheck.test a4b7e878cd97e46108291c409b0bf8214f29e18fddd68a42bc5c1375ad1fb80a
@@ -1607,7 +1610,7 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test f377091779c4099619e78e1f55a0a12513eaac55d5073a14ca6545c6742c746c
F test/shell1.test b49a89913c194c37ca10c9ded1b6b6866506104621c6cc599e557e4cb5ed8cc2
F test/shell2.test 103140814bdc7508aa41dd3462413cbc4aa84b4261112cb8d501d74275cb7d48
F test/shell3.test 840192774cc4edf7653520c0434a311c7477b9bc324abbc7bd2887915792fa8c
F test/shell4.test e25580a792b7b54560c3a76b6968bd8189261f38979fe28e6bc6312c5db280db
@@ -1672,7 +1675,7 @@ F test/strict1.test a7f9091603fe71cdc62baab0766684cba12a97ec69bfbb70be965532669c
F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070
F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49
F test/subquery.test 23087f9b1c15ab9cc5231d04946bdebc51db527c95eb9d7434a2222127e17a84
F test/subquery2.test 5f06ec2dbce42a3f595ab1b73b146592f9ce001cd4ff023d887d643d3560c281
F test/subquery2.test ab96ff3fa9c4e3dce0d699f74e61c50250ed4335bc8f400e127707d552a8999e
F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
F test/substr.test a673e3763e247e9b5e497a6cacbaf3da2bd8ec8921c0677145c109f2e633f36b
F test/subtype1.test 96fd2a59bfc845c955b5f339d23b37ef4d50de5f8a04acd1450a68605fa2e3e7
@@ -2181,8 +2184,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 75c49267ec6b84c8aad0e264c34506e4b24f69475ae5def0ee7530ba3822c15d
R 2e866f8f96424c36ead738f7cc32a381
U dan
Z b33421e6e016ff0d1ecfa51911613b2c
P 3223fee0b93bbbe277b955a98c13bb583ded78109f8e601c9ec0a7bd3749fd55 aef5397569d65d2971367b0278fe3a6f42544cf771572e7d046e2472f052364d
R 7195c1541663c387532db21aed885d33
U drh
Z 19135e17dd3bb54a10cd401bdceed81e
# Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
3223fee0b93bbbe277b955a98c13bb583ded78109f8e601c9ec0a7bd3749fd55
8e8a27c77aa0ea5891968231e13a8caeade48b817419bbf6eda18ad217f1df63

View File

@@ -2110,6 +2110,57 @@ static void renameTableTest(
#endif
}
/*
** Return the number of bytes until the end of the next non-whitespace and
** non-comment token. For the purpose of this function, a "(" token includes
** all of the bytes through and including the matching ")", or until the
** first illegal token, whichever comes first.
**
** Write the token type into *piToken.
**
** The value returned is the number of bytes in the token itself plus
** the number of bytes of leading whitespace and comments skipped plus
** all bytes through the next matching ")" if the token is TK_LP.
**
** Example: (Note: '.' used in place of '*' in the example z[] text)
**
** ,--------- *piToken := TK_RP
** v
** z[] = " /.comment./ --comment\n (two three four) five"
** | |
** |<-------------------------------------->|
** |
** `--- return value
*/
static int getConstraintToken(const u8 *z, int *piToken){
int iOff = 0;
int t = 0;
do {
iOff += sqlite3GetToken(&z[iOff], &t);
}while( t==TK_SPACE || t==TK_COMMENT );
*piToken = t;
if( t==TK_LP ){
int nNest = 1;
while( nNest>0 ){
iOff += sqlite3GetToken(&z[iOff], &t);
if( t==TK_LP ){
nNest++;
}else if( t==TK_RP ){
t = TK_LP;
nNest--;
}else if( t==TK_ILLEGAL ){
break;
}
}
}
*piToken = t;
return iOff;
}
/*
** The implementation of internal UDF sqlite_drop_column().
**
@@ -2154,15 +2205,24 @@ static void dropColumnFunc(
goto drop_column_done;
}
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName);
if( iCol<pTab->nCol-1 ){
RenameToken *pEnd;
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName);
pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName);
zEnd = (const char*)pEnd->t.z;
}else{
int eTok;
assert( IsOrdinaryTable(pTab) );
assert( iCol!=0 );
/* Point pCol->t.z at the "," immediately preceding the definition of
** the column being dropped. To do this, start at the name of the
** previous column, and tokenize until the next ",". */
pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol-1].zCnName);
do {
pCol->t.z += getConstraintToken((const u8*)pCol->t.z, &eTok);
}while( eTok!=TK_COMMA );
pCol->t.z--;
zEnd = (const char*)&zSql[pTab->u.tab.addColOffset];
while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--;
}
zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd);
@@ -2346,56 +2406,6 @@ static int getWhitespace(const u8 *z){
}
/*
** Return the number of bytes until the end of the next non-whitespace and
** non-comment token. For the purpose of this function, a "(" token includes
** all of the bytes through and including the matching ")", or until the
** first illegal token, whichever comes first.
**
** Write the token type into *piToken.
**
** The value returned is the number of bytes in the token itself plus
** the number of bytes of leading whitespace and comments skipped plus
** all bytes through the next matching ")" if the token is TK_LP.
**
** Example: (Note: '.' used in place of '*' in the example z[] text)
**
** ,--------- *piToken := TK_RP
** v
** z[] = " /.comment./ --comment\n (two three four) five"
** | |
** |<-------------------------------------->|
** |
** `--- return value
*/
static int getConstraintToken(const u8 *z, int *piToken){
int iOff = 0;
int t = 0;
do {
iOff += sqlite3GetToken(&z[iOff], &t);
}while( t==TK_SPACE || t==TK_COMMENT );
*piToken = t;
if( t==TK_LP ){
int nNest = 1;
while( nNest>0 ){
iOff += sqlite3GetToken(&z[iOff], &t);
if( t==TK_LP ){
nNest++;
}else if( t==TK_RP ){
t = TK_LP;
nNest--;
}else if( t==TK_ILLEGAL ){
break;
}
}
}
*piToken = t;
return iOff;
}
/*
** Argument z points into the body of a constraint - specifically the
** second token of the constraint definition. For a named constraint,

View File

@@ -935,34 +935,22 @@ Expr *sqlite3ExprAlloc(
int dequote /* True to dequote */
){
Expr *pNew;
int nExtra = 0;
int iValue = 0;
int nExtra = pToken ? pToken->n+1 : 0;
assert( db!=0 );
if( pToken ){
if( op!=TK_INTEGER || pToken->z==0
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
nExtra = pToken->n+1; /* tag-20240227-a */
assert( iValue>=0 );
}
}
pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra);
if( pNew ){
memset(pNew, 0, sizeof(Expr));
pNew->op = (u8)op;
pNew->iAgg = -1;
if( pToken ){
if( nExtra==0 ){
pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse);
pNew->u.iValue = iValue;
}else{
pNew->u.zToken = (char*)&pNew[1];
assert( pToken->z!=0 || pToken->n==0 );
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
pNew->u.zToken[pToken->n] = 0;
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
sqlite3DequoteExpr(pNew);
}
if( nExtra ){
assert( pToken!=0 );
pNew->u.zToken = (char*)&pNew[1];
assert( pToken->z!=0 || pToken->n==0 );
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
pNew->u.zToken[pToken->n] = 0;
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
sqlite3DequoteExpr(pNew);
}
}
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -987,6 +975,24 @@ Expr *sqlite3Expr(
return sqlite3ExprAlloc(db, op, &x, 0);
}
/*
** Allocate an expression for a 32-bit signed integer literal.
*/
Expr *sqlite3ExprInt32(sqlite3 *db, int iVal){
Expr *pNew = sqlite3DbMallocRawNN(db, sizeof(Expr));
if( pNew ){
memset(pNew, 0, sizeof(Expr));
pNew->op = TK_INTEGER;
pNew->iAgg = -1;
pNew->flags = EP_IntValue|EP_Leaf|(iVal?EP_IsTrue:EP_IsFalse);
pNew->u.iValue = iVal;
#if SQLITE_MAX_EXPR_DEPTH>0
pNew->nHeight = 1;
#endif
}
return pNew;
}
/*
** Attach subtrees pLeft and pRight to the Expr node pRoot.
**
@@ -1149,7 +1155,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
){
sqlite3ExprDeferredDelete(pParse, pLeft);
sqlite3ExprDeferredDelete(pParse, pRight);
return sqlite3Expr(db, TK_INTEGER, "0");
return sqlite3ExprInt32(db, 0);
}else{
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
}
@@ -2624,7 +2630,7 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag){
/*
** Walk an expression tree. Return non-zero if the expression is constant
** and 0 if it involves variables or function calls.
** or return zero if the expression involves variables or function calls.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
@@ -3891,9 +3897,22 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
pParse->nMem += nReg;
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
dest.iSdst = dest.iSDParm;
if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){
/* If there is both a DISTINCT and an OFFSET clause, then allocate
** a separate dest.iSdst array for sqlite3Select() and other
** routines to populate. In this case results will be copied over
** into the dest.iSDParm array only after OFFSET processing. This
** ensures that in the case where OFFSET excludes all rows, the
** dest.iSDParm array is not left populated with the contents of the
** last row visited - it should be all NULLs if all rows were
** excluded by OFFSET. */
dest.iSdst = pParse->nMem+1;
pParse->nMem += nReg;
}else{
dest.iSdst = dest.iSDParm;
}
dest.nSdst = nReg;
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem);
VdbeComment((v, "Init subquery result"));
}else{
dest.eDest = SRT_Exists;
@@ -3909,7 +3928,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|| (pLeft->u.iValue!=1 && pLeft->u.iValue!=0)
){
sqlite3 *db = pParse->db;
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
pLimit = sqlite3ExprInt32(db, 0);
if( pLimit ){
pLimit->affExpr = SQLITE_AFF_NUMERIC;
pLimit = sqlite3PExpr(pParse, TK_NE,
@@ -3920,7 +3939,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
}
}else{
/* If there is no pre-existing limit add a limit of 1 */
pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
pLimit = sqlite3ExprInt32(pParse->db, 1);
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
}
pSel->iLimit = 0;

View File

@@ -1169,7 +1169,12 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
term(A) ::= INTEGER(X). {
A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
int iValue;
if( sqlite3GetInt32(X.z, &iValue)==0 ){
A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 0);
}else{
A = sqlite3ExprInt32(pParse->db, iValue);
}
if( A ) A->w.iOfst = (int)(X.z - pParse->zTail);
}
expr(A) ::= VARIABLE(X). {
@@ -1351,43 +1356,67 @@ expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
if( A ) A->flags |= EP_InfixFunc;
}
expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);}
expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);}
%include {
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
** unary TK_ISNULL or TK_NOTNULL expression. */
static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
sqlite3 *db = pParse->db;
if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){
pA->op = (u8)op;
sqlite3ExprDelete(db, pA->pRight);
pA->pRight = 0;
/* Create a TK_ISNULL or TK_NOTNULL expression, perhaps optimized to
** to TK_TRUEFALSE, if possible */
static Expr *sqlite3PExprIsNull(
Parse *pParse, /* Parsing context */
int op, /* TK_ISNULL or TK_NOTNULL */
Expr *pLeft /* Operand */
){
Expr *p = pLeft;
assert( op==TK_ISNULL || op==TK_NOTNULL );
assert( pLeft!=0 );
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
p = p->pLeft;
assert( p!=0 );
}
switch( p->op ){
case TK_INTEGER:
case TK_STRING:
case TK_FLOAT:
case TK_BLOB:
sqlite3ExprDeferredDelete(pParse, pLeft);
return sqlite3ExprInt32(pParse->db, op==TK_NOTNULL);
default:
break;
}
return sqlite3PExpr(pParse, op, pLeft, 0);
}
/* Create a TK_IS or TK_ISNOT operator, perhaps optimized to
** TK_ISNULL or TK_NOTNULL or TK_TRUEFALSE. */
static Expr *sqlite3PExprIs(
Parse *pParse, /* Parsing context */
int op, /* TK_IS or TK_ISNOT */
Expr *pLeft, /* Left operand */
Expr *pRight /* Right operand */
){
if( pRight && pRight->op==TK_NULL ){
sqlite3ExprDeferredDelete(pParse, pRight);
return sqlite3PExprIsNull(pParse, op==TK_IS ? TK_ISNULL : TK_NOTNULL, pLeft);
}
return sqlite3PExpr(pParse, op, pLeft, pRight);
}
}
// expr1 IS expr2
// expr1 IS NOT expr2
expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExprIsNull(pParse,@E,A);}
expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExprIsNull(pParse,TK_NOTNULL,A);}
// expr1 IS expr2 same as expr1 IS NOT DISTICT FROM expr2
// expr1 IS NOT expr2 same as expr1 IS DISTINCT FROM expr2
//
// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2
// is any other expression, code as TK_IS or TK_ISNOT.
//
expr(A) ::= expr(A) IS expr(Y). {
A = sqlite3PExpr(pParse,TK_IS,A,Y);
binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
A = sqlite3PExprIs(pParse, TK_IS, A, Y);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
A = sqlite3PExprIs(pParse, TK_ISNOT, A, Y);
}
expr(A) ::= expr(A) IS NOT DISTINCT FROM expr(Y). {
A = sqlite3PExpr(pParse,TK_IS,A,Y);
binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
A = sqlite3PExprIs(pParse, TK_IS, A, Y);
}
expr(A) ::= expr(A) IS DISTINCT FROM expr(Y). {
A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
A = sqlite3PExprIs(pParse, TK_ISNOT, A, Y);
}
expr(A) ::= NOT(B) expr(X).

View File

@@ -1656,10 +1656,8 @@ static int resolveCompoundOrderBy(
/* Convert the ORDER BY term into an integer column number iCol,
** taking care to preserve the COLLATE clause if it exists. */
if( !IN_RENAME_OBJECT ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
Expr *pNew = sqlite3ExprInt32(db, iCol);
if( pNew==0 ) return 1;
pNew->flags |= EP_IntValue;
pNew->u.iValue = iCol;
if( pItem->pExpr==pE ){
pItem->pExpr = pNew;
}else{

View File

@@ -1445,9 +1445,14 @@ static void selectInnerLoop(
assert( nResultCol<=pDest->nSdst );
pushOntoSorter(
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
pDest->iSDParm = regResult;
}else{
assert( nResultCol==pDest->nSdst );
assert( regResult==iParm );
if( regResult!=iParm ){
/* This occurs in cases where the SELECT had both a DISTINCT and
** an OFFSET clause. */
sqlite3VdbeAddOp3(v, OP_Copy, regResult, iParm, nResultCol-1);
}
/* The LIMIT clause will jump out of the loop for us */
}
break;
@@ -3612,10 +3617,8 @@ static int multiSelectOrderBy(
if( pItem->u.x.iOrderByCol==i ) break;
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
Expr *pNew = sqlite3ExprInt32(db, i);
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
}
@@ -7131,7 +7134,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
&& pExpr->pAggInfo==0
){
sqlite3 *db = pWalker->pParse->db;
Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
Expr *pNew = sqlite3ExprInt32(db, 1);
if( pNew ){
Expr *pWhere = pS->pWhere;
SWAP(Expr, *pNew, *pExpr);

View File

@@ -2391,6 +2391,8 @@ static void shellFormatSchema(
for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
if( c==cEnd ){
cEnd = 0;
}else if( cEnd!=0){
/* No-op */
}else if( c=='"' || c=='\'' || c=='`' ){
cEnd = c;
}else if( c=='[' ){

View File

@@ -4933,6 +4933,7 @@ int sqlite3NoTempsInRange(Parse*,int,int);
#endif
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
Expr *sqlite3Expr(sqlite3*,int,const char*);
Expr *sqlite3ExprInt32(sqlite3*,int);
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
void sqlite3PExprAddSelect(Parse*, Expr*, Select*);

View File

@@ -2361,6 +2361,10 @@ static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
}else if( strcmp(zArg,"-null")==0 ){
qrf.zNull = Tcl_GetString(objv[i+1]);
i++;
}else if( strcmp(zArg,"-version")==0 ){
/* Undocumented. Testing use only */
qrf.iVersion = atoi(Tcl_GetString(objv[i+1]));
i++;
}else{
Tcl_AppendResult(pDb->interp, "unknown option: ", zArg, (char*)0);
rc = TCL_ERROR;

View File

@@ -1609,13 +1609,11 @@ static void whereAddLimitExpr(
int iVal = 0;
if( sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){
Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0);
Expr *pVal = sqlite3ExprInt32(db, iVal);
if( pVal==0 ) return;
ExprSetProperty(pVal, EP_IntValue);
pVal->u.iValue = iVal;
pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);
}else{
Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0);
Expr *pVal = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0);
if( pVal==0 ) return;
pVal->iTable = iReg;
pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);

View File

@@ -717,7 +717,7 @@ void sqlite3WindowUpdate(
pWin->eEnd = aUp[i].eEnd;
pWin->eExclude = 0;
if( pWin->eStart==TK_FOLLOWING ){
pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1");
pWin->pStart = sqlite3ExprInt32(db, 1);
}
break;
}
@@ -1062,9 +1062,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
** keep everything legal in this case.
*/
if( pSublist==0 ){
pSublist = sqlite3ExprListAppend(pParse, 0,
sqlite3Expr(db, TK_INTEGER, "0")
);
pSublist = sqlite3ExprListAppend(pParse, 0, sqlite3ExprInt32(db, 0));
}
pSub = sqlite3SelectNew(

View File

@@ -778,4 +778,52 @@ do_execsql_test 31.2 {
SELECT rr FROM t1 LIMIT 1
} {5.0}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 32.1.0 {
CREATE TABLE t1(
a INT,
b INT,
-- comment with comma
c INT
);
}
do_execsql_test 32.1.1 {
ALTER TABLE t1 DROP COLUMN c;
}
do_execsql_test 32.1.2 {
SELECT sql FROM sqlite_schema
} {{CREATE TABLE t1(
a INT,
b INT)}}
reset_db
do_execsql_test 32.2.0 {
CREATE TABLE t1(
a INT,
b INT,
-- comment with, comma
c INT
);
}
do_execsql_test 32.2.1 {
ALTER TABLE t1 DROP COLUMN c;
}
do_execsql_test 32.2.2 {
SELECT sql FROM sqlite_schema
} {{CREATE TABLE t1(
a INT,
b INT)}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 33.1 {
CREATE TABLE x1(a TEXT, b INTEGER, c CHECK(c!=0));
}
do_execsql_test 33.2 {
ALTER TABLE x1 DROP COLUMN b;
SELECT sql FROM sqlite_schema;
} {{CREATE TABLE x1(a TEXT, c CHECK(c!=0))}}
finish_test

37
test/qrf05.test Normal file
View File

@@ -0,0 +1,37 @@
# 2025-12-02
#
# 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 the Query Result Formatter (QRF)
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix qrf05
do_execsql_test 1.0 {
CREATE TABLE t1(a INT NOT NULL);
}
do_test 1.1 {
set rc [catch {db format -style list \
{INSERT INTO t1 VALUES(123) RETURNING *}} msg]
list $rc [string trim $msg]
} {0 123}
do_test 1.2 {
set rc [catch {db format -style list \
{INSERT INTO t1 VALUES(NULL) RETURNING *}} msg]
list $rc [string trim $msg]
} {1 {NOT NULL constraint failed: t1.a}}
do_test 1.3 {
set rc [catch {db format -version 99 {SELECT * FROM t1}} msg]
list $rc [string trim $msg]
} {1 {unusable sqlite3_qrf_spec.iVersion (99)}}
finish_test

576
test/qrf06.test Normal file
View File

@@ -0,0 +1,576 @@
# 2025-12-02
#
# 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 the Query Result Formatter (QRF), and especially
# the sqlite3_qrf_wcwidth() function and its utilization.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix qrf06
# Data
db eval {
BEGIN TRANSACTION;
CREATE TABLE language(name TEXT);
INSERT INTO language(name) VALUES
('العربية'),
('Deutsch'),
('English'),
('Español'),
('فارسی'),
('Français'),
('Italiano'),
('مصرى'),
('Nederlands'),
('日本語'),
('Polski'),
('Português'),
('Sinugboanong Binisaya'),
('Svenska'),
('Українська'),
('Tiếng Việt'),
('Winaray'),
('中文'),
('Русский'),
('Afrikaans'),
('Shqip'),
('Asturianu'),
('Azərbaycanca'),
('Български'),
('閩南語 / Bân-lâm-gú'),
('বাংলা'),
('Беларуская'),
('Català'),
('Čeština'),
('Cymraeg'),
('Dansk'),
('Eesti'),
('Ελληνικά'),
('Esperanto'),
('Euskara'),
('Galego'),
('한국어'),
('Հայերեն'),
('हिन्दी'),
('Hrvatski'),
('Bahasa Indonesia'),
('עברית'),
('ქართული'),
('Ladin'),
('Latina'),
('Latviešu'),
('Lietuvių'),
('Magyar'),
('Македонски'),
('Malagasy'),
('मराठी'),
('Bahasa Melayu'),
('Bahaso Minangkabau'),
('မြန်မာဘာသာ'),
('Norskbokmålnynorsk'),
('Нохчийн'),
('Oʻzbekcha / Ўзбекча'),
('Қазақша / Qazaqşa / قازاقشا'),
('Română'),
('Simple English'),
('Slovenčina'),
('Slovenščina'),
('Српски / Srpski'),
('Srpskohrvatski / Српскохрватски'),
('Suomi'),
('Kiswahili'),
('தமிழ்'),
('Татарча / Tatarça'),
('తెలుగు'),
('ภาษาไทย'),
('Тоҷикӣ'),
('تۆرکجه'),
('Türkçe'),
('اردو'),
('粵語'),
('Bahsa Acèh'),
('Alemannisch'),
('አማርኛ'),
('Aragonés'),
('Արեւմտահայերէն'),
('Bahasa Hulontalo'),
('Basa Bali'),
('Bahasa Banjar'),
('Basa Banyumasan'),
('Башҡортса'),
('Беларуская (тарашкевіца)'),
('Bikol Central'),
('বিষ্ণুপ্রিয়া মণিপুরী'),
('Boarisch'),
('Bosanski'),
('Brezhoneg'),
('Чӑвашла'),
('Dagbanli'),
('الدارجة'),
('Diné Bizaad'),
('Emigliàn–Rumagnòl'),
('Fiji Hindi'),
('Føroyskt'),
('Frysk'),
('Fulfulde'),
('Gaeilge'),
('Gàidhlig'),
('گیلکی'),
('ગુજરાતી'),
('Hak-kâ-ngî / 客家語'),
('Hausa'),
('Hornjoserbsce'),
('Ido'),
('Igbo'),
('Ilokano'),
('Interlingua'),
('Interlingue'),
('Ирон'),
('Íslenska'),
('Jawa'),
('ಕನ್ನಡ'),
('Kapampangan'),
('ភាសាខ្មែរ'),
('Kotava'),
('Kreyòl Ayisyen'),
('Kurdî / كوردی'),
('کوردیی ناوەندی'),
('Кыргызча'),
('Кырык мары'),
('Lëtzebuergesch'),
('Lìgure'),
('Limburgs'),
('Lombard'),
('मैथिली'),
('മലയാളം'),
('მარგალური'),
('مازِرونی'),
('Mìng-dĕ̤ng-ngṳ̄ / 閩東語'),
('Монгол'),
('Napulitano'),
('नेपाल भाषा'),
('Nordfriisk'),
('Occitan'),
('Олык марий'),
('ଓଡି଼ଆ'),
('অসমীযা়'),
('ਪੰਜਾਬੀ'),
('پنجابی (شاہ مکھی)'),
('پښتو'),
('Piemontèis'),
('Plattdüütsch'),
('Qaraqalpaqsha'),
('Qırımtatarca'),
('Runa Simi'),
('Русиньскый'),
('संस्कृतम्'),
('ᱥᱟᱱᱛᱟᱲᱤ'),
('سرائیکی'),
('Саха Тыла'),
('Scots'),
('ChiShona'),
('Sicilianu'),
('සිංහල'),
('سنڌي'),
('Ślůnski'),
('Basa Sunda'),
('Taclḥit'),
('Tagalog'),
('ၽႃႇသႃႇတႆး'),
('ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ'),
('tolışi'),
('chiTumbuka'),
('Basa Ugi'),
('Vèneto'),
('Volapük'),
('Walon'),
('文言'),
('吴语'),
('ייִדיש'),
('Yorùbá'),
('Zazaki'),
('žemaitėška'),
('isiZulu'),
('नेपाली'),
('ꯃꯤꯇꯩ ꯂꯣꯟ'),
('Dzhudezmo / לאדינו'),
('Адыгэбзэ'),
('Ænglisc'),
('Anarâškielâ'),
('अंगिका'),
('Аԥсшәа'),
('armãneashti'),
('Arpitan'),
('atikamekw'),
('ܐܬܘܪܝܐ'),
('Avañe’ẽ'),
('Авар'),
('Aymar'),
('Batak Toba'),
('Betawi'),
('भोजपुरी'),
('Bislama'),
('བོད་ཡིག'),
('Буряад'),
('Chavacano de Zamboanga'),
('Chichewa'),
('Corsu'),
('Vahcuengh / 話僮'),
('Dagaare'),
('Davvisámegiella'),
('Deitsch'),
('ދިވެހިބަސް'),
('Dolnoserbski'),
('Dusun Bundu-liwan'),
('Эрзянь'),
('Estremeñu'),
('Eʋegbe'),
('Farefare'),
('Fɔ̀ngbè'),
('Furlan'),
('Gaelg'),
('Gagauz'),
('ГӀалгӀай'),
('Ghanaian Pidgin'),
('Gĩkũyũ'),
('赣语 / 贛語'),
('Gungbe'),
('Хальмг'),
('ʻŌlelo Hawaiʻi'),
('Ikinyarwanda'),
('Jaku Iban'),
('Kabɩyɛ'),
('Yerwa Kanuri'),
('Kaszëbsczi'),
('Kernewek'),
('Коми'),
('Перем коми'),
('Kongo'),
('कोंकणी / Konknni'),
('كٲشُر'),
('Kriyòl Gwiyannen'),
('Kumoring'),
('Kʋsaal'),
('ພາສາລາວ'),
('Лакку'),
('Latgaļu'),
('Лезги'),
('Li Niha'),
('Lingála'),
('Lingua Franca Nova'),
('livvinkarjala'),
('lojban'),
('Luganda'),
('Madhurâ'),
('Malti'),
('Mandailing'),
('Māori'),
('Mfantse'),
('Mirandés'),
('Мокшень'),
('ဘာသာ မန်'),
('Moore'),
('ߒߞߏ'),
('Na Vosa Vaka-Viti'),
('Nāhuatlahtōlli'),
('Naijá'),
('Nedersaksisch'),
('Nouormand / Normaund'),
('Novial'),
('Afaan Oromoo'),
('ပအိုဝ်ႏဘာႏသာႏ'),
('Pangasinán'),
('Pangcah'),
('Papiamentu'),
('Patois'),
('Pfälzisch'),
('Picard'),
('Къарачай–малкъар'),
('Ripoarisch'),
('Rumantsch'),
('Sakizaya'),
('Gagana Sāmoa'),
('Sardu'),
('Seediq'),
('Seeltersk'),
('Sesotho'),
('Sesotho sa Leboa'),
('Setswana'),
('ꠍꠤꠟꠐꠤ'),
('Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ'),
('Soomaaliga'),
('Sranantongo'),
('SiSwati'),
('Reo tahiti'),
('Taqbaylit'),
('Tarandíne'),
('Tayal'),
('Tetun'),
('Tok Pisin'),
('faka Tonga'),
('Türkmençe'),
('Twi'),
('Tyap'),
('Тыва дыл'),
('Удмурт'),
('ئۇيغۇرچه'),
('Vepsän'),
('võro'),
('West-Vlams'),
('Wolof'),
('isiXhosa'),
('Zeêuws'),
('алтай тил'),
('अवधी'),
('डोटेली'),
('ತುಳು'),
('ရခိုင်'),
('Bajau Sama'),
('Bamanankan'),
('Chamoru'),
('རྫོང་ཁ'),
('𐌲𐌿𐍄𐌹𐍃𐌺x'),
('Igala'),
('ᐃᓄᒃᑎᑐᑦ / Inuktitut'),
('Iñupiak'),
('isiNdebele seSewula'),
('Kalaallisut'),
('Nupe'),
('Obolo'),
('पालि'),
('pinayuanan'),
('Ποντιακά'),
('romani čhib'),
('Ikirundi'),
('руски'),
('Sängö'),
('ᥖᥭᥰᥖᥬᥳᥑᥨᥒᥰ'),
('ትግርኛ'),
('Thuɔŋjäŋ'),
('ᏣᎳᎩ'),
('Tsėhesenėstsestotse'),
('Xitsonga'),
('Tshivenḓa'),
('Wayuunaiki'),
('адыгабзэ');
COMMIT;
}
do_test 1.2 {
set res \n[db format -style box {
SELECT name, rowid AS id FROM language
WHERE length(name)=2
ORDER BY name
}]
set exp {
┌──────┬─────┐
│ name │ id │
├──────┼─────┤
│ 中文 │ 18 │
│ 吴语 │ 173 │
│ 文言 │ 172 │
│ 粵語 │ 75 │
└──────┴─────┘
}
if {$res ne $exp} {
puts [list $res]
puts [list $exp]
}
string compare $res $exp
} {0}
do_test 1.3 {
set res \n[db format -style box {
SELECT name, rowid AS id FROM language
WHERE length(name)=3
ORDER BY name
}]
set exp {
┌────────┬─────┐
│ name │ id │
├────────┼─────┤
│ Ido │ 108 │
│ Twi │ 297 │
│ ߒߞߏ │ 258 │
│ ᏣᎳᎩ │ 335 │
│ 日本語 │ 10 │
│ 한국어 │ 37 │
└────────┴─────┘
}
if {$res ne $exp} {
puts [list $res]
puts [list $exp]
}
string compare $res $exp
} {0}
do_test 1.4 {
set res \n[db format -style box {
SELECT name, rowid AS id FROM language
WHERE length(name)=4
ORDER BY name
}]
set exp {
┌──────┬─────┐
│ name │ id │
├──────┼─────┤
│ Igbo │ 109 │
│ Jawa │ 115 │
│ Nupe │ 323 │
│ Tyap │ 298 │
│ võro │ 303 │
│ Авар │ 192 │
│ Ирон │ 113 │
│ Коми │ 231 │
│ اردو │ 74 │
│ سنڌي │ 159 │
│ مصرى │ 8 │
│ پښتو │ 144 │
│ अवधी │ 309 │
│ पालि │ 325 │
│ ತುಳು │ 311 │
│ ትግርኛ │ 333 │
│ አማርኛ │ 78 │
└──────┴─────┘
}
if {$res ne $exp} {
puts [list $res]
puts [list $exp]
}
string compare $res $exp
} {0}
do_test 1.5 {
set res \n[db format -style box {
SELECT name, rowid AS id FROM language
WHERE length(name)=5
ORDER BY name
}]
set exp {
┌───────┬─────┐
│ name │ id │
├───────┼─────┤
│ Aymar │ 193 │
│ Corsu │ 202 │
│ Dansk │ 31 │
│ Eesti │ 32 │
│ Frysk │ 99 │
│ Gaelg │ 216 │
│ Hausa │ 106 │
│ Igala │ 318 │
│ Kongo │ 233 │
│ Ladin │ 44 │
│ Malti │ 250 │
│ Moore │ 257 │
│ Māori │ 252 │
│ Naijá │ 261 │
│ Obolo │ 324 │
│ Sardu │ 278 │
│ Scots │ 155 │
│ Shqip │ 21 │
│ Suomi │ 65 │
│ Sängö │ 331 │
│ Tayal │ 292 │
│ Tetun │ 293 │
│ Walon │ 171 │
│ Wolof │ 305 │
│ Лакку │ 240 │
│ Лезги │ 242 │
│ руски │ 330 │
│ עברית │ 42 │
│ فارسی │ 5 │
│ كٲشُر │ 235 │
│ گیلکی │ 103 │
│ मराठी │ 51 │
│ বাংলা │ 26 │
│ ଓଡି଼ଆ │ 140 │
│ தமிழ் │ 67 │
│ ಕನ್ನಡ │ 116 │
│ සිංහල │ 158 │
│ ꠍꠤꠟꠐꠤ │ 284 │
└───────┴─────┘
}
if {$res ne $exp} {
puts [list $res]
puts [list $exp]
}
string compare $res $exp
} {0}
do_test 1.6 {
set res \n[db format -style box {
SELECT name, rowid AS id FROM language
WHERE length(name)=6
ORDER BY name
}]
set exp {
┌────────┬─────┐
│ name │ id │
├────────┼─────┤
│ Betawi │ 195 │
│ Català │ 28 │
│ Eʋegbe │ 212 │
│ Furlan │ 215 │
│ Gagauz │ 217 │
│ Galego │ 36 │
│ Gungbe │ 222 │
│ Gĩkũyũ │ 220 │
│ Kabɩyɛ │ 227 │
│ Kotava │ 119 │
│ Kʋsaal │ 238 │
│ Latina │ 45 │
│ Lìgure │ 126 │
│ Magyar │ 48 │
│ Novial │ 264 │
│ Patois │ 270 │
│ Picard │ 272 │
│ Polski │ 11 │
│ Română │ 59 │
│ Seediq │ 279 │
│ Türkçe │ 73 │
│ Vepsän │ 302 │
│ Vèneto │ 169 │
│ Yorùbá │ 175 │
│ Zazaki │ 176 │
│ Zeêuws │ 307 │
│ lojban │ 247 │
│ tolışi │ 166 │
│ Аԥсшәа │ 186 │
│ Буряад │ 199 │
│ Монгол │ 134 │
│ Тоҷикӣ │ 71 │
│ Удмурт │ 300 │
│ Хальмг │ 223 │
│ Эрзянь │ 210 │
│ ייִדיש │ 174 │
│ تۆرکجه │ 72 │
│ ܐܬܘܪܝܐ │ 190 │
│ अंगिका │ 185 │
│ डोटेली │ 310 │
│ नेपाली │ 179 │
│ मैथिली │ 129 │
│ हिन्दी │ 39 │
│ ਪੰਜਾਬੀ │ 142 │
│ తెలుగు │ 69 │
│ മലയാളം │ 130 │
│ རྫོང་ཁ │ 316 │
│ ရခိုင် │ 312 │
└────────┴─────┘
}
if {$res ne $exp} {
puts [list $res]
puts [list $exp]
}
string compare $res $exp
} {0}
finish_test

View File

@@ -615,6 +615,20 @@ CREATE VIEW v1 AS SELECT y+1 FROM v2
catch {db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}}
}
do_test shell1-3.21.5 {
exec {*}$CLI -noinit test.db \
{CREATE TABLE t2(a INTEGER PRIMARY KEY, b BLOB DEFAULT(jsonb('[]')),c TEXT NOT NULL)STRICT;} \
{.schema -indent t2}
} {CREATE TABLE t2(
a INTEGER PRIMARY KEY,
b BLOB DEFAULT(jsonb('[]')),
c TEXT NOT NULL
)STRICT;}
do_test shell1-3.21.6 {
exec {*}$CLI -noinit test.db \
{DROP TABLE t2;} \
{.schema -indent t2}
} {}
# .separator STRING Change column separator used by output and .import
do_test shell1-3.22.1 {

View File

@@ -215,4 +215,72 @@ do_execsql_test 5.1 {
SELECT ( SELECT y FROM t2 WHERE x = y ORDER BY y, z) FROM t1;
} {ALFKI ANATR}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1234);
}
do_execsql_test 6.1 {
SELECT DISTINCT 'string' FROM t1 LIMIT 1 OFFSET 5;
}
do_execsql_test 6.2 {
SELECT (
SELECT 'string' FROM t1 LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 6.3 {
SELECT (
SELECT DISTINCT 'string' FROM t1 LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 6.4 {
SELECT (
SELECT DISTINCT 'string' FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 6.5 {
SELECT (
SELECT 'string' FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 6.6 {
SELECT (SELECT DISTINCT x, x FROM t1 LIMIT 1 OFFSET 5)==(1234, 1234)
} {{}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
CREATE TABLE t1(x);
CREATE INDEX i1 ON t1(x);
INSERT INTO t1 VALUES(1234);
}
do_execsql_test 7.1 {
SELECT (
SELECT DISTINCT 'string' FROM t1 ORDER BY x LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 7.2 {
DROP INDEX i1;
CREATE UNIQUE INDEX i1 ON t1(x);
}
do_execsql_test 7.3 {
SELECT (
SELECT DISTINCT x FROM t1 ORDER BY 1 LIMIT 1 OFFSET 5
);
} {{}}
do_execsql_test 7.4 {
SELECT (SELECT DISTINCT x FROM t1 ORDER BY +x LIMIT 1 OFFSET 0);
} {1234}
finish_test