1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge the latest trunk enhancements into the reuse-schema branch.

FossilOrigin-Name: c2d4adabb929b6088808b05a2f031d045eb4839b44548a66006dc21e358e71f4
This commit is contained in:
drh
2024-03-18 18:56:10 +00:00
22 changed files with 1251 additions and 184 deletions

View File

@@ -819,8 +819,7 @@ has_tclsh85:
touch .target_source touch .target_source
sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84 sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) \ $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
$(EXTRA_SRC)
cp tsrc/sqlite3ext.h . cp tsrc/sqlite3ext.h .
cp $(TOP)/ext/session/sqlite3session.h . cp $(TOP)/ext/session/sqlite3session.h .
@@ -831,8 +830,7 @@ sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
cp $(TOP)/ext/recover/sqlite3recover.c tsrc/ cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
cp $(TOP)/ext/recover/sqlite3recover.h tsrc/ cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
cp $(TOP)/ext/recover/dbdata.c tsrc/ cp $(TOP)/ext/recover/dbdata.c tsrc/
$(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover \ $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
$(AMALGAMATION_LINE_MACROS) $(EXTRA_SRC)
sqlite3ext.h: .target_source sqlite3ext.h: .target_source
cp tsrc/sqlite3ext.h . cp tsrc/sqlite3ext.h .

View File

@@ -51,7 +51,7 @@
*/ */
"use strict"; "use strict";
const wPost = (type,...args)=>postMessage({type, payload:args}); const wPost = (type,...args)=>postMessage({type, payload:args});
const installAsyncProxy = function(self){ const installAsyncProxy = function(){
const toss = function(...args){throw new Error(args.join(' '))}; const toss = function(...args){throw new Error(args.join(' '))};
if(globalThis.window === globalThis){ if(globalThis.window === globalThis){
toss("This code cannot run from the main thread.", toss("This code cannot run from the main thread.",
@@ -563,12 +563,9 @@ const installAsyncProxy = function(self){
return; return;
} }
if( state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags ){ if( state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN & opfsFlags ){
//log("async proxy opfsFlags =",opfsFlags);
try{ try{
await hDir.removeEntry(filenamePart); await hDir.removeEntry(filenamePart);
//log("Unlinked",filename,hDir,filenamePart); }catch(e){
}
catch(e){
/* ignoring */ /* ignoring */
//warn("Ignoring failed Unlink of",filename,":",e); //warn("Ignoring failed Unlink of",filename,":",e);
} }
@@ -922,5 +919,5 @@ if(!globalThis.SharedArrayBuffer){
!navigator?.storage?.getDirectory){ !navigator?.storage?.getDirectory){
wPost('opfs-unavailable',"Missing required OPFS APIs."); wPost('opfs-unavailable',"Missing required OPFS APIs.");
}else{ }else{
installAsyncProxy(self); installAsyncProxy();
} }

View File

@@ -1,9 +1,9 @@
C Do\snot\sautomatically\sactivate\sSQLITE_ENABLE_SHARED_SCHEMA\sin\sthe\nMakefile.\s\sInstead,\senhance\sthe\smdevtest\sand\ssdevtest\stargets\sof\ntestrunner.tcl\sto\sset\sthat\soption\ssometimes\sand\ssometimes\snot. C Merge\sthe\slatest\strunk\senhancements\sinto\sthe\sreuse-schema\sbranch.
D 2024-03-13T16:49:36.651 D 2024-03-18T18:56:10.107
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in da128eae24b56cbbf05e131d3342323846ea62a534a964d32fb7f06ae974f89f F Makefile.in e4803e664ceb8ddbc3f9ead25cbe0b3d3def21a77c175124b421e6a53b105b8d
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6 F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
F Makefile.msc a6f772c667c3a967c1a65b8f7bf1502b73001052567b5c7702cde8dc80f2568b F Makefile.msc a6f772c667c3a967c1a65b8f7bf1502b73001052567b5c7702cde8dc80f2568b
F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3 F README.md 6358805260a03ebead84e168bbf3740ddf3f683b477e478567186aa7afb490d3
@@ -611,7 +611,7 @@ F ext/wasm/api/sqlite3-api-oo1.js 7f3bcf0549ac44cde4b9da0b642d771916738d3f6781fb
F ext/wasm/api/sqlite3-api-prologue.js 93a72b07b2a5d964d2edc76a90b439ece49298bd7ba60a1c6ae5d4878213701e F ext/wasm/api/sqlite3-api-prologue.js 93a72b07b2a5d964d2edc76a90b439ece49298bd7ba60a1c6ae5d4878213701e
F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b5985e309b69bf71187b525cf F ext/wasm/api/sqlite3-api-worker1.js 8d9c0562831f62218170a3373468d8a0b7a6503b5985e309b69bf71187b525cf
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js b4c7ce9d7f7957f243d0fbd5b6e28bac80cd3c1b738374cd0c96d89df8f2f316 F ext/wasm/api/sqlite3-opfs-async-proxy.js 196ad83d36ca794e564044788c9d21b964679d63cad865f604da37c4afc9a285
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 5a430874906ff3f4a6ca69aadf0c2aaedc1bb45489b8365bff7e955a83a8d42a F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 5a430874906ff3f4a6ca69aadf0c2aaedc1bb45489b8365bff7e955a83a8d42a
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3c72f1a0e6a7343c8c882d29d01bb440f10be12c844651605b486e76f3d6cc8c F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 3c72f1a0e6a7343c8c882d29d01bb440f10be12c844651605b486e76f3d6cc8c
@@ -701,7 +701,7 @@ F src/date.c 126ba2ab10aeb2e7ba6e089b5f07b747c0625b8287f78b60da346eda8d23c875
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782 F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43 F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500 F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
F src/expr.c 05516e8b7d7d22f98160a0360fde69edce3304a430600567ed33e66d588ca59b F src/expr.c d7cfe9b9fe7ab47b254706589467d2e65fec3536b936d6f4eb28b84da6726ecc
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00 F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb F src/func.c 4204c56196847faefef57fa14e43b8e4d65eb8d7e65318abe463472e3fd148cb
@@ -710,7 +710,7 @@ F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c eb33ea46dcab93e90f112fced343aaf41f59cbd2e951d5066f1f9302be1c2f34 F src/insert.c 06ce505713e86172612f9e01febefd2d3331d1f70461b4ada0eae5a76bb6349f
F src/json.c e2e40760d6689134c3e2ece38c6a496b34ff5e2661a8f238444a119af666fdce F src/json.c e2e40760d6689134c3e2ece38c6a496b34ff5e2661a8f238444a119af666fdce
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
@@ -740,23 +740,23 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
F src/parse.y 6209f01e8e7495379571454744fa82a5cfc2e7eeb89e46dee3f410d73ea6252d F src/parse.y 5bcef16094213efcc365a9d4dc4e3131f09251dc8838dce4a9e5f9764bff5b82
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75 F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00 F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
F src/pragma.c e921676f6c29502c681b53d0c5d609a8780eaeeddbaa76459aa7607efc6a2760 F src/pragma.c e921676f6c29502c681b53d0c5d609a8780eaeeddbaa76459aa7607efc6a2760
F src/pragma.h 50f6d3b408ed56bde4f4e4aead8c0b2022030b692e8de237c1b7a0b5ce87a0c8 F src/pragma.h 50f6d3b408ed56bde4f4e4aead8c0b2022030b692e8de237c1b7a0b5ce87a0c8
F src/prepare.c 9fe59f2cf0b75554982ffe906c83ebe478354b6d981ed0c143cc9f2f58c9210a F src/prepare.c 9fe59f2cf0b75554982ffe906c83ebe478354b6d981ed0c143cc9f2f58c9210a
F src/printf.c 10e8bad30042f8bd6114a013b4afc229ec8ad255ab27518d7d9f52e8cbc5cd0a F src/printf.c 87b67bba3662a0523f39ae6b084a3907109702f717c654d6cecb838af5cd57f1
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c ef87e3bc7700bfe761a7bbee2ce6084f1766dc816dd82a3ae77c133eec898432 F src/resolve.c ef87e3bc7700bfe761a7bbee2ce6084f1766dc816dd82a3ae77c133eec898432
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 43fabfc01bf87addd15e39f112f1e2ade15b19594835ab8a9e5bd50839d4e1b1 F src/select.c df2bf515fc36e02e97959a70e82da8a4967d6c85590646a7fda2926a734c81ce
F src/shell.c.in 736d540ed0704e567767c712e1c1c6a3e2f87bb8b7bc9020febb121ee2f70abe F src/shell.c.in 736d540ed0704e567767c712e1c1c6a3e2f87bb8b7bc9020febb121ee2f70abe
F src/sqlite.h.in 1e317e1d0a17becd7ad9d1d30f2a248d78440d3ca2befead0e747043ebb1989a F src/sqlite.h.in 1e317e1d0a17becd7ad9d1d30f2a248d78440d3ca2befead0e747043ebb1989a
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 1e23a22284150bd911b2cb5a041a7f315f5c92167db7822188f970b69f7fa224 F src/sqliteInt.h c472e384c0d70a352ce7239a29a799b93ee6d8bc385bbf0be7e8afcbc525b131
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728 F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
F src/status.c 5028a0afee355aa492f26f0b6a3ec23145caa9261a93164d96cd0b9bf1b2318f F src/status.c 5028a0afee355aa492f26f0b6a3ec23145caa9261a93164d96cd0b9bf1b2318f
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -837,11 +837,11 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
F src/where.c 6e171826508b08356a3a103a6739eb538d755578fdc1dbf5db84f574672db672 F src/where.c a34a0eeb04a6c5916b576752dfdca8947c46d2463a2c9805919c8d781b3bdd1f
F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8 F src/whereInt.h 82a13766f13d1a53b05387c2e60726289ef26404bc7b9b1f7770204d97357fb8
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1 F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c 6ebd90b553f4bb5c7df5a4b2f39b6a7c81a67484353827cdd2048f2514ec6f30 F src/whereexpr.c 7b64295f1d82ad0928df435925dd7bbd5997b44a026153113eace0d9e71ff435
F src/window.c 5b1387d59df30d481ed14cceef5f4d1dab1f8752aa106ba72c8b62777bd139d2 F src/window.c 5d95122dd330bfaebd732358c8ef067c5a9394a53ac249470d611d0ce2c52be2
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9 F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
@@ -869,7 +869,7 @@ F test/altermalloc3.test 8040e486368403f2fdd6fc3998258b499bd4cc2f3ddbb5f8f874cd4
F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba F test/alterqf.test 8ec03d776de9c391daa0078ea8f838903bdcfb11dfae4ba3576b48436834ccba
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27 F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0 F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16 F test/altertab3.test e167ce3b8e243b52306c1e40b13eb868f402a969513c063998593862cc643b44
F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b F test/altertrig.test aacc980b657354fe2d3d4d3a004f07d04ccc1a93e5ef82d68a79088c274ddc6b
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b F test/analyze.test 2fb21d7d64748636384e6cb8998dbf83968caf644c07fcb4f76c18f2e7ede94b
@@ -1233,7 +1233,7 @@ F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test 504d202650c7940b5aa98364dd68f242df87f39f829e51074a55d79fc7bc7414 F test/func.test 504d202650c7940b5aa98364dd68f242df87f39f829e51074a55d79fc7bc7414
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
F test/func4.test e8ef9b2bd6a192a213cbd5cf31a3b35e25cd6ff2fdaeea0b58d63be31b03d220 F test/func4.test a3f9062487dbd826776f54f4e0e9517fe8c3cf689af92735308965774d51fac5
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
F test/func6.test 9cc9b1f43b435af34fe1416eb1e318c8920448ea7a6962f2121972f5215cb9b0 F test/func6.test 9cc9b1f43b435af34fe1416eb1e318c8920448ea7a6962f2121972f5215cb9b0
F test/func7.test adbfc910385a6ffd15dc47be3c619ef070c542fcb7488964badb17b2d9a4d080 F test/func7.test adbfc910385a6ffd15dc47be3c619ef070c542fcb7488964badb17b2d9a4d080
@@ -1273,7 +1273,7 @@ F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6 F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a F test/in4.test bb767ec1cfd1730256f0a83219f0acda36bc251b63f8b8bb7d8c7cff17875a4f
F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f F test/in5.test b32ce7f4a93f44c5dee94af16886d922cc16ebe33c8e1765c73d4049d0f4b40f
F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b F test/in6.test f5f40d6816a8bb7c784424b58a10ac38efb76ab29127a2c17399e0cbeeda0e4b
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822 F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
@@ -1657,7 +1657,7 @@ F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33 F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb
F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb F test/sqldiff1.test 1b7ab4f312442c5cc6b3a5f299fa8ca051416d1dd173cb1126fd51bf64f2c3fb
F test/sqllimits1.test 5880a2f107185744ba4d93637f44c78d17706a9899a38b694d50f209735c81cc F test/sqllimits1.test dee96a51b83ef866d06ec3c687d4c951d97b02549facc5be88c9dfcb215b98bf
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805 F test/startup.c 1beb5ca66fcc0fce95c3444db9d1674f90fc605499a574ae2434dcfc10d22805
F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408 F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac8408
@@ -1696,7 +1696,7 @@ F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d163
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl ad2bf61b6676442e106c147f6d8b3735a61478f7c6ee9916178139efafc39232 F test/tester.tcl ad2bf61b6676442e106c147f6d8b3735a61478f7c6ee9916178139efafc39232
F test/testrunner.tcl 841b082df19abd3d482f893c82a7795401539ba8f0df321290e5f4392cd167a6 F test/testrunner.tcl 125d68bba59070d73cb4b0a8a17bbff414ee1f8081eafb84fa903d274e0bdbb7
F test/testrunner_data.tcl 140b7201874bb2c98ed413f2c7f7beb069a6ef7b5fa619e9b458e20822f09110 F test/testrunner_data.tcl 140b7201874bb2c98ed413f2c7f7beb069a6ef7b5fa619e9b458e20822f09110
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899 F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502 F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
@@ -1931,6 +1931,8 @@ F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7
F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd
F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb
F test/values.test e7c156f92d32ed645908fbad0a1144f0f31650376cdcb212fde701978c89d3b1
F test/valuesfault.test 2ef23ed965e3bd08e268cdc38a0d11653390ddbbe1e8e2e98d16f55edd30f6e8
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test d4c4281e1679245829db35597817282f60dc513fc39cc5439078f009bd118487 F test/view.test d4c4281e1679245829db35597817282f60dc513fc39cc5439078f009bd118487
@@ -2019,7 +2021,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/whereI.test c4bb7e2ca56d49bd8ab5c7bd085b8b83e353922b46904d68aefb3c7468643581 F test/whereI.test c4bb7e2ca56d49bd8ab5c7bd085b8b83e353922b46904d68aefb3c7468643581
F test/whereJ.test fc05e374cc9f2dc204148d6c06822c380ad388895fe97a6d335b94a26a08aecf F test/whereJ.test fc05e374cc9f2dc204148d6c06822c380ad388895fe97a6d335b94a26a08aecf
F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a F test/whereK.test 0270ab7f04ba5436fb9156d31d642a1c82727f4c4bfe5ba90d435c78cf44684a
F test/whereL.test f0e9585623af522ee9f382f8f945ad4b7eb7d806d18746f33f00c374acf6ab65 F test/whereL.test 438a397fa883b77bb6361c08a8befa41b52e9cfbe15a2a43715d122f8cfa8649
F test/whereM.test 0dbc9998783458ddcf3cc078ca7c2951d8b2677d472ecf0028f449ed327c0250 F test/whereM.test 0dbc9998783458ddcf3cc078ca7c2951d8b2677d472ecf0028f449ed327c0250
F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7 F test/wherefault.test 6cf2a9c5712952d463d3f45ebee7f6caf400984df51a195d884cfb7eb0e837a7
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
@@ -2098,7 +2100,7 @@ F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5 F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
F tool/lemon.c 7f264d5d06450f929a20fa63a1b7e8f2df47dfaa6d7f80e4afef3639157497a4 F tool/lemon.c 2eaee61479f9b97056950741c8f671a13281c819b94246698264a322360319a9
F tool/lempar.c e6b649778e5c027c8365ff01d7ef39297cd7285fa1f881cce31792689541e79f F tool/lempar.c e6b649778e5c027c8365ff01d7ef39297cd7285fa1f881cce31792689541e79f
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9 F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
@@ -2187,8 +2189,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P da47151561fb7045dbfe9967b27c10bfd754bc88f537c43f5e3739b52b703f72 P 693b8f9307fc9d3e00f2a573329f054709ad916a570773c986d32524b4d7522e 76fb3a908f45230b956cb659c754e47603e80aa72a2aad50d479437a9c013f61
R f9ddc79a6ef5671bab269c8fc35a39f2 R aa84582729c32dbdf9ff004281703344
U drh U drh
Z 28013b67504b9c056878bcc413a4fa76 Z 1460fe2e76c9e3a0dadc727534aebd41
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
693b8f9307fc9d3e00f2a573329f054709ad916a570773c986d32524b4d7522e c2d4adabb929b6088808b05a2f031d045eb4839b44548a66006dc21e358e71f4

View File

@@ -218,9 +218,10 @@ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->x.pList->nExpr>0 ); assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION ); assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr; pExpr = pExpr->x.pList->a[0].pExpr;
}else{ }else if( pExpr->op==TK_COLLATE ){
assert( pExpr->op==TK_COLLATE );
pExpr = pExpr->pLeft; pExpr = pExpr->pLeft;
}else{
break;
} }
} }
return pExpr; return pExpr;
@@ -1869,6 +1870,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
pNewItem->iCursor = pOldItem->iCursor; pNewItem->iCursor = pOldItem->iCursor;
pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->addrFillSub = pOldItem->addrFillSub;
pNewItem->regReturn = pOldItem->regReturn; pNewItem->regReturn = pOldItem->regReturn;
pNewItem->regResult = pOldItem->regResult;
if( pNewItem->fg.isIndexedBy ){ if( pNewItem->fg.isIndexedBy ){
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
} }
@@ -2345,6 +2347,54 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
return pExpr; return pExpr;
} }
/*
** pExpr is a TK_FUNCTION node. Try to determine whether or not the
** function is a constant function. A function is constant if all of
** the following are true:
**
** (1) It is a scalar function (not an aggregate or window function)
** (2) It has either the SQLITE_FUNC_CONSTANT or SQLITE_FUNC_SLOCHNG
** property.
** (3) All of its arguments are constants
**
** This routine sets pWalker->eCode to 0 if pExpr is not a constant.
** It makes no changes to pWalker->eCode if pExpr is constant. In
** every case, it returns WRC_Abort.
**
** Called as a service subroutine from exprNodeIsConstant().
*/
static SQLITE_NOINLINE int exprNodeIsConstantFunction(
Walker *pWalker,
Expr *pExpr
){
int n; /* Number of arguments */
ExprList *pList; /* List of arguments */
FuncDef *pDef; /* The function */
sqlite3 *db; /* The database */
assert( pExpr->op==TK_FUNCTION );
if( ExprHasProperty(pExpr, EP_TokenOnly)
|| (pList = pExpr->x.pList)==0
){;
n = 0;
}else{
n = pList->nExpr;
sqlite3WalkExprList(pWalker, pList);
if( pWalker->eCode==0 ) return WRC_Abort;
}
db = pWalker->pParse->db;
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
if( pDef==0
|| pDef->xFinalize!=0
|| (pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| ExprHasProperty(pExpr, EP_WinFunc)
){
pWalker->eCode = 0;
return WRC_Abort;
}
return WRC_Continue;
}
/* /*
** These routines are Walker callbacks used to check expressions to ** These routines are Walker callbacks used to check expressions to
@@ -2373,6 +2423,7 @@ Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
** malformed schema error. ** malformed schema error.
*/ */
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
assert( pWalker->eCode>0 );
/* If pWalker->eCode is 2 then any term of the expression that comes from /* If pWalker->eCode is 2 then any term of the expression that comes from
** the ON or USING clauses of an outer join disqualifies the expression ** the ON or USING clauses of an outer join disqualifies the expression
@@ -2392,6 +2443,8 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
){ ){
if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL); if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue; return WRC_Continue;
}else if( pWalker->pParse ){
return exprNodeIsConstantFunction(pWalker, pExpr);
}else{ }else{
pWalker->eCode = 0; pWalker->eCode = 0;
return WRC_Abort; return WRC_Abort;
@@ -2444,9 +2497,10 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
return WRC_Continue; return WRC_Continue;
} }
} }
static int exprIsConst(Expr *p, int initFlag, int iCur){ static int exprIsConst(Parse *pParse, Expr *p, int initFlag, int iCur){
Walker w; Walker w;
w.eCode = initFlag; w.eCode = initFlag;
w.pParse = pParse;
w.xExprCallback = exprNodeIsConstant; w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = sqlite3SelectWalkFail; w.xSelectCallback = sqlite3SelectWalkFail;
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
@@ -2464,9 +2518,15 @@ static int exprIsConst(Expr *p, int initFlag, int iCur){
** For the purposes of this function, a double-quoted string (ex: "abc") ** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is ** is considered a variable but a single-quoted string (ex: 'abc') is
** a constant. ** a constant.
**
** The pParse parameter may be NULL. But if it is NULL, there is no way
** to determine if function calls are constant or not, and hence all
** function calls will be considered to be non-constant. If pParse is
** not NULL, then a function call might be constant, depending on the
** function and on its parameters.
*/ */
int sqlite3ExprIsConstant(Expr *p){ int sqlite3ExprIsConstant(Parse *pParse, Expr *p){
return exprIsConst(p, 1, 0); return exprIsConst(pParse, p, 1, 0);
} }
/* /*
@@ -2482,8 +2542,8 @@ int sqlite3ExprIsConstant(Expr *p){
** can be added to the pParse->pConstExpr list and evaluated once when ** can be added to the pParse->pConstExpr list and evaluated once when
** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). ** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce().
*/ */
int sqlite3ExprIsConstantNotJoin(Expr *p){ static int sqlite3ExprIsConstantNotJoin(Parse *pParse, Expr *p){
return exprIsConst(p, 2, 0); return exprIsConst(pParse, p, 2, 0);
} }
/* /*
@@ -2493,7 +2553,7 @@ int sqlite3ExprIsConstantNotJoin(Expr *p){
** table other than iCur. ** table other than iCur.
*/ */
int sqlite3ExprIsTableConstant(Expr *p, int iCur){ int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur); return exprIsConst(0, p, 3, iCur);
} }
/* /*
@@ -2650,7 +2710,7 @@ int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
*/ */
int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){ int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
assert( isInit==0 || isInit==1 ); assert( isInit==0 || isInit==1 );
return exprIsConst(p, 4+isInit, 0); return exprIsConst(0, p, 4+isInit, 0);
} }
#ifdef SQLITE_ENABLE_CURSOR_HINTS #ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -2895,13 +2955,13 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
** The argument is an IN operator with a list (not a subquery) on the ** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant. ** right-hand side. Return TRUE if that list is constant.
*/ */
static int sqlite3InRhsIsConstant(Expr *pIn){ static int sqlite3InRhsIsConstant(Parse *pParse, Expr *pIn){
Expr *pLHS; Expr *pLHS;
int res; int res;
assert( !ExprHasProperty(pIn, EP_xIsSelect) ); assert( !ExprHasProperty(pIn, EP_xIsSelect) );
pLHS = pIn->pLeft; pLHS = pIn->pLeft;
pIn->pLeft = 0; pIn->pLeft = 0;
res = sqlite3ExprIsConstant(pIn); res = sqlite3ExprIsConstant(pParse, pIn);
pIn->pLeft = pLHS; pIn->pLeft = pLHS;
return res; return res;
} }
@@ -3170,7 +3230,7 @@ int sqlite3FindInIndex(
if( eType==0 if( eType==0
&& (inFlags & IN_INDEX_NOOP_OK) && (inFlags & IN_INDEX_NOOP_OK)
&& ExprUseXList(pX) && ExprUseXList(pX)
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) && (!sqlite3InRhsIsConstant(pParse,pX) || pX->x.pList->nExpr<=2)
){ ){
pParse->nTab--; /* Back out the allocation of the unused cursor */ pParse->nTab--; /* Back out the allocation of the unused cursor */
iTab = -1; /* Cursor is not allocated */ iTab = -1; /* Cursor is not allocated */
@@ -3453,7 +3513,7 @@ void sqlite3CodeRhsOfIN(
** this code only executes once. Because for a non-constant ** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time. ** expression we need to rerun this code each time.
*/ */
if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ if( addrOnce && !sqlite3ExprIsConstant(pParse, pE2) ){
sqlite3VdbeChangeToNoop(v, addrOnce-1); sqlite3VdbeChangeToNoop(v, addrOnce-1);
sqlite3VdbeChangeToNoop(v, addrOnce); sqlite3VdbeChangeToNoop(v, addrOnce);
ExprClearProperty(pExpr, EP_Subrtn); ExprClearProperty(pExpr, EP_Subrtn);
@@ -4790,7 +4850,9 @@ expr_code_doover:
} }
#endif #endif
if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ if( ConstFactorOk(pParse)
&& sqlite3ExprIsConstantNotJoin(pParse,pExpr)
){
/* SQL functions can be expensive. So try to avoid running them /* SQL functions can be expensive. So try to avoid running them
** multiple times if we know they always give the same result */ ** multiple times if we know they always give the same result */
return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -4821,7 +4883,7 @@ expr_code_doover:
} }
for(i=0; i<nFarg; i++){ for(i=0; i<nFarg; i++){
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){ if( i<32 && sqlite3ExprIsConstant(pParse, pFarg->a[i].pExpr) ){
testcase( i==31 ); testcase( i==31 );
constMask |= MASKBIT32(i); constMask |= MASKBIT32(i);
} }
@@ -5288,7 +5350,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
if( ConstFactorOk(pParse) if( ConstFactorOk(pParse)
&& ALWAYS(pExpr!=0) && ALWAYS(pExpr!=0)
&& pExpr->op!=TK_REGISTER && pExpr->op!=TK_REGISTER
&& sqlite3ExprIsConstantNotJoin(pExpr) && sqlite3ExprIsConstantNotJoin(pParse, pExpr)
){ ){
*pReg = 0; *pReg = 0;
r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
@@ -5352,7 +5414,7 @@ void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
** might choose to code the expression at initialization time. ** might choose to code the expression at initialization time.
*/ */
void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pParse,pExpr) ){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
}else{ }else{
sqlite3ExprCodeCopy(pParse, pExpr, target); sqlite3ExprCodeCopy(pParse, pExpr, target);
@@ -5411,7 +5473,7 @@ int sqlite3ExprCodeExprList(
sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
} }
}else if( (flags & SQLITE_ECEL_FACTOR)!=0 }else if( (flags & SQLITE_ECEL_FACTOR)!=0
&& sqlite3ExprIsConstantNotJoin(pExpr) && sqlite3ExprIsConstantNotJoin(pParse,pExpr)
){ ){
sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{ }else{

View File

@@ -577,6 +577,193 @@ void sqlite3AutoincrementEnd(Parse *pParse){
# define autoIncStep(A,B,C) # define autoIncStep(A,B,C)
#endif /* SQLITE_OMIT_AUTOINCREMENT */ #endif /* SQLITE_OMIT_AUTOINCREMENT */
/*
** If argument pVal is a Select object returned by an sqlite3MultiValues()
** that was able to use the co-routine optimization, finish coding the
** co-routine.
*/
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
SrcItem *pItem = &pVal->pSrc->a[0];
sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
}
}
/*
** Return true if all expressions in the expression-list passed as the
** only argument are constant.
*/
static int exprListIsConstant(Parse *pParse, ExprList *pRow){
int ii;
for(ii=0; ii<pRow->nExpr; ii++){
if( 0==sqlite3ExprIsConstant(pParse, pRow->a[ii].pExpr) ) return 0;
}
return 1;
}
/*
** Return true if all expressions in the expression-list passed as the
** only argument are both constant and have no affinity.
*/
static int exprListIsNoAffinity(Parse *pParse, ExprList *pRow){
int ii;
if( exprListIsConstant(pParse,pRow)==0 ) return 0;
for(ii=0; ii<pRow->nExpr; ii++){
assert( pRow->a[ii].pExpr->affExpr==0 );
if( 0!=sqlite3ExprAffinity(pRow->a[ii].pExpr) ) return 0;
}
return 1;
}
/*
** This function is called by the parser for the second and subsequent
** rows of a multi-row VALUES clause. Argument pLeft is the part of
** the VALUES clause already parsed, argument pRow is the vector of values
** for the new row. The Select object returned represents the complete
** VALUES clause, including the new row.
**
** There are two ways in which this may be achieved - by incremental
** coding of a co-routine (the "co-routine" method) or by returning a
** Select object equivalent to the following (the "UNION ALL" method):
**
** "pLeft UNION ALL SELECT pRow"
**
** If the VALUES clause contains a lot of rows, this compound Select
** object may consume a lot of memory.
**
** When the co-routine method is used, each row that will be returned
** by the VALUES clause is coded into part of a co-routine as it is
** passed to this function. The returned Select object is equivalent to:
**
** SELECT * FROM (
** Select object to read co-routine
** )
**
** The co-routine method is used in most cases. Exceptions are:
**
** a) If the current statement has a WITH clause. This is to avoid
** statements like:
**
** WITH cte AS ( VALUES('x'), ('y') ... )
** SELECT * FROM cte AS a, cte AS b;
**
** This will not work, as the co-routine uses a hard-coded register
** for its OP_Yield instructions, and so it is not possible for two
** cursors to iterate through it concurrently.
**
** b) The schema is currently being parsed (i.e. the VALUES clause is part
** of a schema item like a VIEW or TRIGGER). In this case there is no VM
** being generated when parsing is taking place, and so generating
** a co-routine is not possible.
**
** c) There are non-constant expressions in the VALUES clause (e.g.
** the VALUES clause is part of a correlated sub-query).
**
** d) One or more of the values in the first row of the VALUES clause
** has an affinity (i.e. is a CAST expression). This causes problems
** because the complex rules SQLite uses (see function
** sqlite3SubqueryColumnTypes() in select.c) to determine the effective
** affinity of such a column for all rows require access to all values in
** the column simultaneously.
*/
Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
if( pParse->bHasWith /* condition (a) above */
|| pParse->db->init.busy /* condition (b) above */
|| exprListIsConstant(pParse,pRow)==0 /* condition (c) above */
|| (pLeft->pSrc->nSrc==0 &&
exprListIsNoAffinity(pParse,pLeft->pEList)==0) /* condition (d) above */
|| IN_SPECIAL_PARSE
){
/* The co-routine method cannot be used. Fall back to UNION ALL. */
Select *pSelect = 0;
int f = SF_Values | SF_MultiValue;
if( pLeft->pSrc->nSrc ){
sqlite3MultiValuesEnd(pParse, pLeft);
f = SF_Values;
}else if( pLeft->pPrior ){
/* In this case set the SF_MultiValue flag only if it was set on pLeft */
f = (f & pLeft->selFlags);
}
pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
pLeft->selFlags &= ~SF_MultiValue;
if( pSelect ){
pSelect->op = TK_ALL;
pSelect->pPrior = pLeft;
pLeft = pSelect;
}
}else{
SrcItem *p = 0; /* SrcItem that reads from co-routine */
if( pLeft->pSrc->nSrc==0 ){
/* Co-routine has not yet been started and the special Select object
** that accesses the co-routine has not yet been created. This block
** does both those things. */
Vdbe *v = sqlite3GetVdbe(pParse);
Select *pRet = sqlite3SelectNew(pParse, 0, 0, 0, 0, 0, 0, 0, 0);
/* Ensure the database schema has been read. This is to ensure we have
** the correct text encoding. */
if( (pParse->db->mDbFlags & DBFLAG_SchemaKnownOk)==0 ){
sqlite3ReadSchema(pParse);
}
if( pRet ){
SelectDest dest;
pRet->pSrc->nSrc = 1;
pRet->pPrior = pLeft->pPrior;
pRet->op = pLeft->op;
pLeft->pPrior = 0;
pLeft->op = TK_SELECT;
assert( pLeft->pNext==0 );
assert( pRet->pNext==0 );
p = &pRet->pSrc->a[0];
p->pSelect = pLeft;
p->fg.viaCoroutine = 1;
p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
p->regReturn = ++pParse->nMem;
p->iCursor = -1;
p->u1.nRow = 2;
sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
/* Allocate registers for the output of the co-routine. Do so so
** that there are two unused registers immediately before those
** used by the co-routine. This allows the code in sqlite3Insert()
** to use these registers directly, instead of copying the output
** of the co-routine to a separate array for processing. */
dest.iSdst = pParse->nMem + 3;
dest.nSdst = pLeft->pEList->nExpr;
pParse->nMem += 2 + dest.nSdst;
pLeft->selFlags |= SF_MultiValue;
sqlite3Select(pParse, pLeft, &dest);
p->regResult = dest.iSdst;
assert( pParse->nErr || dest.iSdst>0 );
pLeft = pRet;
}
}else{
p = &pLeft->pSrc->a[0];
assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
p->u1.nRow++;
}
if( pParse->nErr==0 ){
assert( p!=0 );
if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
}else{
sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
}
}
sqlite3ExprListDelete(pParse->db, pRow);
}
return pLeft;
}
/* Forward declaration */ /* Forward declaration */
static int xferOptimization( static int xferOptimization(
@@ -913,11 +1100,25 @@ void sqlite3Insert(
if( pSelect ){ if( pSelect ){
/* Data is coming from a SELECT or from a multi-row VALUES clause. /* Data is coming from a SELECT or from a multi-row VALUES clause.
** Generate a co-routine to run the SELECT. */ ** Generate a co-routine to run the SELECT. */
int regYield; /* Register holding co-routine entry-point */
int addrTop; /* Top of the co-routine */
int rc; /* Result code */ int rc; /* Result code */
regYield = ++pParse->nMem; if( pSelect->pSrc->nSrc==1
&& pSelect->pSrc->a[0].fg.viaCoroutine
&& pSelect->pPrior==0
){
SrcItem *pItem = &pSelect->pSrc->a[0];
dest.iSDParm = pItem->regReturn;
regFromSelect = pItem->regResult;
nColumn = pItem->pSelect->pEList->nExpr;
ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
if( bIdListInOrder && nColumn==pTab->nCol ){
regData = regFromSelect;
regRowid = regData - 1;
regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
}
}else{
int addrTop; /* Top of the co-routine */
int regYield = ++pParse->nMem;
addrTop = sqlite3VdbeCurrentAddr(v) + 1; addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
@@ -932,6 +1133,7 @@ void sqlite3Insert(
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
assert( pSelect->pEList ); assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr; nColumn = pSelect->pEList->nExpr;
}
/* Set useTempTable to TRUE if the result of the SELECT statement /* Set useTempTable to TRUE if the result of the SELECT statement
** should be written into a temporary table (template 4). Set to ** should be written into a temporary table (template 4). Set to

View File

@@ -565,6 +565,7 @@ cmd ::= select(X). {
select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);} select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);}
select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X).
{A = attachWithToSelect(pParse,X,W);} {A = attachWithToSelect(pParse,X,W);}
%endif /* SQLITE_OMIT_CTE */ %endif /* SQLITE_OMIT_CTE */
select(A) ::= selectnowith(A). { select(A) ::= selectnowith(A). {
Select *p = A; Select *p = A;
@@ -622,24 +623,27 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
%endif %endif
oneselect(A) ::= values(A). // Single row VALUES clause.
//
%type values {Select*} %type values {Select*}
oneselect(A) ::= values(A).
%destructor values {sqlite3SelectDelete(pParse->db, $$);} %destructor values {sqlite3SelectDelete(pParse->db, $$);}
values(A) ::= VALUES LP nexprlist(X) RP. { values(A) ::= VALUES LP nexprlist(X) RP. {
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0); A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0);
} }
values(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
Select *pRight, *pLeft = A; // Multiple row VALUES clause.
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0); //
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; %type mvalues {Select*}
if( pRight ){ oneselect(A) ::= mvalues(A). {
pRight->op = TK_ALL; sqlite3MultiValuesEnd(pParse, A);
pRight->pPrior = pLeft; }
A = pRight; %destructor mvalues {sqlite3SelectDelete(pParse->db, $$);}
}else{ mvalues(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
A = pLeft; A = sqlite3MultiValues(pParse, A, Y);
} }
mvalues(A) ::= mvalues(A) COMMA LP nexprlist(Y) RP. {
A = sqlite3MultiValues(pParse, A, Y);
} }
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is // The "distinct" nonterminal is true (1) if the DISTINCT keyword is
@@ -1321,7 +1325,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
if( A ) sqlite3ExprIdToTrueFalse(A); if( A ) sqlite3ExprIdToTrueFalse(A);
}else{ }else{
Expr *pRHS = Y->a[0].pExpr; Expr *pRHS = Y->a[0].pExpr;
if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){ if( Y->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && A->op!=TK_VECTOR ){
Y->a[0].pExpr = 0; Y->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, Y); sqlite3ExprListDelete(pParse->db, Y);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
@@ -1761,9 +1765,10 @@ with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); }
wqas(A) ::= AS. {A = M10d_Any;} wqas(A) ::= AS. {A = M10d_Any;}
wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;} wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;}
wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;} wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;}
wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. { wqitem(A) ::= withnm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. {
A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/ A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/
} }
withnm(A) ::= nm(A). {pParse->bHasWith = 1;}
wqlist(A) ::= wqitem(X). { wqlist(A) ::= wqitem(X). {
A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/ A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/
} }

View File

@@ -860,6 +860,10 @@ void sqlite3_str_vappendf(
assert( pSel!=0 ); assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){ if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
}else if( pSel->selFlags & SF_MultiValue ){
assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
pItem->u1.nRow);
}else{ }else{
sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId); sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
} }

View File

@@ -4776,7 +4776,7 @@ static void constInsert(
){ ){
int i; int i;
assert( pColumn->op==TK_COLUMN ); assert( pColumn->op==TK_COLUMN );
assert( sqlite3ExprIsConstant(pValue) ); assert( sqlite3ExprIsConstant(pConst->pParse, pValue) );
if( ExprHasProperty(pColumn, EP_FixedCol) ) return; if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
if( sqlite3ExprAffinity(pValue)!=0 ) return; if( sqlite3ExprAffinity(pValue)!=0 ) return;
@@ -4834,10 +4834,10 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
pLeft = pExpr->pLeft; pLeft = pExpr->pLeft;
assert( pRight!=0 ); assert( pRight!=0 );
assert( pLeft!=0 ); assert( pLeft!=0 );
if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){ if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pLeft) ){
constInsert(pConst,pRight,pLeft,pExpr); constInsert(pConst,pRight,pLeft,pExpr);
} }
if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){ if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pConst->pParse, pRight) ){
constInsert(pConst,pLeft,pRight,pExpr); constInsert(pConst,pLeft,pRight,pExpr);
} }
} }
@@ -7636,7 +7636,7 @@ int sqlite3Select(
/* Generate code for all sub-queries in the FROM clause /* Generate code for all sub-queries in the FROM clause
*/ */
pSub = pItem->pSelect; pSub = pItem->pSelect;
if( pSub==0 ) continue; if( pSub==0 || pItem->addrFillSub!=0 ) continue;
/* The code for a subquery should only be generated once. */ /* The code for a subquery should only be generated once. */
assert( pItem->addrFillSub==0 ); assert( pItem->addrFillSub==0 );

View File

@@ -3292,6 +3292,8 @@ struct IdList {
** **
** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc ** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy ** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
**
** u2.pIBIndex fg.isIndexedBy && !fg.isCte ** u2.pIBIndex fg.isIndexedBy && !fg.isCte
** u2.pCteUse fg.isCte && !fg.isIndexedBy ** u2.pCteUse fg.isCte && !fg.isIndexedBy
*/ */
@@ -3331,6 +3333,7 @@ struct SrcItem {
union { union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */ ExprList *pFuncArg; /* Arguments to table-valued-function */
u32 nRow; /* Number of rows in a VALUES clause */
} u1; } u1;
union { union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
@@ -3832,6 +3835,7 @@ struct Parse {
u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 disableLookaside; /* Number of times lookaside has been disabled */
u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
u8 bHasWith; /* True if statement contains WITH */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif #endif
@@ -4510,6 +4514,9 @@ struct Window {
** due to the SQLITE_SUBTYPE flag */ ** due to the SQLITE_SUBTYPE flag */
}; };
Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow);
void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal);
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3WindowDelete(sqlite3*, Window*); void sqlite3WindowDelete(sqlite3*, Window*);
void sqlite3WindowUnlinkFromSelect(Window*); void sqlite3WindowUnlinkFromSelect(Window*);
@@ -5078,8 +5085,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
u32 sqlite3IsTrueOrFalse(const char*); u32 sqlite3IsTrueOrFalse(const char*);
int sqlite3ExprIdToTrueFalse(Expr*); int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*); int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstant(Parse*,Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8); int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int); int sqlite3ExprIsTableConstant(Expr*,int);

View File

@@ -1329,7 +1329,7 @@ static sqlite3_index_info *allocateIndexInfo(
Expr *pE2; Expr *pE2;
/* Skip over constant terms in the ORDER BY clause */ /* Skip over constant terms in the ORDER BY clause */
if( sqlite3ExprIsConstant(pExpr) ){ if( sqlite3ExprIsConstant(0, pExpr) ){
continue; continue;
} }
@@ -1441,7 +1441,7 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxInfo->nConstraint = j; pIdxInfo->nConstraint = j;
for(i=j=0; i<nOrderBy; i++){ for(i=j=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr; Expr *pExpr = pOrderBy->a[i].pExpr;
if( sqlite3ExprIsConstant(pExpr) ) continue; if( sqlite3ExprIsConstant(0, pExpr) ) continue;
assert( pExpr->op==TK_COLUMN assert( pExpr->op==TK_COLUMN
|| (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
&& pExpr->iColumn==pExpr->pLeft->iColumn) ); && pExpr->iColumn==pExpr->pLeft->iColumn) );
@@ -3623,7 +3623,7 @@ static void wherePartIdxExpr(
u8 aff; u8 aff;
if( pLeft->op!=TK_COLUMN ) return; if( pLeft->op!=TK_COLUMN ) return;
if( !sqlite3ExprIsConstant(pRight) ) return; if( !sqlite3ExprIsConstant(0, pRight) ) return;
if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return; if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
if( pLeft->iColumn<0 ) return; if( pLeft->iColumn<0 ) return;
aff = pIdx->pTable->aCol[pLeft->iColumn].affinity; aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
@@ -4997,7 +4997,7 @@ static i8 wherePathSatisfiesOrderBy(
if( MASKBIT(i) & obSat ) continue; if( MASKBIT(i) & obSat ) continue;
p = pOrderBy->a[i].pExpr; p = pOrderBy->a[i].pExpr;
mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p);
if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; if( mTerm==0 && !sqlite3ExprIsConstant(0,p) ) continue;
if( (mTerm&~orderDistinctMask)==0 ){ if( (mTerm&~orderDistinctMask)==0 ){
obSat |= MASKBIT(i); obSat |= MASKBIT(i);
} }
@@ -5866,7 +5866,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
}else{ }else{
continue; continue;
} }
if( sqlite3ExprIsConstant(pExpr) ) continue; if( sqlite3ExprIsConstant(0,pExpr) ) continue;
if( pExpr->op==TK_FUNCTION ){ if( pExpr->op==TK_FUNCTION ){
/* Functions that might set a subtype should not be replaced by the /* Functions that might set a subtype should not be replaced by the
** value taken from an expression index since the index omits the ** value taken from an expression index since the index omits the
@@ -6144,7 +6144,11 @@ WhereInfo *sqlite3WhereBegin(
){ ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
} }
if( ALWAYS(pWInfo->pSelect)
&& (pWInfo->pSelect->selFlags & SF_MultiValue)==0
){
ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
}
}else{ }else{
/* Assign a bit from the bitmask to every term in the FROM clause. /* Assign a bit from the bitmask to every term in the FROM clause.
** **
@@ -6896,6 +6900,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
*/ */
if( pTabItem->fg.viaCoroutine ){ if( pTabItem->fg.viaCoroutine ){
testcase( pParse->db->mallocFailed ); testcase( pParse->db->mallocFailed );
assert( pTabItem->regResult>=0 );
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0); pTabItem->regResult, 0);
continue; continue;

View File

@@ -989,7 +989,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
if( pIdx->aiColumn[i]!=XN_EXPR ) continue; if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
assert( pIdx->bHasExpr ); assert( pIdx->bHasExpr );
if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
&& !sqlite3ExprIsConstant(pIdx->aColExpr->a[i].pExpr) && !sqlite3ExprIsConstant(0,pIdx->aColExpr->a[i].pExpr)
){ ){
aiCurCol[0] = iCur; aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR; aiCurCol[1] = XN_EXPR;

View File

@@ -1164,7 +1164,7 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){
** variable values in the expression tree. ** variable values in the expression tree.
*/ */
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
if( 0==sqlite3ExprIsConstant(pExpr) ){ if( 0==sqlite3ExprIsConstant(0,pExpr) ){
if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr); if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr);
sqlite3ExprDelete(pParse->db, pExpr); sqlite3ExprDelete(pParse->db, pExpr);
pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0); pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);

View File

@@ -736,4 +736,31 @@ do_execsql_test 29.7 {
END} END}
} }
#-------------------------------------------------------------------------
reset_db
do_execsql_test 30.0 {
CREATE TABLE t1(a, b);
CREATE VIEW v1 AS
SELECT ( VALUES(a), (b) ) FROM (
SELECT a, b FROM t1
)
;
}
do_execsql_test 30.1 {
SELECT * FROM v1
}
do_execsql_test 30.1 {
ALTER TABLE t1 RENAME TO t2;
}
do_execsql_test 30.2 {
SELECT sql FROM sqlite_schema WHERE type='view'
} {
{CREATE VIEW v1 AS
SELECT ( VALUES(a), (b) ) FROM (
SELECT a, b FROM "t2"
)}
}
finish_test finish_test

View File

@@ -1,4 +1,4 @@
# 2013 March 10 # 2023-03-10
# #
# The author disclaims copyright to this source code. In place of # The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing: # a legal notice, here is a blessing:
@@ -9,7 +9,10 @@
# #
#*********************************************************************** #***********************************************************************
# This file implements regression tests for SQLite library. The focus of # This file implements regression tests for SQLite library. The focus of
# this file is testing the tointeger() and toreal() functions. # this file is testing the tointeger() and toreal() functions that are
# part of the "totype.c" extension. This file does not test the core
# SQLite library. Failures of tests in this file are related to the
# ext/misc/totype.c extension.
# #
# Several of the toreal() tests are disabled on platforms where floating # Several of the toreal() tests are disabled on platforms where floating
# point precision is not high enough to represent their constant integer # point precision is not high enough to represent their constant integer
@@ -23,6 +26,20 @@ load_static_extension db totype
set highPrecision(1) [expr \ set highPrecision(1) [expr \
{[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}] {[db eval {SELECT tointeger(9223372036854775807 + 1);}] eq {{}}}]
set highPrecision(2) [expr \
{[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]
# highPrecision(3) is only known to be false on i586 with gcc-13 and -O2.
# It is true on the exact same platform with -O0. Both results seem
# reasonable, so we'll just very the expectation accordingly.
#
set highPrecision(3) [expr \
{[db eval {SELECT toreal(9007199254740992 + 1);}] eq {{}}}]
if {!$highPrecision(1) || !$highPrecision(2) || !$highPrecision(3)} {
puts "NOTICE: use_long_double: [use_long_double] \
highPrecision: $highPrecision(1) $highPrecision(2) $highPrecision(3)"
}
do_execsql_test func4-1.1 { do_execsql_test func4-1.1 {
SELECT tointeger(NULL); SELECT tointeger(NULL);
@@ -195,8 +212,6 @@ do_execsql_test func4-1.55 {
} {{}} } {{}}
ifcapable floatingpoint { ifcapable floatingpoint {
set highPrecision(2) [expr \
{[db eval {SELECT toreal(-9223372036854775808 + 1);}] eq {{}}}]
do_execsql_test func4-2.1 { do_execsql_test func4-2.1 {
SELECT toreal(NULL); SELECT toreal(NULL);
@@ -341,10 +356,14 @@ ifcapable floatingpoint {
do_execsql_test func4-2.45 { do_execsql_test func4-2.45 {
SELECT toreal(9007199254740992); SELECT toreal(9007199254740992);
} {9007199254740992.0} } {9007199254740992.0}
if {$highPrecision(2)} { if {$highPrecision(3)} {
do_execsql_test func4-2.46 { do_execsql_test func4-2.46 {
SELECT toreal(9007199254740992 + 1); SELECT toreal(9007199254740992 + 1);
} {{}} } {{}}
} else {
do_execsql_test func4-2.46 {
SELECT toreal(9007199254740992 + 1);
} {9007199254740992.0}
} }
do_execsql_test func4-2.47 { do_execsql_test func4-2.47 {
SELECT toreal(9007199254740992 + 2); SELECT toreal(9007199254740992 + 2);
@@ -626,10 +645,14 @@ ifcapable floatingpoint {
do_execsql_test func4-5.22 { do_execsql_test func4-5.22 {
SELECT tointeger(toreal(9007199254740992)); SELECT tointeger(toreal(9007199254740992));
} {9007199254740992} } {9007199254740992}
if {$highPrecision(2)} { if {$highPrecision(3)} {
do_execsql_test func4-5.23 { do_execsql_test func4-5.23 {
SELECT tointeger(toreal(9007199254740992 + 1)); SELECT tointeger(toreal(9007199254740992 + 1));
} {{}} } {{}}
} else {
do_execsql_test func4-5.23 {
SELECT tointeger(toreal(9007199254740992 + 1));
} {9007199254740992}
} }
do_execsql_test func4-5.24 { do_execsql_test func4-5.24 {
SELECT tointeger(toreal(9007199254740992 + 2)); SELECT tointeger(toreal(9007199254740992 + 2));

View File

@@ -458,14 +458,14 @@ do_execsql_test 11.0 {
do_execsql_test 11.1 { do_execsql_test 11.1 {
SELECT * FROM t1 SELECT * FROM t1
WHERE b IN (345, (SELECT 1 FROM t1 WHERE b IN (345, (SELECT 1 FROM t1
WHERE b IN (345 NOT GLOB 510) WHERE b IN (coalesce(1,random()))
AND c GLOB 'abc*xyz')) AND c GLOB 'abc*xyz'))
AND c BETWEEN 'abc' AND 'xyz'; AND c BETWEEN 'abc' AND 'xyz';
} {xyz 1 abcdefxyz 99} } {xyz 1 abcdefxyz 99}
do_execsql_test 11.2 { do_execsql_test 11.2 {
EXPLAIN SELECT * FROM t1 EXPLAIN SELECT * FROM t1
WHERE b IN (345, (SELECT 1 FROM t1 WHERE b IN (345, (SELECT 1 FROM t1
WHERE b IN (345 NOT GLOB 510) WHERE b IN (coalesce(1,random()))
AND c GLOB 'abc*xyz')) AND c GLOB 'abc*xyz'))
AND c BETWEEN 'abc' AND 'xyz'; AND c BETWEEN 'abc' AND 'xyz';
} {/ SeekScan /} } {/ SeekScan /}

View File

@@ -922,7 +922,7 @@ do_catchsql_test sqllimits1-18.1 {
do_catchsql_test sqllimits1-18.2 { do_catchsql_test sqllimits1-18.2 {
INSERT INTO b1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10) INSERT INTO b1 VALUES(1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
UNION VALUES(11); UNION VALUES(11);
} {1 {too many terms in compound SELECT}} } {0 {}}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #

View File

@@ -64,6 +64,8 @@ Usage:
--dryrun --dryrun
--explain --explain
--jobs NUMBER-OF-JOBS --jobs NUMBER-OF-JOBS
--stop-on-coredump
--stop-on-error
--zipvfs ZIPVFS-SOURCE-DIR --zipvfs ZIPVFS-SOURCE-DIR
Special values for PERMUTATION that work with plain tclsh: Special values for PERMUTATION that work with plain tclsh:
@@ -172,6 +174,8 @@ set TRG(zipvfs) "" ;# -zipvfs option, if any
set TRG(buildonly) 0 ;# True if --buildonly option set TRG(buildonly) 0 ;# True if --buildonly option
set TRG(dryrun) 0 ;# True if --dryrun option set TRG(dryrun) 0 ;# True if --dryrun option
set TRG(explain) 0 ;# True for the --explain option set TRG(explain) 0 ;# True for the --explain option
set TRG(stopOnError) 0 ;# Stop running at first failure
set TRG(stopOnCore) 0 ;# Stop on a core-dump
switch -nocase -glob -- $tcl_platform(os) { switch -nocase -glob -- $tcl_platform(os) {
*darwin* { *darwin* {
@@ -468,6 +472,10 @@ for {set ii 0} {$ii < [llength $argv]} {incr ii} {
set TRG(dryrun) 1 set TRG(dryrun) 1
} elseif {($n>2 && [string match "$a*" --explain]) || $a=="-e"} { } elseif {($n>2 && [string match "$a*" --explain]) || $a=="-e"} {
set TRG(explain) 1 set TRG(explain) 1
} elseif {[string match "$a*" --stop-on-error]} {
set TRG(stopOnError) 1
} elseif {[string match "$a*" --stop-on-coredump]} {
set TRG(stopOnCore) 1
} else { } else {
usage usage
} }
@@ -993,6 +1001,14 @@ proc script_input_ready {fd iJob jobid} {
} }
puts "FAILED: $job(displayname) ($iJob)" puts "FAILED: $job(displayname) ($iJob)"
set state "failed" set state "failed"
if {$TRG(stopOnError)} {
puts "OUTPUT: $O($iJob)"
exit 1
}
if {$TRG(stopOnCore) && [string first {core dumped} $O($iJob)]>0} {
puts "OUTPUT: $O($iJob)"
exit 1
}
} }
set tm [clock_milliseconds] set tm [clock_milliseconds]

583
test/values.test Normal file
View File

@@ -0,0 +1,583 @@
# 2024 March 3
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix values
do_execsql_test 1.0 {
CREATE TABLE x1(a, b, c);
}
explain_i {
INSERT INTO x1(a, b, c) VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
}
do_execsql_test 1.1.1 {
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
}
do_execsql_test 1.1.2 {
SELECT * FROM x1;
} {
1 1 1
2 2 2
3 3 3
4 4 4
}
do_execsql_test 1.2.0 {
DELETE FROM x1
}
do_execsql_test 1.2.1 {
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 4, 4, 4;
SELECT * FROM x1;
} {1 1 1 2 2 2 3 3 3 4 4 4}
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 4
do_execsql_test 1.2.2 {
DELETE FROM x1;
INSERT INTO x1
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)
UNION ALL SELECT 6, 6, 6;
SELECT * FROM x1;
} {1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6}
do_execsql_test 1.2.3 {
DELETE FROM x1;
INSERT INTO x1
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)
UNION ALL SELECT 6, 6, 6;
SELECT * FROM x1;
} {1 1 1 2 2 2 3 3 3 4 4 4 6 6 6}
do_execsql_test 1.2.4 {
DELETE FROM x1;
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 6, 6, 6;
SELECT * FROM x1;
} {
1 1 1
2 2 2
3 3 3
6 6 6
}
set a 4
set b 5
set c 6
do_execsql_test 1.2.5 {
DELETE FROM x1;
INSERT INTO x1
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3),
(4, 4, $a), (5, 5, $b), (6, 6, $c)
}
do_execsql_test 1.2.6 {
SELECT * FROM x1;
} {
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
}
#-------------------------------------------------------------------------
# SQLITE_LIMIT_COMPOUND_SELECT set to 0.
#
reset_db
do_execsql_test 2.0 {
CREATE TABLE x1(a, b, c);
}
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 3
do_catchsql_test 2.1.1 {
INSERT INTO x1 VALUES
(1, 1, 1),
(2, 2, 2),
(3, 3, 3),
(4, 4, 4),
(5, 5, 5),
(6, 6, 6),
(7, 7, 7),
(8, 8, 8),
(9, 9, 9),
(10, 10, 10, 10)
} {1 {all VALUES must have the same number of terms}}
do_catchsql_test 2.1.2 {
INSERT INTO x1 VALUES
(1, 1, 1),
(2, 2, 2, 2),
(3, 3, 3),
(4, 4, 4),
(5, 5, 5),
(6, 6, 6),
(7, 7, 7),
(8, 8, 8),
(9, 9, 9),
(10, 10, 10)
} {1 {all VALUES must have the same number of terms}}
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 0
do_execsql_test 2.2 {
INSERT INTO x1 VALUES
(1, 1, 1),
(2, 2, 2),
(3, 3, 3),
(4, 4, 4),
(5, 5, 5),
(6, 6, 6),
(7, 7, 7),
(8, 8, 8),
(9, 9, 9),
(10, 10, 10)
} {}
do_execsql_test 2.3 {
INSERT INTO x1 VALUES
(1, 1, 1),
(2, 2, 2),
(3, 3, 3),
(4, 4, 4),
(5, 5, 5),
(6, 6, 6),
(7, 7, 7),
(8, 8, 8),
(9, 9, 9),
(10, 10, 10)
UNION ALL
SELECT 5, 12, 12
ORDER BY 1
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {
CREATE TABLE y1(x, y);
}
do_execsql_test 3.1.1 {
DELETE FROM y1;
INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 5);
}
do_execsql_test 3.1.2 {
SELECT * FROM y1;
} {1 2 3 4 1 5}
do_execsql_test 3.2.1 {
DELETE FROM y1;
INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 6)
, (row_number() OVER (), 7)
}
do_execsql_test 3.1.2 {
SELECT * FROM y1;
} {1 2 3 4 1 6 1 7}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 4.0 {
CREATE TABLE x1(a PRIMARY KEY, b) WITHOUT ROWID;
}
foreach {tn iLimit} {1 0 2 3} {
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT $iLimit
do_execsql_test 4.1.1 {
DELETE FROM x1;
INSERT INTO x1 VALUES
(1, 1),
(2, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
}
do_execsql_test 4.1.2 {
SELECT * FROM x1
} {1 1 2 a}
do_execsql_test 4.2.1 {
DELETE FROM x1;
INSERT INTO x1 VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
}
do_execsql_test 4.2.2 {
SELECT * FROM x1
} {1 1 2 2 3 3 4 4 5 a}
do_execsql_test 4.3.1 {
DELETE FROM x1;
INSERT INTO x1 VALUES
(1, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d'), ('e')) ))
}
do_execsql_test 4.3.2 {
SELECT * FROM x1
} {1 a}
}
#------------------------------------------------------------------------
reset_db
do_execsql_test 5.0 {
CREATE VIEW v1 AS VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9);
}
do_execsql_test 5.1 {
SELECT * FROM v1
} {1 2 3 4 5 6 7 8 9}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1), (2);
}
do_execsql_test 6.1 {
SELECT ( VALUES( x ), ( x ) ) FROM t1;
} {1 2}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('x'), ('y');
}
do_execsql_test 6.1 {
SELECT * FROM t1, (VALUES(1), (2))
} {x 1 x 2 y 1 y 2}
do_execsql_test 6.2 {
VALUES(CAST(44 AS REAL)),(55);
} {44.0 55}
#------------------------------------------------------------------------
do_execsql_test 7.1 {
WITH x1(a, b) AS (
VALUES(1, 2), ('a', 'b')
)
SELECT * FROM x1 one, x1 two
} {
1 2 1 2
1 2 a b
a b 1 2
a b a b
}
#-------------------------------------------------------------------------
reset_db
set VVV {
( VALUES('a', 'b'), ('c', 'd'), (123, NULL) )
}
set VVV2 {
(
SELECT 'a' AS column1, 'b' AS column2
UNION ALL SELECT 'c', 'd' UNION ALL SELECT 123, NULL
)
}
do_execsql_test 8.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('d'), (NULL), (123)
}
foreach {tn q res} {
1 "SELECT * FROM t1 LEFT JOIN VVV" {
d a b d c d d 123 {}
{} a b {} c d {} 123 {}
123 a b 123 c d 123 123 {}
}
2 "SELECT * FROM t1 LEFT JOIN VVV ON (column1=x)" {
d {} {}
{} {} {}
123 123 {}
}
3 "SELECT * FROM t1 RIGHT JOIN VVV" {
d a b d c d d 123 {}
{} a b {} c d {} 123 {}
123 a b 123 c d 123 123 {}
}
4 "SELECT * FROM t1 RIGHT JOIN VVV ON (column1=x)" {
123 123 {}
{} a b
{} c d
}
5 "SELECT * FROM t1 FULL OUTER JOIN VVV ON (column1=x)" {
d {} {}
{} {} {}
123 123 {}
{} a b
{} c d
}
6 "SELECT count(*) FROM VVV" { 3 }
7 "SELECT (SELECT column1 FROM VVV)" { a }
8 "SELECT * FROM VVV UNION ALL SELECT * FROM VVV" {
a b c d 123 {}
a b c d 123 {}
}
9 "SELECT * FROM VVV INTERSECT SELECT * FROM VVV" {
123 {} a b c d
}
10 "SELECT * FROM VVV eXCEPT SELECT * FROM VVV" { }
11 "SELECT * FROM VVV eXCEPT SELECT 'a', 'b'" { 123 {} c d }
} {
set q1 [string map [list VVV $VVV] $q]
set q2 [string map [list VVV $VVV2] $q]
set q3 "WITH VVV AS $VVV $q"
do_execsql_test 8.1.$tn.1 $q1 $res
do_execsql_test 8.1.$tn.2 $q2 $res
do_execsql_test 8.1.$tn.3 $q3 $res
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 9.1 {
VALUES(456), (123), (NULL) UNION ALL SELECT 122 ORDER BY 1
} { {} 122 123 456 }
do_execsql_test 9.2 {
VALUES (1, 2), (3, 4), (
( SELECT column1 FROM ( VALUES (5, 6), (7, 8) ) ),
( SELECT max(column2) FROM ( VALUES (5, 1), (7, 6) ) )
)
} { 1 2 3 4 5 6 }
do_execsql_test 10.1 {
CREATE TABLE a2(a, b, c DEFAULT 'xyz');
}
do_execsql_test 10.2 {
INSERT INTO a2(a) VALUES(3),(4);
}
#-------------------------------------------------------------------------
reset_db
ifcapable fts5 {
do_execsql_test 11.0 {
CREATE VIRTUAL TABLE ft USING fts3(x);
}
do_execsql_test 11.1 {
INSERT INTO ft VALUES('one'), ('two');
}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 12.0 {
CREATE TABLE t1(a, b);
}
do_execsql_test 12.1 {
INSERT INTO t1 SELECT 1, 2 UNION ALL VALUES(3, 4), (5, 6);
}
do_execsql_test 12.2 {
SELECT * FROM t1
} {1 2 3 4 5 6}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('xyz');
SELECT (
VALUES( (max(substr('abc', 1, 1), x)) ),
(123),
(456)
)
FROM t1;
} {xyz}
do_catchsql_test 13.1 {
VALUES(300), (zeroblob(300) OVER win);
} {1 {zeroblob() may not be used as a window function}}
#--------------------------------------------------------------------------
reset_db
do_execsql_test 14.1 {
PRAGMA encoding = utf16;
CREATE TABLE t1(a, b);
} {}
db close
sqlite3 db test.db
do_execsql_test 14.2 {
INSERT INTO t1 VALUES
(17, 'craft'),
(16, 'urtlek' IN(1,2,3));
}
#--------------------------------------------------------------------------
#
reset_db
do_eqp_test 15.1 {
VALUES(1),(2),(3),(4),(5);
} {
QUERY PLAN
`--SCAN 5-ROW VALUES CLAUSE
}
do_execsql_test 15.2 {
CREATE TABLE t1(a,b);
}
do_eqp_test 15.3 {
INSERT INTO t1 VALUES
(1,2),(3,4),(7,8);
} {
QUERY PLAN
`--SCAN 3-ROW VALUES CLAUSE
}
do_eqp_test 15.4 {
INSERT INTO t1 VALUES
(1,2),(3,4),(7,8),
(5,row_number()OVER());
} {
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN 3-ROW VALUES CLAUSE
`--UNION ALL
|--CO-ROUTINE (subquery-xxxxxx)
| `--SCAN CONSTANT ROW
`--SCAN (subquery-xxxxxx)
}
do_eqp_test 15.5 {
SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6)), (VALUES('a'),('b'),('c'));
} {
QUERY PLAN
|--SCAN 6-ROW VALUES CLAUSE
`--SCAN 3-ROW VALUES CLAUSE
}
do_execsql_test 15.6 {
CREATE TABLE t2(x,y);
}
do_eqp_test 15.7 {
SELECT * FROM t2 UNION ALL VALUES(1,2),(3,4),(5,6),(7,8);
} {
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN t2
`--UNION ALL
`--SCAN 4-ROW VALUES CLAUSE
}
#--------------------------------------------------------------------------
# The VALUES-as-coroutine optimization can be applied to later rows of
# a VALUES clause even if earlier rows do not qualify.
#
reset_db
do_execsql_test 16.1 {
CREATE TABLE t1(a,b);
}
do_execsql_test 16.2 {
BEGIN;
INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
(7,row_number()OVER()),
(9,10), (11,12), (13,14), (15,16);
SELECT * FROM t1 ORDER BY a, b;
ROLLBACK;
} {1 2 3 4 5 6 7 1 9 10 11 12 13 14 15 16}
do_eqp_test 16.3 {
INSERT INTO t1 VALUES(1,2),(3,4),(5,6),
(7,row_number()OVER()),
(9,10), (11,12), (13,14), (15,16);
} {
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN 3-ROW VALUES CLAUSE
|--UNION ALL
| |--CO-ROUTINE (subquery-xxxxxx)
| | `--SCAN CONSTANT ROW
| `--SCAN (subquery-xxxxxx)
`--UNION ALL
`--SCAN 4-ROW VALUES CLAUSE
}
do_execsql_test 16.4 {
BEGIN;
INSERT INTO t1 VALUES
(1,row_number()OVER()),
(2,3), (4,5), (6,7);
SELECT * FROM t1 ORDER BY a, b;
ROLLBACK;
} {1 1 2 3 4 5 6 7}
do_eqp_test 16.5 {
INSERT INTO t1 VALUES
(1,row_number()OVER()),
(2,3), (4,5), (6,7);
} {
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| |--CO-ROUTINE (subquery-xxxxxx)
| | `--SCAN CONSTANT ROW
| `--SCAN (subquery-xxxxxx)
`--UNION ALL
`--SCAN 3-ROW VALUES CLAUSE
}
do_execsql_test 16.6 {
BEGIN;
INSERT INTO t1 VALUES
(1,2),(3,4),
(5,row_number()OVER()),
(7,8),(9,10),(11,12),
(13,row_number()OVER()),
(15,16),(17,18),(19,20),(21,22);
SELECT * FROM t1 ORDER BY a, b;
ROLLBACK;
} { 1 2 3 4 5 1 7 8 9 10 11 12 13 1 15 16 17 18 19 20 21 22}
do_eqp_test 16.7 {
INSERT INTO t1 VALUES
(1,2),(3,4),
(5,row_number()OVER()),
(7,8),(9,10),(11,12),
(13,row_number()OVER()),
(15,16),(17,18),(19,20),(21,22);
} {
QUERY PLAN
`--COMPOUND QUERY
|--LEFT-MOST SUBQUERY
| `--SCAN 2-ROW VALUES CLAUSE
|--UNION ALL
| |--CO-ROUTINE (subquery-xxxxxx)
| | `--SCAN CONSTANT ROW
| `--SCAN (subquery-xxxxxx)
|--UNION ALL
| `--SCAN 3-ROW VALUES CLAUSE
|--UNION ALL
| |--CO-ROUTINE (subquery-xxxxxx)
| | `--SCAN CONSTANT ROW
| `--SCAN (subquery-xxxxxx)
`--UNION ALL
`--SCAN 4-ROW VALUES CLAUSE
}
finish_test

37
test/valuesfault.test Normal file
View File

@@ -0,0 +1,37 @@
# 2024 March 3
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix valuesfault
source $testdir/malloc_common.tcl
do_execsql_test 1.0 {
CREATE TABLE x1(a, b, c);
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 2
} -body {
execsql {
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
}
} -test {
faultsim_test_result {0 {}}
}
finish_test

View File

@@ -49,6 +49,33 @@ do_eqp_test 120 {
|--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?) |--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
`--SCAN t3 `--SCAN t3
} }
do_eqp_test 121 {
SELECT * FROM t1, t2, t3
WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=abs(5)
ORDER BY t1.a;
} {
QUERY PLAN
|--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
`--SCAN t3
}
# The sqlite3ExprIsConstant() routine does not believe that
# the expression "coalesce(5,random())" is constant. So the
# optimization does not apply in this case.
#
sqlite3_create_function db
do_eqp_test 122 {
SELECT * FROM t1, t2, t3
WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=coalesce(5,random())
ORDER BY t1.a;
} {
QUERY PLAN
|--SCAN t3
|--SEARCH t1 USING INDEX sqlite_autoindex_t1_1 (a=?)
|--SEARCH t2 USING INDEX sqlite_autoindex_t2_1 (a=?)
`--USE TEMP B-TREE FOR ORDER BY
}
# Constant propagation in the face of collating sequences: # Constant propagation in the face of collating sequences:
# #

View File

@@ -59,6 +59,82 @@ static char *msort(char*,char**,int(*)(const char*,const char*));
*/ */
#define lemonStrlen(X) ((int)strlen(X)) #define lemonStrlen(X) ((int)strlen(X))
/*
** Header on the linked list of memory allocations.
*/
typedef struct MemChunk MemChunk;
struct MemChunk {
MemChunk *pNext;
size_t sz;
/* Actually memory follows */
};
/*
** Global linked list of all memory allocations.
*/
static MemChunk *memChunkList = 0;
/*
** Wrappers around malloc(), calloc(), realloc() and free().
**
** All memory allocations are kept on a doubly-linked list. The
** lemon_free_all() function can be called prior to exit to clean
** up any memory leaks.
**
** This is not necessary. But compilers and getting increasingly
** fussy about memory leaks, even in command-line programs like Lemon
** where they do not matter. So this code is provided to hush the
** warnings.
*/
static void *lemon_malloc(size_t nByte){
MemChunk *p;
if( nByte<0 ) return 0;
p = malloc( nByte + sizeof(MemChunk) );
if( p==0 ){
fprintf(stderr, "Out of memory. Failed to allocate %lld bytes.\n",
(long long int)nByte);
exit(1);
}
p->pNext = memChunkList;
p->sz = nByte;
memChunkList = p;
return (void*)&p[1];
}
static void *lemon_calloc(size_t nElem, size_t sz){
void *p = lemon_malloc(nElem*sz);
memset(p, 0, nElem*sz);
return p;
}
static void lemon_free(void *pOld){
if( pOld ){
MemChunk *p = (MemChunk*)pOld;
p--;
memset(pOld, 0, p->sz);
}
}
static void *lemon_realloc(void *pOld, size_t nNew){
void *pNew;
MemChunk *p;
if( pOld==0 ) return lemon_malloc(nNew);
p = (MemChunk*)pOld;
p--;
if( p->sz>=nNew ) return pOld;
pNew = lemon_malloc( nNew );
memcpy(pNew, pOld, p->sz);
return pNew;
}
/* Free all outstanding memory allocations.
** Do this right before exiting.
*/
static void lemon_free_all(void){
while( memChunkList ){
MemChunk *pNext = memChunkList->pNext;
free( memChunkList );
memChunkList = pNext;
}
}
/* /*
** Compilers are starting to complain about the use of sprintf() and strcpy(), ** Compilers are starting to complain about the use of sprintf() and strcpy(),
** saying they are unsafe. So we define our own versions of those routines too. ** saying they are unsafe. So we define our own versions of those routines too.
@@ -497,7 +573,7 @@ static struct action *Action_new(void){
if( actionfreelist==0 ){ if( actionfreelist==0 ){
int i; int i;
int amt = 100; int amt = 100;
actionfreelist = (struct action *)calloc(amt, sizeof(struct action)); actionfreelist = (struct action *)lemon_calloc(amt, sizeof(struct action));
if( actionfreelist==0 ){ if( actionfreelist==0 ){
fprintf(stderr,"Unable to allocate memory for a new parser action."); fprintf(stderr,"Unable to allocate memory for a new parser action.");
exit(1); exit(1);
@@ -616,14 +692,14 @@ struct acttab {
/* Free all memory associated with the given acttab */ /* Free all memory associated with the given acttab */
void acttab_free(acttab *p){ void acttab_free(acttab *p){
free( p->aAction ); lemon_free( p->aAction );
free( p->aLookahead ); lemon_free( p->aLookahead );
free( p ); lemon_free( p );
} }
/* Allocate a new acttab structure */ /* Allocate a new acttab structure */
acttab *acttab_alloc(int nsymbol, int nterminal){ acttab *acttab_alloc(int nsymbol, int nterminal){
acttab *p = (acttab *) calloc( 1, sizeof(*p) ); acttab *p = (acttab *) lemon_calloc( 1, sizeof(*p) );
if( p==0 ){ if( p==0 ){
fprintf(stderr,"Unable to allocate memory for a new acttab."); fprintf(stderr,"Unable to allocate memory for a new acttab.");
exit(1); exit(1);
@@ -642,7 +718,7 @@ acttab *acttab_alloc(int nsymbol, int nterminal){
void acttab_action(acttab *p, int lookahead, int action){ void acttab_action(acttab *p, int lookahead, int action){
if( p->nLookahead>=p->nLookaheadAlloc ){ if( p->nLookahead>=p->nLookaheadAlloc ){
p->nLookaheadAlloc += 25; p->nLookaheadAlloc += 25;
p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, p->aLookahead = (struct lookahead_action *) lemon_realloc( p->aLookahead,
sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
if( p->aLookahead==0 ){ if( p->aLookahead==0 ){
fprintf(stderr,"malloc failed\n"); fprintf(stderr,"malloc failed\n");
@@ -692,7 +768,7 @@ int acttab_insert(acttab *p, int makeItSafe){
if( p->nAction + n >= p->nActionAlloc ){ if( p->nAction + n >= p->nActionAlloc ){
int oldAlloc = p->nActionAlloc; int oldAlloc = p->nActionAlloc;
p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
p->aAction = (struct lookahead_action *) realloc( p->aAction, p->aAction = (struct lookahead_action *) lemon_realloc( p->aAction,
sizeof(p->aAction[0])*p->nActionAlloc); sizeof(p->aAction[0])*p->nActionAlloc);
if( p->aAction==0 ){ if( p->aAction==0 ){
fprintf(stderr,"malloc failed\n"); fprintf(stderr,"malloc failed\n");
@@ -1314,7 +1390,7 @@ static struct config **basisend = 0; /* End of list of basis configs */
/* Return a pointer to a new configuration */ /* Return a pointer to a new configuration */
PRIVATE struct config *newconfig(void){ PRIVATE struct config *newconfig(void){
return (struct config*)calloc(1, sizeof(struct config)); return (struct config*)lemon_calloc(1, sizeof(struct config));
} }
/* The configuration "old" is no longer used */ /* The configuration "old" is no longer used */
@@ -1530,19 +1606,19 @@ static char *bDefineUsed = 0; /* True for every -D macro actually used */
static void handle_D_option(char *z){ static void handle_D_option(char *z){
char **paz; char **paz;
nDefine++; nDefine++;
azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); azDefine = (char **) lemon_realloc(azDefine, sizeof(azDefine[0])*nDefine);
if( azDefine==0 ){ if( azDefine==0 ){
fprintf(stderr,"out of memory\n"); fprintf(stderr,"out of memory\n");
exit(1); exit(1);
} }
bDefineUsed = (char*)realloc(bDefineUsed, nDefine); bDefineUsed = (char*)lemon_realloc(bDefineUsed, nDefine);
if( bDefineUsed==0 ){ if( bDefineUsed==0 ){
fprintf(stderr,"out of memory\n"); fprintf(stderr,"out of memory\n");
exit(1); exit(1);
} }
bDefineUsed[nDefine-1] = 0; bDefineUsed[nDefine-1] = 0;
paz = &azDefine[nDefine-1]; paz = &azDefine[nDefine-1];
*paz = (char *) malloc( lemonStrlen(z)+1 ); *paz = (char *) lemon_malloc( lemonStrlen(z)+1 );
if( *paz==0 ){ if( *paz==0 ){
fprintf(stderr,"out of memory\n"); fprintf(stderr,"out of memory\n");
exit(1); exit(1);
@@ -1556,7 +1632,7 @@ static void handle_D_option(char *z){
*/ */
static char *outputDir = NULL; static char *outputDir = NULL;
static void handle_d_option(char *z){ static void handle_d_option(char *z){
outputDir = (char *) malloc( lemonStrlen(z)+1 ); outputDir = (char *) lemon_malloc( lemonStrlen(z)+1 );
if( outputDir==0 ){ if( outputDir==0 ){
fprintf(stderr,"out of memory\n"); fprintf(stderr,"out of memory\n");
exit(1); exit(1);
@@ -1566,7 +1642,7 @@ static void handle_d_option(char *z){
static char *user_templatename = NULL; static char *user_templatename = NULL;
static void handle_T_option(char *z){ static void handle_T_option(char *z){
user_templatename = (char *) malloc( lemonStrlen(z)+1 ); user_templatename = (char *) lemon_malloc( lemonStrlen(z)+1 );
if( user_templatename==0 ){ if( user_templatename==0 ){
memory_error(); memory_error();
} }
@@ -1803,6 +1879,7 @@ int main(int argc, char **argv){
/* return 0 on success, 1 on failure. */ /* return 0 on success, 1 on failure. */
exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0; exitcode = ((lem.errorcnt > 0) || (lem.nconflict > 0)) ? 1 : 0;
lemon_free_all();
exit(exitcode); exit(exitcode);
return (exitcode); return (exitcode);
} }
@@ -2391,7 +2468,7 @@ static void parseonetoken(struct pstate *psp)
case IN_RHS: case IN_RHS:
if( x[0]=='.' ){ if( x[0]=='.' ){
struct rule *rp; struct rule *rp;
rp = (struct rule *)calloc( sizeof(struct rule) + rp = (struct rule *)lemon_calloc( sizeof(struct rule) +
sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1); sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs, 1);
if( rp==0 ){ if( rp==0 ){
ErrorMsg(psp->filename,psp->tokenlineno, ErrorMsg(psp->filename,psp->tokenlineno,
@@ -2443,17 +2520,17 @@ static void parseonetoken(struct pstate *psp)
struct symbol *msp = psp->rhs[psp->nrhs-1]; struct symbol *msp = psp->rhs[psp->nrhs-1];
if( msp->type!=MULTITERMINAL ){ if( msp->type!=MULTITERMINAL ){
struct symbol *origsp = msp; struct symbol *origsp = msp;
msp = (struct symbol *) calloc(1,sizeof(*msp)); msp = (struct symbol *) lemon_calloc(1,sizeof(*msp));
memset(msp, 0, sizeof(*msp)); memset(msp, 0, sizeof(*msp));
msp->type = MULTITERMINAL; msp->type = MULTITERMINAL;
msp->nsubsym = 1; msp->nsubsym = 1;
msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); msp->subsym = (struct symbol**)lemon_calloc(1,sizeof(struct symbol*));
msp->subsym[0] = origsp; msp->subsym[0] = origsp;
msp->name = origsp->name; msp->name = origsp->name;
psp->rhs[psp->nrhs-1] = msp; psp->rhs[psp->nrhs-1] = msp;
} }
msp->nsubsym++; msp->nsubsym++;
msp->subsym = (struct symbol **) realloc(msp->subsym, msp->subsym = (struct symbol **) lemon_realloc(msp->subsym,
sizeof(struct symbol*)*msp->nsubsym); sizeof(struct symbol*)*msp->nsubsym);
msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){ if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){
@@ -2669,7 +2746,7 @@ static void parseonetoken(struct pstate *psp)
nLine = lemonStrlen(zLine); nLine = lemonStrlen(zLine);
n += nLine + lemonStrlen(psp->filename) + nBack; n += nLine + lemonStrlen(psp->filename) + nBack;
} }
*psp->declargslot = (char *) realloc(*psp->declargslot, n); *psp->declargslot = (char *) lemon_realloc(*psp->declargslot, n);
zBuf = *psp->declargslot + nOld; zBuf = *psp->declargslot + nOld;
if( addLineMacro ){ if( addLineMacro ){
if( nOld && zBuf[-1]!='\n' ){ if( nOld && zBuf[-1]!='\n' ){
@@ -2783,7 +2860,7 @@ static void parseonetoken(struct pstate *psp)
}else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){ }else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){
struct symbol *msp = psp->tkclass; struct symbol *msp = psp->tkclass;
msp->nsubsym++; msp->nsubsym++;
msp->subsym = (struct symbol **) realloc(msp->subsym, msp->subsym = (struct symbol **) lemon_realloc(msp->subsym,
sizeof(struct symbol*)*msp->nsubsym); sizeof(struct symbol*)*msp->nsubsym);
if( !ISUPPER(x[0]) ) x++; if( !ISUPPER(x[0]) ) x++;
msp->subsym[msp->nsubsym-1] = Symbol_new(x); msp->subsym[msp->nsubsym-1] = Symbol_new(x);
@@ -2998,10 +3075,10 @@ void Parse(struct lemon *gp)
fseek(fp,0,2); fseek(fp,0,2);
filesize = ftell(fp); filesize = ftell(fp);
rewind(fp); rewind(fp);
filebuf = (char *)malloc( filesize+1 ); filebuf = (char *)lemon_malloc( filesize+1 );
if( filesize>100000000 || filebuf==0 ){ if( filesize>100000000 || filebuf==0 ){
ErrorMsg(ps.filename,0,"Input file too large."); ErrorMsg(ps.filename,0,"Input file too large.");
free(filebuf); lemon_free(filebuf);
gp->errorcnt++; gp->errorcnt++;
fclose(fp); fclose(fp);
return; return;
@@ -3009,7 +3086,7 @@ void Parse(struct lemon *gp)
if( fread(filebuf,1,filesize,fp)!=filesize ){ if( fread(filebuf,1,filesize,fp)!=filesize ){
ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
filesize); filesize);
free(filebuf); lemon_free(filebuf);
gp->errorcnt++; gp->errorcnt++;
fclose(fp); fclose(fp);
return; return;
@@ -3121,7 +3198,7 @@ void Parse(struct lemon *gp)
*cp = (char)c; /* Restore the buffer */ *cp = (char)c; /* Restore the buffer */
cp = nextcp; cp = nextcp;
} }
free(filebuf); /* Release the buffer after parsing */ lemon_free(filebuf); /* Release the buffer after parsing */
gp->rule = ps.firstrule; gp->rule = ps.firstrule;
gp->errorcnt = ps.errorcnt; gp->errorcnt = ps.errorcnt;
} }
@@ -3139,7 +3216,7 @@ struct plink *Plink_new(void){
if( plink_freelist==0 ){ if( plink_freelist==0 ){
int i; int i;
int amt = 100; int amt = 100;
plink_freelist = (struct plink *)calloc( amt, sizeof(struct plink) ); plink_freelist = (struct plink *)lemon_calloc( amt, sizeof(struct plink) );
if( plink_freelist==0 ){ if( plink_freelist==0 ){
fprintf(stderr, fprintf(stderr,
"Unable to allocate memory for a new follow-set propagation link.\n"); "Unable to allocate memory for a new follow-set propagation link.\n");
@@ -3192,9 +3269,7 @@ void Plink_delete(struct plink *plp)
** Procedures for generating reports and tables in the LEMON parser generator. ** Procedures for generating reports and tables in the LEMON parser generator.
*/ */
/* Generate a filename with the given suffix. Space to hold the /* Generate a filename with the given suffix.
** name comes from malloc() and must be freed by the calling
** function.
*/ */
PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) PRIVATE char *file_makename(struct lemon *lemp, const char *suffix)
{ {
@@ -3211,7 +3286,7 @@ PRIVATE char *file_makename(struct lemon *lemp, const char *suffix)
sz += lemonStrlen(suffix); sz += lemonStrlen(suffix);
if( outputDir ) sz += lemonStrlen(outputDir) + 1; if( outputDir ) sz += lemonStrlen(outputDir) + 1;
sz += 5; sz += 5;
name = (char*)malloc( sz ); name = (char*)lemon_malloc( sz );
if( name==0 ){ if( name==0 ){
fprintf(stderr,"Can't allocate space for a filename.\n"); fprintf(stderr,"Can't allocate space for a filename.\n");
exit(1); exit(1);
@@ -3238,7 +3313,7 @@ PRIVATE FILE *file_open(
){ ){
FILE *fp; FILE *fp;
if( lemp->outname ) free(lemp->outname); if( lemp->outname ) lemon_free(lemp->outname);
lemp->outname = file_makename(lemp, suffix); lemp->outname = file_makename(lemp, suffix);
fp = fopen(lemp->outname,mode); fp = fopen(lemp->outname,mode);
if( fp==0 && *mode=='w' ){ if( fp==0 && *mode=='w' ){
@@ -3554,14 +3629,14 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
if( cp ){ if( cp ){
c = *cp; c = *cp;
*cp = 0; *cp = 0;
path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 ); path = (char *)lemon_malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
if( path ) lemon_sprintf(path,"%s/%s",argv0,name); if( path ) lemon_sprintf(path,"%s/%s",argv0,name);
*cp = c; *cp = c;
}else{ }else{
pathlist = getenv("PATH"); pathlist = getenv("PATH");
if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 ); pathbuf = (char *) lemon_malloc( lemonStrlen(pathlist) + 1 );
path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 ); path = (char *)lemon_malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
if( (pathbuf != 0) && (path!=0) ){ if( (pathbuf != 0) && (path!=0) ){
pathbufptr = pathbuf; pathbufptr = pathbuf;
lemon_strcpy(pathbuf, pathlist); lemon_strcpy(pathbuf, pathlist);
@@ -3577,7 +3652,7 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
if( access(path,modemask)==0 ) break; if( access(path,modemask)==0 ) break;
} }
} }
free(pathbufptr); lemon_free(pathbufptr);
} }
return path; return path;
} }
@@ -3708,7 +3783,7 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname); fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname);
lemp->errorcnt++; lemp->errorcnt++;
} }
free(toFree); lemon_free(toFree);
return in; return in;
} }
@@ -3837,7 +3912,7 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2){
} }
if( (int) (n+sizeof(zInt)*2+used) >= alloced ){ if( (int) (n+sizeof(zInt)*2+used) >= alloced ){
alloced = n + sizeof(zInt)*2 + used + 200; alloced = n + sizeof(zInt)*2 + used + 200;
z = (char *) realloc(z, alloced); z = (char *) lemon_realloc(z, alloced);
} }
if( z==0 ) return empty; if( z==0 ) return empty;
while( n-- > 0 ){ while( n-- > 0 ){
@@ -4127,7 +4202,7 @@ void print_stack_union(
/* Allocate and initialize types[] and allocate stddt[] */ /* Allocate and initialize types[] and allocate stddt[] */
arraysize = lemp->nsymbol * 2; arraysize = lemp->nsymbol * 2;
types = (char**)calloc( arraysize, sizeof(char*) ); types = (char**)lemon_calloc( arraysize, sizeof(char*) );
if( types==0 ){ if( types==0 ){
fprintf(stderr,"Out of memory.\n"); fprintf(stderr,"Out of memory.\n");
exit(1); exit(1);
@@ -4144,7 +4219,7 @@ void print_stack_union(
len = lemonStrlen(sp->datatype); len = lemonStrlen(sp->datatype);
if( len>maxdtlength ) maxdtlength = len; if( len>maxdtlength ) maxdtlength = len;
} }
stddt = (char*)malloc( maxdtlength*2 + 1 ); stddt = (char*)lemon_malloc( maxdtlength*2 + 1 );
if( stddt==0 ){ if( stddt==0 ){
fprintf(stderr,"Out of memory.\n"); fprintf(stderr,"Out of memory.\n");
exit(1); exit(1);
@@ -4193,7 +4268,7 @@ void print_stack_union(
} }
if( types[hash]==0 ){ if( types[hash]==0 ){
sp->dtnum = hash + 1; sp->dtnum = hash + 1;
types[hash] = (char*)malloc( lemonStrlen(stddt)+1 ); types[hash] = (char*)lemon_malloc( lemonStrlen(stddt)+1 );
if( types[hash]==0 ){ if( types[hash]==0 ){
fprintf(stderr,"Out of memory.\n"); fprintf(stderr,"Out of memory.\n");
exit(1); exit(1);
@@ -4215,13 +4290,13 @@ void print_stack_union(
for(i=0; i<arraysize; i++){ for(i=0; i<arraysize; i++){
if( types[i]==0 ) continue; if( types[i]==0 ) continue;
fprintf(out," %s yy%d;\n",types[i],i+1); lineno++; fprintf(out," %s yy%d;\n",types[i],i+1); lineno++;
free(types[i]); lemon_free(types[i]);
} }
if( lemp->errsym && lemp->errsym->useCnt ){ if( lemp->errsym && lemp->errsym->useCnt ){
fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++; fprintf(out," int yy%d;\n",lemp->errsym->dtnum); lineno++;
} }
free(stddt); lemon_free(stddt);
free(types); lemon_free(types);
fprintf(out,"} YYMINORTYPE;\n"); lineno++; fprintf(out,"} YYMINORTYPE;\n"); lineno++;
*plineno = lineno; *plineno = lineno;
} }
@@ -4450,7 +4525,7 @@ void ReportTable(
if( mhflag ){ if( mhflag ){
char *incName = file_makename(lemp, ".h"); char *incName = file_makename(lemp, ".h");
fprintf(out,"#include \"%s\"\n", incName); lineno++; fprintf(out,"#include \"%s\"\n", incName); lineno++;
free(incName); lemon_free(incName);
} }
tplt_xfer(lemp->name,in,out,&lineno); tplt_xfer(lemp->name,in,out,&lineno);
@@ -4557,7 +4632,7 @@ void ReportTable(
** table must be computed before generating the YYNSTATE macro because ** table must be computed before generating the YYNSTATE macro because
** we need to know how many states can be eliminated. ** we need to know how many states can be eliminated.
*/ */
ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0])); ax = (struct axset *) lemon_calloc(lemp->nxstate*2, sizeof(ax[0]));
if( ax==0 ){ if( ax==0 ){
fprintf(stderr,"malloc failed\n"); fprintf(stderr,"malloc failed\n");
exit(1); exit(1);
@@ -4615,7 +4690,7 @@ void ReportTable(
} }
#endif #endif
} }
free(ax); lemon_free(ax);
/* Mark rules that are actually used for reduce actions after all /* Mark rules that are actually used for reduce actions after all
** optimizations have been applied ** optimizations have been applied
@@ -5241,7 +5316,7 @@ void SetSize(int n)
/* Allocate a new set */ /* Allocate a new set */
char *SetNew(void){ char *SetNew(void){
char *s; char *s;
s = (char*)calloc( size, 1); s = (char*)lemon_calloc( size, 1);
if( s==0 ){ if( s==0 ){
memory_error(); memory_error();
} }
@@ -5251,7 +5326,7 @@ char *SetNew(void){
/* Deallocate a set */ /* Deallocate a set */
void SetFree(char *s) void SetFree(char *s)
{ {
free(s); lemon_free(s);
} }
/* Add a new element to the set. Return TRUE if the element was added /* Add a new element to the set. Return TRUE if the element was added
@@ -5310,7 +5385,7 @@ const char *Strsafe(const char *y)
if( y==0 ) return 0; if( y==0 ) return 0;
z = Strsafe_find(y); z = Strsafe_find(y);
if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){ if( z==0 && (cpy=(char *)lemon_malloc( lemonStrlen(y)+1 ))!=0 ){
lemon_strcpy(cpy,y); lemon_strcpy(cpy,y);
z = cpy; z = cpy;
Strsafe_insert(z); Strsafe_insert(z);
@@ -5346,13 +5421,13 @@ static struct s_x1 *x1a;
/* Allocate a new associative array */ /* Allocate a new associative array */
void Strsafe_init(void){ void Strsafe_init(void){
if( x1a ) return; if( x1a ) return;
x1a = (struct s_x1*)malloc( sizeof(struct s_x1) ); x1a = (struct s_x1*)lemon_malloc( sizeof(struct s_x1) );
if( x1a ){ if( x1a ){
x1a->size = 1024; x1a->size = 1024;
x1a->count = 0; x1a->count = 0;
x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); x1a->tbl = (x1node*)lemon_calloc(1024, sizeof(x1node) + sizeof(x1node*));
if( x1a->tbl==0 ){ if( x1a->tbl==0 ){
free(x1a); lemon_free(x1a);
x1a = 0; x1a = 0;
}else{ }else{
int i; int i;
@@ -5387,7 +5462,7 @@ int Strsafe_insert(const char *data)
struct s_x1 array; struct s_x1 array;
array.size = arrSize = x1a->size*2; array.size = arrSize = x1a->size*2;
array.count = x1a->count; array.count = x1a->count;
array.tbl = (x1node*)calloc(arrSize, sizeof(x1node) + sizeof(x1node*)); array.tbl = (x1node*)lemon_calloc(arrSize, sizeof(x1node)+sizeof(x1node*));
if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
array.ht = (x1node**)&(array.tbl[arrSize]); array.ht = (x1node**)&(array.tbl[arrSize]);
for(i=0; i<arrSize; i++) array.ht[i] = 0; for(i=0; i<arrSize; i++) array.ht[i] = 0;
@@ -5402,7 +5477,7 @@ int Strsafe_insert(const char *data)
newnp->from = &(array.ht[h]); newnp->from = &(array.ht[h]);
array.ht[h] = newnp; array.ht[h] = newnp;
} }
/* free(x1a->tbl); // This program was originally for 16-bit machines. /* lemon_free(x1a->tbl); // This program was originally for 16-bit machines.
** Don't worry about freeing memory on modern platforms. */ ** Don't worry about freeing memory on modern platforms. */
*x1a = array; *x1a = array;
} }
@@ -5443,7 +5518,7 @@ struct symbol *Symbol_new(const char *x)
sp = Symbol_find(x); sp = Symbol_find(x);
if( sp==0 ){ if( sp==0 ){
sp = (struct symbol *)calloc(1, sizeof(struct symbol) ); sp = (struct symbol *)lemon_calloc(1, sizeof(struct symbol) );
MemoryCheck(sp); MemoryCheck(sp);
sp->name = Strsafe(x); sp->name = Strsafe(x);
sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL; sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL;
@@ -5514,13 +5589,13 @@ static struct s_x2 *x2a;
/* Allocate a new associative array */ /* Allocate a new associative array */
void Symbol_init(void){ void Symbol_init(void){
if( x2a ) return; if( x2a ) return;
x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); x2a = (struct s_x2*)lemon_malloc( sizeof(struct s_x2) );
if( x2a ){ if( x2a ){
x2a->size = 128; x2a->size = 128;
x2a->count = 0; x2a->count = 0;
x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); x2a->tbl = (x2node*)lemon_calloc(128, sizeof(x2node) + sizeof(x2node*));
if( x2a->tbl==0 ){ if( x2a->tbl==0 ){
free(x2a); lemon_free(x2a);
x2a = 0; x2a = 0;
}else{ }else{
int i; int i;
@@ -5555,7 +5630,7 @@ int Symbol_insert(struct symbol *data, const char *key)
struct s_x2 array; struct s_x2 array;
array.size = arrSize = x2a->size*2; array.size = arrSize = x2a->size*2;
array.count = x2a->count; array.count = x2a->count;
array.tbl = (x2node*)calloc(arrSize, sizeof(x2node) + sizeof(x2node*)); array.tbl = (x2node*)lemon_calloc(arrSize, sizeof(x2node)+sizeof(x2node*));
if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
array.ht = (x2node**)&(array.tbl[arrSize]); array.ht = (x2node**)&(array.tbl[arrSize]);
for(i=0; i<arrSize; i++) array.ht[i] = 0; for(i=0; i<arrSize; i++) array.ht[i] = 0;
@@ -5571,7 +5646,7 @@ int Symbol_insert(struct symbol *data, const char *key)
newnp->from = &(array.ht[h]); newnp->from = &(array.ht[h]);
array.ht[h] = newnp; array.ht[h] = newnp;
} }
/* free(x2a->tbl); // This program was originally written for 16-bit /* lemon_free(x2a->tbl); // This program was originally written for 16-bit
** machines. Don't worry about freeing this trivial amount of memory ** machines. Don't worry about freeing this trivial amount of memory
** on modern platforms. Just leak it. */ ** on modern platforms. Just leak it. */
*x2a = array; *x2a = array;
@@ -5632,7 +5707,7 @@ struct symbol **Symbol_arrayof()
int i,arrSize; int i,arrSize;
if( x2a==0 ) return 0; if( x2a==0 ) return 0;
arrSize = x2a->count; arrSize = x2a->count;
array = (struct symbol **)calloc(arrSize, sizeof(struct symbol *)); array = (struct symbol **)lemon_calloc(arrSize, sizeof(struct symbol *));
if( array ){ if( array ){
for(i=0; i<arrSize; i++) array[i] = x2a->tbl[i].data; for(i=0; i<arrSize; i++) array[i] = x2a->tbl[i].data;
} }
@@ -5680,7 +5755,7 @@ PRIVATE unsigned statehash(struct config *a)
struct state *State_new() struct state *State_new()
{ {
struct state *newstate; struct state *newstate;
newstate = (struct state *)calloc(1, sizeof(struct state) ); newstate = (struct state *)lemon_calloc(1, sizeof(struct state) );
MemoryCheck(newstate); MemoryCheck(newstate);
return newstate; return newstate;
} }
@@ -5713,13 +5788,13 @@ static struct s_x3 *x3a;
/* Allocate a new associative array */ /* Allocate a new associative array */
void State_init(void){ void State_init(void){
if( x3a ) return; if( x3a ) return;
x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); x3a = (struct s_x3*)lemon_malloc( sizeof(struct s_x3) );
if( x3a ){ if( x3a ){
x3a->size = 128; x3a->size = 128;
x3a->count = 0; x3a->count = 0;
x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); x3a->tbl = (x3node*)lemon_calloc(128, sizeof(x3node) + sizeof(x3node*));
if( x3a->tbl==0 ){ if( x3a->tbl==0 ){
free(x3a); lemon_free(x3a);
x3a = 0; x3a = 0;
}else{ }else{
int i; int i;
@@ -5754,7 +5829,7 @@ int State_insert(struct state *data, struct config *key)
struct s_x3 array; struct s_x3 array;
array.size = arrSize = x3a->size*2; array.size = arrSize = x3a->size*2;
array.count = x3a->count; array.count = x3a->count;
array.tbl = (x3node*)calloc(arrSize, sizeof(x3node) + sizeof(x3node*)); array.tbl = (x3node*)lemon_calloc(arrSize, sizeof(x3node)+sizeof(x3node*));
if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
array.ht = (x3node**)&(array.tbl[arrSize]); array.ht = (x3node**)&(array.tbl[arrSize]);
for(i=0; i<arrSize; i++) array.ht[i] = 0; for(i=0; i<arrSize; i++) array.ht[i] = 0;
@@ -5770,7 +5845,7 @@ int State_insert(struct state *data, struct config *key)
newnp->from = &(array.ht[h]); newnp->from = &(array.ht[h]);
array.ht[h] = newnp; array.ht[h] = newnp;
} }
free(x3a->tbl); lemon_free(x3a->tbl);
*x3a = array; *x3a = array;
} }
/* Insert the new data */ /* Insert the new data */
@@ -5811,7 +5886,7 @@ struct state **State_arrayof(void)
int i,arrSize; int i,arrSize;
if( x3a==0 ) return 0; if( x3a==0 ) return 0;
arrSize = x3a->count; arrSize = x3a->count;
array = (struct state **)calloc(arrSize, sizeof(struct state *)); array = (struct state **)lemon_calloc(arrSize, sizeof(struct state *));
if( array ){ if( array ){
for(i=0; i<arrSize; i++) array[i] = x3a->tbl[i].data; for(i=0; i<arrSize; i++) array[i] = x3a->tbl[i].data;
} }
@@ -5853,13 +5928,13 @@ static struct s_x4 *x4a;
/* Allocate a new associative array */ /* Allocate a new associative array */
void Configtable_init(void){ void Configtable_init(void){
if( x4a ) return; if( x4a ) return;
x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); x4a = (struct s_x4*)lemon_malloc( sizeof(struct s_x4) );
if( x4a ){ if( x4a ){
x4a->size = 64; x4a->size = 64;
x4a->count = 0; x4a->count = 0;
x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); x4a->tbl = (x4node*)lemon_calloc(64, sizeof(x4node) + sizeof(x4node*));
if( x4a->tbl==0 ){ if( x4a->tbl==0 ){
free(x4a); lemon_free(x4a);
x4a = 0; x4a = 0;
}else{ }else{
int i; int i;
@@ -5894,7 +5969,8 @@ int Configtable_insert(struct config *data)
struct s_x4 array; struct s_x4 array;
array.size = arrSize = x4a->size*2; array.size = arrSize = x4a->size*2;
array.count = x4a->count; array.count = x4a->count;
array.tbl = (x4node*)calloc(arrSize, sizeof(x4node) + sizeof(x4node*)); array.tbl = (x4node*)lemon_calloc(arrSize,
sizeof(x4node) + sizeof(x4node*));
if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ if( array.tbl==0 ) return 0; /* Fail due to malloc failure */
array.ht = (x4node**)&(array.tbl[arrSize]); array.ht = (x4node**)&(array.tbl[arrSize]);
for(i=0; i<arrSize; i++) array.ht[i] = 0; for(i=0; i<arrSize; i++) array.ht[i] = 0;
@@ -5909,9 +5985,6 @@ int Configtable_insert(struct config *data)
newnp->from = &(array.ht[h]); newnp->from = &(array.ht[h]);
array.ht[h] = newnp; array.ht[h] = newnp;
} }
/* free(x4a->tbl); // This code was originall written for 16-bit machines.
** on modern machines, don't worry about freeing this trival amount of
** memory. */
*x4a = array; *x4a = array;
} }
/* Insert the new data */ /* Insert the new data */