Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge version 3.14 plus some subsequent patches (including the page-cache performance patch) from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent |
Files: | files | file ages | folders |
SHA1: |
d9f8918c5b7b6c8540b3f433142e1b4a |
User & Date: | drh 2016-08-11 19:12:25.266 |
Context
2017-01-09
| ||
06:33 | Upgrade this branch to 3.16 plus the various fixes that appeared after its release. (check-in: d0e212d08f user: dan tags: begin-concurrent) | |
2016-08-11
| ||
19:12 | Merge version 3.14 plus some subsequent patches (including the page-cache performance patch) from trunk. (check-in: d9f8918c5b user: drh tags: begin-concurrent) | |
18:05 | Add the "modeof=<filename>" URI parameter to os_unix.c - used to specify a file to copy permissions from when a new database is created. Also allow passing NULL as the second parameter to sqlite3rbu_vacuum(). (check-in: ed406d31ff user: dan tags: trunk) | |
2016-07-06
| ||
08:32 | Fix a typo in test program bc_test1.c. (check-in: 2c61b7ab18 user: dan tags: begin-concurrent) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
78 79 80 81 82 83 84 | TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@ # Enable/disable loadable extensions, and other optional features # based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). # The same set of OMIT and ENABLE flags should be passed to the # LEMON parser generator and the mkkeywordhash tool as well. OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ | < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@ # Enable/disable loadable extensions, and other optional features # based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). # The same set of OMIT and ENABLE flags should be passed to the # LEMON parser generator and the mkkeywordhash tool as well. OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ TCC += $(OPT_FEATURE_FLAGS) # Add in any optional parameters specified on the make commane line # ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1". TCC += $(OPTS) |
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | $(TOP)/ext/session/test_session.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ | > > | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | $(TOP)/ext/session/test_session.c \ $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/carray.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/fts5/fts5_test_tok.c \ $(TOP)/ext/misc/ieee754.c \ |
︙ | ︙ | |||
535 536 537 538 539 540 541 | # executables needed for testing # TESTPROGS = \ testfixture$(TEXE) \ sqlite3$(TEXE) \ sqlite3_analyzer$(TEXE) \ | | > > > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | # executables needed for testing # TESTPROGS = \ testfixture$(TEXE) \ sqlite3$(TEXE) \ sqlite3_analyzer$(TEXE) \ sqldiff$(TEXE) \ dbhash$(TEXE) # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 # SHELL_OPT += -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) |
︙ | ︙ | |||
583 584 585 586 587 588 589 | -avoid-version sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ $(TOP)/src/shell.c sqlite3.c \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" | | | > > > > > > > | | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | -avoid-version sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \ $(TOP)/src/shell.c sqlite3.c \ $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)" sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.lo $(TLIBS) dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.lo sqlite3.h $(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.lo $(TLIBS) scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.lo $(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \ $(TOP)/ext/misc/scrub.c sqlite3.lo $(TLIBS) srcck1$(BEXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c sourcetest: srcck1$(BEXE) sqlite3.c ./srcck1 sqlite3.c fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS) mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \ $(TLIBS) -rpath "$(libdir)" MPTEST1=./mptester$(TEXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20 MPTEST2=./mptester$(TEXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20 mptest: mptester$(TEXE) rm -f mptest.db $(MPTEST1) --journalmode DELETE |
︙ | ︙ | |||
1144 1145 1146 1147 1148 1149 1150 | rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS) LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c | | | | | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 | rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS) LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS) speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS) rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS) loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la $(LTLINK) $(TOP)/tool/loadfts.c libsqlite3.la -o $@ $(TLIBS) # This target will fail if the SQLite amalgamation contains any exported # symbols that do not begin with "sqlite3_". It is run as part of the # releasetest.tcl script. # VALIDIDS=' sqlite3(changeset|changegroup|session)?_' checksymbols: sqlite3.lo nm -g --defined-only sqlite3.lo | egrep -v $(VALIDIDS); test $$? -ne 0 echo '0 errors out of 1 tests' # Build the amalgamation-autoconf package. The amalamgation-tarball target builds # a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz. # The snapshot-tarball target builds a tarball named by the SHA1 hash # amalgamation-tarball: sqlite3.c |
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 | rm -f sqlite-*-output.vsix rm -f mptester mptester.exe rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f fts5.* fts5parse.* distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section | > | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | rm -f sqlite-*-output.vsix rm -f mptester mptester.exe rm -f rbu rbu.exe rm -f srcck1 srcck1.exe rm -f fuzzershell fuzzershell.exe rm -f fuzzcheck fuzzcheck.exe rm -f sqldiff sqldiff.exe rm -f dbhash dbhash.exe rm -f fts5.* fts5parse.* distclean: clean rm -f config.h config.log config.status libtool Makefile sqlite3.pc # # Windows section |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c | > > > > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c |
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # | > > > > > > | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. # !IF $(SESSION)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # |
︙ | ︙ | |||
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | $(TOP)\ext\rbu\test_rbu.c \ $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ | > > | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | $(TOP)\ext\rbu\test_rbu.c \ $(TOP)\ext\session\test_session.c # Statically linked extensions. # TESTEXT = \ $(TOP)\ext\misc\amatch.c \ $(TOP)\ext\misc\carray.c \ $(TOP)\ext\misc\closure.c \ $(TOP)\ext\misc\csv.c \ $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\fts5\fts5_test_tok.c \ $(TOP)\ext\misc\ieee754.c \ |
︙ | ︙ | |||
1361 1362 1363 1364 1365 1366 1367 | # executables needed for testing # TESTPROGS = \ testfixture.exe \ $(SQLITE3EXE) \ sqlite3_analyzer.exe \ | | > | 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 | # executables needed for testing # TESTPROGS = \ testfixture.exe \ $(SQLITE3EXE) \ sqlite3_analyzer.exe \ sqldiff.exe \ dbhash.exe # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)\test\fuzzdata1.db \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db \ |
︙ | ︙ | |||
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 | $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # <<mark>> sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) srcck1.exe: $(TOP)\tool\srcck1.c $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c sourcetest: srcck1.exe sqlite3.c srcck1.exe sqlite3.c fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) | > > > > > > | 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 | $(LTLINK) $(SHELL_COMPILE_OPTS) $(READLINE_FLAGS) $(TOP)\src\shell.c $(SHELL_CORE_SRC) \ /link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS) # <<mark>> sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) srcck1.exe: $(TOP)\tool\srcck1.c $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c sourcetest: srcck1.exe sqlite3.c srcck1.exe sqlite3.c fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) |
︙ | ︙ | |||
2085 2086 2087 2088 2089 2090 2091 | del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL | | | 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 | del /Q showjournal.exe showstat4.exe showwal.exe speedtest1.exe 2>NUL del /Q mptester.exe wordcount.exe rbu.exe srcck1.exe 2>NUL del /Q sqlite3.c sqlite3-*.c 2>NUL del /Q sqlite3rc.h 2>NUL del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL del /Q sqlite-*-output.vsix 2>NUL del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL del /Q fts5.* fts5parse.* 2>NUL # <</mark>> |
Changes to VERSION.
|
| | | 1 | 3.15.0 |
Changes to autoconf/Makefile.am.
1 |
| | | 1 2 3 4 5 6 7 8 9 | AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ @SESSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE lib_LTLIBRARIES = libsqlite3.la libsqlite3_la_SOURCES = sqlite3.c libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 sqlite3_SOURCES = shell.c sqlite3.h |
︙ | ︙ |
Changes to autoconf/Makefile.msc.
︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # Set this non-0 to enable full warnings (-W4, etc) when compiling. # !IFNDEF USE_FULLWARN USE_FULLWARN = 0 !ENDIF # Set this non-0 to use "stdcall" calling convention for the core library # and shell executable. # !IFNDEF USE_STDCALL USE_STDCALL = 0 !ENDIF | > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # Set this non-0 to enable full warnings (-W4, etc) when compiling. # !IFNDEF USE_FULLWARN USE_FULLWARN = 0 !ENDIF # Set this non-0 to enable full runtime error checks (-RTC1, etc). This # has no effect if (any) optimizations are enabled. # !IFNDEF USE_RUNTIME_CHECKS USE_RUNTIME_CHECKS = 0 !ENDIF # Set this non-0 to use "stdcall" calling convention for the core library # and shell executable. # !IFNDEF USE_STDCALL USE_STDCALL = 0 !ENDIF |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 189 190 191 | # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c | > > > > > > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | # Enable use of available compiler optimizations? Normally, this should be # non-zero. Setting this to zero, thus disabling all compiler optimizations, # can be useful for testing. # !IFNDEF OPTIMIZATIONS OPTIMIZATIONS = 2 !ENDIF # Set this to non-0 to enable support for the session extension. # !IFNDEF SESSION SESSION = 0 !ENDIF # Set the source code file to be used by executables and libraries when # they need the amalgamation. # !IFNDEF SQLITE3C !IF $(SPLIT_AMALGAMATION)!=0 SQLITE3C = sqlite3-all.c |
︙ | ︙ | |||
245 246 247 248 249 250 251 252 253 254 255 256 257 258 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # | > > > > > > | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF # Should the session extension be enabled? If so, add compilation options # to enable it. # !IF $(SESSION)!=0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1 !ENDIF # These are the "extended" SQLite compilation options used when compiling for # the Windows 10 platform. # |
︙ | ︙ | |||
433 434 435 436 437 438 439 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" | | | | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE !IFNDEF PLATFORM CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = !ENDIF !ENDIF !ELSE CORE_CCONV_OPTS = |
︙ | ︙ | |||
724 725 726 727 728 729 730 731 732 733 734 735 736 737 | # If optimizations are enabled or disabled (either implicitly or # explicitly), add the necessary flags. # !IF $(DEBUG)>1 || $(OPTIMIZATIONS)==0 TCC = $(TCC) -Od BCC = $(BCC) -Od !ELSEIF $(OPTIMIZATIONS)>=3 TCC = $(TCC) -Ox BCC = $(BCC) -Ox !ELSEIF $(OPTIMIZATIONS)==2 TCC = $(TCC) -O2 BCC = $(BCC) -O2 !ELSEIF $(OPTIMIZATIONS)==1 | > > > > | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 | # If optimizations are enabled or disabled (either implicitly or # explicitly), add the necessary flags. # !IF $(DEBUG)>1 || $(OPTIMIZATIONS)==0 TCC = $(TCC) -Od BCC = $(BCC) -Od !IF $(USE_RUNTIME_CHECKS)!=0 TCC = $(TCC) -RTC1 BCC = $(BCC) -RTC1 !ENDIF !ELSEIF $(OPTIMIZATIONS)>=3 TCC = $(TCC) -Ox BCC = $(BCC) -Ox !ELSEIF $(OPTIMIZATIONS)==2 TCC = $(TCC) -O2 BCC = $(BCC) -O2 !ELSEIF $(OPTIMIZATIONS)==1 |
︙ | ︙ |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
26 27 28 29 30 31 32 | # Check for library functions that SQLite can optionally use. AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R AC_CONFIG_FILES([Makefile sqlite3.pc]) AC_SUBST(BUILD_CFLAGS) | | > > > > > > > > > > > > | < < < | | < < | > | | | < < | < > > > | < | > > | | > | | | | | | > | > > | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # Check for library functions that SQLite can optionally use. AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R AC_CONFIG_FILES([Makefile sqlite3.pc]) AC_SUBST(BUILD_CFLAGS) #------------------------------------------------------------------------- # Two options to enable readline compatible libraries: # # --enable-editline # --enable-readline # # Both are enabled by default. If, after command line processing both are # still enabled, the script searches for editline first and automatically # disables readline if it is found. So, to use readline explicitly, the # user must pass "--disable-editline". To disable command line editing # support altogether, "--disable-editline --disable-readline". # # When searching for either library, check for headers before libraries # as some distros supply packages that contain libraries but not header # files, which come as a separate development package. # AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])]) AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])]) AS_IF([ test x"$enable_editline" != xno ],[ AC_CHECK_HEADERS([editline/readline.h],[ sLIBS=$LIBS LIBS="" AC_SEARCH_LIBS([readline],[edit],[ AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline) READLINE_LIBS=$LIBS enable_readline=no ]) AS_UNSET(ac_cv_search_readline) LIBS=$sLIBS ]) ]) AS_IF([ test x"$enable_readline" != xno ],[ AC_CHECK_HEADERS([readline/readline.h],[ sLIBS=$LIBS LIBS="" AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], []) AC_SEARCH_LIBS(readline,[readline edit], [ AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper) READLINE_LIBS=$LIBS ]) LIBS=$sLIBS ]) ]) AC_SUBST(READLINE_LIBS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-threadsafe # AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING( |
︙ | ︙ | |||
99 100 101 102 103 104 105 | #----------------------------------------------------------------------- # --enable-fts5 # AC_ARG_ENABLE(fts5, [AS_HELP_STRING( [--enable-fts5], [include fts5 support [default=no]])], [], [enable_fts5=no]) | | | > > > > > > > > > > > > | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | #----------------------------------------------------------------------- # --enable-fts5 # AC_ARG_ENABLE(fts5, [AS_HELP_STRING( [--enable-fts5], [include fts5 support [default=no]])], [], [enable_fts5=no]) if test x"$enable_fts5" = "xyes"; then AC_SEARCH_LIBS(log, m) FTS5_FLAGS=-DSQLITE_ENABLE_FTS5 fi AC_SUBST(FTS5_FLAGS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-json1 # AC_ARG_ENABLE(json1, [AS_HELP_STRING( [--enable-json1], [include json1 support [default=no]])], [], [enable_json1=no]) if test x"$enable_json1" = "xyes"; then JSON1_FLAGS=-DSQLITE_ENABLE_JSON1 fi AC_SUBST(JSON1_FLAGS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-session # AC_ARG_ENABLE(session, [AS_HELP_STRING( [--enable-session], [enable the session extension [default=no]])], [], [enable_session=no]) if test x"$enable_session" = "xyes"; then SESSION_FLAGS="-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK" fi AC_SUBST(SESSION_FLAGS) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-static-shell # AC_ARG_ENABLE(static-shell, [AS_HELP_STRING( [--enable-static-shell], [statically link libsqlite3 into shell tool [default=yes]])], [], [enable_static_shell=yes]) if test x"$enable_static_shell" = "xyes"; then EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT else EXTRA_SHELL_OBJ=libsqlite3.la fi AC_SUBST(EXTRA_SHELL_OBJ) #----------------------------------------------------------------------- |
︙ | ︙ |
Changes to autoconf/tea/configure.ac.
︙ | ︙ | |||
74 75 76 77 78 79 80 | TEA_ADD_SOURCES([tclsqlite3.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1]) TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1]) | < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | TEA_ADD_SOURCES([tclsqlite3.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1]) TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # The --with-system-sqlite causes the TCL bindings to SQLite to use # the system shared library for SQLite rather than statically linking # against its own private copy. This is dangerous and leads to |
︙ | ︙ |
Changes to configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for sqlite 3.15.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. |
︙ | ︙ | |||
722 723 724 725 726 727 728 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' PACKAGE_VERSION='3.15.0' PACKAGE_STRING='sqlite 3.15.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | enable_editline enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_rtree enable_gcov ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS | > > > | 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | enable_editline enable_readline with_readline_lib with_readline_inc enable_debug enable_amalgamation enable_load_extension enable_memsys5 enable_memsys3 enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_rtree enable_session enable_gcov ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS |
︙ | ︙ | |||
1456 1457 1458 1459 1460 1461 1462 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures sqlite 3.15.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 | --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in | | | 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 | --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of sqlite 3.15.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] |
︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 | --enable-editline enable BSD editline support --disable-readline disable readline support --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --enable-fts3 Enable the FTS3 extension --enable-fts4 Enable the FTS4 extension --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-rtree Enable the RTREE extension --enable-gcov Enable coverage testing using gcov Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] | > > > | 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | --enable-editline enable BSD editline support --disable-readline disable readline support --enable-debug enable debugging & verbose explain --disable-amalgamation Disable the amalgamation and instead build all files separately --disable-load-extension Disable loading of external extensions --enable-memsys5 Enable MEMSYS5 --enable-memsys3 Enable MEMSYS3 --enable-fts3 Enable the FTS3 extension --enable-fts4 Enable the FTS4 extension --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-rtree Enable the RTREE extension --enable-session Enable the SESSION extension --enable-gcov Enable coverage testing using gcov Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] |
︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sqlite configure 3.15.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit |
︙ | ︙ | |||
2061 2062 2063 2064 2065 2066 2067 | eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. | | | 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 | eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sqlite $as_me 3.15.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3919 3920 3921 3922 3923 3924 3925 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext | | | | | 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:3932: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3935: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3938: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 |
︙ | ︙ | |||
5131 5132 5133 5134 5135 5136 5137 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5144 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in |
︙ | ︙ | |||
6656 6657 6658 6659 6660 6661 6662 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6669: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6673: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes |
︙ | ︙ | |||
6995 6996 6997 6998 6999 7000 7001 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7008: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7012: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes |
︙ | ︙ | |||
7100 7101 7102 7103 7104 7105 7106 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7113: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7117: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
7155 7156 7157 7158 7159 7160 7161 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7168: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7172: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
9535 9536 9537 9538 9539 9540 9541 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9548 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9631 9632 9633 9634 9635 9636 9637 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 9644 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 | if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ | > > > > > > > > > > > > > > | 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 | if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # Recent versions of Xcode on Macs hid the tclConfig.sh file # in a strange place. if test x"${ac_cv_c_tclconfig}" = x ; then if test x"$cross_compiling" = xno; then for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ |
︙ | ︙ | |||
11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # See whether we should enable Full Text Search extensions # Check whether --enable-fts3 was given. if test "${enable_fts3+set}" = set; then : enableval=$enable_fts3; enable_fts3=yes else | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support memsys3 and/or memsys5 # # Check whether --enable-memsys5 was given. if test "${enable_memsys5+set}" = set; then : enableval=$enable_memsys5; enable_memsys5=yes else enable_memsys5=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS5" >&5 $as_echo_n "checking whether to support MEMSYS5... " >&6; } if test "${enable_memsys5}" = "yes"; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --enable-memsys3 was given. if test "${enable_memsys3+set}" = set; then : enableval=$enable_memsys3; enable_memsys3=yes else enable_memsys3=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS3" >&5 $as_echo_n "checking whether to support MEMSYS3... " >&6; } if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ######### # See whether we should enable Full Text Search extensions # Check whether --enable-fts3 was given. if test "${enable_fts3+set}" = set; then : enableval=$enable_fts3; enable_fts3=yes else |
︙ | ︙ | |||
11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 | else enable_rtree=no fi if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; | > > > > > > > > > > > > > > | 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 | else enable_rtree=no fi if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # See whether we should enable the SESSION extension # Check whether --enable-session was given. if test "${enable_session+set}" = set; then : enableval=$enable_session; enable_session=yes else enable_session=no fi if test "${enable_session}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; |
︙ | ︙ | |||
12075 12076 12077 12078 12079 12080 12081 | test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 | test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sqlite $as_me 3.15.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
︙ | ︙ | |||
12141 12142 12143 12144 12145 12146 12147 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ | | | 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sqlite config.status 3.15.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
︙ | ︙ |
Changes to configure.ac.
︙ | ︙ | |||
329 330 331 332 333 334 335 336 337 338 339 340 341 342 | if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ | > > > > > > > > > > > > > > | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # Recent versions of Xcode on Macs hid the tclConfig.sh file # in a strange place. if test x"${ac_cv_c_tclconfig}" = x ; then if test x"$cross_compiling" = xno; then for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="$i" break fi done fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ |
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 | [use_loadextension=$enableval],[use_loadextension=yes]) if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ######### # See whether we should enable Full Text Search extensions AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension]), [enable_fts3=yes],[enable_fts3=no]) if test "${enable_fts3}" = "yes" ; then | > > > > > > > > > > > > > > > > > > > > > > > > | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | [use_loadextension=$enableval],[use_loadextension=yes]) if test "${use_loadextension}" = "yes" ; then OPT_FEATURE_FLAGS="" AC_SEARCH_LIBS(dlopen, dl) else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi ########## # Do we want to support memsys3 and/or memsys5 # AC_ARG_ENABLE(memsys5, AC_HELP_STRING([--enable-memsys5],[Enable MEMSYS5]), [enable_memsys5=yes],[enable_memsys5=no]) AC_MSG_CHECKING([whether to support MEMSYS5]) if test "${enable_memsys5}" = "yes"; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS5" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_ARG_ENABLE(memsys3, AC_HELP_STRING([--enable-memsys3],[Enable MEMSYS3]), [enable_memsys3=yes],[enable_memsys3=no]) AC_MSG_CHECKING([whether to support MEMSYS3]) if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_MEMSYS3" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ######### # See whether we should enable Full Text Search extensions AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3], [Enable the FTS3 extension]), [enable_fts3=yes],[enable_fts3=no]) if test "${enable_fts3}" = "yes" ; then |
︙ | ︙ | |||
610 611 612 613 614 615 616 617 618 619 620 621 622 623 | # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension]), [enable_rtree=yes],[enable_rtree=no]) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; | > > > > > > > > > > | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension]), [enable_rtree=yes],[enable_rtree=no]) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi ######### # See whether we should enable the SESSION extension AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session], [Enable the SESSION extension]), [enable_session=yes],[enable_session=no]) if test "${enable_session}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS do case $option in -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";; |
︙ | ︙ |
Changes to ext/fts2/fts2_tokenizer.c.
︙ | ︙ | |||
95 96 97 98 99 100 101 | } sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } #ifdef SQLITE_TEST | > > > | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | } sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <string.h> /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two arguments: ** |
︙ | ︙ |
Changes to ext/fts3/fts3_test.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** testing. It contains a Tcl command that can be used to test if a document ** matches an FTS NEAR expression. ** ** As of March 2012, it also contains a version 1 tokenizer used for testing ** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly. */ | > > > | > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** testing. It contains a Tcl command that can be used to test if a document ** matches an FTS NEAR expression. ** ** As of March 2012, it also contains a version 1 tokenizer used for testing ** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly. */ #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include <string.h> #include <assert.h> #if defined(SQLITE_TEST) #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) /* Required so that the "ifdef SQLITE_ENABLE_FTS3" below works */ |
︙ | ︙ | |||
139 140 141 142 143 144 145 | return nOcc; } /* ** Tclcmd: fts3_near_match DOCUMENT EXPR ?OPTIONS? */ | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | return nOcc; } /* ** Tclcmd: fts3_near_match DOCUMENT EXPR ?OPTIONS? */ static int SQLITE_TCLAPI fts3_near_match_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nTotal = 0; int rc; |
︙ | ︙ | |||
274 275 276 277 278 279 280 | ** set cfg [fts3_configure_incr_load $new_chunksize $new_threshold] ** ** .... run tests .... ** ** # Restore initial incr-load settings: ** eval fts3_configure_incr_load $cfg */ | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | ** set cfg [fts3_configure_incr_load $new_chunksize $new_threshold] ** ** .... run tests .... ** ** # Restore initial incr-load settings: ** eval fts3_configure_incr_load $cfg */ static int SQLITE_TCLAPI fts3_configure_incr_load_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_ENABLE_FTS3 extern int test_fts3_node_chunksize; |
︙ | ︙ | |||
484 485 486 487 488 489 490 | if( pCsr->iLangid>=100 ){ rc = SQLITE_ERROR; } return rc; } #endif | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | if( pCsr->iLangid>=100 ){ rc = SQLITE_ERROR; } return rc; } #endif static int SQLITE_TCLAPI fts3_test_tokenizer_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_ENABLE_FTS3 static const sqlite3_tokenizer_module testTokenizerModule = { |
︙ | ︙ | |||
513 514 515 516 517 518 519 | (const unsigned char *)&pPtr, sizeof(sqlite3_tokenizer_module *) )); #endif UNUSED_PARAMETER(clientData); return TCL_OK; } | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | (const unsigned char *)&pPtr, sizeof(sqlite3_tokenizer_module *) )); #endif UNUSED_PARAMETER(clientData); return TCL_OK; } static int SQLITE_TCLAPI fts3_test_varint_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_ENABLE_FTS3 char aBuf[24]; |
︙ | ︙ |
Changes to ext/fts3/fts3_tokenizer.c.
︙ | ︙ | |||
220 221 222 223 224 225 226 | sqlite3_free(zCopy); return rc; } #ifdef SQLITE_TEST | > > > | > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | sqlite3_free(zCopy); return rc; } #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <string.h> /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two or more arguments: ** |
︙ | ︙ |
Changes to ext/fts5/fts5.h.
︙ | ︙ | |||
139 140 141 142 143 144 145 | ** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): ** This API function is used to query the FTS table for phrase iPhrase ** of the current query. Specifically, a query equivalent to: ** ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the | > > | | | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | ** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback): ** This API function is used to query the FTS table for phrase iPhrase ** of the current query. Specifically, a query equivalent to: ** ** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid ** ** with $p set to a phrase equivalent to the phrase iPhrase of the ** current query is executed. Any column filter that applies to ** phrase iPhrase of the current query is included in $p. For each ** row visited, the callback function passed as the fourth argument ** is invoked. The context and API objects passed to the callback ** function may be used to access the properties of each matched row. ** Invoking Api.xUserData() returns a copy of the pointer passed as ** the third argument to pUserData. ** ** If the callback function returns any value other than SQLITE_OK, the ** query is abandoned and the xQueryPhrase function returns immediately. ** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK. ** Otherwise, the error code is propagated upwards. ** ** If the query runs to completion without incident, SQLITE_OK is returned. |
︙ | ︙ | |||
312 313 314 315 316 317 318 | ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | ** Applications may also register custom tokenizer types. A tokenizer ** is registered by providing fts5 with a populated instance of the ** following structure. All structure methods must be defined, setting ** any member of the fts5_tokenizer struct to NULL leads to undefined ** behaviour. The structure methods are expected to function as follows: ** ** xCreate: ** This function is used to allocate and initialize a tokenizer instance. ** A tokenizer instance is required to actually tokenize text. ** ** The first argument passed to this function is a copy of the (void*) ** pointer provided by the application when the fts5_tokenizer object ** was registered with FTS5 (the third argument to xCreateTokenizer()). ** The second and third arguments are an array of nul-terminated strings ** containing the tokenizer arguments, if any, specified following the |
︙ | ︙ | |||
571 572 573 574 575 576 577 | *************************************************************************/ #ifdef __cplusplus } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ | < | 573 574 575 576 577 578 579 | *************************************************************************/ #ifdef __cplusplus } /* end of the 'extern "C"' block */ #endif #endif /* _FTS5_H */ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
682 683 684 685 686 687 688 | typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); int sqlite3Fts5ExprPopulatePoslists( Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int ); void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); | < | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | typedef struct Fts5PoslistPopulator Fts5PoslistPopulator; Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr*, int); int sqlite3Fts5ExprPopulatePoslists( Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int ); void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); /******************************************* ** The fts5_expr.c API above this point is used by the other hand-written |
︙ | ︙ | |||
734 735 736 737 738 739 740 741 742 743 744 745 746 747 | void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*); void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /* ** End of interface to code in fts5_expr.c. **************************************************************************/ | > | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*); void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*); void sqlite3Fts5ParseNodeFree(Fts5ExprNode*); void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*); void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*); Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*); void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p); void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*); /* ** End of interface to code in fts5_expr.c. **************************************************************************/ |
︙ | ︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 | case ')': tok = FTS5_RP; break; case '{': tok = FTS5_LCP; break; case '}': tok = FTS5_RCP; break; case ':': tok = FTS5_COLON; break; case ',': tok = FTS5_COMMA; break; case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; case '\0': tok = FTS5_EOF; break; case '"': { const char *z2; tok = FTS5_STRING; for(z2=&z[1]; 1; z2++){ | > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | case ')': tok = FTS5_RP; break; case '{': tok = FTS5_LCP; break; case '}': tok = FTS5_RCP; break; case ':': tok = FTS5_COLON; break; case ',': tok = FTS5_COMMA; break; case '+': tok = FTS5_PLUS; break; case '*': tok = FTS5_STAR; break; case '-': tok = FTS5_MINUS; break; case '\0': tok = FTS5_EOF; break; case '"': { const char *z2; tok = FTS5_STRING; for(z2=&z[1]; 1; z2++){ |
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 | pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNode)); } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ int tflags = 0; Fts5ExprTerm *p; for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ const char *zTerm = p->zTerm; rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), | > > > > > > > > > > > | 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 | pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNode)); } if( rc==SQLITE_OK ){ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)); } if( rc==SQLITE_OK ){ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset; if( pColsetOrig ){ int nByte = sizeof(Fts5Colset) + pColsetOrig->nCol * sizeof(int); Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ memcpy(pColset, pColsetOrig, nByte); } pNew->pRoot->pNear->pColset = pColset; } } for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ int tflags = 0; Fts5ExprTerm *p; for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ const char *zTerm = p->zTerm; rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), |
︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 | /* Check that the array is in order and contains no duplicate entries. */ for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); #endif } return pNew; } Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ Fts5Token *p ){ Fts5Colset *pRet = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 | /* Check that the array is in order and contains no duplicate entries. */ for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] ); #endif } return pNew; } /* ** Allocate and return an Fts5Colset object specifying the inverse of ** the colset passed as the second argument. Free the colset passed ** as the second argument before returning. */ Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){ Fts5Colset *pRet; int nCol = pParse->pConfig->nCol; pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5Colset) + sizeof(int)*nCol ); if( pRet ){ int i; int iOld = 0; for(i=0; i<nCol; i++){ if( iOld>=p->nCol || p->aiCol[iOld]!=i ){ pRet->aiCol[pRet->nCol++] = i; }else{ iOld++; } } } sqlite3_free(p); return pRet; } Fts5Colset *sqlite3Fts5ParseColset( Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */ Fts5Colset *pColset, /* Existing colset object */ Fts5Token *p ){ Fts5Colset *pRet = 0; |
︙ | ︙ | |||
2602 2603 2604 2605 2606 2607 2608 | return 1; } void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ fts5ExprCheckPoslists(pExpr->pRoot, iRowid); } | < < < < < < < < < < < | 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 | return 1; } void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){ fts5ExprCheckPoslists(pExpr->pRoot, iRowid); } /* ** This function is only called for detail=columns tables. */ int sqlite3Fts5ExprPhraseCollist( Fts5Expr *pExpr, int iPhrase, const u8 **ppCollist, |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 | ** Fts5Iter.poslist buffer and then set the output pointer to point ** to this buffer. */ fts5BufferZero(&pIter->poslist); fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); pIter->base.pData = pIter->poslist.p; } } /* ** xSetOutputs callback used by detail=col when there is a column filter ** and there are 100 or more columns. Also called as a fallback from ** fts5IterSetOutputs_Col100 if the column-list spans more than one page. */ static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ | > > > > > > > > > | 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 | ** Fts5Iter.poslist buffer and then set the output pointer to point ** to this buffer. */ fts5BufferZero(&pIter->poslist); fts5SegiterPoslist(pIter->pIndex, pSeg, 0, &pIter->poslist); pIter->base.pData = pIter->poslist.p; } } /* ** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match ** against no columns at all). */ static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){ UNUSED_PARAM(pSeg); pIter->base.nData = 0; } /* ** xSetOutputs callback used by detail=col when there is a column filter ** and there are 100 or more columns. Also called as a fallback from ** fts5IterSetOutputs_Col100 if the column-list spans more than one page. */ static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){ |
︙ | ︙ | |||
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 | if( pConfig->eDetail==FTS5_DETAIL_NONE ){ pIter->xSetOutputs = fts5IterSetOutputs_None; } else if( pIter->pColset==0 ){ pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; } else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ pIter->xSetOutputs = fts5IterSetOutputs_Full; } else{ assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS ); | > > > > | 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 | if( pConfig->eDetail==FTS5_DETAIL_NONE ){ pIter->xSetOutputs = fts5IterSetOutputs_None; } else if( pIter->pColset==0 ){ pIter->xSetOutputs = fts5IterSetOutputs_Nocolset; } else if( pIter->pColset->nCol==0 ){ pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset; } else if( pConfig->eDetail==FTS5_DETAIL_FULL ){ pIter->xSetOutputs = fts5IterSetOutputs_Full; } else{ assert( pConfig->eDetail==FTS5_DETAIL_COLUMNS ); |
︙ | ︙ |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 | assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); | < | 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 | assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 ); assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 ); assert( pCsr->iLastRowid==LARGEST_INT64 ); assert( pCsr->iFirstRowid==SMALLEST_INT64 ); pCsr->ePlan = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; rc = fts5CursorFirst(pTab, pCsr, bDesc); }else if( pMatch ){ const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); if( zExpr==0 ) zExpr = ""; rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ if( zExpr[0]=='*' ){ |
︙ | ︙ |
Changes to ext/fts5/fts5_storage.c.
︙ | ︙ | |||
243 244 245 246 247 248 249 | int bWithout, /* True for without rowid */ char **pzErr /* OUT: Error message */ ){ int rc; char *zErr = 0; rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", | | > > > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | int bWithout, /* True for without rowid */ char **pzErr /* OUT: Error message */ ){ int rc; char *zErr = 0; rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s", pConfig->zDb, pConfig->zName, zPost, zDefn, #ifndef SQLITE_FTS5_NO_WITHOUT_ROWID bWithout?" WITHOUT ROWID": #endif "" ); if( zErr ){ *pzErr = sqlite3_mprintf( "fts5: error creating shadow table %q_%s: %s", pConfig->zName, zPost, zErr ); sqlite3_free(zErr); |
︙ | ︙ |
Changes to ext/fts5/fts5_tcl.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ****************************************************************************** ** */ #ifdef SQLITE_TEST | > > > | > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** ****************************************************************************** ** */ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #ifdef SQLITE_ENABLE_FTS5 #include "fts5.h" #include <string.h> #include <assert.h> |
︙ | ︙ | |||
74 75 76 77 78 79 80 | return aErr[i].rc; } } return SQLITE_ERROR; } | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | return aErr[i].rc; } } return SQLITE_ERROR; } static int SQLITE_TCLAPI f5tDbAndApi( Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **ppDb, fts5_api **ppApi ){ sqlite3 *db = 0; int rc = f5tDbPointer(interp, pObj, &db); |
︙ | ︙ | |||
160 161 162 163 164 165 166 | if( rc==TCL_OK ){ rc = f5tResultToErrorCode(Tcl_GetStringResult(p->interp)); } return rc; } | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | if( rc==TCL_OK ){ rc = f5tResultToErrorCode(Tcl_GetStringResult(p->interp)); } return rc; } static int SQLITE_TCLAPI xF5tApi(void*, Tcl_Interp*, int, Tcl_Obj *CONST []); static int xQueryPhraseCb( const Fts5ExtensionApi *pApi, Fts5Context *pFts, void *pCtx ){ F5tFunction *p = (F5tFunction*)pCtx; |
︙ | ︙ | |||
205 206 207 208 209 210 211 | } /* ** api sub-command... ** ** Description... */ | | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | } /* ** api sub-command... ** ** Description... */ static int SQLITE_TCLAPI xF5tApi( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct Sub { const char *zName; |
︙ | ︙ | |||
598 599 600 601 602 603 604 | } /* ** sqlite3_fts5_create_function DB NAME SCRIPT ** ** Description... */ | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | } /* ** sqlite3_fts5_create_function DB NAME SCRIPT ** ** Description... */ static int SQLITE_TCLAPI f5tCreateFunction( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *zName; Tcl_Obj *pScript; |
︙ | ︙ | |||
668 669 670 671 672 673 674 | /* ** sqlite3_fts5_tokenize DB TOKENIZER TEXT ** ** Description... */ | | | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | /* ** sqlite3_fts5_tokenize DB TOKENIZER TEXT ** ** Description... */ static int SQLITE_TCLAPI f5tTokenize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *zText; int nText; |
︙ | ︙ | |||
874 875 876 877 878 879 880 | pInst->pContext->xToken = xOldToken; return rc; } /* ** sqlite3_fts5_token ?-colocated? TEXT START END */ | | | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | pInst->pContext->xToken = xOldToken; return rc; } /* ** sqlite3_fts5_token ?-colocated? TEXT START END */ static int SQLITE_TCLAPI f5tTokenizerReturn( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ F5tTokenizerContext *p = (F5tTokenizerContext*)clientData; int iStart; |
︙ | ︙ | |||
945 946 947 948 949 950 951 | ** tokenizer instance "returned" by SCRIPT. Specifically, to tokenize ** text SCRIPT2 is invoked with a single argument appended to it - the ** text to tokenize. ** ** SCRIPT2 should invoke the [sqlite3_fts5_token] command once for each ** token within the tokenized text. */ | | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 | ** tokenizer instance "returned" by SCRIPT. Specifically, to tokenize ** text SCRIPT2 is invoked with a single argument appended to it - the ** text to tokenize. ** ** SCRIPT2 should invoke the [sqlite3_fts5_token] command once for each ** token within the tokenized text. */ static int SQLITE_TCLAPI f5tCreateTokenizer( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ F5tTokenizerContext *pContext = (F5tTokenizerContext*)clientData; sqlite3 *db; |
︙ | ︙ | |||
988 989 990 991 992 993 994 | Tcl_AppendResult(interp, "error in fts5_api.xCreateTokenizer()", 0); return TCL_ERROR; } return TCL_OK; } | | | | 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | Tcl_AppendResult(interp, "error in fts5_api.xCreateTokenizer()", 0); return TCL_ERROR; } return TCL_OK; } static void SQLITE_TCLAPI xF5tFree(ClientData clientData){ ckfree(clientData); } /* ** sqlite3_fts5_may_be_corrupt BOOLEAN ** ** Set or clear the global "may-be-corrupt" flag. Return the old value. */ static int SQLITE_TCLAPI f5tMayBeCorrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int bOld = sqlite3_fts5_may_be_corrupt; |
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | unsigned int h = 13; for(i=n-1; i>=0; i--){ h = (h << 3) ^ h ^ p[i]; } return (h % nSlot); } | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | unsigned int h = 13; for(i=n-1; i>=0; i--){ h = (h << 3) ^ h ^ p[i]; } return (h % nSlot); } static int SQLITE_TCLAPI f5tTokenHash( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *z; int n; |
︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 | z = Tcl_GetStringFromObj(objv[2], &n); iVal = f5t_fts5HashKey(nSlot, z, n); Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); return TCL_OK; } | | | 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | z = Tcl_GetStringFromObj(objv[2], &n); iVal = f5t_fts5HashKey(nSlot, z, n); Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); return TCL_OK; } static int SQLITE_TCLAPI f5tRegisterMatchinfo( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3 *db = 0; |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 | if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } | | | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } static int SQLITE_TCLAPI f5tRegisterTok( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3 *db = 0; |
︙ | ︙ |
Changes to ext/fts5/fts5parse.y.
︙ | ︙ | |||
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | } %type colset {Fts5Colset*} %destructor colset { sqlite3_free($$); } %type colsetlist {Fts5Colset*} %destructor colsetlist { sqlite3_free($$); } colset(A) ::= LCP colsetlist(X) RCP. { A = X; } colset(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } colsetlist(A) ::= colsetlist(Y) STRING(X). { A = sqlite3Fts5ParseColset(pParse, Y, &X); } colsetlist(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } | > > > > > > > < | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | } %type colset {Fts5Colset*} %destructor colset { sqlite3_free($$); } %type colsetlist {Fts5Colset*} %destructor colsetlist { sqlite3_free($$); } colset(A) ::= MINUS LCP colsetlist(X) RCP. { A = sqlite3Fts5ParseColsetInvert(pParse, X); } colset(A) ::= LCP colsetlist(X) RCP. { A = X; } colset(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } colset(A) ::= MINUS STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); A = sqlite3Fts5ParseColsetInvert(pParse, A); } colsetlist(A) ::= colsetlist(Y) STRING(X). { A = sqlite3Fts5ParseColset(pParse, Y, &X); } colsetlist(A) ::= STRING(X). { A = sqlite3Fts5ParseColset(pParse, 0, &X); } %type nearset {Fts5ExprNearset*} %type nearphrases {Fts5ExprNearset*} %destructor nearset { sqlite3Fts5ParseNearsetFree($$); } %destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); } nearset(A) ::= phrase(X). { A = sqlite3Fts5ParseNearset(pParse, 0, X); } |
︙ | ︙ |
Changes to ext/fts5/test/fts5aux.test.
︙ | ︙ | |||
241 242 243 244 245 246 247 248 249 250 | execsql { DELETE FROM x1 } foreach row $lRow { execsql { INSERT INTO x1 VALUES($row) } } breakpoint do_execsql_test 8.$tn { SELECT highlight(x1, 0, '[', ']') FROM x1 WHERE x1 MATCH 'a OR (b AND d)'; } $res } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | execsql { DELETE FROM x1 } foreach row $lRow { execsql { INSERT INTO x1 VALUES($row) } } breakpoint do_execsql_test 8.$tn { SELECT highlight(x1, 0, '[', ']') FROM x1 WHERE x1 MATCH 'a OR (b AND d)'; } $res } #------------------------------------------------------------------------- # Test the built-in bm25() demo. # reset_db do_execsql_test 9.1 { CREATE VIRTUAL TABLE t1 USING fts5(a, b); INSERT INTO t1 VALUES('a', NULL); -- 1 INSERT INTO t1 VALUES('a', NULL); -- 2 INSERT INTO t1 VALUES('a', NULL); -- 3 INSERT INTO t1 VALUES('a', NULL); -- 4 INSERT INTO t1 VALUES('a', NULL); -- 5 INSERT INTO t1 VALUES('a', NULL); -- 6 INSERT INTO t1 VALUES('a', NULL); -- 7 INSERT INTO t1 VALUES('a', NULL); -- 8 INSERT INTO t1 VALUES(NULL, 'a a b'); -- 9 INSERT INTO t1 VALUES(NULL, 'b b a'); -- 10 } do_execsql_test 9.2 { SELECT rowid FROM t1('a AND b') ORDER BY rank; } { 10 9 } do_execsql_test 9.3 { SELECT rowid FROM t1('b:a AND b:b') ORDER BY rank; } { 9 10 } finish_test |
Added ext/fts5/test/fts5colset.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # 2016 August 10 # # 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. The # focus of this script is testing the FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5colset # If SQLITE_ENABLE_FTS5 is not defined, omit this file. ifcapable !fts5 { finish_test return } foreach_detail_mode $::testprefix { if {[detail_is_none]} continue do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, d, detail=%DETAIL%); INSERT INTO t1 VALUES('a', 'b', 'c', 'd'); -- 1 INSERT INTO t1 VALUES('d', 'a', 'b', 'c'); -- 2 INSERT INTO t1 VALUES('c', 'd', 'a', 'b'); -- 3 INSERT INTO t1 VALUES('b', 'c', 'd', 'a'); -- 4 } foreach {tn q res} { 1 "a" {1 2 3 4} 2 "{a} : a" {1} 3 "-{a} : a" {2 3 4} 4 "- {a c} : a" {2 4} 5 " - {d d c} : a" {1 2} 6 "- {d c b a} : a" {} 7 "-{\"a\"} : b" {1 2 3} 8 "- c : a" {1 2 4} 9 "-c : a" {1 2 4} 10 "-\"c\" : a" {1 2 4} } { breakpoint do_execsql_test 1.$tn { SELECT rowid FROM t1($q) } $res } } finish_test |
Changes to ext/fts5/test/fts5rank.test.
︙ | ︙ | |||
87 88 89 90 91 92 93 | } {1 3 2} do_test 2.7 { execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db } {1 3 2} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | } {1 3 2} do_test 2.7 { execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db } {1 3 2} #-------------------------------------------------------------------------- # At one point there was a problem with queries such as: # # ... MATCH 'x OR y' ORDER BY rank; # # if there were zero occurrences of token 'y' in the dataset. The # following tests verify that that problem has been addressed. # foreach_detail_mode $::testprefix { do_execsql_test 3.1.0 { CREATE VIRTUAL TABLE y1 USING fts5(z, detail=%DETAIL%); INSERT INTO y1 VALUES('test xyz'); INSERT INTO y1 VALUES('test test xyz test'); INSERT INTO y1 VALUES('test test xyz'); } do_execsql_test 3.1.1 { SELECT rowid FROM y1('test OR tset'); } {1 2 3} do_execsql_test 3.1.2 { SELECT rowid FROM y1('test OR tset') ORDER BY bm25(y1) } {2 3 1} do_execsql_test 3.1.3 { SELECT rowid FROM y1('test OR tset') ORDER BY +rank } {2 3 1} do_execsql_test 3.1.4 { SELECT rowid FROM y1('test OR tset') ORDER BY rank } {2 3 1} do_execsql_test 3.1.5 { SELECT rowid FROM y1('test OR xyz') ORDER BY rank } {3 2 1} do_execsql_test 3.2.1 { CREATE VIRTUAL TABLE z1 USING fts5(a, detail=%DETAIL%); INSERT INTO z1 VALUES('wrinkle in time'); SELECT * FROM z1 WHERE z1 MATCH 'wrinkle in time OR a wrinkle in time'; } {{wrinkle in time}} } do_execsql_test 4.1 { DROP TABLE IF EXISTS VTest; CREATE virtual TABLE VTest USING FTS5( Title, AUthor, tokenize ='porter unicode61 remove_diacritics 1', columnsize='1', detail=full ); INSERT INTO VTest (Title, Author) VALUES ('wrinkle in time', 'Bill Smith'); SELECT * FROM VTest WHERE VTest MATCH 'wrinkle in time OR a wrinkle in time' ORDER BY rank; } {{wrinkle in time} {Bill Smith}} finish_test |
Changes to ext/fts5/test/fts5simple.test.
︙ | ︙ | |||
261 262 263 264 265 266 267 | # Test that character 0x1A is allowed in fts5 barewords. # do_test 11.0 { execsql "CREATE VIRTUAL TABLE t4 USING fts5(x, tokenize=\"ascii tokenchars '\x1A'\")" execsql " INSERT INTO t4 VALUES('a b c \x1A'); INSERT INTO t4 VALUES('a b c d\x1A'); | | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | # Test that character 0x1A is allowed in fts5 barewords. # do_test 11.0 { execsql "CREATE VIRTUAL TABLE t4 USING fts5(x, tokenize=\"ascii tokenchars '\x1A'\")" execsql " INSERT INTO t4 VALUES('a b c \x1A'); INSERT INTO t4 VALUES('a b c d\x1A'); INSERT INTO t4 VALUES('a b c \x1Ag'); INSERT INTO t4 VALUES('a b c d'); " } {} do_test 11.1 { execsql "SELECT rowid FROM t4('\x1A')" } {1} |
︙ | ︙ |
Added ext/misc/carray.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | /* ** 2016-06-29 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file demonstrates how to create a table-valued-function that ** returns the values in a C-language array. ** Examples: ** ** SELECT * FROM carray($ptr,5) ** ** The query above returns 5 integers contained in a C-language array ** at the address $ptr. $ptr is a pointer to the array of integers that ** has been cast to an integer. ** ** There is an optional third parameter to determine the datatype of ** the C-language array. Allowed values of the third parameter are ** 'int32', 'int64', 'double', 'char*'. Example: ** ** SELECT * FROM carray($ptr,10,'char*'); ** ** HOW IT WORKS ** ** The carray "function" is really a virtual table with the ** following schema: ** ** CREATE TABLE carray( ** value, ** pointer HIDDEN, ** count HIDDEN, ** ctype TEXT HIDDEN ** ); ** ** If the hidden columns "pointer" and "count" are unconstrained, then ** the virtual table has no rows. Otherwise, the virtual table interprets ** the integer value of "pointer" as a pointer to the array and "count" ** as the number of elements in the array. The virtual table steps through ** the array, element by element. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Allowed datatypes */ #define CARRAY_INT32 0 #define CARRAY_INT64 1 #define CARRAY_DOUBLE 2 #define CARRAY_TEXT 3 /* ** Names of types */ static const char *azType[] = { "int32", "int64", "double", "char*" }; /* carray_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ typedef struct carray_cursor carray_cursor; struct carray_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3_int64 iRowid; /* The rowid */ sqlite3_int64 iPtr; /* Pointer to array of values */ sqlite3_int64 iCnt; /* Number of integers in the array */ unsigned char eType; /* One of the CARRAY_type values */ }; /* ** The carrayConnect() method is invoked to create a new ** carray_vtab that describes the carray virtual table. ** ** Think of this routine as the constructor for carray_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the carray_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against carray will look like. */ static int carrayConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define CARRAY_COLUMN_VALUE 0 #define CARRAY_COLUMN_POINTER 1 #define CARRAY_COLUMN_COUNT 2 #define CARRAY_COLUMN_CTYPE 3 rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* ** This method is the destructor for carray_cursor objects. */ static int carrayDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new carray_cursor object. */ static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ carray_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a carray_cursor. */ static int carrayClose(sqlite3_vtab_cursor *cur){ sqlite3_free(cur); return SQLITE_OK; } /* ** Advance a carray_cursor to its next row of output. */ static int carrayNext(sqlite3_vtab_cursor *cur){ carray_cursor *pCur = (carray_cursor*)cur; pCur->iRowid++; return SQLITE_OK; } /* ** Return values of columns for the row at which the carray_cursor ** is currently pointing. */ static int carrayColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ carray_cursor *pCur = (carray_cursor*)cur; sqlite3_int64 x = 0; switch( i ){ case CARRAY_COLUMN_POINTER: x = pCur->iPtr; break; case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break; case CARRAY_COLUMN_CTYPE: { sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC); return SQLITE_OK; } default: { switch( pCur->eType ){ case CARRAY_INT32: { int *p = (int*)pCur->iPtr; sqlite3_result_int(ctx, p[pCur->iRowid-1]); return SQLITE_OK; } case CARRAY_INT64: { sqlite3_int64 *p = (sqlite3_int64*)pCur->iPtr; sqlite3_result_int64(ctx, p[pCur->iRowid-1]); return SQLITE_OK; } case CARRAY_DOUBLE: { double *p = (double*)pCur->iPtr; sqlite3_result_double(ctx, p[pCur->iRowid-1]); return SQLITE_OK; } case CARRAY_TEXT: { const char **p = (const char**)pCur->iPtr; sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); return SQLITE_OK; } } } } sqlite3_result_int64(ctx, x); return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ carray_cursor *pCur = (carray_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int carrayEof(sqlite3_vtab_cursor *cur){ carray_cursor *pCur = (carray_cursor*)cur; return pCur->iRowid>pCur->iCnt; } /* ** This method is called to "rewind" the carray_cursor object back ** to the first row of output. */ static int carrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ carray_cursor *pCur = (carray_cursor *)pVtabCursor; if( idxNum ){ pCur->iPtr = sqlite3_value_int64(argv[0]); pCur->iCnt = sqlite3_value_int64(argv[1]); if( idxNum<3 ){ pCur->eType = CARRAY_INT32; }else{ unsigned char i; const char *zType = (const char*)sqlite3_value_text(argv[2]); for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){ if( sqlite3_stricmp(zType, azType[i])==0 ) break; } if( i>=sizeof(azType)/sizeof(azType[0]) ){ pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( "unknown datatype: %Q", zType); return SQLITE_ERROR; }else{ pCur->eType = i; } } }else{ pCur->iPtr = 0; pCur->iCnt = 0; } pCur->iRowid = 1; return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the carray virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. ** ** In this implementation idxNum is used to represent the ** query plan. idxStr is unused. ** ** idxNum is 2 if the pointer= and count= constraints exist, ** 3 if the ctype= constraint also exists, and is 0 otherwise. ** If idxNum is 0, then carray becomes an empty table. */ static int carrayBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; /* Loop over constraints */ int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */ int cntIdx = -1; /* Index of the count= constraint, or -1 if none */ int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */ const struct sqlite3_index_constraint *pConstraint; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; switch( pConstraint->iColumn ){ case CARRAY_COLUMN_POINTER: ptrIdx = i; break; case CARRAY_COLUMN_COUNT: cntIdx = i; break; case CARRAY_COLUMN_CTYPE: ctypeIdx = i; break; } } if( ptrIdx>=0 && cntIdx>=0 ){ pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; pIdxInfo->aConstraintUsage[cntIdx].omit = 1; pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 100; pIdxInfo->idxNum = 2; if( ctypeIdx>=0 ){ pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3; pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1; pIdxInfo->idxNum = 3; } }else{ pIdxInfo->estimatedCost = (double)2147483647; pIdxInfo->estimatedRows = 2147483647; pIdxInfo->idxNum = 0; } return SQLITE_OK; } /* ** This following structure defines all the methods for the ** carray virtual table. */ static sqlite3_module carrayModule = { 0, /* iVersion */ 0, /* xCreate */ carrayConnect, /* xConnect */ carrayBestIndex, /* xBestIndex */ carrayDisconnect, /* xDisconnect */ 0, /* xDestroy */ carrayOpen, /* xOpen - open a cursor */ carrayClose, /* xClose - close a cursor */ carrayFilter, /* xFilter - configure scan constraints */ carrayNext, /* xNext - advance a cursor */ carrayEof, /* xEof - check for end of scan */ carrayColumn, /* xColumn - read data */ carrayRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_carray_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_create_module(db, "carray", &carrayModule, 0); #endif return rc; } |
Added ext/misc/csv.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | /* ** 2016-05-28 ** ** 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 contains the implementation of an SQLite virtual table for ** reading CSV files. ** ** Usage: ** ** .load ./csv ** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME); ** SELECT * FROM csv; ** ** The columns are named "c1", "c2", "c3", ... by default. But the ** application can define its own CREATE TABLE statement as an additional ** parameter. For example: ** ** CREATE VIRTUAL TABLE temp.csv2 USING csv( ** filename = "../http.log", ** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)" ** ); ** ** Instead of specifying a file, the text of the CSV can be loaded using ** the data= parameter. ** ** If the columns=N parameter is supplied, then the CSV file is assumed to have ** N columns. If the columns parameter is omitted, the CSV file is opened ** as soon as the virtual table is constructed and the first row of the CSV ** is read in order to count the tables. ** ** Some extra debugging features (used for testing virtual tables) are available ** if this module is compiled with -DSQLITE_TEST. */ #include <sqlite3ext.h> SQLITE_EXTENSION_INIT1 #include <string.h> #include <stdlib.h> #include <assert.h> #include <stdarg.h> #include <ctype.h> #include <stdio.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define CSV_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) && _MSC_VER>=1310 # define CSV_NOINLINE __declspec(noinline) #else # define CSV_NOINLINE #endif /* Max size of the error message in a CsvReader */ #define CSV_MXERR 200 /* Size of the CsvReader input buffer */ #define CSV_INBUFSZ 1024 /* A context object used when read a CSV file. */ typedef struct CsvReader CsvReader; struct CsvReader { FILE *in; /* Read the CSV text from this input stream */ char *z; /* Accumulated text for a field */ int n; /* Number of bytes in z */ int nAlloc; /* Space allocated for z[] */ int nLine; /* Current line number */ char cTerm; /* Character that terminated the most recent field */ size_t iIn; /* Next unread character in the input buffer */ size_t nIn; /* Number of characters in the input buffer */ char *zIn; /* The input buffer */ char zErr[CSV_MXERR]; /* Error message */ }; /* Initialize a CsvReader object */ static void csv_reader_init(CsvReader *p){ p->in = 0; p->z = 0; p->n = 0; p->nAlloc = 0; p->nLine = 0; p->nIn = 0; p->zIn = 0; p->zErr[0] = 0; } /* Close and reset a CsvReader object */ static void csv_reader_reset(CsvReader *p){ if( p->in ){ fclose(p->in); sqlite3_free(p->zIn); } sqlite3_free(p->z); csv_reader_init(p); } /* Report an error on a CsvReader */ static void csv_errmsg(CsvReader *p, const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); sqlite3_vsnprintf(CSV_MXERR, p->zErr, zFormat, ap); va_end(ap); } /* Open the file associated with a CsvReader ** Return the number of errors. */ static int csv_reader_open( CsvReader *p, /* The reader to open */ const char *zFilename, /* Read from this filename */ const char *zData /* ... or use this data */ ){ if( zFilename ){ p->zIn = sqlite3_malloc( CSV_INBUFSZ ); if( p->zIn==0 ){ csv_errmsg(p, "out of memory"); return 1; } p->in = fopen(zFilename, "rb"); if( p->in==0 ){ csv_reader_reset(p); csv_errmsg(p, "cannot open '%s' for reading", zFilename); return 1; } }else{ assert( p->in==0 ); p->zIn = (char*)zData; p->nIn = strlen(zData); } return 0; } /* The input buffer has overflowed. Refill the input buffer, then ** return the next character */ static CSV_NOINLINE int csv_getc_refill(CsvReader *p){ size_t got; assert( p->iIn>=p->nIn ); /* Only called on an empty input buffer */ assert( p->in!=0 ); /* Only called if reading froma file */ got = fread(p->zIn, 1, CSV_INBUFSZ, p->in); if( got==0 ) return EOF; p->nIn = got; p->iIn = 1; return p->zIn[0]; } /* Return the next character of input. Return EOF at end of input. */ static int csv_getc(CsvReader *p){ if( p->iIn >= p->nIn ){ if( p->in!=0 ) return csv_getc_refill(p); return EOF; } return p->zIn[p->iIn++]; } /* Increase the size of p->z and append character c to the end. ** Return 0 on success and non-zero if there is an OOM error */ static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){ char *zNew; int nNew = p->nAlloc*2 + 100; zNew = sqlite3_realloc64(p->z, nNew); if( zNew ){ p->z = zNew; p->nAlloc = nNew; p->z[p->n++] = c; return 0; }else{ csv_errmsg(p, "out of memory"); return 1; } } /* Append a single character to the CsvReader.z[] array. ** Return 0 on success and non-zero if there is an OOM error */ static int csv_append(CsvReader *p, char c){ if( p->n>=p->nAlloc-1 ) return csv_resize_and_append(p, c); p->z[p->n++] = c; return 0; } /* Read a single field of CSV text. Compatible with rfc4180 and extended ** with the option of having a separator other than ",". ** ** + Input comes from p->in. ** + Store results in p->z of length p->n. Space to hold p->z comes ** from sqlite3_malloc64(). ** + Keep track of the line number in p->nLine. ** + Store the character that terminates the field in p->cTerm. Store ** EOF on end-of-file. ** ** Return "" at EOF. Return 0 on an OOM error. */ static char *csv_read_one_field(CsvReader *p){ int c; p->n = 0; c = csv_getc(p); if( c==EOF ){ p->cTerm = EOF; return ""; } if( c=='"' ){ int pc, ppc; int startLine = p->nLine; pc = ppc = 0; while( 1 ){ c = csv_getc(p); if( c<='"' || pc=='"' ){ if( c=='\n' ) p->nLine++; if( c=='"' ){ if( pc=='"' ){ pc = 0; continue; } } if( (c==',' && pc=='"') || (c=='\n' && pc=='"') || (c=='\n' && pc=='\r' && ppc=='"') || (c==EOF && pc=='"') ){ do{ p->n--; }while( p->z[p->n]!='"' ); p->cTerm = (char)c; break; } if( pc=='"' && c!='\r' ){ csv_errmsg(p, "line %d: unescaped %c character", p->nLine, '"'); break; } if( c==EOF ){ csv_errmsg(p, "line %d: unterminated %c-quoted field\n", startLine, '"'); p->cTerm = (char)c; break; } } if( csv_append(p, (char)c) ) return 0; ppc = pc; pc = c; } }else{ while( c>',' || (c!=EOF && c!=',' && c!='\n') ){ if( csv_append(p, (char)c) ) return 0; c = csv_getc(p); } if( c=='\n' ){ p->nLine++; if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = (char)c; } if( p->z ) p->z[p->n] = 0; return p->z; } /* Forward references to the various virtual table methods implemented ** in this file. */ static int csvtabCreate(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int csvtabConnect(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int csvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*); static int csvtabDisconnect(sqlite3_vtab*); static int csvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); static int csvtabClose(sqlite3_vtab_cursor*); static int csvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); static int csvtabNext(sqlite3_vtab_cursor*); static int csvtabEof(sqlite3_vtab_cursor*); static int csvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int); static int csvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*); /* An instance of the CSV virtual table */ typedef struct CsvTable { sqlite3_vtab base; /* Base class. Must be first */ char *zFilename; /* Name of the CSV file */ char *zData; /* Raw CSV data in lieu of zFilename */ long iStart; /* Offset to start of data in zFilename */ int nCol; /* Number of columns in the CSV file */ unsigned int tstFlags; /* Bit values used for testing */ } CsvTable; /* Allowed values for tstFlags */ #define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/ /* A cursor for the CSV virtual table */ typedef struct CsvCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ CsvReader rdr; /* The CsvReader object */ char **azVal; /* Value of the current row */ int *aLen; /* Length of each entry */ sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */ } CsvCursor; /* Transfer error message text from a reader into a CsvTable */ static void csv_xfer_error(CsvTable *pTab, CsvReader *pRdr){ sqlite3_free(pTab->base.zErrMsg); pTab->base.zErrMsg = sqlite3_mprintf("%s", pRdr->zErr); } /* ** This method is the destructor fo a CsvTable object. */ static int csvtabDisconnect(sqlite3_vtab *pVtab){ CsvTable *p = (CsvTable*)pVtab; sqlite3_free(p->zFilename); sqlite3_free(p->zData); sqlite3_free(p); return SQLITE_OK; } /* Skip leading whitespace. Return a pointer to the first non-whitespace ** character, or to the zero terminator if the string has only whitespace */ static const char *csv_skip_whitespace(const char *z){ while( isspace((unsigned char)z[0]) ) z++; return z; } /* Remove trailing whitespace from the end of string z[] */ static void csv_trim_whitespace(char *z){ size_t n = strlen(z); while( n>0 && isspace((unsigned char)z[n]) ) n--; z[n] = 0; } /* Dequote the string */ static void csv_dequote(char *z){ int j; char cQuote = z[0]; size_t i, n; if( cQuote!='\'' && cQuote!='"' ) return; n = strlen(z); if( n<2 || z[n-1]!=z[0] ) return; for(i=1, j=0; i<n-1; i++){ if( z[i]==cQuote && z[i+1]==cQuote ) i++; z[j++] = z[i]; } z[j] = 0; } /* Check to see if the string is of the form: "TAG = VALUE" with optional ** whitespace before and around tokens. If it is, return a pointer to the ** first character of VALUE. If it is not, return NULL. */ static const char *csv_parameter(const char *zTag, int nTag, const char *z){ z = csv_skip_whitespace(z); if( strncmp(zTag, z, nTag)!=0 ) return 0; z = csv_skip_whitespace(z+nTag); if( z[0]!='=' ) return 0; return csv_skip_whitespace(z+1); } /* Decode a parameter that requires a dequoted string. ** ** Return 1 if the parameter is seen, or 0 if not. 1 is returned ** even if there is an error. If an error occurs, then an error message ** is left in p->zErr. If there are no errors, p->zErr[0]==0. */ static int csv_string_parameter( CsvReader *p, /* Leave the error message here, if there is one */ const char *zParam, /* Parameter we are checking for */ const char *zArg, /* Raw text of the virtual table argment */ char **pzVal /* Write the dequoted string value here */ ){ const char *zValue; zValue = csv_parameter(zParam,(int)strlen(zParam),zArg); if( zValue==0 ) return 0; p->zErr[0] = 0; if( *pzVal ){ csv_errmsg(p, "more than one '%s' parameter", zParam); return 1; } *pzVal = sqlite3_mprintf("%s", zValue); if( *pzVal==0 ){ csv_errmsg(p, "out of memory"); return 1; } csv_trim_whitespace(*pzVal); csv_dequote(*pzVal); return 1; } /* Return 0 if the argument is false and 1 if it is true. Return -1 if ** we cannot really tell. */ static int csv_boolean(const char *z){ if( sqlite3_stricmp("yes",z)==0 || sqlite3_stricmp("on",z)==0 || sqlite3_stricmp("true",z)==0 || (z[0]=='1' && z[0]==0) ){ return 1; } if( sqlite3_stricmp("no",z)==0 || sqlite3_stricmp("off",z)==0 || sqlite3_stricmp("false",z)==0 || (z[0]=='0' && z[1]==0) ){ return 0; } return -1; } /* ** Parameters: ** filename=FILENAME Name of file containing CSV content ** data=TEXT Direct CSV content. ** schema=SCHEMA Alternative CSV schema. ** header=YES|NO First row of CSV defines the names of ** columns if "yes". Default "no". ** columns=N Assume the CSV file contains N columns. ** ** Only available if compiled with SQLITE_TEST: ** ** testflags=N Bitmask of test flags. Optional ** ** If schema= is omitted, then the columns are named "c0", "c1", "c2", ** and so forth. If columns=N is omitted, then the file is opened and ** the number of columns in the first row is counted to determine the ** column count. If header=YES, then the first row is skipped. */ static int csvtabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ CsvTable *pNew = 0; /* The CsvTable object to construct */ int bHeader = -1; /* header= flags. -1 means not seen yet */ int rc = SQLITE_OK; /* Result code from this routine */ int i, j; /* Loop counters */ #ifdef SQLITE_TEST int tstFlags = 0; /* Value for testflags=N parameter */ #endif int nCol = -99; /* Value of the columns= parameter */ CsvReader sRdr; /* A CSV file reader used to store an error ** message and/or to count the number of columns */ static const char *azParam[] = { "filename", "data", "schema", }; char *azPValue[3]; /* Parameter values */ # define CSV_FILENAME (azPValue[0]) # define CSV_DATA (azPValue[1]) # define CSV_SCHEMA (azPValue[2]) assert( sizeof(azPValue)==sizeof(azParam) ); memset(&sRdr, 0, sizeof(sRdr)); memset(azPValue, 0, sizeof(azPValue)); for(i=3; i<argc; i++){ const char *z = argv[i]; const char *zValue; for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){ if( csv_string_parameter(&sRdr, azParam[j], z, &azPValue[j]) ) break; } if( j<sizeof(azParam)/sizeof(azParam[0]) ){ if( sRdr.zErr[0] ) goto csvtab_connect_error; }else if( (zValue = csv_parameter("header",6,z))!=0 ){ int x; if( bHeader>=0 ){ csv_errmsg(&sRdr, "more than one 'header' parameter"); goto csvtab_connect_error; } x = csv_boolean(zValue); if( x==1 ){ bHeader = 1; }else if( x==0 ){ bHeader = 0; }else{ csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue); goto csvtab_connect_error; } }else #ifdef SQLITE_TEST if( (zValue = csv_parameter("testflags",9,z))!=0 ){ tstFlags = (unsigned int)atoi(zValue); }else #endif if( (zValue = csv_parameter("columns",7,z))!=0 ){ if( nCol>0 ){ csv_errmsg(&sRdr, "more than one 'columns' parameter"); goto csvtab_connect_error; } nCol = atoi(zValue); if( nCol<=0 ){ csv_errmsg(&sRdr, "must have at least one column"); goto csvtab_connect_error; } }else { csv_errmsg(&sRdr, "unrecognized parameter '%s'", z); goto csvtab_connect_error; } } if( (CSV_FILENAME==0)==(CSV_DATA==0) ){ csv_errmsg(&sRdr, "must either filename= or data= but not both"); goto csvtab_connect_error; } if( nCol<=0 && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA) ){ goto csvtab_connect_error; } pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) goto csvtab_connect_oom; memset(pNew, 0, sizeof(*pNew)); if( nCol>0 ){ pNew->nCol = nCol; }else{ do{ const char *z = csv_read_one_field(&sRdr); if( z==0 ) goto csvtab_connect_oom; pNew->nCol++; }while( sRdr.cTerm==',' ); } pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0; pNew->zData = CSV_DATA; CSV_DATA = 0; #ifdef SQLITE_TEST pNew->tstFlags = tstFlags; #endif pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0; csv_reader_reset(&sRdr); if( CSV_SCHEMA==0 ){ char *zSep = ""; CSV_SCHEMA = sqlite3_mprintf("CREATE TABLE x("); if( CSV_SCHEMA==0 ) goto csvtab_connect_oom; for(i=0; i<pNew->nCol; i++){ CSV_SCHEMA = sqlite3_mprintf("%z%sc%d TEXT",CSV_SCHEMA, zSep, i); zSep = ","; } CSV_SCHEMA = sqlite3_mprintf("%z);", CSV_SCHEMA); } rc = sqlite3_declare_vtab(db, CSV_SCHEMA); if( rc ) goto csvtab_connect_error; for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ sqlite3_free(azPValue[i]); } return SQLITE_OK; csvtab_connect_oom: rc = SQLITE_NOMEM; csv_errmsg(&sRdr, "out of memory"); csvtab_connect_error: if( pNew ) csvtabDisconnect(&pNew->base); for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ sqlite3_free(azPValue[i]); } if( sRdr.zErr[0] ){ sqlite3_free(*pzErr); *pzErr = sqlite3_mprintf("%s", sRdr.zErr); } csv_reader_reset(&sRdr); if( rc==SQLITE_OK ) rc = SQLITE_ERROR; return rc; } /* ** Reset the current row content held by a CsvCursor. */ static void csvtabCursorRowReset(CsvCursor *pCur){ CsvTable *pTab = (CsvTable*)pCur->base.pVtab; int i; for(i=0; i<pTab->nCol; i++){ sqlite3_free(pCur->azVal[i]); pCur->azVal[i] = 0; pCur->aLen[i] = 0; } } /* ** The xConnect and xCreate methods do the same thing, but they must be ** different so that the virtual table is not an eponymous virtual table. */ static int csvtabCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return csvtabConnect(db, pAux, argc, argv, ppVtab, pzErr); } /* ** Destructor for a CsvCursor. */ static int csvtabClose(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; csvtabCursorRowReset(pCur); csv_reader_reset(&pCur->rdr); sqlite3_free(cur); return SQLITE_OK; } /* ** Constructor for a new CsvTable cursor object. */ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ CsvTable *pTab = (CsvTable*)p; CsvCursor *pCur; size_t nByte; nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol; pCur = sqlite3_malloc64( nByte ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, nByte); pCur->azVal = (char**)&pCur[1]; pCur->aLen = (int*)&pCur->azVal[pTab->nCol]; *ppCursor = &pCur->base; if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){ csv_xfer_error(pTab, &pCur->rdr); return SQLITE_ERROR; } return SQLITE_OK; } /* ** Advance a CsvCursor to its next row of input. ** Set the EOF marker if we reach the end of input. */ static int csvtabNext(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; int i = 0; char *z; do{ z = csv_read_one_field(&pCur->rdr); if( z==0 ){ csv_xfer_error(pTab, &pCur->rdr); break; } if( i<pTab->nCol ){ if( pCur->aLen[i] < pCur->rdr.n+1 ){ char *zNew = sqlite3_realloc64(pCur->azVal[i], pCur->rdr.n+1); if( zNew==0 ){ csv_errmsg(&pCur->rdr, "out of memory"); csv_xfer_error(pTab, &pCur->rdr); break; } pCur->azVal[i] = zNew; pCur->aLen[i] = pCur->rdr.n+1; } memcpy(pCur->azVal[i], z, pCur->rdr.n+1); i++; } }while( pCur->rdr.cTerm==',' ); while( i<pTab->nCol ){ sqlite3_free(pCur->azVal[i]); pCur->azVal[i] = 0; pCur->aLen[i] = 0; i++; } if( z==0 || pCur->rdr.cTerm==EOF ){ pCur->iRowid = -1; }else{ pCur->iRowid++; } return SQLITE_OK; } /* ** Return values of columns for the row at which the CsvCursor ** is currently pointing. */ static int csvtabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ CsvCursor *pCur = (CsvCursor*)cur; CsvTable *pTab = (CsvTable*)cur->pVtab; if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){ sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC); } return SQLITE_OK; } /* ** Return the rowid for the current row. */ static int csvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ CsvCursor *pCur = (CsvCursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int csvtabEof(sqlite3_vtab_cursor *cur){ CsvCursor *pCur = (CsvCursor*)cur; return pCur->iRowid<0; } /* ** Only a full table scan is supported. So xFilter simply rewinds to ** the beginning. */ static int csvtabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ CsvCursor *pCur = (CsvCursor*)pVtabCursor; CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab; pCur->iRowid = 0; if( pCur->rdr.in==0 ){ assert( pCur->rdr.zIn==pTab->zData ); assert( pTab->iStart>=0 ); assert( (size_t)pTab->iStart<=pCur->rdr.nIn ); pCur->rdr.iIn = pTab->iStart; }else{ fseek(pCur->rdr.in, pTab->iStart, SEEK_SET); pCur->rdr.iIn = 0; pCur->rdr.nIn = 0; } return csvtabNext(pVtabCursor); } /* ** Only a forward full table scan is supported. xBestIndex is mostly ** a no-op. If CSVTEST_FIDX is set, then the presence of equality ** constraints lowers the estimated cost, which is fiction, but is useful ** for testing certain kinds of virtual table behavior. */ static int csvtabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ pIdxInfo->estimatedCost = 1000000; #ifdef SQLITE_TEST if( (((CsvTable*)tab)->tstFlags & CSVTEST_FIDX)!=0 ){ /* The usual (and sensible) case is to always do a full table scan. ** The code in this branch only runs when testflags=1. This code ** generates an artifical and unrealistic plan which is useful ** for testing virtual table logic but is not helpful to real applications. ** ** Any ==, LIKE, or GLOB constraint is marked as usable by the virtual ** table (even though it is not) and the cost of running the virtual table ** is reduced from 1 million to just 10. The constraints are *not* marked ** as omittable, however, so the query planner should still generate a ** plan that gives a correct answer, even if they plan is not optimal. */ int i; int nConst = 0; for(i=0; i<pIdxInfo->nConstraint; i++){ unsigned char op; if( pIdxInfo->aConstraint[i].usable==0 ) continue; op = pIdxInfo->aConstraint[i].op; if( op==SQLITE_INDEX_CONSTRAINT_EQ || op==SQLITE_INDEX_CONSTRAINT_LIKE || op==SQLITE_INDEX_CONSTRAINT_GLOB ){ pIdxInfo->estimatedCost = 10; pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1; nConst++; } } } #endif return SQLITE_OK; } static sqlite3_module CsvModule = { 0, /* iVersion */ csvtabCreate, /* xCreate */ csvtabConnect, /* xConnect */ csvtabBestIndex, /* xBestIndex */ csvtabDisconnect, /* xDisconnect */ csvtabDisconnect, /* xDestroy */ csvtabOpen, /* xOpen - open a cursor */ csvtabClose, /* xClose - close a cursor */ csvtabFilter, /* xFilter - configure scan constraints */ csvtabNext, /* xNext - advance a cursor */ csvtabEof, /* xEof - check for end of scan */ csvtabColumn, /* xColumn - read data */ csvtabRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #ifdef SQLITE_TEST /* ** For virtual table testing, make a version of the CSV virtual table ** available that has an xUpdate function. But the xUpdate always returns ** SQLITE_READONLY since the CSV file is not really writable. */ static int csvtabUpdate(sqlite3_vtab *p,int n,sqlite3_value**v,sqlite3_int64*x){ return SQLITE_READONLY; } static sqlite3_module CsvModuleFauxWrite = { 0, /* iVersion */ csvtabCreate, /* xCreate */ csvtabConnect, /* xConnect */ csvtabBestIndex, /* xBestIndex */ csvtabDisconnect, /* xDisconnect */ csvtabDisconnect, /* xDestroy */ csvtabOpen, /* xOpen - open a cursor */ csvtabClose, /* xClose - close a cursor */ csvtabFilter, /* xFilter - configure scan constraints */ csvtabNext, /* xNext - advance a cursor */ csvtabEof, /* xEof - check for end of scan */ csvtabColumn, /* xColumn - read data */ csvtabRowid, /* xRowid - read data */ csvtabUpdate, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_TEST */ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifdef _WIN32 __declspec(dllexport) #endif /* ** This routine is called when the extension is loaded. The new ** CSV virtual table module is registered with the calling database ** connection. */ int sqlite3_csv_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ #ifndef SQLITE_OMIT_VIRTUALTABLE int rc; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_module(db, "csv", &CsvModule, 0); #ifdef SQLITE_TEST if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0); } #endif return rc; #else return SQLITE_OK; #endif } |
Changes to ext/misc/json1.c.
︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 | sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. */ static void jsonArrayFunc( | > > > > > > > > > > > > > > > > > > > > | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ /* ** Implementation of the json_QUOTE(VALUE) function. Return a JSON value ** corresponding to the SQL value input. Mostly this means putting ** double-quotes around strings and returning the unquoted string "null" ** when given a NULL input. */ static void jsonQuoteFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString jx; UNUSED_PARAM(argc); jsonInit(&jx, ctx); jsonAppendValue(&jx, argv[0]); jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. */ static void jsonArrayFunc( |
︙ | ︙ | |||
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 | { "json", 1, 0, jsonRemoveFunc }, { "json_array", -1, 0, jsonArrayFunc }, { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, { "json_extract", -1, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, { "json_type", 1, 0, jsonTypeFunc }, { "json_type", 2, 0, jsonTypeFunc }, { "json_valid", 1, 0, jsonValidFunc }, | > | 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 | { "json", 1, 0, jsonRemoveFunc }, { "json_array", -1, 0, jsonArrayFunc }, { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, { "json_extract", -1, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, { "json_quote", 1, 0, jsonQuoteFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, { "json_type", 1, 0, jsonTypeFunc }, { "json_type", 2, 0, jsonTypeFunc }, { "json_valid", 1, 0, jsonValidFunc }, |
︙ | ︙ |
Changes to ext/misc/percentile.c.
︙ | ︙ | |||
163 164 165 166 167 168 169 | } p->a[p->nUsed++] = y; } /* ** Compare to doubles for sorting using qsort() */ | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | } p->a[p->nUsed++] = y; } /* ** Compare to doubles for sorting using qsort() */ static int SQLITE_CDECL doubleCmp(const void *pA, const void *pB){ double a = *(double*)pA; double b = *(double*)pB; if( a==b ) return 0; if( a<b ) return -1; return +1; } |
︙ | ︙ |
Added ext/misc/scrub.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | /* ** 2016-05-05 ** ** 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 a utility function (and a utility program) that ** makes a copy of an SQLite database while simultaneously zeroing out all ** deleted content. ** ** Normally (when PRAGMA secure_delete=OFF, which is the default) when SQLite ** deletes content, it does not overwrite the deleted content but rather marks ** the region of the file that held that content as being reusable. This can ** cause deleted content to recoverable from the database file. This stale ** content is removed by the VACUUM command, but VACUUM can be expensive for ** large databases. When in PRAGMA secure_delete=ON mode, the deleted content ** is zeroed, but secure_delete=ON has overhead as well. ** ** This utility attempts to make a copy of a complete SQLite database where ** all of the deleted content is zeroed out in the copy, and it attempts to ** do so while being faster than running VACUUM. ** ** Usage: ** ** int sqlite3_scrub_backup( ** const char *zSourceFile, // Source database filename ** const char *zDestFile, // Destination database filename ** char **pzErrMsg // Write error message here ** ); ** ** Simply call the API above specifying the filename of the source database ** and the name of the backup copy. The source database must already exist ** and can be in active use. (A read lock is held during the backup.) The ** destination file should not previously exist. If the pzErrMsg parameter ** is non-NULL and if an error occurs, then an error message might be written ** into memory obtained from sqlite3_malloc() and *pzErrMsg made to point to ** that error message. But if the error is an OOM, the error might not be ** reported. The routine always returns non-zero if there is an error. ** ** If compiled with -DSCRUB_STANDALONE then a main() procedure is added and ** this file becomes a standalone program that can be run as follows: ** ** ./sqlite3scrub SOURCE DEST */ #include "sqlite3.h" #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> typedef struct ScrubState ScrubState; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; /* State information for a scrub-and-backup operation */ struct ScrubState { const char *zSrcFile; /* Name of the source file */ const char *zDestFile; /* Name of the destination file */ int rcErr; /* Error code */ char *zErr; /* Error message text */ sqlite3 *dbSrc; /* Source database connection */ sqlite3_file *pSrc; /* Source file handle */ sqlite3 *dbDest; /* Destination database connection */ sqlite3_file *pDest; /* Destination file handle */ u32 szPage; /* Page size */ u32 szUsable; /* Usable bytes on each page */ u32 nPage; /* Number of pages */ u32 iLastPage; /* Page number of last page written so far*/ u8 *page1; /* Content of page 1 */ }; /* Store an error message */ static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){ va_list ap; sqlite3_free(p->zErr); va_start(ap, zFormat); p->zErr = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( p->rcErr==0 ) p->rcErr = SQLITE_ERROR; } /* Allocate memory to hold a single page of content */ static u8 *scrubBackupAllocPage(ScrubState *p){ u8 *pPage; if( p->rcErr ) return 0; pPage = sqlite3_malloc( p->szPage ); if( pPage==0 ) p->rcErr = SQLITE_NOMEM; return pPage; } /* Read a page from the source database into memory. Use the memory ** provided by pBuf if not NULL or allocate a new page if pBuf==NULL. */ static u8 *scrubBackupRead(ScrubState *p, int pgno, u8 *pBuf){ int rc; sqlite3_int64 iOff; u8 *pOut = pBuf; if( p->rcErr ) return 0; if( pOut==0 ){ pOut = scrubBackupAllocPage(p); if( pOut==0 ) return 0; } iOff = (pgno-1)*(sqlite3_int64)p->szPage; rc = p->pSrc->pMethods->xRead(p->pSrc, pOut, p->szPage, iOff); if( rc!=SQLITE_OK ){ if( pBuf==0 ) sqlite3_free(pOut); pOut = 0; scrubBackupErr(p, "read failed for page %d", pgno); p->rcErr = SQLITE_IOERR; } return pOut; } /* Write a page to the destination database */ static void scrubBackupWrite(ScrubState *p, int pgno, const u8 *pData){ int rc; sqlite3_int64 iOff; if( p->rcErr ) return; iOff = (pgno-1)*(sqlite3_int64)p->szPage; rc = p->pDest->pMethods->xWrite(p->pDest, pData, p->szPage, iOff); if( rc!=SQLITE_OK ){ scrubBackupErr(p, "write failed for page %d", pgno); p->rcErr = SQLITE_IOERR; } if( pgno>p->iLastPage ) p->iLastPage = pgno; } /* Prepare a statement against the "db" database. */ static sqlite3_stmt *scrubBackupPrepare( ScrubState *p, /* Backup context */ sqlite3 *db, /* Database to prepare against */ const char *zSql /* SQL statement */ ){ sqlite3_stmt *pStmt; if( p->rcErr ) return 0; p->rcErr = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( p->rcErr ){ scrubBackupErr(p, "SQL error \"%s\" on \"%s\"", sqlite3_errmsg(db), zSql); sqlite3_finalize(pStmt); return 0; } return pStmt; } /* Open the source database file */ static void scrubBackupOpenSrc(ScrubState *p){ sqlite3_stmt *pStmt; int rc; /* Open the source database file */ p->rcErr = sqlite3_open_v2(p->zSrcFile, &p->dbSrc, SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot open source database: %s", sqlite3_errmsg(p->dbSrc)); return; } p->rcErr = sqlite3_exec(p->dbSrc, "SELECT 1 FROM sqlite_master; BEGIN;", 0, 0, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot start a read transaction on the source database: %s", sqlite3_errmsg(p->dbSrc)); return; } rc = sqlite3_wal_checkpoint_v2(p->dbSrc, "main", SQLITE_CHECKPOINT_FULL, 0, 0); if( rc ){ scrubBackupErr(p, "cannot checkpoint the source database"); return; } pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_size"); if( pStmt==0 ) return; rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW ){ p->szPage = sqlite3_column_int(pStmt, 0); }else{ scrubBackupErr(p, "unable to determine the page size"); } sqlite3_finalize(pStmt); if( p->rcErr ) return; pStmt = scrubBackupPrepare(p, p->dbSrc, "PRAGMA page_count"); if( pStmt==0 ) return; rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW ){ p->nPage = sqlite3_column_int(pStmt, 0); }else{ scrubBackupErr(p, "unable to determine the size of the source database"); } sqlite3_finalize(pStmt); sqlite3_file_control(p->dbSrc, "main", SQLITE_FCNTL_FILE_POINTER, &p->pSrc); if( p->pSrc==0 || p->pSrc->pMethods==0 ){ scrubBackupErr(p, "cannot get the source file handle"); p->rcErr = SQLITE_ERROR; } } /* Create and open the destination file */ static void scrubBackupOpenDest(ScrubState *p){ sqlite3_stmt *pStmt; int rc; char *zSql; if( p->rcErr ) return; p->rcErr = sqlite3_open_v2(p->zDestFile, &p->dbDest, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI | SQLITE_OPEN_PRIVATECACHE, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot open destination database: %s", sqlite3_errmsg(p->dbDest)); return; } zSql = sqlite3_mprintf("PRAGMA page_size(%u);", p->szPage); if( zSql==0 ){ p->rcErr = SQLITE_NOMEM; return; } p->rcErr = sqlite3_exec(p->dbDest, zSql, 0, 0, 0); sqlite3_free(zSql); if( p->rcErr ){ scrubBackupErr(p, "cannot set the page size on the destination database: %s", sqlite3_errmsg(p->dbDest)); return; } sqlite3_exec(p->dbDest, "PRAGMA journal_mode=OFF;", 0, 0, 0); p->rcErr = sqlite3_exec(p->dbDest, "BEGIN EXCLUSIVE;", 0, 0, 0); if( p->rcErr ){ scrubBackupErr(p, "cannot start a write transaction on the destination database: %s", sqlite3_errmsg(p->dbDest)); return; } pStmt = scrubBackupPrepare(p, p->dbDest, "PRAGMA page_count;"); if( pStmt==0 ) return; rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW ){ scrubBackupErr(p, "cannot measure the size of the destination"); }else if( sqlite3_column_int(pStmt, 0)>1 ){ scrubBackupErr(p, "destination database is not empty - holds %d pages", sqlite3_column_int(pStmt, 0)); } sqlite3_finalize(pStmt); sqlite3_file_control(p->dbDest, "main", SQLITE_FCNTL_FILE_POINTER, &p->pDest); if( p->pDest==0 || p->pDest->pMethods==0 ){ scrubBackupErr(p, "cannot get the destination file handle"); p->rcErr = SQLITE_ERROR; } } /* Read a 32-bit big-endian integer */ static u32 scrubBackupInt32(const u8 *a){ u32 v = a[3]; v += ((u32)a[2])<<8; v += ((u32)a[1])<<16; v += ((u32)a[0])<<24; return v; } /* Read a 16-bit big-endian integer */ static u32 scrubBackupInt16(const u8 *a){ return (a[0]<<8) + a[1]; } /* ** Read a varint. Put the value in *pVal and return the number of bytes. */ static int scrubBackupVarint(const u8 *z, sqlite3_int64 *pVal){ sqlite3_int64 v = 0; int i; for(i=0; i<8; i++){ v = (v<<7) + (z[i]&0x7f); if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } } v = (v<<8) + (z[i]&0xff); *pVal = v; return 9; } /* ** Return the number of bytes in a varint. */ static int scrubBackupVarintSize(const u8 *z){ int i; for(i=0; i<8; i++){ if( (z[i]&0x80)==0 ){ return i+1; } } return 9; } /* ** Copy the freelist trunk page given, and all its descendents, ** zeroing out as much as possible in the process. */ static void scrubBackupFreelist(ScrubState *p, int pgno, u32 nFree){ u8 *a, *aBuf; u32 n, mx; if( p->rcErr ) return; aBuf = scrubBackupAllocPage(p); if( aBuf==0 ) return; while( pgno && nFree){ a = scrubBackupRead(p, pgno, aBuf); if( a==0 ) break; n = scrubBackupInt32(&a[4]); mx = p->szUsable/4 - 2; if( n<mx ){ memset(&a[n*4+8], 0, 4*(mx-n)); } scrubBackupWrite(p, pgno, a); pgno = scrubBackupInt32(a); #if 0 /* There is really no point in copying the freelist leaf pages. ** Simply leave them uninitialized in the destination database. The ** OS filesystem should zero those pages for us automatically. */ for(i=0; i<n && nFree; i++){ u32 iLeaf = scrubBackupInt32(&a[i*4+8]); if( aZero==0 ){ aZero = scrubBackupAllocPage(p); if( aZero==0 ){ pgno = 0; break; } memset(aZero, 0, p->szPage); } scrubBackupWrite(p, iLeaf, aZero); nFree--; } #endif } sqlite3_free(aBuf); } /* ** Copy an overflow chain from source to destination. Zero out any ** unused tail at the end of the overflow chain. */ static void scrubBackupOverflow(ScrubState *p, int pgno, u32 nByte){ u8 *a, *aBuf; aBuf = scrubBackupAllocPage(p); if( aBuf==0 ) return; while( nByte>0 && pgno!=0 ){ a = scrubBackupRead(p, pgno, aBuf); if( a==0 ) break; if( nByte >= (p->szUsable)-4 ){ nByte -= (p->szUsable) - 4; }else{ u32 x = (p->szUsable - 4) - nByte; u32 i = p->szUsable - x; memset(&a[i], 0, x); nByte = 0; } scrubBackupWrite(p, pgno, a); pgno = scrubBackupInt32(a); } sqlite3_free(aBuf); } /* ** Copy B-Tree page pgno, and all of its children, from source to destination. ** Zero out deleted content during the copy. */ static void scrubBackupBtree(ScrubState *p, int pgno, int iDepth){ u8 *a; u32 i, n, pc; u32 nCell; u32 nPrefix; u32 szHdr; u32 iChild; u8 *aTop; u8 *aCell; u32 x, y; int ln = 0; if( p->rcErr ) return; if( iDepth>50 ){ scrubBackupErr(p, "corrupt: b-tree too deep at page %d", pgno); return; } if( pgno==1 ){ a = p->page1; }else{ a = scrubBackupRead(p, pgno, 0); if( a==0 ) return; } nPrefix = pgno==1 ? 100 : 0; aTop = &a[nPrefix]; szHdr = 8 + 4*(aTop[0]==0x02 || aTop[0]==0x05); aCell = aTop + szHdr; nCell = scrubBackupInt16(&aTop[3]); /* Zero out the gap between the cell index and the start of the ** cell content area */ x = scrubBackupInt16(&aTop[5]); /* First byte of cell content area */ if( x>p->szUsable ){ ln=__LINE__; goto btree_corrupt; } y = szHdr + nPrefix + nCell*2; if( y>x ){ ln=__LINE__; goto btree_corrupt; } if( y<x ) memset(a+y, 0, x-y); /* Zero the gap */ /* Zero out all the free blocks */ pc = scrubBackupInt16(&aTop[1]); if( pc>0 && pc<x ){ ln=__LINE__; goto btree_corrupt; } while( pc ){ if( pc>(p->szUsable)-4 ){ ln=__LINE__; goto btree_corrupt; } n = scrubBackupInt16(&a[pc+2]); if( pc+n>(p->szUsable) ){ ln=__LINE__; goto btree_corrupt; } if( n>4 ) memset(&a[pc+4], 0, n-4); x = scrubBackupInt16(&a[pc]); if( x<pc+4 && x>0 ){ ln=__LINE__; goto btree_corrupt; } pc = x; } /* Write this one page */ scrubBackupWrite(p, pgno, a); /* Walk the tree and process child pages */ for(i=0; i<nCell; i++){ u32 X, M, K, nLocal; sqlite3_int64 P; pc = scrubBackupInt16(&aCell[i*2]); if( pc <= szHdr ){ ln=__LINE__; goto btree_corrupt; } if( pc > p->szUsable-3 ){ ln=__LINE__; goto btree_corrupt; } if( aTop[0]==0x05 || aTop[0]==0x02 ){ if( pc+4 > p->szUsable ){ ln=__LINE__; goto btree_corrupt; } iChild = scrubBackupInt32(&a[pc]); pc += 4; scrubBackupBtree(p, iChild, iDepth+1); if( aTop[0]==0x05 ) continue; } pc += scrubBackupVarint(&a[pc], &P); if( pc >= p->szUsable ){ ln=__LINE__; goto btree_corrupt; } if( aTop[0]==0x0d ){ X = p->szUsable - 35; }else{ X = ((p->szUsable - 12)*64/255) - 23; } if( P<=X ){ /* All content is local. No overflow */ continue; } M = ((p->szUsable - 12)*32/255)-23; K = M + ((P-M)%(p->szUsable-4)); if( aTop[0]==0x0d ){ pc += scrubBackupVarintSize(&a[pc]); if( pc > (p->szUsable-4) ){ ln=__LINE__; goto btree_corrupt; } } nLocal = K<=X ? K : M; if( pc+nLocal > p->szUsable-4 ){ ln=__LINE__; goto btree_corrupt; } iChild = scrubBackupInt32(&a[pc+nLocal]); scrubBackupOverflow(p, iChild, P-nLocal); } /* Walk the right-most tree */ if( aTop[0]==0x05 || aTop[0]==0x02 ){ iChild = scrubBackupInt32(&aTop[8]); scrubBackupBtree(p, iChild, iDepth+1); } /* All done */ if( pgno>1 ) sqlite3_free(a); return; btree_corrupt: scrubBackupErr(p, "corruption on page %d of source database (errid=%d)", pgno, ln); if( pgno>1 ) sqlite3_free(a); } /* ** Copy all ptrmap pages from source to destination. ** This routine is only called if the source database is in autovacuum ** or incremental vacuum mode. */ static void scrubBackupPtrmap(ScrubState *p){ u32 pgno = 2; u32 J = p->szUsable/5; u32 iLock = (1073742335/p->szPage)+1; u8 *a, *pBuf; if( p->rcErr ) return; pBuf = scrubBackupAllocPage(p); if( pBuf==0 ) return; while( pgno<=p->nPage ){ a = scrubBackupRead(p, pgno, pBuf); if( a==0 ) break; scrubBackupWrite(p, pgno, a); pgno += J+1; if( pgno==iLock ) pgno++; } sqlite3_free(pBuf); } int sqlite3_scrub_backup( const char *zSrcFile, /* Source file */ const char *zDestFile, /* Destination file */ char **pzErr /* Write error here if non-NULL */ ){ ScrubState s; u32 n, i; sqlite3_stmt *pStmt; memset(&s, 0, sizeof(s)); s.zSrcFile = zSrcFile; s.zDestFile = zDestFile; /* Open both source and destination databases */ scrubBackupOpenSrc(&s); scrubBackupOpenDest(&s); /* Read in page 1 */ s.page1 = scrubBackupRead(&s, 1, 0); if( s.page1==0 ) goto scrub_abort; s.szUsable = s.szPage - s.page1[20]; /* Copy the freelist */ n = scrubBackupInt32(&s.page1[36]); i = scrubBackupInt32(&s.page1[32]); if( n ) scrubBackupFreelist(&s, i, n); /* Copy ptrmap pages */ n = scrubBackupInt32(&s.page1[52]); if( n ) scrubBackupPtrmap(&s); /* Copy all of the btrees */ scrubBackupBtree(&s, 1, 0); pStmt = scrubBackupPrepare(&s, s.dbSrc, "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0"); if( pStmt==0 ) goto scrub_abort; while( sqlite3_step(pStmt)==SQLITE_ROW ){ i = (u32)sqlite3_column_int(pStmt, 0); scrubBackupBtree(&s, i, 0); } sqlite3_finalize(pStmt); /* If the last page of the input db file is a free-list leaf, then the ** backup file on disk is still smaller than the size indicated within ** the database header. In this case, write a page of zeroes to the ** last page of the backup database so that SQLite does not mistakenly ** think the db is corrupt. */ if( s.iLastPage<s.nPage ){ u8 *aZero = scrubBackupAllocPage(&s); if( aZero ){ memset(aZero, 0, s.szPage); scrubBackupWrite(&s, s.nPage, aZero); sqlite3_free(aZero); } } scrub_abort: /* Close the destination database without closing the transaction. If we ** commit, page zero will be overwritten. */ sqlite3_close(s.dbDest); /* But do close out the read-transaction on the source database */ sqlite3_exec(s.dbSrc, "COMMIT;", 0, 0, 0); sqlite3_close(s.dbSrc); sqlite3_free(s.page1); if( pzErr ){ *pzErr = s.zErr; }else{ sqlite3_free(s.zErr); } return s.rcErr; } #ifdef SCRUB_STANDALONE /* Error and warning log */ static void errorLogCallback(void *pNotUsed, int iErr, const char *zMsg){ const char *zType; switch( iErr&0xff ){ case SQLITE_WARNING: zType = "WARNING"; break; case SQLITE_NOTICE: zType = "NOTICE"; break; default: zType = "ERROR"; break; } fprintf(stderr, "%s: %s\n", zType, zMsg); } /* The main() routine when this utility is run as a stand-alone program */ int main(int argc, char **argv){ char *zErr = 0; int rc; if( argc!=3 ){ fprintf(stderr,"Usage: %s SOURCE DESTINATION\n", argv[0]); exit(1); } sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, 0); rc = sqlite3_scrub_backup(argv[1], argv[2], &zErr); if( rc==SQLITE_NOMEM ){ fprintf(stderr, "%s: out of memory\n", argv[0]); exit(1); } if( zErr ){ fprintf(stderr, "%s: %s\n", argv[0], zErr); sqlite3_free(zErr); exit(1); } return 0; } #endif |
Changes to ext/misc/spellfix.c.
︙ | ︙ | |||
2227 2228 2229 2230 2231 2232 2233 | return iDistance + 32 - iLog2; } /* ** Compare two spellfix1_row objects for sorting purposes in qsort() such ** that they sort in order of increasing distance. */ | | | 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 | return iDistance + 32 - iLog2; } /* ** Compare two spellfix1_row objects for sorting purposes in qsort() such ** that they sort in order of increasing distance. */ static int SQLITE_CDECL spellfix1RowCompare(const void *A, const void *B){ const struct spellfix1_row *a = (const struct spellfix1_row*)A; const struct spellfix1_row *b = (const struct spellfix1_row*)B; return a->iScore - b->iScore; } /* ** A structure used to pass information from spellfix1FilterForMatch() |
︙ | ︙ |
Added ext/misc/vfsstat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | /* ** 2016-05-27 ** ** 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 contains the implementation of an SQLite vfs shim that ** tracks I/O. Access to the accumulated status counts is provided using ** an eponymous virtual table. */ #include <sqlite3ext.h> SQLITE_EXTENSION_INIT1 /* ** This module contains code for a wrapper VFS that cause stats for ** most VFS calls to be recorded. ** ** To use this module, first compile it as a loadable extension. See ** https://www.sqlite.org/loadext.html#build for compilations instructions. ** ** After compliing, load this extension, then open database connections to be ** measured. Query usages status using the vfsstat virtual table: ** ** SELECT * FROM vfsstat; ** ** Reset counters using UPDATE statements against vfsstat: ** ** UPDATE vfsstat SET count=0; ** ** EXAMPLE SCRIPT: ** ** .load ./vfsstat ** .open test.db ** DROP TABLE IF EXISTS t1; ** CREATE TABLE t1(x,y); ** INSERT INTO t1 VALUES(123, randomblob(5000)); ** CREATE INDEX t1x ON t1(x); ** DROP TABLE t1; ** VACUUM; ** SELECT * FROM vfsstat WHERE count>0; ** ** LIMITATIONS: ** ** This module increments counters without using mutex protection. So if ** two or more threads try to use this module at the same time, race conditions ** may occur which mess up the counts. This is harmless, other than giving ** incorrect statistics. */ #include <string.h> #include <stdlib.h> #include <assert.h> /* ** File types */ #define VFSSTAT_MAIN 0 /* Main database file */ #define VFSSTAT_JOURNAL 1 /* Rollback journal */ #define VFSSTAT_WAL 2 /* Write-ahead log file */ #define VFSSTAT_MASTERJRNL 3 /* Master journal */ #define VFSSTAT_SUBJRNL 4 /* Subjournal */ #define VFSSTAT_TEMPDB 5 /* TEMP database */ #define VFSSTAT_TEMPJRNL 6 /* Journal for TEMP database */ #define VFSSTAT_TRANSIENT 7 /* Transient database */ #define VFSSTAT_ANY 8 /* Unspecified file type */ #define VFSSTAT_nFile 9 /* This many file types */ /* Names of the file types. These are allowed values for the ** first column of the vfsstat virtual table. */ static const char *azFile[] = { "database", "journal", "wal", "master-journal", "sub-journal", "temp-database", "temp-journal", "transient-db", "*" }; /* ** Stat types */ #define VFSSTAT_BYTESIN 0 /* Bytes read in */ #define VFSSTAT_BYTESOUT 1 /* Bytes written out */ #define VFSSTAT_READ 2 /* Read requests */ #define VFSSTAT_WRITE 3 /* Write requests */ #define VFSSTAT_SYNC 4 /* Syncs */ #define VFSSTAT_OPEN 5 /* File opens */ #define VFSSTAT_LOCK 6 /* Lock requests */ #define VFSSTAT_ACCESS 0 /* xAccess calls. filetype==ANY only */ #define VFSSTAT_DELETE 1 /* xDelete calls. filetype==ANY only */ #define VFSSTAT_FULLPATH 2 /* xFullPathname calls. ANY only */ #define VFSSTAT_RANDOM 3 /* xRandomness calls. ANY only */ #define VFSSTAT_SLEEP 4 /* xSleep calls. ANY only */ #define VFSSTAT_CURTIME 5 /* xCurrentTime calls. ANY only */ #define VFSSTAT_nStat 7 /* This many stat types */ /* Names for the second column of the vfsstat virtual table for all ** cases except when the first column is "*" or VFSSTAT_ANY. */ static const char *azStat[] = { "bytes-in", "bytes-out", "read", "write", "sync", "open", "lock", }; static const char *azStatAny[] = { "access", "delete", "fullpathname", "randomness", "sleep", "currenttimestamp", "not-used" }; /* Total number of counters */ #define VFSSTAT_MXCNT (VFSSTAT_nStat*VFSSTAT_nFile) /* ** Performance stats are collected in an instance of the following ** global array. */ static sqlite3_uint64 aVfsCnt[VFSSTAT_MXCNT]; /* ** Access to a specific counter */ #define STATCNT(filetype,stat) (aVfsCnt[(filetype)*VFSSTAT_nStat+(stat)]) /* ** Forward declaration of objects used by this utility */ typedef struct VStatVfs VStatVfs; typedef struct VStatFile VStatFile; /* An instance of the VFS */ struct VStatVfs { sqlite3_vfs base; /* VFS methods */ sqlite3_vfs *pVfs; /* Parent VFS */ }; /* An open file */ struct VStatFile { sqlite3_file base; /* IO methods */ sqlite3_file *pReal; /* Underlying file handle */ unsigned char eFiletype; /* What type of file is this */ }; #define REALVFS(p) (((VStatVfs*)(p))->pVfs) /* ** Methods for VStatFile */ static int vstatClose(sqlite3_file*); static int vstatRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); static int vstatWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); static int vstatTruncate(sqlite3_file*, sqlite3_int64 size); static int vstatSync(sqlite3_file*, int flags); static int vstatFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int vstatLock(sqlite3_file*, int); static int vstatUnlock(sqlite3_file*, int); static int vstatCheckReservedLock(sqlite3_file*, int *pResOut); static int vstatFileControl(sqlite3_file*, int op, void *pArg); static int vstatSectorSize(sqlite3_file*); static int vstatDeviceCharacteristics(sqlite3_file*); static int vstatShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); static int vstatShmLock(sqlite3_file*, int offset, int n, int flags); static void vstatShmBarrier(sqlite3_file*); static int vstatShmUnmap(sqlite3_file*, int deleteFlag); static int vstatFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int vstatUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); /* ** Methods for VStatVfs */ static int vstatOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); static int vstatDelete(sqlite3_vfs*, const char *zName, int syncDir); static int vstatAccess(sqlite3_vfs*, const char *zName, int flags, int *); static int vstatFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); static void *vstatDlOpen(sqlite3_vfs*, const char *zFilename); static void vstatDlError(sqlite3_vfs*, int nByte, char *zErrMsg); static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); static void vstatDlClose(sqlite3_vfs*, void*); static int vstatRandomness(sqlite3_vfs*, int nByte, char *zOut); static int vstatSleep(sqlite3_vfs*, int microseconds); static int vstatCurrentTime(sqlite3_vfs*, double*); static int vstatGetLastError(sqlite3_vfs*, int, char *); static int vstatCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static VStatVfs vstat_vfs = { { 2, /* iVersion */ 0, /* szOsFile (set by register_vstat()) */ 1024, /* mxPathname */ 0, /* pNext */ "vfslog", /* zName */ 0, /* pAppData */ vstatOpen, /* xOpen */ vstatDelete, /* xDelete */ vstatAccess, /* xAccess */ vstatFullPathname, /* xFullPathname */ vstatDlOpen, /* xDlOpen */ vstatDlError, /* xDlError */ vstatDlSym, /* xDlSym */ vstatDlClose, /* xDlClose */ vstatRandomness, /* xRandomness */ vstatSleep, /* xSleep */ vstatCurrentTime, /* xCurrentTime */ vstatGetLastError, /* xGetLastError */ vstatCurrentTimeInt64 /* xCurrentTimeInt64 */ }, 0 }; static const sqlite3_io_methods vstat_io_methods = { 3, /* iVersion */ vstatClose, /* xClose */ vstatRead, /* xRead */ vstatWrite, /* xWrite */ vstatTruncate, /* xTruncate */ vstatSync, /* xSync */ vstatFileSize, /* xFileSize */ vstatLock, /* xLock */ vstatUnlock, /* xUnlock */ vstatCheckReservedLock, /* xCheckReservedLock */ vstatFileControl, /* xFileControl */ vstatSectorSize, /* xSectorSize */ vstatDeviceCharacteristics, /* xDeviceCharacteristics */ vstatShmMap, /* xShmMap */ vstatShmLock, /* xShmLock */ vstatShmBarrier, /* xShmBarrier */ vstatShmUnmap, /* xShmUnmap */ vstatFetch, /* xFetch */ vstatUnfetch /* xUnfetch */ }; /* ** Close an vstat-file. */ static int vstatClose(sqlite3_file *pFile){ VStatFile *p = (VStatFile *)pFile; int rc = SQLITE_OK; if( p->pReal->pMethods ){ rc = p->pReal->pMethods->xClose(p->pReal); } return rc; } /* ** Read data from an vstat-file. */ static int vstatRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); STATCNT(p->eFiletype,VFSSTAT_READ)++; if( rc==SQLITE_OK ){ STATCNT(p->eFiletype,VFSSTAT_BYTESIN) += iAmt; } return rc; } /* ** Write data to an vstat-file. */ static int vstatWrite( sqlite3_file *pFile, const void *z, int iAmt, sqlite_int64 iOfst ){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst); STATCNT(p->eFiletype,VFSSTAT_WRITE)++; if( rc==SQLITE_OK ){ STATCNT(p->eFiletype,VFSSTAT_BYTESOUT) += iAmt; } return rc; } /* ** Truncate an vstat-file. */ static int vstatTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xTruncate(p->pReal, size); return rc; } /* ** Sync an vstat-file. */ static int vstatSync(sqlite3_file *pFile, int flags){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xSync(p->pReal, flags); STATCNT(p->eFiletype,VFSSTAT_SYNC)++; return rc; } /* ** Return the current file-size of an vstat-file. */ static int vstatFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); return rc; } /* ** Lock an vstat-file. */ static int vstatLock(sqlite3_file *pFile, int eLock){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xLock(p->pReal, eLock); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** Unlock an vstat-file. */ static int vstatUnlock(sqlite3_file *pFile, int eLock){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** Check if another file-handle holds a RESERVED lock on an vstat-file. */ static int vstatCheckReservedLock(sqlite3_file *pFile, int *pResOut){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); STATCNT(p->eFiletype,VFSSTAT_LOCK)++; return rc; } /* ** File control method. For custom operations on an vstat-file. */ static int vstatFileControl(sqlite3_file *pFile, int op, void *pArg){ VStatFile *p = (VStatFile *)pFile; int rc; rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg); if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){ *(char**)pArg = sqlite3_mprintf("vstat/%z", *(char**)pArg); } return rc; } /* ** Return the sector-size in bytes for an vstat-file. */ static int vstatSectorSize(sqlite3_file *pFile){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xSectorSize(p->pReal); return rc; } /* ** Return the device characteristic flags supported by an vstat-file. */ static int vstatDeviceCharacteristics(sqlite3_file *pFile){ int rc; VStatFile *p = (VStatFile *)pFile; rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); return rc; } /* Create a shared memory file mapping */ static int vstatShmMap( sqlite3_file *pFile, int iPg, int pgsz, int bExtend, void volatile **pp ){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp); } /* Perform locking on a shared-memory segment */ static int vstatShmLock(sqlite3_file *pFile, int offset, int n, int flags){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags); } /* Memory barrier operation on shared memory */ static void vstatShmBarrier(sqlite3_file *pFile){ VStatFile *p = (VStatFile *)pFile; p->pReal->pMethods->xShmBarrier(p->pReal); } /* Unmap a shared memory segment */ static int vstatShmUnmap(sqlite3_file *pFile, int deleteFlag){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag); } /* Fetch a page of a memory-mapped file */ static int vstatFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp); } /* Release a memory-mapped page */ static int vstatUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ VStatFile *p = (VStatFile *)pFile; return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage); } /* ** Open an vstat file handle. */ static int vstatOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ int rc; VStatFile *p = (VStatFile*)pFile; p->pReal = (sqlite3_file*)&p[1]; rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags); if( flags & SQLITE_OPEN_MAIN_DB ){ p->eFiletype = VFSSTAT_MAIN; }else if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ p->eFiletype = VFSSTAT_JOURNAL; }else if( flags & SQLITE_OPEN_WAL ){ p->eFiletype = VFSSTAT_WAL; }else if( flags & SQLITE_OPEN_MASTER_JOURNAL ){ p->eFiletype = VFSSTAT_MASTERJRNL; }else if( flags & SQLITE_OPEN_SUBJOURNAL ){ p->eFiletype = VFSSTAT_SUBJRNL; }else if( flags & SQLITE_OPEN_TEMP_DB ){ p->eFiletype = VFSSTAT_TEMPDB; }else if( flags & SQLITE_OPEN_TEMP_JOURNAL ){ p->eFiletype = VFSSTAT_TEMPJRNL; }else{ p->eFiletype = VFSSTAT_TRANSIENT; } STATCNT(p->eFiletype,VFSSTAT_OPEN)++; pFile->pMethods = rc ? 0 : &vstat_io_methods; return rc; } /* ** Delete the file located at zPath. If the dirSync argument is true, ** ensure the file-system modifications are synced to disk before ** returning. */ static int vstatDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int rc; rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync); STATCNT(VFSSTAT_ANY,VFSSTAT_DELETE)++; return rc; } /* ** Test for access permissions. Return true if the requested permission ** is available, or false otherwise. */ static int vstatAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ int rc; rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut); STATCNT(VFSSTAT_ANY,VFSSTAT_ACCESS)++; return rc; } /* ** Populate buffer zOut with the full canonical pathname corresponding ** to the pathname in zPath. zOut is guaranteed to point to a buffer ** of at least (INST_MAX_PATHNAME+1) bytes. */ static int vstatFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nOut, char *zOut ){ STATCNT(VFSSTAT_ANY,VFSSTAT_FULLPATH)++; return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); } /* ** Open the dynamic library located at zPath and return a handle. */ static void *vstatDlOpen(sqlite3_vfs *pVfs, const char *zPath){ return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); } /* ** Populate the buffer zErrMsg (size nByte bytes) with a human readable ** utf-8 string describing the most recent error encountered associated ** with dynamic libraries. */ static void vstatDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); } /* ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. */ static void (*vstatDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); } /* ** Close the dynamic library handle pHandle. */ static void vstatDlClose(sqlite3_vfs *pVfs, void *pHandle){ REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); } /* ** Populate the buffer pointed to by zBufOut with nByte bytes of ** random data. */ static int vstatRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ STATCNT(VFSSTAT_ANY,VFSSTAT_RANDOM)++; return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); } /* ** Sleep for nMicro microseconds. Return the number of microseconds ** actually slept. */ static int vstatSleep(sqlite3_vfs *pVfs, int nMicro){ STATCNT(VFSSTAT_ANY,VFSSTAT_SLEEP)++; return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro); } /* ** Return the current time as a Julian Day number in *pTimeOut. */ static int vstatCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++; return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut); } static int vstatGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b); } static int vstatCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ STATCNT(VFSSTAT_ANY,VFSSTAT_CURTIME)++; return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p); } /* ** A virtual table for accessing the stats collected by this VFS shim */ static int vstattabConnect(sqlite3*, void*, int, const char*const*, sqlite3_vtab**,char**); static int vstattabBestIndex(sqlite3_vtab*,sqlite3_index_info*); static int vstattabDisconnect(sqlite3_vtab*); static int vstattabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); static int vstattabClose(sqlite3_vtab_cursor*); static int vstattabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); static int vstattabNext(sqlite3_vtab_cursor*); static int vstattabEof(sqlite3_vtab_cursor*); static int vstattabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int); static int vstattabRowid(sqlite3_vtab_cursor*,sqlite3_int64*); static int vstattabUpdate(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); /* A cursor for the vfsstat virtual table */ typedef struct VfsStatCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ int i; /* Pointing to this aVfsCnt[] value */ } VfsStatCursor; static int vstattabConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define VSTAT_COLUMN_FILE 0 #define VSTAT_COLUMN_STAT 1 #define VSTAT_COLUMN_COUNT 2 rc = sqlite3_declare_vtab(db,"CREATE TABLE x(file,stat,count)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* ** This method is the destructor for vstat table object. */ static int vstattabDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new vstat table cursor object. */ static int vstattabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ VfsStatCursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a VfsStatCursor. */ static int vstattabClose(sqlite3_vtab_cursor *cur){ sqlite3_free(cur); return SQLITE_OK; } /* ** Advance a VfsStatCursor to its next row of output. */ static int vstattabNext(sqlite3_vtab_cursor *cur){ ((VfsStatCursor*)cur)->i++; return SQLITE_OK; } /* ** Return values of columns for the row at which the VfsStatCursor ** is currently pointing. */ static int vstattabColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ VfsStatCursor *pCur = (VfsStatCursor*)cur; switch( i ){ case VSTAT_COLUMN_FILE: { sqlite3_result_text(ctx, azFile[pCur->i/VFSSTAT_nStat], -1, SQLITE_STATIC); break; } case VSTAT_COLUMN_STAT: { const char **az; az = (pCur->i/VFSSTAT_nStat)==VFSSTAT_ANY ? azStatAny : azStat; sqlite3_result_text(ctx, az[pCur->i%VFSSTAT_nStat], -1, SQLITE_STATIC); break; } case VSTAT_COLUMN_COUNT: { sqlite3_result_int64(ctx, aVfsCnt[pCur->i]); break; } } return SQLITE_OK; } /* ** Return the rowid for the current row. */ static int vstattabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ VfsStatCursor *pCur = (VfsStatCursor*)cur; *pRowid = pCur->i; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int vstattabEof(sqlite3_vtab_cursor *cur){ VfsStatCursor *pCur = (VfsStatCursor*)cur; return pCur->i >= VFSSTAT_MXCNT; } /* ** Only a full table scan is supported. So xFilter simply rewinds to ** the beginning. */ static int vstattabFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ VfsStatCursor *pCur = (VfsStatCursor*)pVtabCursor; pCur->i = 0; return SQLITE_OK; } /* ** Only a forwards full table scan is supported. xBestIndex is a no-op. */ static int vstattabBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ return SQLITE_OK; } /* ** Any VSTAT_COLUMN_COUNT can be changed to a positive integer. ** No deletions or insertions are allowed. No changes to other ** columns are allowed. */ static int vstattabUpdate( sqlite3_vtab *tab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid ){ sqlite3_int64 iRowid, x; if( argc==1 ) return SQLITE_ERROR; if( sqlite3_value_type(argv[0])!=SQLITE_INTEGER ) return SQLITE_ERROR; iRowid = sqlite3_value_int64(argv[0]); if( iRowid!=sqlite3_value_int64(argv[1]) ) return SQLITE_ERROR; if( iRowid<0 || iRowid>=VFSSTAT_MXCNT ) return SQLITE_ERROR; if( sqlite3_value_type(argv[VSTAT_COLUMN_COUNT+2])!=SQLITE_INTEGER ){ return SQLITE_ERROR; } x = sqlite3_value_int64(argv[VSTAT_COLUMN_COUNT+2]); if( x<0 ) return SQLITE_ERROR; aVfsCnt[iRowid] = x; return SQLITE_OK; } static sqlite3_module VfsStatModule = { 0, /* iVersion */ 0, /* xCreate */ vstattabConnect, /* xConnect */ vstattabBestIndex, /* xBestIndex */ vstattabDisconnect, /* xDisconnect */ 0, /* xDestroy */ vstattabOpen, /* xOpen - open a cursor */ vstattabClose, /* xClose - close a cursor */ vstattabFilter, /* xFilter - configure scan constraints */ vstattabNext, /* xNext - advance a cursor */ vstattabEof, /* xEof - check for end of scan */ vstattabColumn, /* xColumn - read data */ vstattabRowid, /* xRowid - read data */ vstattabUpdate, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** This routine is an sqlite3_auto_extension() callback, invoked to register ** the vfsstat virtual table for all new database connections. */ static int vstatRegister( sqlite3 *db, const char **pzErrMsg, const struct sqlite3_api_routines *pThunk ){ return sqlite3_create_module(db, "vfsstat", &VfsStatModule, 0); } #ifdef _WIN32 __declspec(dllexport) #endif /* ** This routine is called when the extension is loaded. ** ** Register the new VFS. Make arrangement to register the virtual table ** for each new database connection. */ int sqlite3_vfsstat_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); vstat_vfs.base.szOsFile = sizeof(VStatFile) + vstat_vfs.pVfs->szOsFile; rc = sqlite3_vfs_register(&vstat_vfs.base, 1); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension(vstatRegister); } if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; } |
Changes to ext/rbu/rbu1.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2014 August 30 # # 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. # #*********************************************************************** # | < | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2014 August 30 # # 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. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbu1 db close sqlite3_shutdown sqlite3_config_uri 1 # Create a simple RBU database. That expects to write to a table: |
︙ | ︙ | |||
92 93 94 95 96 97 98 | INSERT INTO data_t1 VALUES(2, NULL, 10, 5, '..xx'); -- SET c=10, d = 5 INSERT INTO data_t1 VALUES(3, 11, NULL, NULL, '.x..'); -- SET b=11 } rbu5 close return $filename } | < < < < < < < < < < < < < < < < < < < < | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | INSERT INTO data_t1 VALUES(2, NULL, 10, 5, '..xx'); -- SET c=10, d = 5 INSERT INTO data_t1 VALUES(3, 11, NULL, NULL, '.x..'); -- SET b=11 } rbu5 close return $filename } # Same as [step_rbu], except using a URI to open the target db. # proc step_rbu_uri {target rbu} { while 1 { sqlite3rbu rbu file:$target?xyz=&abc=123 $rbu set rc [rbu step] |
︙ | ︙ | |||
637 638 639 640 641 642 643 | } } # Test that an RBU database containing no input tables is handled # correctly. reset_db forcedelete rbu.db | > > > > > > > > > > > > > > > | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | } } # Test that an RBU database containing no input tables is handled # correctly. reset_db forcedelete rbu.db do_test $tn3.8.1 { list [catch { run_rbu test.db rbu.db } msg] $msg } {0 SQLITE_DONE} # Test that an RBU database containing only empty data_xxx tables is # also handled correctly. reset_db forcedelete rbu.db do_execsql_test $tn3.8.2.1 { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 2); ATTACH 'rbu.db' AS rbu; CREATE TABLE data_t1(a, b, rbu_control); DETACH rbu; } do_test $tn3.8.2.1 { list [catch { run_rbu test.db rbu.db } msg] $msg } {0 SQLITE_DONE} # Test that RBU can update indexes containing NULL values. # reset_db forcedelete rbu.db do_execsql_test $tn3.9.1 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b, c); |
︙ | ︙ |
Changes to ext/rbu/rbu5.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test some properties of the pager_rbu_mode and rbu_mode pragmas. # | < | < < < < < < < < < < < < < < < < < < < < < < < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test some properties of the pager_rbu_mode and rbu_mode pragmas. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbu5 # Return a list of the primary key columns for table $tbl in the database # opened by database handle $db. # proc pkcols {db tbl} { set ret [list] $db eval "PRAGMA table_info = '$tbl'" { if {$pk} { lappend ret $name } |
︙ | ︙ |
Changes to ext/rbu/rbu_common.tcl.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl # Run the RBU in file $rbu on target database $target until completion. # proc run_rbu {target rbu} { sqlite3rbu rbu $target $rbu while 1 { set rc [rbu step] if {$rc!="SQLITE_OK"} break } rbu close } proc step_rbu {target rbu} { while 1 { sqlite3rbu rbu $target $rbu set rc [rbu step] rbu close if {$rc != "SQLITE_OK"} break } set rc } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl proc check_prestep_state {target state} { set oal_exists [file exists $target-oal] set wal_exists [file exists $target-wal] set progress [rbu progress] if {($progress==0 && $state!="oal" && $state!="done") || ($oal_exists && $wal_exists) || ($progress>0 && $state=="oal" && (!$oal_exists || $wal_exists)) || ($state=="move" && (!$oal_exists || $wal_exists)) || ($state=="checkpoint" && ($oal_exists || !$wal_exists)) || ($state=="done" && ($oal_exists && $progress!=0)) } { error "B: state=$state progress=$progress oal=$oal_exists wal=$wal_exists" } } proc check_poststep_state {rc target state} { if {$rc=="SQLITE_OK" || $rc=="SQLITE_DONE"} { set oal_exists [file exists $target-oal] set wal_exists [file exists $target-wal] if {$state=="move" && ($oal_exists || !$wal_exists)} { error "A: state=$state progress=$progress oal=$oal_exists wal=$wal_exists" } } } # Run the RBU in file $rbu on target database $target until completion. # proc run_rbu {target rbu} { sqlite3rbu rbu $target $rbu while 1 { set state [rbu state] check_prestep_state $target $state set rc [rbu step] check_poststep_state $rc $target $state if {$rc!="SQLITE_OK"} break } rbu close } proc step_rbu {target rbu} { while 1 { sqlite3rbu rbu $target $rbu set state [rbu state] check_prestep_state $target $state set rc [rbu step] check_poststep_state $rc $target $state rbu close if {$rc != "SQLITE_OK"} break } set rc } proc do_rbu_vacuum_test {tn step} { uplevel [list do_test $tn.1 { if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db } while 1 { if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db } set state [rbu state] check_prestep_state test.db $state set rc [rbu step] check_poststep_state $rc test.db $state if {$rc!="SQLITE_OK"} break if {$step==1} { rbu close } } rbu close } {SQLITE_DONE}] uplevel [list do_execsql_test $tn.2 { PRAGMA integrity_check } ok] } |
Changes to ext/rbu/rbudiff.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | set PROG [test_find_sqldiff] db close proc get_rbudiff_sql {db1 db2} { exec $::PROG --rbu $db1 $db2 } proc step_rbu {target rbu} { while 1 { sqlite3rbu rbu $target $rbu set rc [rbu step] rbu close if {$rc != "SQLITE_OK"} break } set rc } proc apply_rbudiff {sql target} { test_rbucount $sql forcedelete rbu.db sqlite3 rbudb rbu.db rbudb eval $sql rbudb close step_rbu $target rbu.db } # The only argument is the output of an [sqldiff -rbu] run. This command # tests that the contents of the rbu_count table is correct. An exception # is thrown if it is not. # proc test_rbucount {sql} { sqlite3 tmpdb "" tmpdb eval $sql tmpdb eval { SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table' } { | > > > > > > > > > | | > > | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | set PROG [test_find_sqldiff] db close proc get_rbudiff_sql {db1 db2} { exec $::PROG --rbu $db1 $db2 } proc get_vtab_rbudiff_sql {db1 db2} { exec $::PROG --vtab --rbu $db1 $db2 } proc step_rbu {target rbu} { while 1 { sqlite3rbu rbu $target $rbu set rc [rbu step] rbu close if {$rc != "SQLITE_OK"} break } set rc } proc apply_rbudiff {sql target} { test_rbucount $sql forcedelete rbu.db sqlite3 rbudb rbu.db rbudb eval $sql rbudb close step_rbu $target rbu.db } proc sqlesc {id} { set ret "'[string map {' ''} $id]'" set ret } # The only argument is the output of an [sqldiff -rbu] run. This command # tests that the contents of the rbu_count table is correct. An exception # is thrown if it is not. # proc test_rbucount {sql} { sqlite3 tmpdb "" tmpdb eval $sql tmpdb eval { SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table' } { set a [tmpdb eval "SELECT count(*) FROM [sqlesc $name]"] set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}] if {$a != $b} { tmpdb close error "rbu_count error - tbl = $name" } } tmpdb close return "" } proc rbudiff_cksum {db1} { set txt "" sqlite3 dbtmp $db1 foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] { set cols [list] dbtmp eval "PRAGMA table_info = [sqlesc $tbl]" { lappend cols "quote( $name )" } append txt [dbtmp eval \ "SELECT [join $cols {||'.'||}] FROM [sqlesc $tbl] ORDER BY 1" ] } dbtmp close md5 $txt } |
︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 | do_test 1.$tn.4 { set sql [get_rbudiff_sql test.db test.db2] apply_rbudiff $sql test.db } {SQLITE_DONE} do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | do_test 1.$tn.4 { set sql [get_rbudiff_sql test.db test.db2] apply_rbudiff $sql test.db } {SQLITE_DONE} do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] } #------------------------------------------------------------------------- # Test that if the --vtab switch is present, [sqldiff] handles virtual # table types fts[345] and rtree correctly. # ifcapable fts3&&fts5&&rtree { foreach {tn init mod} { 1 { CREATE VIRTUAL TABLE t1 USING fts5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } 2 { CREATE VIRTUAL TABLE "x y" USING 'rtree'(id, x1, x2); INSERT INTO "x y" VALUES(1, 2, 3); INSERT INTO "x y" VALUES(2, 4, 6); } { DELETE FROM "x y" WHERE rowid = 1; INSERT INTO "x y" VALUES(3, 6, 9); } 3 { CREATE VIRTUAL TABLE 'x''y' USING fts3; INSERT INTO 'x''y' VALUES('one two three'); INSERT INTO 'x''y' VALUES('four five six'); } { DELETE FROM 'x''y' WHERE rowid = 1; INSERT INTO 'x''y' VALUES('one two three'); } } { forcedelete test.db test.db2 sqlite3 db test.db db eval "$init" sqlite3 db test.db2 db eval "$init ; $mod" db close do_test 2.$tn.1 { set sql [get_vtab_rbudiff_sql test.db test.db2] apply_rbudiff $sql test.db } {SQLITE_DONE} do_test 2.$tn.2 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] } } ifcapable fts5 { foreach {tn init mod} { 1 { CREATE VIRTUAL TABLE t1 USING fts5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } 2 { CREATE VIRTUAL TABLE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } 3 { creAte virTUal tablE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); INSERT INTO t1 VALUES('a b c'); } { DELETE FROM t1 WHERE rowid = 1; INSERT INTO t1 VALUES('a b c'); } } { forcedelete test.db test.db2 sqlite3 db test.db db eval "$init" sqlite3 db test.db2 db eval "$init ; $mod" db eval { INSERT INTO t1(t1) VALUES('optimize') } db close do_test 3.$tn.1 { set sql [get_vtab_rbudiff_sql test.db test.db2] apply_rbudiff $sql test.db } {SQLITE_DONE} sqlite3 db test.db sqlite3 db2 test.db2 do_test 3.$tn.2 { db2 eval { SELECT * FROM t1 ORDER BY rowid } } [db eval { SELECT * FROM t1 ORDER BY rowid }] do_test 3.$tn.3 { db2 eval { INSERT INTO t1(t1) VALUES('integrity-check') } } {} db close db2 close } } finish_test |
Changes to ext/rbu/rbuprogress.test.
︙ | ︙ | |||
356 357 358 359 360 361 362 363 364 365 366 367 368 369 | CREATE TABLE t1(a, b, c); CREATE INDEX t1c ON t1(c); } vtab { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); } } { foreach {tn2 rbusql r1 r2} { 1 { CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control); INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0); INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0); CREATE TABLE rbu_count(tbl, cnt); | > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | CREATE TABLE t1(a, b, c); CREATE INDEX t1c ON t1(c); } vtab { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); } } { if {$tn=="vtab"} { ifcapable !fts5 break } foreach {tn2 rbusql r1 r2} { 1 { CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control); INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0); INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0); CREATE TABLE rbu_count(tbl, cnt); |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuvacuum | < < < < < < < < < < < < < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuvacuum foreach step {0 1} { set ::testprefix rbuvacuum-step=$step reset_db # Simplest possible vacuum. do_execsql_test 1.0 { |
︙ | ︙ | |||
399 400 401 402 403 404 405 | sqlite3_create_collation_v2 $db1 length length_cmp noop sqlite3_create_collation_v2 $db2 length length_cmp noop while {[rbu step]=="SQLITE_OK"} {} list [catch { rbu close } msg] $msg } {0 SQLITE_DONE} | < | 382 383 384 385 386 387 388 389 390 391 392 | sqlite3_create_collation_v2 $db1 length length_cmp noop sqlite3_create_collation_v2 $db2 length length_cmp noop while {[rbu step]=="SQLITE_OK"} {} list [catch { rbu close } msg] $msg } {0 SQLITE_DONE} catch { db close } finish_test |
Added ext/rbu/rbuvacuum2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | # 2016 June 1 # # 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 contains tests for the RBU module. More specifically, it # contains tests to ensure that the sqlite3rbu_vacuum() API works as # expected. # source [file join [file dirname [info script]] rbu_common.tcl] foreach step {0 1} { set ::testprefix rbuvacuum2-$step #------------------------------------------------------------------------- # Test that a database that contains fts3 tables can be vacuumed. # ifcapable fts3 { reset_db do_execsql_test 1.1 { CREATE VIRTUAL TABLE t1 USING fts3(z, y); INSERT INTO t1 VALUES('fix this issue', 'at some point'); } do_rbu_vacuum_test 1.2 $step do_execsql_test 1.3 { SELECT * FROM t1; } {{fix this issue} {at some point}} do_execsql_test 1.4 { SELECT rowid FROM t1 WHERE t1 MATCH 'fix'; } {1} do_execsql_test 1.5 { INSERT INTO t1 VALUES('a b c', 'd e f'); INSERT INTO t1 VALUES('l h i', 'd e f'); DELETE FROM t1 WHERE docid = 2; INSERT INTO t1 VALUES('a b c', 'x y z'); } do_rbu_vacuum_test 1.6 $step do_execsql_test 1.7 { INSERT INTO t1(t1) VALUES('integrity-check'); SELECT * FROM t1; } { {fix this issue} {at some point} {l h i} {d e f} {a b c} {x y z} } } #------------------------------------------------------------------------- # Test that a database that contains fts5 tables can be vacuumed. # ifcapable fts5 { reset_db do_execsql_test 2.1 { CREATE VIRTUAL TABLE t1 USING fts5(z, y); INSERT INTO t1 VALUES('fix this issue', 'at some point'); } do_rbu_vacuum_test 2.2 $step do_execsql_test 2.3 { SELECT * FROM t1; } {{fix this issue} {at some point}} do_execsql_test 2.4 { SELECT rowid FROM t1 ('fix'); } {1} do_execsql_test 2.5 { INSERT INTO t1 VALUES('a b c', 'd e f'); INSERT INTO t1 VALUES('l h i', 'd e f'); DELETE FROM t1 WHERE rowid = 2; INSERT INTO t1 VALUES('a b c', 'x y z'); } do_rbu_vacuum_test 2.6 $step do_execsql_test 2.7 { INSERT INTO t1(t1) VALUES('integrity-check'); SELECT * FROM t1; } { {fix this issue} {at some point} {l h i} {d e f} {a b c} {x y z} } } #------------------------------------------------------------------------- # Test that a database that contains an rtree table can be vacuumed. # ifcapable rtree { reset_db do_execsql_test 3.1 { CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2); INSERT INTO rt VALUES(1, 45, 55); INSERT INTO rt VALUES(2, 50, 60); INSERT INTO rt VALUES(3, 55, 65); } do_rbu_vacuum_test 3.2 $step do_execsql_test 3.3 { SELECT * FROM rt; } {1 45.0 55.0 2 50.0 60.0 3 55.0 65.0} do_execsql_test 3.4.1 { SELECT rowid FROM rt WHERE x2>51 AND x1 < 51 } {1 2} do_execsql_test 3.4.2 { SELECT rowid FROM rt WHERE x2>59 AND x1 < 59 } {2 3} do_rbu_vacuum_test 3.5 $step do_execsql_test 3.6.1 { SELECT rowid FROM rt WHERE x2>51 AND x1 < 51 } {1 2} do_execsql_test 3.6.2 { SELECT rowid FROM rt WHERE x2>59 AND x1 < 59 } {2 3} } ifcapable trigger { reset_db do_execsql_test 4.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END; } do_execsql_test 4.2 { SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } do_rbu_vacuum_test 4.3 $step do_execsql_test 4.4 { SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } } } #------------------------------------------------------------------------- # Test that passing a NULL value as the second argument to # sqlite3rbu_vacuum() causes it to: # # * Use <database>-vacuum as the state db, and # * Set the state db permissions to the same as those on the db file. # db close if {$::tcl_platform(platform)=="unix"} { forcedelete test.db sqlite3 db test.db do_execsql_test 5.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); } db close foreach {tn perm} { 1 00755 2 00666 3 00644 4 00444 } { forcedelete test.db-vacuum do_test 5.$tn.1 { file attributes test.db -permissions $perm sqlite3rbu_vacuum rbu test.db rbu step } {SQLITE_OK} do_test 5.$tn.2 { file exists test.db-vacuum } 1 do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm rbu close } } finish_test |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
917 918 919 920 921 922 923 | ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); | | > > < > | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | ** left in the RBU handle passed as the first argument. A copy of the ** error code is returned. */ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){ int rc; memset(pIter, 0, sizeof(RbuObjIter)); rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, sqlite3_mprintf( "SELECT rbu_target_name(name, type='view') AS target, name " "FROM sqlite_master " "WHERE type IN ('table', 'view') AND target IS NOT NULL " " %s " "ORDER BY name" , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : "")); if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg, "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' " " FROM main.sqlite_master " " WHERE type='index' AND tbl_name = ?" ); |
︙ | ︙ | |||
2328 2329 2330 2331 2332 2333 2334 | /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ | < | | > > > > | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 | /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); if( p->zState==0 ){ const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState); memcpy(p->zStateDb, "stat", 4); |
︙ | ︙ | |||
2501 2502 2503 2504 2505 2506 2507 | static void rbuFileSuffix3(const char *zBase, char *z){ #ifdef SQLITE_ENABLE_8_3_NAMES #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; | | | | 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 | static void rbuFileSuffix3(const char *zBase, char *z){ #ifdef SQLITE_ENABLE_8_3_NAMES #if SQLITE_ENABLE_8_3_NAMES<2 if( sqlite3_uri_boolean(zBase, "8_3_names", 0) ) #endif { int i, sz; sz = (int)strlen(z)&0xffffff; for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4); } #endif } /* ** Return the current wal-index header checksum for the target database ** as a 64-bit integer. |
︙ | ︙ | |||
3471 3472 3473 3474 3475 3476 3477 | const char *zTarget, const char *zRbu, const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); | < | | 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 | const char *zTarget, const char *zRbu, const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1; p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; /* Create the custom VFS. */ memset(p, 0, sizeof(sqlite3rbu)); |
︙ | ︙ | |||
3494 3495 3496 3497 3498 3499 3500 | memcpy(p->zTarget, zTarget, nTarget+1); pCsr += nTarget+1; } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ | | < | 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 | memcpy(p->zTarget, zTarget, nTarget+1); pCsr += nTarget+1; } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ p->zState = rbuMPrintf(p, "%s", zState); } rbuOpenDatabase(p); } if( p->rc==SQLITE_OK ){ pState = rbuLoadState(p); assert( pState || p->rc!=SQLITE_OK ); |
︙ | ︙ | |||
3549 3550 3551 3552 3553 3554 3555 | ); } } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ sqlite3 *db = p->dbMain; | < < < < < < < < < < < < | < < < < < < < < < < < > > > > > | > > | > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > | 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 | ); } } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ sqlite3 *db = p->dbMain; p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg); /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = rbuObjIterFirst(p, &p->objiter); } /* If the RBU database contains no data_xxx tables, declare the RBU ** update finished. */ if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){ p->rc = SQLITE_DONE; p->eStage = RBU_STAGE_DONE; }else{ if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){ rbuCopyPragma(p, "page_size"); rbuCopyPragma(p, "auto_vacuum"); } /* Open transactions both databases. The *-oal file is opened or ** created at this point. */ if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); } /* Check if the main database is a zipvfs db. If it is, set the upper ** level pager to use "journal_mode=off". This prevents it from ** generating a large journal using a temp file. */ if( p->rc==SQLITE_OK ){ int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); if( frc==SQLITE_OK ){ p->rc = sqlite3_exec( db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); } } if( p->rc==SQLITE_OK ){ rbuSetupOal(p, pState); } } }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ rbuSetupCheckpoint(p, pState); }else if( p->eStage==RBU_STAGE_DONE ){ p->rc = SQLITE_DONE; }else{ p->rc = SQLITE_CORRUPT; } } rbuFreeState(pState); } return p; } /* ** Allocate and return an RBU handle with all fields zeroed except for the ** error code, which is set to SQLITE_MISUSE. */ static sqlite3rbu *rbuMisuseError(void){ sqlite3rbu *pRet; pRet = sqlite3_malloc64(sizeof(sqlite3rbu)); if( pRet ){ memset(pRet, 0, sizeof(sqlite3rbu)); pRet->rc = SQLITE_MISUSE; } return pRet; } /* ** Open and return a new RBU handle. */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* ** Open a handle to begin or resume an RBU VACUUM operation. */ sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState ){ if( zTarget==0 ){ return rbuMisuseError(); } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } /* ** Return the database handle used by pRbu. */ |
︙ | ︙ | |||
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 | rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } return rc; } | > | 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 | rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } return rc; } |
︙ | ︙ | |||
3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 | *pnTwo = MAX_PROGRESS; break; default: assert( 0 ); } } int sqlite3rbu_savestate(sqlite3rbu *p){ int rc = p->rc; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 | *pnTwo = MAX_PROGRESS; break; default: assert( 0 ); } } /* ** Return the current state of the RBU vacuum or update operation. */ int sqlite3rbu_state(sqlite3rbu *p){ int aRes[] = { 0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE, 0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE }; assert( RBU_STAGE_OAL==1 ); assert( RBU_STAGE_MOVE==2 ); assert( RBU_STAGE_CKPT==4 ); assert( RBU_STAGE_DONE==5 ); assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL ); assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE ); assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT ); assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE ); if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){ return SQLITE_RBU_STATE_ERROR; }else{ assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE ); assert( p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE || p->eStage==RBU_STAGE_CKPT || p->eStage==RBU_STAGE_DONE ); return aRes[p->eStage]; } } int sqlite3rbu_savestate(sqlite3rbu *p){ int rc = p->rc; if( rc==SQLITE_DONE ) return SQLITE_OK; assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE ); if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0); } |
︙ | ︙ |
Changes to ext/rbu/sqlite3rbu.h.
︙ | ︙ | |||
315 316 317 318 319 320 321 | ); /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** | | | | | | > > > > > > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | ); /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** ** The second argument to this function identifies a database in which ** to store the state of the RBU vacuum operation if it is suspended. The ** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum ** operation, the state database should either not exist or be empty ** (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has ** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. ** ** If the second argument passed to this function is NULL, then the ** name of the state database is "<database>-vacuum", where <database> ** is the name of the target database file. In this case, on UNIX, if the ** state database is not already present in the file-system, it is created ** with the same permissions as the target db is made. ** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. |
︙ | ︙ | |||
470 471 472 473 474 475 476 477 478 479 480 481 482 483 | ** permyriadage progress of the same stage. If the rbu_count table does ** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo); /* ** Create an RBU VFS named zName that accesses the underlying file-system ** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. ** The new object is registered as a non-default VFS with SQLite before ** returning. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | ** permyriadage progress of the same stage. If the rbu_count table does ** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count ** table exists but is not correctly populated, the value of the *pnOne ** output variable during stage 1 is undefined. */ void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo); /* ** Obtain an indication as to the current stage of an RBU update or vacuum. ** This function always returns one of the SQLITE_RBU_STATE_XXX constants ** defined in this file. Return values should be interpreted as follows: ** ** SQLITE_RBU_STATE_OAL: ** RBU is currently building a *-oal file. The next call to sqlite3rbu_step() ** may either add further data to the *-oal file, or compute data that will ** be added by a subsequent call. ** ** SQLITE_RBU_STATE_MOVE: ** RBU has finished building the *-oal file. The next call to sqlite3rbu_step() ** will move the *-oal file to the equivalent *-wal path. If the current ** operation is an RBU update, then the updated version of the database ** file will become visible to ordinary SQLite clients following the next ** call to sqlite3rbu_step(). ** ** SQLITE_RBU_STATE_CHECKPOINT: ** RBU is currently performing an incremental checkpoint. The next call to ** sqlite3rbu_step() will copy a page of data from the *-wal file into ** the target database file. ** ** SQLITE_RBU_STATE_DONE: ** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step() ** will immediately return SQLITE_DONE. ** ** SQLITE_RBU_STATE_ERROR: ** An error has occurred. Any subsequent calls to sqlite3rbu_step() will ** immediately return the SQLite error code associated with the error. */ #define SQLITE_RBU_STATE_OAL 1 #define SQLITE_RBU_STATE_MOVE 2 #define SQLITE_RBU_STATE_CHECKPOINT 3 #define SQLITE_RBU_STATE_DONE 4 #define SQLITE_RBU_STATE_ERROR 5 int sqlite3rbu_state(sqlite3rbu *pRbu); /* ** Create an RBU VFS named zName that accesses the underlying file-system ** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. ** The new object is registered as a non-default VFS with SQLite before ** returning. ** |
︙ | ︙ |
Changes to ext/rbu/test_rbu.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "sqlite3.h" #if defined(SQLITE_TEST) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) #include "sqlite3rbu.h" | > > > | > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include "sqlite3.h" #if defined(SQLITE_TEST) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) #include "sqlite3rbu.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include <assert.h> /* From main.c */ extern const char *sqlite3ErrName(int); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){ |
︙ | ︙ | |||
45 46 47 48 49 50 51 | Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pScript); } | | > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pScript); } static int SQLITE_TCLAPI test_sqlite3rbu_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ret = TCL_OK; sqlite3rbu *pRbu = (sqlite3rbu*)clientData; struct RbuCmd { const char *zName; int nArg; const char *zUsage; } aCmd[] = { {"step", 2, ""}, /* 0 */ {"close", 2, ""}, /* 1 */ {"create_rbu_delta", 2, ""}, /* 2 */ {"savestate", 2, ""}, /* 3 */ {"dbMain_eval", 3, "SQL"}, /* 4 */ {"bp_progress", 2, ""}, /* 5 */ {"db", 3, "RBU"}, /* 6 */ {"state", 2, ""}, /* 7 */ {"progress", 2, ""}, /* 8 */ {0,0,0} }; int iCmd; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "METHOD"); return TCL_ERROR; |
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ret = TCL_ERROR; }else{ Tcl_SetResult(interp, zBuf, TCL_VOLATILE); } } break; } default: /* seems unlikely */ assert( !"cannot happen" ); break; } return ret; } /* ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>? */ | > > > > > > > > > > > > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | ret = TCL_ERROR; }else{ Tcl_SetResult(interp, zBuf, TCL_VOLATILE); } } break; } case 7: /* state */ { const char *aRes[] = { 0, "oal", "move", "checkpoint", "done", "error" }; int eState = sqlite3rbu_state(pRbu); assert( eState>0 && eState<=5 ); Tcl_SetResult(interp, (char*)aRes[eState], TCL_STATIC); break; } case 8: /* progress */ { sqlite3_int64 nStep = sqlite3rbu_progress(pRbu); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nStep)); break; } default: /* seems unlikely */ assert( !"cannot happen" ); break; } return ret; } /* ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>? */ static int SQLITE_TCLAPI test_sqlite3rbu( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3rbu *pRbu = 0; const char *zCmd; |
︙ | ︙ | |||
204 205 206 207 208 209 210 | Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_vacuum CMD <target-db> <state-db> */ | | | | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_vacuum CMD <target-db> <state-db> */ static int SQLITE_TCLAPI test_sqlite3rbu_vacuum( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3rbu *pRbu = 0; const char *zCmd; const char *zTarget; const char *zStateDb = 0; if( objc!=3 && objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB ?STATE-DB?"); return TCL_ERROR; } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_create_vfs ?-default? NAME PARENT */ static int SQLITE_TCLAPI test_sqlite3rbu_create_vfs( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zName; const char *zParent; |
︙ | ︙ | |||
267 268 269 270 271 272 273 | Tcl_ResetResult(interp); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_destroy_vfs NAME */ | | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | Tcl_ResetResult(interp); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_destroy_vfs NAME */ static int SQLITE_TCLAPI test_sqlite3rbu_destroy_vfs( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zName; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "NAME"); return TCL_ERROR; } zName = Tcl_GetString(objv[1]); sqlite3rbu_destroy_vfs(zName); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_internal_test */ static int SQLITE_TCLAPI test_sqlite3rbu_internal_test( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; |
︙ | ︙ | |||
329 330 331 332 333 334 335 | for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } return TCL_OK; } #else | > > > | > | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } return TCL_OK; } #else #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */ #endif /* defined(SQLITE_TEST) */ |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 | if( f<d ){ f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY)); } return f; } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 | if( f<d ){ f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY)); } return f; } #endif /* !defined(SQLITE_RTREE_INT_ONLY) */ /* ** A constraint has failed while inserting a row into an rtree table. ** Assuming no OOM error occurs, this function sets the error message ** (at pRtree->base.zErrMsg) to an appropriate value and returns ** SQLITE_CONSTRAINT. ** ** Parameter iCol is the index of the leftmost column involved in the ** constraint failure. If it is 0, then the constraint that failed is ** the unique constraint on the id column. Otherwise, it is the rtree ** (c1<=c2) constraint on columns iCol and iCol+1 that has failed. ** ** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT. */ static int rtreeConstraintError(Rtree *pRtree, int iCol){ sqlite3_stmt *pStmt = 0; char *zSql; int rc; assert( iCol==0 || iCol%2 ); zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName); if( zSql ){ rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); if( rc==SQLITE_OK ){ if( iCol==0 ){ const char *zCol = sqlite3_column_name(pStmt, 0); pRtree->base.zErrMsg = sqlite3_mprintf( "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol ); }else{ const char *zCol1 = sqlite3_column_name(pStmt, iCol); const char *zCol2 = sqlite3_column_name(pStmt, iCol+1); pRtree->base.zErrMsg = sqlite3_mprintf( "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2 ); } } sqlite3_finalize(pStmt); return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc); } /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, |
︙ | ︙ | |||
2846 2847 2848 2849 2850 2851 2852 | #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ | | | | | 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 | #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } }else #endif { for(ii=0; ii<nData-4; ii+=2){ cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } } /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ cell.iRowid = sqlite3_value_int64(azData[2]); if( sqlite3_value_type(azData[0])==SQLITE_NULL || sqlite3_value_int64(azData[0])!=cell.iRowid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ rc = rtreeConstraintError(pRtree, 0); goto constraint; } } } bHaveRowid = 1; } } |
︙ | ︙ | |||
2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 | static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); | > > > > > | 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 | static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){ const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'"; char *zSql; sqlite3_stmt *p; int rc; i64 nRow = 0; if( sqlite3_table_column_metadata(db,pRtree->zDb,"sqlite_stat1", 0,0,0,0,0,0)==SQLITE_ERROR ){ pRtree->nRowEst = RTREE_DEFAULT_ROWEST; return SQLITE_OK; } zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0); if( rc==SQLITE_OK ){ if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
190 191 192 193 194 195 196 | do_test rtree-2.1.3 { execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.2.1 { catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) } | | | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | do_test rtree-2.1.3 { execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.2.1 { catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) } } {1 {UNIQUE constraint failed: t1.ii}} do_test rtree-2.2.2 { catchsql { INSERT INTO t1 VALUES(4, 1, 3, 4, 2) } } {1 {rtree constraint failed: t1.(y1<=y2)}} do_test rtree-2.2.3 { catchsql { INSERT INTO t1 VALUES(4, 3, 1, 2, 4) } } {1 {rtree constraint failed: t1.(x1<=x2)}} do_test rtree-2.2.4 { execsql { SELECT ii FROM t1 ORDER BY ii } } {1 2 3} do_test rtree-2.X { execsql { DROP TABLE t1 } } {} |
︙ | ︙ | |||
232 233 234 235 236 237 238 | SELECT * FROM t1; } } {5 1 3 2 4 6 2 6 4 8} # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): do_test rtree-3.2.1 { catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) } | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | SELECT * FROM t1; } } {5 1 3 2 4 6 2 6 4 8} # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): do_test rtree-3.2.1 { catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) } } {1 {rtree constraint failed: t1.(y1<=y2)}} do_test rtree-3.2.2 { catchsql { INSERT INTO t1 VALUES(8, 2, 6, 3, 3) } } {0 {}} #---------------------------------------------------------------------------- # Test cases rtree-5.* test DELETE operations. # |
︙ | ︙ | |||
486 487 488 489 490 491 492 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} REPLACE 1 0 {1 4 5 6 7 2 2 3 4 5 5 3 4 5 6} } 4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" { | | | | | | > > | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 4 4 5 6 7 5 3 4 5 6} REPLACE 1 0 {1 4 5 6 7 2 2 3 4 5 5 3 4 5 6} } 4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" { ROLLBACK 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6} ABORT 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} FAIL 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} REPLACE 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7} } } { foreach {mode uses error data} $testdata { db_restore_and_reopen set sql [string map [list %CONF% "OR $mode"] $sql_template] set testname "12.$tn.[string tolower $mode]" execsql { BEGIN; INSERT INTO t1 VALUES(4, 4, 5, 6, 7); } set res(0) {0 {}} set res(1) {1 {UNIQUE constraint failed: t1.idx}} set res(2) {1 {rtree constraint failed: t1.(x1<=x2)}} do_catchsql_test $testname.1 $sql $res($error) do_test $testname.2 [list sql_uses_stmt db $sql] $uses do_execsql_test $testname.3 { SELECT * FROM t1 ORDER BY idx } $data do_test $testname.4 { rtree_check db t1 } 0 db close } |
︙ | ︙ |
Changes to ext/rtree/rtree3.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 | # # rtree3-6: Test OOM while deleting all rows of a table, one at a time. # # rtree3-7: OOM during an ALTER TABLE RENAME TABLE command. # # rtree3-8: Test OOM while registering the r-tree module with sqlite. # | > | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # # rtree3-6: Test OOM while deleting all rows of a table, one at a time. # # rtree3-7: OOM during an ALTER TABLE RENAME TABLE command. # # rtree3-8: Test OOM while registering the r-tree module with sqlite. # # rtree3-11: OOM following a constraint failure # do_faultsim_test rtree3-1 -faults oom* -prep { faultsim_delete_and_reopen } -body { execsql { BEGIN TRANSACTION; CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2); INSERT INTO rt VALUES(NULL, 3, 5, 7, 9); |
︙ | ︙ | |||
230 231 232 233 234 235 236 237 | execsql { SELECT * FROM rt } } -body { execsql { SELECT ii FROM rt WHERE ii MATCH cube(4.5, 5.5, 6.5, 1, 1, 1) } } -test { faultsim_test_result {0 2} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | execsql { SELECT * FROM rt } } -body { execsql { SELECT ii FROM rt WHERE ii MATCH cube(4.5, 5.5, 6.5, 1, 1, 1) } } -test { faultsim_test_result {0 2} } do_test rtree3-11.prep { faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2); INSERT INTO rt VALUES(1, 2, 3, 4, 5); } faultsim_save_and_close } {} do_faultsim_test rtree3-10.1 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM rt } } -body { execsql { INSERT INTO rt VALUES(1, 2, 3, 4, 5) } } -test { faultsim_test_result {1 {UNIQUE constraint failed: rt.ii}} \ {1 {constraint failed}} } do_faultsim_test rtree3-10.2 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM rt } } -body { execsql { INSERT INTO rt VALUES(2, 2, 3, 5, 4) } } -test { faultsim_test_result {1 {rtree constraint failed: rt.(y1<=y2)}} \ {1 {constraint failed}} } finish_test |
Changes to ext/rtree/rtreeC.test.
︙ | ︙ | |||
344 345 346 347 348 349 350 | WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 1 {SCAN TABLE xdir} 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } | < < < < | 344 345 346 347 348 349 350 351 352 | WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 1 {SCAN TABLE xdir} 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } finish_test |
Added ext/rtree/rtreeG.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | # 2016-05-32 # # 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 contains tests for the r-tree module. # # Verify that no invalid SQL is run during initialization if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl ifcapable !rtree { finish_test ; return } db close sqlite3_shutdown test_sqlite3_log [list lappend ::log] set ::log [list] sqlite3 db test.db set ::log {} do_execsql_test rtreeG-1.1 { CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1); } {} do_test rtreeG-1.1log { set ::log } {} do_execsql_test rtreeG-1.2 { INSERT INTO t1 VALUES(1,10,15,5,23),(2,20,21,5,23),(3,10,15,20,30); SELECT id from t1 WHERE x0>8 AND x1<16 AND y0>2 AND y1<25; } {1} do_test rtreeG-1.2log { set ::log } {} db close sqlite3 db test.db do_execsql_test rtreeG-1.3 { SELECT id from t1 WHERE x0>8 AND x1<16 AND y0>2 AND y1<25; } {1} do_test rtreeG-1.3log { set ::log } {} do_execsql_test rtreeG-1.4 { DROP TABLE t1; } {} do_test rtreeG-1.4log { set ::log } {} db close sqlite3_shutdown test_sqlite3_log sqlite3_initialize sqlite3 db test.db finish_test |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
274 275 276 277 278 279 280 281 282 283 284 285 | ** Read a varint value from aBuf[] into *piVal. Return the number of ** bytes read. */ static int sessionVarintGet(u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } /* ** Read a 64-bit big-endian integer value from buffer aRec[]. Return ** the value read. */ static sqlite3_int64 sessionGetI64(u8 *aRec){ | > > > < | | | | < < < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | ** Read a varint value from aBuf[] into *piVal. Return the number of ** bytes read. */ static int sessionVarintGet(u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } /* Load an unaligned and unsigned 32-bit integer */ #define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) /* ** Read a 64-bit big-endian integer value from buffer aRec[]. Return ** the value read. */ static sqlite3_int64 sessionGetI64(u8 *aRec){ u64 x = SESSION_UINT32(aRec); u32 y = SESSION_UINT32(aRec+4); x = (x<<32) + y; return (sqlite3_int64)x; } /* ** Write a 64-bit big-endian integer value to the buffer aBuf[]. */ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){ aBuf[0] = (i>>56) & 0xFF; |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
1 |
| | | 1 2 3 4 5 6 7 8 9 | #if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) #define __SQLITESESSION_H_ 1 /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus extern "C" { |
︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus } #endif | | | 1270 1271 1272 1273 1274 1275 1276 1277 | /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus } #endif #endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */ |
Changes to ext/session/test_session.c.
1 2 3 4 5 6 7 | #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_SESSION) \ && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #include "sqlite3session.h" #include <assert.h> #include <string.h> | > > > | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_SESSION) \ && defined(SQLITE_ENABLE_PREUPDATE_HOOK) #include "sqlite3session.h" #include <assert.h> #include <string.h> #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif typedef struct TestSession TestSession; struct TestSession { sqlite3_session *pSession; Tcl_Interp *interp; Tcl_Obj *pFilterScript; }; |
︙ | ︙ | |||
103 104 105 106 107 108 109 | ** $session changeset ** $session delete ** $session enable BOOL ** $session indirect INTEGER ** $session patchset ** $session table_filter SCRIPT */ | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | ** $session changeset ** $session delete ** $session enable BOOL ** $session indirect INTEGER ** $session patchset ** $session table_filter SCRIPT */ static int SQLITE_TCLAPI test_session_cmd( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ TestSession *p = (TestSession*)clientData; sqlite3_session *pSession = p->pSession; |
︙ | ︙ | |||
236 237 238 239 240 241 242 | break; } } return TCL_OK; } | | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | break; } } return TCL_OK; } static void SQLITE_TCLAPI test_session_del(void *clientData){ TestSession *p = (TestSession*)clientData; if( p->pFilterScript ) Tcl_DecrRefCount(p->pFilterScript); sqlite3session_delete(p->pSession); ckfree((char*)p); } /* ** Tclcmd: sqlite3session CMD DB-HANDLE DB-NAME */ static int SQLITE_TCLAPI test_sqlite3session( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; Tcl_CmdInfo info; |
︙ | ︙ | |||
602 603 604 605 606 607 608 | return SQLITE_OK; } /* ** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT? */ | | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | return SQLITE_OK; } /* ** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT? */ static int SQLITE_TCLAPI test_sqlite3changeset_apply( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; /* Database handle */ Tcl_CmdInfo info; /* Database Tcl command (objv[1]) info */ |
︙ | ︙ | |||
657 658 659 660 661 662 663 | Tcl_ResetResult(interp); return TCL_OK; } /* ** sqlite3changeset_apply_replace_all DB CHANGESET */ | | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | Tcl_ResetResult(interp); return TCL_OK; } /* ** sqlite3changeset_apply_replace_all DB CHANGESET */ static int SQLITE_TCLAPI test_sqlite3changeset_apply_replace_all( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; /* Database handle */ Tcl_CmdInfo info; /* Database Tcl command (objv[1]) info */ |
︙ | ︙ | |||
692 693 694 695 696 697 698 | return TCL_OK; } /* ** sqlite3changeset_invert CHANGESET */ | | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | return TCL_OK; } /* ** sqlite3changeset_invert CHANGESET */ static int SQLITE_TCLAPI test_sqlite3changeset_invert( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; /* Return code from changeset_invert() */ TestStreamInput sIn; /* Input stream */ |
︙ | ︙ | |||
731 732 733 734 735 736 737 | sqlite3_free(sOut.p); return rc; } /* ** sqlite3changeset_concat LEFT RIGHT */ | | | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | sqlite3_free(sOut.p); return rc; } /* ** sqlite3changeset_concat LEFT RIGHT */ static int SQLITE_TCLAPI test_sqlite3changeset_concat( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; /* Return code from changeset_invert() */ |
︙ | ︙ | |||
779 780 781 782 783 784 785 | sqlite3_free(sOut.p); return rc; } /* ** sqlite3session_foreach VARNAME CHANGESET SCRIPT */ | | | 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 | sqlite3_free(sOut.p); return rc; } /* ** sqlite3session_foreach VARNAME CHANGESET SCRIPT */ static int SQLITE_TCLAPI test_sqlite3session_foreach( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *pChangeset; int nChangeset; |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | $(TOP)/src/test_windirent.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ | > > | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | $(TOP)/src/test_windirent.c \ $(TOP)/src/test_wsd.c # Extensions to be statically loaded. # TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/carray.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/csv.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ |
︙ | ︙ | |||
384 385 386 387 388 389 390 | $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/session/sqlite3session.c \ | | < | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/test_session.c # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
447 448 449 450 451 452 453 | # executables needed for testing # TESTPROGS = \ testfixture$(EXE) \ sqlite3$(EXE) \ sqlite3_analyzer$(EXE) \ | | > > > > > > > > > > | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | # executables needed for testing # TESTPROGS = \ testfixture$(EXE) \ sqlite3$(EXE) \ sqlite3_analyzer$(EXE) \ sqldiff$(EXE) \ dbhash$(EXE) # Databases containing fuzzer test cases # FUZZDATA = \ $(TOP)/test/fuzzdata1.db \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db \ $(TOP)/test/fuzzdata4.db # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.a sqlite3$(EXE) libsqlite3.a: $(LIBOBJ) $(AR) libsqlite3.a $(LIBOBJ) $(RANLIB) libsqlite3.a sqlite3$(EXE): $(TOP)/src/shell.c libsqlite3.a sqlite3.h $(TCCX) $(READLINE_FLAGS) -o sqlite3$(EXE) $(SHELL_OPT) \ $(TOP)/src/shell.c libsqlite3.a $(LIBREADLINE) $(TLIBS) $(THREADLIB) sqldiff$(EXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h $(TCCX) -o sqldiff$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS) $(THREADLIB) dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h $(TCCX) -o dbhash$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB) scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB) srcck1$(EXE): $(TOP)/tool/srcck1.c $(BCC) -o srcck1$(EXE) $(TOP)/tool/srcck1.c sourcetest: srcck1$(EXE) sqlite3.c ./srcck1 sqlite3.c fuzzershell$(EXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h |
︙ | ︙ |
Changes to src/alter.c.
︙ | ︙ | |||
597 598 599 600 601 602 603 604 605 606 607 608 609 610 | const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); | > | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; assert( v!=0 ); pNew = pParse->pNewTable; assert( pNew ); |
︙ | ︙ | |||
691 692 693 694 695 696 697 | zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); db->flags = savedDbFlags; } | | | < < < < | > > > > > > | < > | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); db->flags = savedDbFlags; } /* Make sure the schema version is at least 3. But do not upgrade ** from less than 3 to 4, as that will corrupt any preexisting DESC ** index. */ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2); sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3); sqlite3ReleaseTempReg(pParse, r1); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); } /* ** This function is called by the parser after the table-name in |
︙ | ︙ |
Changes to src/auth.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 | const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ sqlite3 *db = pParse->db; /* Database handle */ char *zDb = db->aDb[iDb].zName; /* Name of attached database */ int rc; /* Auth callback return code */ rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); if( rc==SQLITE_DENY ){ if( db->nDb>2 || iDb!=0 ){ | > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ sqlite3 *db = pParse->db; /* Database handle */ char *zDb = db->aDb[iDb].zName; /* Name of attached database */ int rc; /* Auth callback return code */ if( db->init.busy ) return SQLITE_OK; rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext #ifdef SQLITE_USER_AUTHENTICATION ,db->auth.zAuthUser #endif ); if( rc==SQLITE_DENY ){ if( db->nDb>2 || iDb!=0 ){ |
︙ | ︙ |
Changes to src/backup.c.
︙ | ︙ | |||
773 774 775 776 777 778 779 | #endif /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE | | < > | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | #endif /* 0x7FFFFFFF is the hard limit for the number of pages in a database ** file. By passing this as the number of pages to copy to ** sqlite3_backup_step(), we can guarantee that the copy finishes ** within a single call (unless an error occurs). The assert() statement ** checks this assumption - (p->rc) should be set to either SQLITE_DONE ** or an error code. */ sqlite3_backup_step(&b, 0x7FFFFFFF); assert( b.rc!=SQLITE_OK ); rc = sqlite3_backup_finish(&b); if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
642 643 644 645 646 647 648 649 650 651 652 653 654 655 | ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif /* | > > > > > > > > > | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } /* Verify that the cursor and the BtShared agree about what is the current ** database connetion. This is important in shared-cache mode. If the database ** connection pointers get out-of-sync, it is possible for routines like ** btreeInitPage() to reference an stale connection pointer that references a ** a connection that has already closed. This routine is used inside assert() ** statements only and for the purpose of double-checking that the btree code ** does keep the database connection pointers up-to-date. */ static int cursorOwnsBtShared(BtCursor *p){ assert( cursorHoldsMutex(p) ); return (p->pBtree->db==p->pBt->db); } #endif /* |
︙ | ︙ | |||
801 802 803 804 805 806 807 | ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ | | > > | < | < | < < | | | | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | ** If the cursor is open on an intkey table, then the integer key ** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to ** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is ** set to point to a malloced buffer pCur->nKey bytes in size containing ** the key. */ static int saveCursorKey(BtCursor *pCur){ int rc = SQLITE_OK; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); if( pCur->curIntKey ){ /* Only the rowid is required for a table btree */ pCur->nKey = sqlite3BtreeIntegerKey(pCur); }else{ /* For an index btree, save the complete key content */ void *pKey; pCur->nKey = sqlite3BtreePayloadSize(pCur); pKey = sqlite3Malloc( pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ sqlite3_free(pKey); } |
︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 ); flagByte &= ~PTF_LEAF; pPage->childPtrSize = 4-4*pPage->leaf; pPage->xCellSize = cellSizePtr; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ | | | | | | | | | | 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 | assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 ); flagByte &= ~PTF_LEAF; pPage->childPtrSize = 4-4*pPage->leaf; pPage->xCellSize = cellSizePtr; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an ** interior table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY)==5 ); /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a ** leaf table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); pPage->intKey = 1; if( pPage->leaf ){ pPage->intKeyLeaf = 1; pPage->xParseCell = btreeParseCellPtr; }else{ pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtrNoPayload; pPage->xParseCell = btreeParseCellPtrNoPayload; } pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==PTF_ZERODATA ){ /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an ** interior index b-tree page. */ assert( (PTF_ZERODATA)==2 ); /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a ** leaf index b-tree page. */ assert( (PTF_ZERODATA|PTF_LEAF)==10 ); pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ |
︙ | ︙ | |||
2529 2530 2531 2532 2533 2534 2535 2536 2537 | if( rc ) goto btree_open_out; pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) | > < | 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 | if( rc ) goto btree_open_out; pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* Add the new BtShared object to the linked list sharable BtShareds. */ pBt->nRef = 1; if( p->sharable ){ MUTEX_LOGIC( sqlite3_mutex *mutexShared; ) MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } |
︙ | ︙ | |||
2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 | sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); } } if( mutexOpen ){ assert( sqlite3_mutex_held(mutexOpen) ); sqlite3_mutex_leave(mutexOpen); } return rc; } /* ** Decrement the BtShared.nRef counter. When it reaches zero, ** remove the BtShared structure from the sharing list. Return ** true if the BtShared.nRef counter reaches zero and return | > | 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 | sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); } } if( mutexOpen ){ assert( sqlite3_mutex_held(mutexOpen) ); sqlite3_mutex_leave(mutexOpen); } assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 ); return rc; } /* ** Decrement the BtShared.nRef counter. When it reaches zero, ** remove the BtShared structure from the sharing list. Return ** true if the BtShared.nRef counter reaches zero and return |
︙ | ︙ | |||
4654 4655 4656 4657 4658 4659 4660 | */ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* | | > | | < < < < < < < | > | < | | > < < < < | | < < < | < | 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 | */ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* ** Return the value of the integer key or "rowid" for a table btree. ** This routine is only valid for a cursor that is pointing into a ** ordinary table btree. If the cursor points to an index btree or ** is invalid, the result of this routine is undefined. */ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } /* ** Return the number of bytes of payload for the entry that pCur is ** currently pointing to. For table btrees, this will be the amount ** of data. For index btrees, this will be the size of the key. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. */ u32 sqlite3BtreePayloadSize(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); return pCur->info.nPayload; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. |
︙ | ︙ | |||
5135 5136 5137 5138 5139 5140 5141 | ** including calls from other threads against the same cache. ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ | | < < < | 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 | ** including calls from other threads against the same cache. ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){ return fetchPayload(pCur, pAmt); } /* ** Move the cursor down to a new child page. The newPgno argument is the ** page number of the child page to move to. |
︙ | ︙ | |||
5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 | int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ | > > | < | 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 | int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pIdxKey==0 && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){ if( pCur->info.nKey==intKey ){ *pRes = 0; return SQLITE_OK; } if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){ *pRes = -1; |
︙ | ︙ | |||
6474 6475 6476 6477 6478 6479 6480 | ** area. pCell might point to some temporary storage. The cell will ** be constructed in this temporary area then copied into pPage->aData ** later. */ static int fillInCell( MemPage *pPage, /* The page that contains the cell */ unsigned char *pCell, /* Complete text of the cell */ | < < | | 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 | ** area. pCell might point to some temporary storage. The cell will ** be constructed in this temporary area then copied into pPage->aData ** later. */ static int fillInCell( MemPage *pPage, /* The page that contains the cell */ unsigned char *pCell, /* Complete text of the cell */ const BtreePayload *pX, /* Payload with which to construct the cell */ int *pnSize /* Write cell size here */ ){ int nPayload; const u8 *pSrc; int nSrc, n, rc; int spaceLeft; MemPage *pOvfl = 0; |
︙ | ︙ | |||
6500 6501 6502 6503 6504 6505 6506 | /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ nHeader = pPage->childPtrSize; | < | > > > > > | | < < < < < < < < < | | | < > > > | 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 | /* pPage is not necessarily writeable since pCell might be auxiliary ** buffer space that is separate from the pPage buffer area */ assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize] || sqlite3PagerIswriteable(pPage->pDbPage) ); /* Fill in the header. */ nHeader = pPage->childPtrSize; if( pPage->intKey ){ nPayload = pX->nData + pX->nZero; pSrc = pX->pData; nSrc = pX->nData; assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */ nHeader += putVarint32(&pCell[nHeader], nPayload); nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey); }else{ assert( pX->nData==0 ); assert( pX->nZero==0 ); assert( pX->nKey<=0x7fffffff && pX->pKey!=0 ); nSrc = nPayload = (int)pX->nKey; pSrc = pX->pKey; nHeader += putVarint32(&pCell[nHeader], nPayload); } /* Fill in the payload */ if( nPayload<=pPage->maxLocal ){ n = nHeader + nPayload; testcase( n==3 ); testcase( n==4 ); if( n<4 ) n = 4; *pnSize = n; spaceLeft = nPayload; |
︙ | ︙ | |||
6557 6558 6559 6560 6561 6562 6563 | ** were computed correctly. */ #if SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); assert( nHeader==(int)(info.pPayload - pCell) ); | | | 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 | ** were computed correctly. */ #if SQLITE_DEBUG { CellInfo info; pPage->xParseCell(pPage, pCell, &info); assert( nHeader==(int)(info.pPayload - pCell) ); assert( info.nKey==pX->nKey ); assert( *pnSize == info.nSize ); assert( spaceLeft == info.nLocal ); } #endif /* Write the payload into the local Cell and any extra into overflow pages */ while( nPayload>0 ){ |
︙ | ︙ | |||
6641 6642 6643 6644 6645 6646 6647 | memset(pPayload, 0, n); } nPayload -= n; pPayload += n; pSrc += n; nSrc -= n; spaceLeft -= n; | < < < < | 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 | memset(pPayload, 0, n); } nPayload -= n; pPayload += n; pSrc += n; nSrc -= n; spaceLeft -= n; } releasePage(pToRelease); return SQLITE_OK; } /* ** Remove the i-th cell from pPage. This routine effects pPage only. |
︙ | ︙ | |||
6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz, /* Bytes of content in pCell */ u8 *pTemp, /* Temp storage space for pCell, if needed */ Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ int *pRC /* Read and write return code from here */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ | > > < | | 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. ** ** *pRC must be SQLITE_OK when this routine is called. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz, /* Bytes of content in pCell */ u8 *pTemp, /* Temp storage space for pCell, if needed */ Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ int *pRC /* Read and write return code from here */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ assert( *pRC==SQLITE_OK ); assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( MX_CELL(pPage->pBt)<=10921 ); assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB ); assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) ); assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); /* The cell should normally be sized correctly. However, when moving a |
︙ | ︙ | |||
6800 6801 6802 6803 6804 6805 6806 | ptrmapPutOvflPtr(pPage, pCell, pRC); } } } /* ** A CellArray object contains a cache of pointers and sizes for a | | | 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 | ptrmapPutOvflPtr(pPage, pCell, pRC); } } } /* ** A CellArray object contains a cache of pointers and sizes for a ** consecutive sequence of cells that might be held on multiple pages. */ typedef struct CellArray CellArray; struct CellArray { int nCell; /* Number of cells in apCell[] */ MemPage *pRef; /* Reference page */ u8 **apCell; /* All cells begin balanced */ u16 *szCell; /* Local size of all cells in apCell[] */ |
︙ | ︙ | |||
7232 7233 7234 7235 7236 7237 7238 | pCell = findCell(pPage, pPage->nCell-1); pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ | > | | > | 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 | pCell = findCell(pPage, pPage->nCell-1); pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ if( rc==SQLITE_OK ){ insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), 0, pPage->pgno, &rc); } /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); /* Release the reference to the new page. */ releasePage(pNew); } |
︙ | ︙ | |||
7753 7754 7755 7756 7757 7758 7759 | d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ assert( d<nMaxCells ); assert( r<nMaxCells ); (void)cachedCellSize(&b, r); if( szRight!=0 | | | 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 | d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ assert( d<nMaxCells ); assert( r<nMaxCells ); (void)cachedCellSize(&b, r); if( szRight!=0 && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ break; } szRight += b.szCell[d] + 2; szLeft -= b.szCell[r] + 2; cntNew[i-1] = r; r--; d--; |
︙ | ︙ | |||
8325 8326 8327 8328 8329 8330 8331 | sqlite3PageFree(pFree); } return rc; } /* | | | | | > | < > > > > > > < < | | 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 | sqlite3PageFree(pFree); } return rc; } /* ** Insert a new record into the BTree. The content of the new record ** is described by the pX object. The pCur cursor is used only to ** define what table the record should be inserted into, and is left ** pointing at a random location. ** ** For a table btree (used for rowid tables), only the pX.nKey value of ** the key is used. The pX.pKey value must be NULL. The pX.nKey is the ** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields ** hold the content of the row. ** ** For an index btree (used for indexes and WITHOUT ROWID tables), the ** key is an arbitrary byte sequence stored in pX.pKey,nKey. The ** pX.pData,nData,nZero fields must be zero. ** ** If the seekResult parameter is non-zero, then a successful call to ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already ** been performed. seekResult is the search result returned (a negative ** number if pCur points at an entry that is smaller than (pKey, nKey), or ** a positive value if pCur points at an entry that is larger than ** (pKey, nKey)). ** ** If the seekResult parameter is non-zero, then the caller guarantees that ** cursor pCur is pointing at the existing copy of a row that is to be ** overwritten. If the seekResult parameter is 0, then cursor pCur may ** point to any entry or to no entry at all and so this function has to seek ** the cursor before the new key can be inserted. */ int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const BtreePayload *pX, /* Content of the row to be inserted */ int appendBias, /* True if this is likely an append */ int seekResult /* Result of prior MovetoUnpacked() call */ ){ int rc; int loc = seekResult; /* -1: before desired location +1: after */ int szNew = 0; int idx; |
︙ | ︙ | |||
8380 8381 8382 8383 8384 8385 8386 | assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ | | | | | | | | | | | | 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 | assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); /* Assert that the caller has been consistent. If this cursor was opened ** expecting an index b-tree, then the caller should be inserting blob ** keys with no associated data. If the cursor was opened expecting an ** intkey table, the caller should be inserting integer keys with a ** blob of associated data. */ assert( (pX->pKey==0)==(pCur->pKeyInfo==0) ); /* Save the positions of any other cursors open on this table. ** ** In some cases, the call to btreeMoveto() below is a no-op. For ** example, when inserting data into a table with auto-generated integer ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the ** integer key to use. It then calls this function to actually insert the ** data into the intkey B-Tree. In this case btreeMoveto() recognizes ** that the cursor is already where it needs to be and returns without ** doing any work. To avoid thwarting these optimizations, it is important ** not to clear the cursor here. */ if( pCur->curFlags & BTCF_Multiple ){ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; } if( pCur->pKeyInfo==0 ){ assert( pX->pKey==0 ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced */ invalidateIncrblobCursors(p, pX->nKey, 0); /* If the cursor is currently on the last row and we are appending a ** new row onto the end, set the "loc" to avoid an unnecessary ** btreeMoveto() call */ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0 && pCur->info.nKey==pX->nKey-1 ){ loc = -1; }else if( loc==0 ){ rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc); if( rc ) return rc; } }else if( loc==0 ){ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc); if( rc ) return rc; } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); pPage = pCur->apPage[pCur->iPage]; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); rc = fillInCell(pPage, newCell, pX, &szNew); if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->aiIdx[pCur->iPage]; if( loc==0 ){ u16 szOld; assert( idx<pPage->nCell ); |
︙ | ︙ | |||
8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 | }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. ** | > | 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 | }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. ** |
︙ | ︙ | |||
8479 8480 8481 8482 8483 8484 8485 | ** is advantageous to leave the cursor pointing to the last entry in ** the b-tree if possible. If the cursor is left pointing to the last ** entry in the table, and the next row inserted has an integer key ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ pCur->info.nSize = 0; | | > | 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 | ** is advantageous to leave the cursor pointing to the last entry in ** the b-tree if possible. If the cursor is left pointing to the last ** entry in the table, and the next row inserted has an integer key ** larger than the largest existing key, it is possible to insert the ** row without seeking the cursor. This can be a big performance boost. */ pCur->info.nSize = 0; if( pPage->nOverflow ){ assert( rc==SQLITE_OK ); pCur->curFlags &= ~(BTCF_ValidNKey); rc = balance(pCur); /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ |
︙ | ︙ | |||
8615 8616 8617 8618 8619 8620 8621 | pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); | > | > | 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 | pCell = findCell(pLeaf, pLeaf->nCell-1); if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } /* Balance the tree. If the entry deleted was located on a leaf page, ** then the cursor still points to that page. In this case the first ** call to balance() repairs the tree, and the if(...) condition is |
︙ | ︙ | |||
10133 10134 10135 10136 10137 10138 10139 10140 | #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ int sqlite3BtreeSharable(Btree *p){ return p->sharable; } #endif | > > > > > > > > > > | 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 | #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ int sqlite3BtreeSharable(Btree *p){ return p->sharable; } /* ** Return the number of connections to the BtShared object accessed by ** the Btree handle passed as the only argument. For private caches ** this is always 1. For shared caches it may be 1 or greater. */ int sqlite3BtreeConnectionCount(Btree *p){ testcase( p->sharable ); return p->pBt->nRef; } #endif |
Changes to src/btree.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ #ifndef SQLITE_BTREE_H #define SQLITE_BTREE_H /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ #define SQLITE_N_BTREE_META 16 /* |
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ | > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; typedef struct BtreePayload BtreePayload; int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ |
︙ | ︙ | |||
246 247 248 249 250 251 252 | int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*, u8 flags); /* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */ #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ | > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | | < | | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*, u8 flags); /* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */ #define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */ #define BTREE_AUXDELETE 0x04 /* not the primary delete operation */ /* An instance of the BtreePayload object describes the content of a single ** entry in either an index or table btree. ** ** Index btrees (used for indexes and also WITHOUT ROWID tables) contain ** an arbitrary key and no data. These btrees have pKey,nKey set to their ** key and pData,nData,nZero set to zero. ** ** Table btrees (used for rowid tables) contain an integer rowid used as ** the key and passed in the nKey field. The pKey field is zero. ** pData,nData hold the content of the new entry. nZero extra zero bytes ** are appended to the end of the content when constructing the entry. ** ** This object is used to pass information into sqlite3BtreeInsert(). The ** same information used to be passed as five separate parameters. But placing ** the information into this object helps to keep the interface more ** organized and understandable, and it also helps the resulting code to ** run a little faster by using fewer registers for parameter passing. */ struct BtreePayload { const void *pKey; /* Key content for indexes. NULL for tables */ sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */ const void *pData; /* Data for tables. NULL for indexes */ int nData; /* Size of pData. 0 if none. */ int nZero; /* Extra zero data appended after pData,nData */ }; int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int *pRes); i64 sqlite3BtreeIntegerKey(BtCursor*); int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt); u32 sqlite3BtreePayloadSize(BtCursor*); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); void sqlite3BtreeIncrblobCursor(BtCursor *); |
︙ | ︙ | |||
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3BtreeEnter(Btree*); void sqlite3BtreeEnterAll(sqlite3*); int sqlite3BtreeSharable(Btree*); void sqlite3BtreeEnterCursor(BtCursor*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeEnterCursor(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE void sqlite3BtreeLeave(Btree*); void sqlite3BtreeLeaveCursor(BtCursor*); void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG | > > | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3BtreeEnter(Btree*); void sqlite3BtreeEnterAll(sqlite3*); int sqlite3BtreeSharable(Btree*); void sqlite3BtreeEnterCursor(BtCursor*); int sqlite3BtreeConnectionCount(Btree*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeConnectionCount(X) 1 #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE void sqlite3BtreeLeave(Btree*); void sqlite3BtreeLeaveCursor(BtCursor*); void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG |
︙ | ︙ | |||
329 330 331 332 333 334 335 | # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif | | | 356 357 358 359 360 361 362 363 | # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* SQLITE_BTREE_H */ |
Changes to src/build.c.
︙ | ︙ | |||
334 335 336 337 338 339 340 | ** ** The difference between this routine and sqlite3FindTable() is that this ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ | | | > | | | | | | > | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | ** ** The difference between this routine and sqlite3FindTable() is that this ** routine leaves an error message in pParse->zErrMsg where ** sqlite3FindTable() does not. */ Table *sqlite3LocateTable( Parse *pParse, /* context in which to report errors */ u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */ const char *zName, /* Name of the table we are looking for */ const char *zDbase /* Name of the database. Might be NULL */ ){ Table *p; /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3FindDbName(pParse->db, zDbase)<1 ){ /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ return pMod->pEpoTab; } } #endif if( (flags & LOCATE_NOERR)==0 ){ if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } } return p; } /* ** Locate the table identified by *p. ** ** This is a wrapper around sqlite3LocateTable(). The difference between ** sqlite3LocateTable() and this function is that this function restricts ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be ** non-NULL if it is part of a view or trigger program definition. See ** sqlite3FixSrcList() for details. */ Table *sqlite3LocateTableItem( Parse *pParse, u32 flags, struct SrcList_item *p ){ const char *zDb; assert( p->pSchema==0 || p->zDatabase==0 ); if( p->pSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); zDb = pParse->db->aDb[iDb].zName; }else{ zDb = p->zDatabase; } return sqlite3LocateTable(pParse, flags, p->zName, zDb); } /* ** Locate the in-memory structure that describes ** a particular index given the name of that index ** and the name of the database that contains the index. ** Return NULL if not found. |
︙ | ︙ | |||
588 589 590 591 592 593 594 | ** ** The db parameter is optional. It is needed if the Table object ** contains lookaside memory. (Table objects in the schema do not use ** lookaside memory, but some ephemeral Table objects do.) Or the ** db parameter can be used with db->pnBytesFreed to measure the memory ** used by the Table object. */ | | < < < < < < | > | | 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | ** ** The db parameter is optional. It is needed if the Table object ** contains lookaside memory. (Table objects in the schema do not use ** lookaside memory, but some ephemeral Table objects do.) Or the ** db parameter can be used with db->pnBytesFreed to measure the memory ** used by the Table object. */ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */ /* Record the number of outstanding lookaside allocations in schema Tables ** prior to doing any free() operations. Since schema Tables do not use ** lookaside, this number should not change. */ TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ? db->lookaside.nOut : 0 ); /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) ); if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){ char *zName = pIndex->zName; TESTONLY ( Index *pOld = ) sqlite3HashInsert( &pIndex->pSchema->idxHash, zName, 0 ); assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( pOld==pIndex || pOld==0 ); } |
︙ | ︙ | |||
637 638 639 640 641 642 643 644 645 646 647 648 649 650 | sqlite3VtabClear(db, pTable); #endif sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); } /* ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. */ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ Table *p; | > > > > > > > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | sqlite3VtabClear(db, pTable); #endif sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); } void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ /* Do not delete the table until the reference count reaches zero. */ if( !pTable ) return; if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return; deleteTable(db, pTable); } /* ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. */ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){ Table *p; |
︙ | ︙ | |||
1283 1284 1285 1286 1287 1288 1289 | int autoInc, /* True if the AUTOINCREMENT keyword is present */ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; | | | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | int autoInc, /* True if the AUTOINCREMENT keyword is present */ int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; Column *pCol = 0; int iCol = -1, i; int nTerm; if( pTab==0 ) goto primary_key_exit; if( pTab->tabFlags & TF_HasPrimaryKey ){ sqlite3ErrorMsg(pParse, "table \"%s\" has more than one primary key", pTab->zName); goto primary_key_exit; } pTab->tabFlags |= TF_HasPrimaryKey; if( pList==0 ){ |
︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 | if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ | < | | < < < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); return; } |
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 | /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** | > | | | < > > > > > > > > > > > > > > > > | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | /* ** This routine runs at the end of parsing a CREATE TABLE statement that ** has a WITHOUT ROWID clause. The job of this routine is to convert both ** internal schema data structures and the generated VDBE code so that they ** are appropriate for a WITHOUT ROWID table instead of a rowid table. ** Changes include: ** ** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL. ** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is ** no rowid btree for a WITHOUT ROWID. Instead, the canonical ** data storage is a covering index btree. ** (3) Bypass the creation of the sqlite_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master table entry of the table itself. ** (4) Set the Index.tnum of the PRIMARY KEY Index object in the ** schema to the rootpage from the main table. ** (5) Add all table columns to the PRIMARY KEY Index object ** so that the PRIMARY KEY is a covering index. The surplus ** columns are part of KeyInfo.nXField and are not used for ** sorting or lookup or uniqueness checks. ** (6) Replace the rowid tail on all automatically generated UNIQUE ** indices with the PRIMARY KEY columns. ** ** For virtual tables, only (1) is performed. */ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ Index *pIdx; Index *pPk; int nPk; int i, j; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables) */ if( !db->init.imposterTable ){ for(i=0; i<pTab->nCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ pTab->aCol[i].notNull = OE_Abort; } } } /* The remaining transformations only apply to b-tree tables, not to ** virtual tables */ if( IN_DECLARE_VTAB ) return; /* Convert the OP_CreateTable opcode that would normally create the ** root-page for the table into an OP_CreateIndex opcode. The index ** created will become the PRIMARY KEY index. */ if( pParse->addrCrTab ){ assert( v ); |
︙ | ︙ | |||
1696 1697 1698 1699 1700 1701 1702 | Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); | | < | > > | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | Token ipkToken; sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed ) return; pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master ** table entry. This is only required if currently generating VDBE ** code for a CREATE TABLE (not when parsing one as part of reading |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | pPk->nColumn--; }else{ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } | < < | < < | < < < | | < | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 | pPk->nColumn--; }else{ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; /* The root page of the PRIMARY KEY is the table root page */ pPk->tnum = pTab->tnum; /* Update the in-memory representation of all UNIQUE indices by converting ** the final rowid column into one or more columns of the PRIMARY KEY. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
︙ | ︙ | |||
2217 2218 2219 2220 2221 2222 2223 | pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); }else{ pTable->nCol = 0; nErr++; } | | | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 | pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); }else{ pTable->nCol = 0; nErr++; } sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); db->lookaside.bDisable--; } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; #endif /* SQLITE_OMIT_VIEW */ |
︙ | ︙ | |||
2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } | > | 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | if( db->mallocFailed ){ goto exit_drop_table; } assert( pParse->nErr==0 ); assert( pName->nSrc==1 ); if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; if( noErr ) db->suppressErr++; assert( isView==0 || isView==LOCATE_VIEW ); pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); if( noErr ) db->suppressErr--; if( pTab==0 ){ if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); goto exit_drop_table; } |
︙ | ︙ | |||
2863 2864 2865 2866 2867 2868 2869 | ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. | < < < < | | > < | > > > | 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 | ** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable ** as the table to be indexed. pParse->pNewTable is a table that is ** currently being constructed by a CREATE TABLE statement. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. */ void sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ Expr *pPIWhere, /* WHERE clause for partial indices */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist, /* Omit error if index already exists */ u8 idxType /* The index type */ ){ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; DbFixer sFix; /* For assigning database names to pTable */ int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ sqlite3 *db = pParse->db; Db *pDb; /* The specific table containing the indexed database */ int iDb; /* Index of the database that is being written */ Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ if( db->mallocFailed || pParse->nErr>0 ){ goto exit_create_index; } if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_create_index; } /* |
︙ | ︙ | |||
3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 | int n; Index *pLoop; for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); if( zName==0 ){ goto exit_create_index; } } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { const char *zDb = pDb->zName; | > > > > > > > | 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 | int n; Index *pLoop; for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){} zName = sqlite3MPrintf(db, "sqlite_autoindex_%s_%d", pTab->zName, n); if( zName==0 ){ goto exit_create_index; } /* Automatic index names generated from within sqlite3_declare_vtab() ** must have names that are distinct from normal automatic index names. ** The following statement converts "sqlite3_autoindex..." into ** "sqlite3_butoindex..." in order to make the names distinct. ** The "vtab_err.test" test demonstrates the need of this statement. */ if( IN_DECLARE_VTAB ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { const char *zDb = pDb->zName; |
︙ | ︙ | |||
3087 3088 3089 3090 3091 3092 3093 | assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; | | | 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 | assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) ); pIndex->zName = zExtra; zExtra += nName + 1; memcpy(pIndex->zName, zName, nName+1); pIndex->pTable = pTab; pIndex->onError = (u8)onError; pIndex->uniqNotNull = onError!=OE_None; pIndex->idxType = idxType; pIndex->pSchema = db->aDb[iDb].pSchema; pIndex->nKeyCol = pList->nExpr; if( pPIWhere ){ sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0); pIndex->pPartIdxWhere = pPIWhere; pPIWhere = 0; } |
︙ | ︙ | |||
3267 3268 3269 3270 3271 3272 3273 | sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } | | > | 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 | sqlite3ErrorMsg(pParse, "conflicting ON CONFLICT clauses specified", 0); } if( pIdx->onError==OE_Default ){ pIdx->onError = pIndex->onError; } } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } /* Link the new Index structure to its table and to the other ** in-memory database structures. */ assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( !IN_DECLARE_VTAB ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ sqlite3OomFault(db); goto exit_create_index; |
︙ | ︙ | |||
3360 3361 3362 3363 3364 3365 3366 | ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); | | | 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 | ** to invalidate all pre-compiled statements. */ if( pTblName ){ sqlite3RefillIndex(pParse, pIndex, iMem); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName)); sqlite3VdbeAddOp0(v, OP_Expire); } sqlite3VdbeJumpHere(v, pIndex->tnum); } /* When adding an index to the list of indices for a table, make ** sure all indices labeled OE_Replace come after all those labeled |
︙ | ︙ | |||
3385 3386 3387 3388 3389 3390 3391 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } | < < | 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ) freeIndex(db, pIndex); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** ** aiRowEst[0] is supposed to contain the number of elements in the index. |
︙ | ︙ | |||
3425 3426 3427 3428 3429 3430 3431 | /* 10, 9, 8, 7, 6 */ LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Set the first entry (number of rows in the index) to the estimated | | | > | | 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 | /* 10, 9, 8, 7, 6 */ LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol); int i; /* Set the first entry (number of rows in the index) to the estimated ** number of rows in the table, or half the number of rows in the table ** for a partial index. But do not let the estimate drop below 10. */ a[0] = pIdx->pTable->nRowLogEst; if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); /* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is ** 6 and each subsequent value (if any) is 5. */ memcpy(&a[1], aVal, nCopy*sizeof(LogEst)); for(i=nCopy+1; i<=pIdx->nKeyCol; i++){ a[i] = 23; assert( 23==sqlite3LogEst(5) ); } |
︙ | ︙ | |||
4310 4311 4312 4313 4314 4315 4316 | sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** | < < < < | 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 | sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } #endif /* ** Return a KeyInfo structure that is appropriate for the given Index. ** ** The caller should invoke sqlite3KeyInfoUnref() on the returned object ** when it has finished using it. */ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; int nKey = pIdx->nKeyCol; |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #endif #if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", #endif #if SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_ENABLE_8_3_NAMES | > > > > > > > > > | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #endif #if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #if SQLITE_CHECK_PAGES "CHECK_PAGES", #endif #if defined(__clang__) && defined(__clang_major__) "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "." CTIMEOPT_VAL(__clang_minor__) "." CTIMEOPT_VAL(__clang_patchlevel__), #elif defined(_MSC_VER) "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER), #elif defined(__GNUC__) && defined(__VERSION__) "COMPILER=gcc-" __VERSION__, #endif #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", #endif #if SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc) "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif #if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_ENABLE_8_3_NAMES "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), #endif #if SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #if SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif |
︙ | ︙ |
Changes to src/date.c.
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | static void currentTimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ time_t t; char *zFormat = (char *)sqlite3_user_data(context); | < | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | static void currentTimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ time_t t; char *zFormat = (char *)sqlite3_user_data(context); sqlite3_int64 iT; struct tm *pTm; struct tm sNow; char zBuf[20]; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); |
︙ | ︙ |
Changes to src/dbstat.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ | | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** the overflow pages associated with a cell will appear earlier in the ** sort-order than its child page: ** ** '/1c2/000/' // Left-most child of 451st child of root */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ " name TEXT, /* Name of table or index */" \ " path TEXT, /* Path to page from root */" \ " pageno INTEGER, /* Page number */" \ " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ " ncell INTEGER, /* Cells on page (0 for overflow) */" \ " payload INTEGER, /* Bytes of payload on this page */" \ " unused INTEGER, /* Bytes of unused space on this page */" \ " mx_payload INTEGER, /* Largest payload size of all cells */" \ " pgoffset INTEGER, /* Offset of page in file */" \ " pgsize INTEGER, /* Size of the page */" \ " schema TEXT HIDDEN /* Database schema being analyzed */" \ |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
235 236 237 238 239 240 241 242 243 244 245 | int iKey; /* Memory cell holding key of row to be deleted */ i16 nKey; /* Number of memory cells in the row key */ int iEphCur = 0; /* Ephemeral table holding all primary key values */ int iRowSet = 0; /* Register for rowset of rows to delete */ int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ | > > < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | int iKey; /* Memory cell holding key of row to be deleted */ i16 nKey; /* Number of memory cells in the row key */ int iEphCur = 0; /* Ephemeral table holding all primary key values */ int iRowSet = 0; /* Register for rowset of rows to delete */ int addrBypass = 0; /* Address of jump over the delete logic */ int addrLoop = 0; /* Top of the delete loop */ int addrEphOpen = 0; /* Instruction to open the Ephemeral table */ int bComplex; /* True if there are triggers or FKs or ** subqueries in the WHERE clause */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ #endif memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto delete_from_cleanup; } |
︙ | ︙ | |||
267 268 269 270 271 272 273 | #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); isView = pTab->pSelect!=0; bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #else # define pTrigger 0 # define isView 0 | < | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | #ifndef SQLITE_OMIT_TRIGGER pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); isView = pTab->pSelect!=0; bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #else # define pTrigger 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif /* If pTab is really a view, make sure it has been initialized. |
︙ | ︙ | |||
369 370 371 372 373 374 375 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { | | > | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE; if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ /* For a rowid table, initialize the RowSet to an empty set */ pPk = 0; nPk = 1; iRowSet = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 | sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ *prRhsHasNull = ++pParse->nMem; sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } } } } /* If no preexisting index is available for the IN clause ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery | > > > > > | | 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 | sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK const i64 sOne = 1; sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iTab, 0, 0, (u8*)&sOne, P4_INT64); #endif *prRhsHasNull = ++pParse->nMem; sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } } } } /* If no preexisting index is available for the IN clause ** and IN_INDEX_NOOP is an allowed reply ** and the RHS of the IN operator is a list, not a subquery ** and the RHS is not constant or has two or fewer terms, ** then it is not worth creating an ephemeral table to evaluate ** the IN operator so return IN_INDEX_NOOP. */ if( eType==0 && (inFlags & IN_INDEX_NOOP_OK) && !ExprHasProperty(pX, EP_xIsSelect) && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) |
︙ | ︙ | |||
2218 2219 2220 2221 2222 2223 2224 | sqlite3VdbeJumpHere(v, addr1); } } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ | < | | 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 | sqlite3VdbeJumpHere(v, addr1); } } if( eType==IN_INDEX_ROWID ){ /* In this case, the RHS is the ROWID of table b-tree */ sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ /* In this case, the RHS is an index b-tree. */ sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); /* If the set membership test fails, then the result of the |
︙ | ︙ | |||
2532 2533 2534 2535 2536 2537 2538 | int regOut /* Extract the value into this register */ ){ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; | | | 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 | int regOut /* Extract the value into this register */ ){ if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; if( !HasRowid(pTab) && !IsVirtual(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } |
︙ | ︙ | |||
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 | }else{ pFarg = pExpr->x.pList; } nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); if( pDef==0 || pDef->xFinalize!=0 ){ sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); break; } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evaluation of | > > > > > | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 | }else{ pFarg = pExpr->x.pList; } nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0); #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION if( pDef==0 && pParse->explain ){ pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); } #endif if( pDef==0 || pDef->xFinalize!=0 ){ sqlite3ErrorMsg(pParse, "unknown function: %s()", zId); break; } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evaluation of |
︙ | ︙ | |||
3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 | && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0 && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS) ){ return 1; } return 0; } /* ** An instance of the following structure is used by the tree walker ** to count references to table columns in the arguments of an ** aggregate function, in order to implement the ** sqlite3FunctionThisSrc() routine. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 | && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0 && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS) ){ return 1; } return 0; } /* ** An instance of the following structure is used by the tree walker ** to determine if an expression can be evaluated by reference to the ** index only, without having to do a search for the corresponding ** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur ** is the cursor for the table. */ struct IdxCover { Index *pIdx; /* The index to be tested for coverage */ int iCur; /* Cursor number for the table corresponding to the index */ }; /* ** Check to see if there are references to columns in table ** pWalker->u.pIdxCover->iCur can be satisfied using the index ** pWalker->u.pIdxCover->pIdx. */ static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Continue; } /* ** Determine if an index pIdx on table with cursor iCur contains will ** the expression pExpr. Return true if the index does cover the ** expression and false if the pExpr expression references table columns ** that are not found in the index pIdx. ** ** An index covering an expression means that the expression can be ** evaluated using only the index and without having to lookup the ** corresponding table entry. */ int sqlite3ExprCoveredByIndex( Expr *pExpr, /* The index to be tested */ int iCur, /* The cursor number for the corresponding table */ Index *pIdx /* The index that might be used for coverage */ ){ Walker w; struct IdxCover xcov; memset(&w, 0, sizeof(w)); xcov.iCur = iCur; xcov.pIdx = pIdx; w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } /* ** An instance of the following structure is used by the tree walker ** to count references to table columns in the arguments of an ** aggregate function, in order to implement the ** sqlite3FunctionThisSrc() routine. */ |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ | > | | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ assert( db==0 || IsVirtual(pTab) || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
736 737 738 739 740 741 742 | return 0; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | return 0; } continue; } } c2 = Utf8Read(zString); if( c==c2 ) continue; if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){ continue; } if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue; return 0; } return *zString==0; } |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 | if( zCharSet ){ sqlite3_free(azChar); } } sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); } /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. */ #ifdef SQLITE_SOUNDEX /* | > > > > > > > > > > > > > > > > > > > > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 | if( zCharSet ){ sqlite3_free(azChar); } } sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT); } #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION /* ** The "unknown" function is automatically substituted in place of ** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN ** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used. ** When the "sqlite3" command-line shell is built using this functionality, ** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries ** involving application-defined functions to be examined in a generic ** sqlite3 shell. */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. */ #ifdef SQLITE_SOUNDEX /* |
︙ | ︙ | |||
1782 1783 1784 1785 1786 1787 1788 | AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, SQLITE_FUNC_COUNT ), AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), | | | | > > > | 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 | AGGREGATE2(count, 0, 0, 0, countStep, countFinalize, SQLITE_FUNC_COUNT ), AGGREGATE(count, 1, 0, 0, countStep, countFinalize ), AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize), AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize), LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #ifdef SQLITE_CASE_SENSITIVE_LIKE LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE), #else LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE), LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE), #endif #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION FUNCTION(unknown, -1, 0, 0, unknownFunc ), #endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif |
︙ | ︙ |
Changes to src/hash.h.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. */ | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. */ #ifndef SQLITE_HASH_H #define SQLITE_HASH_H /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client |
︙ | ︙ | |||
89 90 91 92 93 94 95 | /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ /* #define sqliteHashCount(H) ((H)->count) // NOT USED */ | | | 89 90 91 92 93 94 95 96 | /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ /* #define sqliteHashCount(H) ((H)->count) // NOT USED */ #endif /* SQLITE_HASH_H */ |
Changes to src/hwtime.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ #ifndef SQLITE_HWTIME_H #define SQLITE_HWTIME_H /* ** The following routine only works on pentium-class (or newer) processors. ** It uses the RDTSC opcode to read the cycle count value out of the ** processor and returns that value. This can be used for high-res ** profiling. */ |
︙ | ︙ | |||
78 79 80 81 82 83 84 | ** of the debugging and testing utilities, but it should at ** least compile and run. */ sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif | | | 78 79 80 81 82 83 84 85 | ** of the debugging and testing utilities, but it should at ** least compile and run. */ sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); } #endif #endif /* !defined(SQLITE_HWTIME_H) */ |
Changes to src/loadext.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif #include "sqlite3ext.h" #include "sqliteInt.h" #include <string.h> #ifndef SQLITE_OMIT_LOAD_EXTENSION | < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif #include "sqlite3ext.h" #include "sqliteInt.h" #include <string.h> #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Some API routines are omitted when various features are ** excluded from a build of SQLite. Substitute a NULL pointer ** for any missing APIs. */ #ifndef SQLITE_ENABLE_COLUMN_METADATA # define sqlite3_column_database_name 0 |
︙ | ︙ | |||
87 88 89 90 91 92 93 | # define sqlite3_vtab_on_conflict 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE # define sqlite3_enable_shared_cache 0 #endif | | > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | # define sqlite3_vtab_on_conflict 0 #endif #ifdef SQLITE_OMIT_SHARED_CACHE # define sqlite3_enable_shared_cache 0 #endif #if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED) # define sqlite3_profile 0 # define sqlite3_trace 0 #endif #ifdef SQLITE_OMIT_GET_TABLE # define sqlite3_free_table 0 # define sqlite3_get_table 0 #endif #ifdef SQLITE_OMIT_INCRBLOB #define sqlite3_bind_zeroblob 0 #define sqlite3_blob_bytes 0 #define sqlite3_blob_close 0 #define sqlite3_blob_open 0 #define sqlite3_blob_read 0 #define sqlite3_blob_write 0 #define sqlite3_blob_reopen 0 #endif #if defined(SQLITE_OMIT_TRACE) # define sqlite3_trace_v2 0 #endif /* ** The following structure contains pointers to all SQLite API routines. ** A pointer to this structure is passed into extensions when they are ** loaded so that the extension can make calls back into the SQLite ** library. ** |
︙ | ︙ | |||
412 413 414 415 416 417 418 | sqlite3_value_subtype, sqlite3_result_subtype, /* Version 3.10.0 and later */ sqlite3_status64, sqlite3_strlike, sqlite3_db_cacheflush, /* Version 3.12.0 and later */ | | > > > | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | sqlite3_value_subtype, sqlite3_result_subtype, /* Version 3.10.0 and later */ sqlite3_status64, sqlite3_strlike, sqlite3_db_cacheflush, /* Version 3.12.0 and later */ sqlite3_system_errno, /* Version 3.14.0 and later */ sqlite3_trace_v2, sqlite3_expanded_sql }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a ** default entry point name (sqlite3_extension_init) is used. Use ** of the default name is recommended. |
︙ | ︙ | |||
435 436 437 438 439 440 441 | sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; | | > | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ){ sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(zFile); int ii; int rc; /* Shared library endings to try if zFile cannot be loaded as written */ static const char *azEndings[] = { #if SQLITE_OS_WIN "dll" #elif defined(__APPLE__) "dylib" |
︙ | ︙ | |||
493 494 495 496 497 498 499 | sqlite3_snprintf(nMsg, zErrmsg, "unable to open shared library [%s]", zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } | < | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | sqlite3_snprintf(nMsg, zErrmsg, "unable to open shared library [%s]", zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); /* If no entry point was specified and the default legacy ** entry point name "sqlite3_extension_init" was not found, then ** construct an entry point name "sqlite3_X_init" where the X is ** replaced by the lowercase value of every ASCII alphabetic ** character in the filename after the last "/" upto the first ".", ** and eliding the first three characters if they are "lib". |
︙ | ︙ | |||
526 527 528 529 530 531 532 | for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ if( sqlite3Isalpha(c) ){ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; } } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; | < | | > > | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ if( sqlite3Isalpha(c) ){ zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; } } memcpy(zAltEntry+iEntry, "_init", 6); zEntry = zAltEntry; xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); } if( xInit==0 ){ if( pzErrMsg ){ nMsg += sqlite3Strlen30(zEntry); *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; } sqlite3_free(zAltEntry); rc = xInit(db, &zErrmsg, &sqlite3Apis); if( rc ){ if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK; if( pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg); } sqlite3_free(zErrmsg); sqlite3OsDlClose(pVfs, handle); return SQLITE_ERROR; } |
︙ | ︙ | |||
655 656 657 658 659 660 661 | #endif /* ** Register a statically linked extension that is automatically ** loaded by every new database connection. */ | | > > | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | #endif /* ** Register a statically linked extension that is automatically ** loaded by every new database connection. */ int sqlite3_auto_extension( void (*xInit)(void) ){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ){ return rc; }else #endif |
︙ | ︙ | |||
700 701 702 703 704 705 706 | ** set of routines that is invoked for each new database connection, if it ** is currently on the list. If xInit is not on the list, then this ** routine is a no-op. ** ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ | | > > | 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | ** set of routines that is invoked for each new database connection, if it ** is currently on the list. If xInit is not on the list, then this ** routine is a no-op. ** ** Return 1 if xInit was found on the list and removed. Return 0 if xInit ** was not on the list. */ int sqlite3_cancel_auto_extension( void (*xInit)(void) ){ #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif int i; int n = 0; wsdAutoextInit; sqlite3_mutex_enter(mutex); |
︙ | ︙ | |||
749 750 751 752 753 754 755 | ** ** If anything goes wrong, set an error in the database connection. */ void sqlite3AutoLoadExtensions(sqlite3 *db){ u32 i; int go = 1; int rc; | | < | | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | ** ** If anything goes wrong, set an error in the database connection. */ void sqlite3AutoLoadExtensions(sqlite3 *db){ u32 i; int go = 1; int rc; sqlite3_loadext_entry xInit; wsdAutoextInit; if( wsdAutoext.nExt==0 ){ /* Common case: early out without every having to acquire a mutex */ return; } for(i=0; go; i++){ char *zErrmsg; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif sqlite3_mutex_enter(mutex); if( i>=wsdAutoext.nExt ){ xInit = 0; go = 0; }else{ xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i]; } sqlite3_mutex_leave(mutex); zErrmsg = 0; if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){ sqlite3ErrorWithMsg(db, rc, "automatic extension loading failed: %s", zErrmsg); go = 0; } sqlite3_free(zErrmsg); } } |
Changes to src/main.c.
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 | ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); /* If a transaction is open, the disconnectAllVtab() call above ** will not have called the xDisconnect() method on any virtual ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() | > > > | 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | ** sqlite3_close_v2() with a NULL pointer argument is a harmless no-op. */ return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0); } /* Force xDisconnect calls on all virtual tables */ disconnectAllVtab(db); /* If a transaction is open, the disconnectAllVtab() call above ** will not have called the xDisconnect() method on any virtual ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback() |
︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 | ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ | > | > | > > > > > > > > > > > > > > > > > > > > > > > > | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 | ** Register a trace function. The pArg from the previously registered trace ** is returned. ** ** A NULL trace function means that no tracing is executes. A non-NULL ** trace is a pointer to a function that is invoked at the start of each ** SQL statement. */ #ifndef SQLITE_OMIT_DEPRECATED void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){ void *pOld; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ /* Register a trace callback using the version-2 interface. */ int sqlite3_trace_v2( sqlite3 *db, /* Trace this connection */ unsigned mTrace, /* Mask of events to be traced */ int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */ void *pArg /* Context */ ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); db->mTrace = mTrace; db->xTrace = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* ** Register a profile function. The pArg from the previously registered ** profile function is returned. ** ** A NULL profile function means that no profiling is executes. A non-NULL ** profile is a pointer to a function that is invoked at the conclusion of ** each SQL statement that is run. |
︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 | sqlite3_mutex_enter(db->mutex); pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_TRACE */ /* ** Register a function to be invoked when a transaction commits. ** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ | > | 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 | sqlite3_mutex_enter(db->mutex); pOld = db->pProfileArg; db->xProfile = xProfile; db->pProfileArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ #endif /* SQLITE_OMIT_TRACE */ /* ** Register a function to be invoked when a transaction commits. ** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ |
︙ | ︙ |
Changes to src/msvc.h.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to MSVC. */ | | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to MSVC. */ #ifndef SQLITE_MSVC_H #define SQLITE_MSVC_H #if defined(_MSC_VER) #pragma warning(disable : 4054) #pragma warning(disable : 4055) #pragma warning(disable : 4100) #pragma warning(disable : 4127) #pragma warning(disable : 4130) #pragma warning(disable : 4152) #pragma warning(disable : 4189) #pragma warning(disable : 4206) #pragma warning(disable : 4210) #pragma warning(disable : 4232) #pragma warning(disable : 4244) #pragma warning(disable : 4305) #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ #endif /* SQLITE_MSVC_H */ |
Changes to src/os.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains OS interface code that is common to all ** architectures. */ | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains OS interface code that is common to all ** architectures. */ #include "sqliteInt.h" /* ** If we compile with the SQLITE_TEST macro set, then the following block ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ #if defined(SQLITE_TEST) |
︙ | ︙ |
Changes to src/os_setup.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains pre-processor directives related to operating system ** detection and/or setup. */ | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains pre-processor directives related to operating system ** detection and/or setup. */ #ifndef SQLITE_OS_SETUP_H #define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating ** system. ** ** After the following block of preprocess macros, all of SQLITE_OS_UNIX, ** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of |
︙ | ︙ | |||
50 51 52 53 54 55 56 | # endif #else # ifndef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # endif #endif | | | 50 51 52 53 54 55 56 57 | # endif #else # ifndef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # endif #endif #endif /* SQLITE_OS_SETUP_H */ |
Changes to src/os_unix.c.
︙ | ︙ | |||
5408 5409 5410 5411 5412 5413 5414 | 0, 0, "/var/tmp", "/usr/tmp", "/tmp", "." }; | | | | | | | > | > > > | 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 | 0, 0, "/var/tmp", "/usr/tmp", "/tmp", "." }; unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 && S_ISDIR(buf.st_mode) && osAccess(zDir, 03)==0 ){ return zDir; } if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; zDir = azDirs[i++]; } return 0; } /* ** Create a temporary file name in zBuf. zBuf must be allocated ** by the calling process and must be big enough to hold at least |
︙ | ︙ | |||
5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 | } } unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. | > > > > > > > > > > > > > > > > > > > > > | 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 | } } unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } /* ** Find the mode, uid and gid of file zFile. */ static int getFileMode( const char *zFile, /* File name */ mode_t *pMode, /* OUT: Permissions of zFile */ uid_t *pUid, /* OUT: uid of zFile. */ gid_t *pGid /* OUT: gid of zFile. */ ){ struct stat sStat; /* Output of stat() on database file */ int rc = SQLITE_OK; if( 0==osStat(zFile, &sStat) ){ *pMode = sStat.st_mode & 0777; *pUid = sStat.st_uid; *pGid = sStat.st_gid; }else{ rc = SQLITE_IOERR_FSTAT; } return rc; } /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. |
︙ | ︙ | |||
5556 5557 5558 5559 5560 5561 5562 | int rc = SQLITE_OK; /* Return Code */ *pMode = 0; *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ | < | 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 | int rc = SQLITE_OK; /* Return Code */ *pMode = 0; *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles ** the following naming conventions: ** ** "<path to db>-journal" ** "<path to db>-wal" |
︙ | ︙ | |||
5587 5588 5589 5590 5591 5592 5593 | if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; #endif nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; | | < < < < < < > > > > > > > > > | 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 | if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; #endif nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; }else if( flags & SQLITE_OPEN_URI ){ /* If this is a main database file and the file was opened using a URI ** filename, check for the "modeof" parameter. If present, interpret ** its value as a filename and try to copy the mode, uid and gid from ** that file. */ const char *z = sqlite3_uri_parameter(zPath, "modeof"); if( z ){ rc = getFileMode(z, pMode, pUid, pGid); } } return rc; } /* ** Open the file zPath. ** |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
286 287 288 289 290 291 292 293 294 295 296 297 298 299 | void *pMapRegion; /* Area memory mapped */ sqlite3_int64 mmapSize; /* Usable size of mapped region */ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_RDONLY 0x02 /* Connection is read only */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ | > > > > > > > > > > > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | void *pMapRegion; /* Area memory mapped */ sqlite3_int64 mmapSize; /* Usable size of mapped region */ sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */ sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */ #endif }; /* ** The winVfsAppData structure is used for the pAppData member for all of the ** Win32 VFS variants. */ typedef struct winVfsAppData winVfsAppData; struct winVfsAppData { const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */ void *pAppData; /* The extra pAppData, if any. */ BOOL bNoLock; /* Non-zero if locking is disabled. */ }; /* ** Allowed values for winFile.ctrlFlags */ #define WINFILE_RDONLY 0x02 /* Connection is read only */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ |
︙ | ︙ | |||
2607 2608 2609 2610 2611 2612 2613 | do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 | > > > | > > | 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 | do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 { winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData; if( pAppData==NULL || !pAppData->bNoLock ){ winceDestroyLock(pFile); } } if( pFile->zDeleteOnClose ){ int cnt = 0; while( osDeleteFileW(pFile->zDeleteOnClose)==0 && osGetFileAttributesW(pFile->zDeleteOnClose)!=0xffffffff && cnt++ < WINCE_DELETION_ATTEMPTS ){ |
︙ | ︙ | |||
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 | } pFile->locktype = (u8)locktype; OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. */ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 | } pFile->locktype = (u8)locktype; OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n", pFile->h, pFile->locktype, sqlite3ErrName(rc))); return rc; } /****************************************************************************** ****************************** No-op Locking ********************************** ** ** Of the various locking implementations available, this is by far the ** simplest: locking is ignored. No attempt is made to lock the database ** file for reading or writing. ** ** This locking mode is appropriate for use on read-only databases ** (ex: databases that are burned into CD-ROM, for example.) It can ** also be used if the application employs some external mechanism to ** prevent simultaneous access of the same database by two or more ** database connections. But there is a serious risk of database ** corruption if this locking mode is used in situations where multiple ** database connections are accessing the same database file at the same ** time and one or more of those connections are writing. */ static int winNolockLock(sqlite3_file *id, int locktype){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(locktype); return SQLITE_OK; } static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(pResOut); return SQLITE_OK; } static int winNolockUnlock(sqlite3_file *id, int locktype){ UNUSED_PARAMETER(id); UNUSED_PARAMETER(locktype); return SQLITE_OK; } /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /* ** If *pArg is initially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ** ** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. */ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ |
︙ | ︙ | |||
3617 3618 3619 3620 3621 3622 3623 | */ #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Apply advisory locks for all n bytes beginning at ofst. */ | | | | | | | | | 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 | */ #define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ /* ** Apply advisory locks for all n bytes beginning at ofst. */ #define WINSHM_UNLCK 1 #define WINSHM_RDLCK 2 #define WINSHM_WRLCK 3 static int winShmSystemLock( winShmNode *pFile, /* Apply locks to this open shared-memory segment */ int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */ int ofst, /* Offset to first byte to be locked/unlocked */ int nByte /* Number of bytes to lock or unlock */ ){ int rc = 0; /* Result code form Lock/UnlockFileEx() */ /* Access to the winShmNode object is serialized by the caller */ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 ); OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n", pFile->hFile.h, lockType, ofst, nByte)); /* Release/Acquire the system-level lock */ if( lockType==WINSHM_UNLCK ){ rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0); }else{ /* Initialize the locking parameters */ DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0); } if( rc!= 0 ){ rc = SQLITE_OK; }else{ pFile->lastErrno = osGetLastError(); rc = SQLITE_BUSY; } OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n", pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" : "winLockFile", pFile->lastErrno, sqlite3ErrName(rc))); return rc; } /* Forward references to VFS methods */ static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*); |
︙ | ︙ | |||
3780 3781 3782 3783 3784 3785 3786 | if( SQLITE_OK!=rc ){ goto shm_open_err; } /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. */ | | | | | 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 | if( SQLITE_OK!=rc ){ goto shm_open_err; } /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. */ if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); if( rc!=SQLITE_OK ){ rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(), "winOpenShm", pDbFd->zPath); } } if( rc==SQLITE_OK ){ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1); } if( rc ) goto shm_open_err; } /* Make the new connection a child of the winShmNode */ p->pShmNode = pShmNode; #if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE) |
︙ | ︙ | |||
3818 3819 3820 3821 3822 3823 3824 | p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; sqlite3_mutex_leave(pShmNode->mutex); return SQLITE_OK; /* Jump here on any error */ shm_open_err: | | | 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 | p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; sqlite3_mutex_leave(pShmNode->mutex); return SQLITE_OK; /* Jump here on any error */ shm_open_err: winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1); winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */ sqlite3_free(p); sqlite3_free(pNew); winShmLeaveMutex(); return rc; } |
︙ | ︙ | |||
3907 3908 3909 3910 3911 3912 3913 | if( pX==p ) continue; assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); allMask |= pX->sharedMask; } /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ | | | 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 | if( pX==p ) continue; assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); allMask |= pX->sharedMask; } /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; |
︙ | ︙ | |||
3935 3936 3937 3938 3939 3940 3941 | } allShared |= pX->sharedMask; } /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ | | | 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 | } allShared |= pX->sharedMask; } /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n); }else{ rc = SQLITE_OK; } } /* Get the local shared locks */ if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3960 3961 3962 3963 3964 3965 3966 | } } /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ | | | 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 | } } /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ if( rc==SQLITE_OK ){ rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n); if( rc==SQLITE_OK ){ assert( (p->sharedMask & mask)==0 ); p->exclMask |= mask; } } } sqlite3_mutex_leave(pShmNode->mutex); |
︙ | ︙ | |||
4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 | winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 | winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; /* ** This vector defines all the methods that can operate on an ** sqlite3_file for win32 without performing any locking. */ static const sqlite3_io_methods winIoNolockMethod = { 3, /* iVersion */ winClose, /* xClose */ winRead, /* xRead */ winWrite, /* xWrite */ winTruncate, /* xTruncate */ winSync, /* xSync */ winFileSize, /* xFileSize */ winNolockLock, /* xLock */ winNolockUnlock, /* xUnlock */ winNolockCheckReservedLock, /* xCheckReservedLock */ winFileControl, /* xFileControl */ winSectorSize, /* xSectorSize */ winDeviceCharacteristics, /* xDeviceCharacteristics */ winShmMap, /* xShmMap */ winShmLock, /* xShmLock */ winShmBarrier, /* xShmBarrier */ winShmUnmap, /* xShmUnmap */ winFetch, /* xFetch */ winUnfetch /* xUnfetch */ }; static winVfsAppData winAppData = { &winIoMethod, /* pMethod */ 0, /* pAppData */ 0 /* bNoLock */ }; static winVfsAppData winNolockAppData = { &winIoNolockMethod, /* pMethod */ 0, /* pAppData */ 1 /* bNoLock */ }; /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. */ |
︙ | ︙ | |||
4735 4736 4737 4738 4739 4740 4741 | return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } /* ** Open a file. */ static int winOpen( | | > | 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 | return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY); } /* ** Open a file. */ static int winOpen( sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */ const char *zName, /* Name of the file (UTF-8) */ sqlite3_file *id, /* Write the SQLite file handle here */ int flags, /* Open mode flags */ int *pOutFlags /* Status return flags */ ){ HANDLE h; DWORD lastErrno = 0; DWORD dwDesiredAccess; DWORD dwShareMode; DWORD dwCreationDisposition; DWORD dwFlagsAndAttributes = 0; #if SQLITE_OS_WINCE int isTemp = 0; #endif winVfsAppData *pAppData; winFile *pFile = (winFile*)id; void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ int cnt = 0; /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. |
︙ | ︙ | |||
4971 4972 4973 4974 4975 4976 4977 4978 | } } OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); #if SQLITE_OS_WINCE | > > > | > | | | | | | | > | | 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 | } } OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, " "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ? *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok")); pAppData = (winVfsAppData*)pVfs->pAppData; #if SQLITE_OS_WINCE { if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB && ((pAppData==NULL) || !pAppData->bNoLock) && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK ){ osCloseHandle(h); sqlite3_free(zConverted); sqlite3_free(zTmpname); OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc))); return rc; } } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; |
︙ | ︙ | |||
5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 | */ static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* | > > > > > > > > > > > > | 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 | */ static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif /* If this path name begins with "/X:", where "X" is any alphabetic ** character, discard the initial "/" from the pathname. */ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ zRelative++; } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ /* |
︙ | ︙ | |||
5343 5344 5345 5346 5347 5348 5349 | }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) | < < < < < < < < < < < | 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 | }else{ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zRelative); } return SQLITE_OK; #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){ |
︙ | ︙ | |||
5712 5713 5714 5715 5716 5717 5718 | } /* ** Initialize and deinitialize the operating system interface. */ int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 | } /* ** Initialize and deinitialize the operating system interface. */ int sqlite3_os_init(void){ static sqlite3_vfs winVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32", /* zName */ &winAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-longpath", /* zName */ &winAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #endif static sqlite3_vfs winNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-none", /* zName */ &winNolockAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #if defined(SQLITE_WIN32_HAS_WIDE) static sqlite3_vfs winLongPathNolockVfs = { 3, /* iVersion */ sizeof(winFile), /* szOsFile */ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */ 0, /* pNext */ "win32-longpath-none", /* zName */ &winNolockAppData, /* pAppData */ winOpen, /* xOpen */ winDelete, /* xDelete */ winAccess, /* xAccess */ winFullPathname, /* xFullPathname */ winDlOpen, /* xDlOpen */ winDlError, /* xDlError */ winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError, /* xGetLastError */ winCurrentTimeInt64, /* xCurrentTimeInt64 */ winSetSystemCall, /* xSetSystemCall */ winGetSystemCall, /* xGetSystemCall */ winNextSystemCall, /* xNextSystemCall */ }; #endif /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==80 ); |
︙ | ︙ | |||
5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 | assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathVfs, 0); #endif return SQLITE_OK; } int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ | > > > > > > | 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 | assert( winSysInfo.dwPageSize>0 ); sqlite3_vfs_register(&winVfs, 1); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathVfs, 0); #endif sqlite3_vfs_register(&winNolockVfs, 0); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathNolockVfs, 0); #endif return SQLITE_OK; } int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ |
︙ | ︙ |
Changes to src/os_win.h.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to Windows. */ | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to Windows. */ #ifndef SQLITE_OS_WIN_H #define SQLITE_OS_WIN_H /* ** Include the primary Windows SDK header file. */ #include "windows.h" #ifdef __CYGWIN__ |
︙ | ︙ | |||
81 82 83 84 85 86 87 | #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else # define SQLITE_OS_WIN_THREADS 0 #endif | | | 81 82 83 84 85 86 87 88 | #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else # define SQLITE_OS_WIN_THREADS 0 #endif #endif /* SQLITE_OS_WIN_H */ |
Changes to src/pager.c.
︙ | ︙ | |||
1922 1923 1924 1925 1926 1927 1928 | } return rc; } static int pager_truncate(Pager *pPager, Pgno nPage); /* | | | > | < | | > | > > | | > | 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | } return rc; } static int pager_truncate(Pager *pPager, Pgno nPage); /* ** The write transaction open on pPager is being committed (bCommit==1) ** or rolled back (bCommit==0). ** ** Return TRUE if and only if all dirty pages should be flushed to disk. ** ** Rules: ** ** * For non-TEMP databases, always sync to disk. This is necessary ** for transactions to be durable. ** ** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing ** file has been created already (via a spill on pagerStress()) and ** when the number of dirty pages in memory exceeds 25% of the total ** cache size. */ static int pagerFlushOnCommit(Pager *pPager, int bCommit){ if( pPager->tempFile==0 ) return 1; if( !bCommit ) return 0; if( !isOpen(pPager->fd) ) return 0; return (sqlite3PCachePercentDirty(pPager->pPCache)>=25); } /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called |
︙ | ︙ | |||
2043 2044 2045 2046 2047 2048 2049 | rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ | | | 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 | rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile); pPager->journalOff = 0; }else{ /* This branch may be executed with Pager.journalMode==MEMORY if ** a hot-journal was just rolled back. In this case the journal ** file should be closed and deleted. If this connection writes to ** the database file, it will do so using an in-memory journal. */ |
︙ | ︙ | |||
2077 2078 2079 2080 2081 2082 2083 | sqlite3PagerUnrefNotNull(p); } } #endif pagerFreeBitvecs(pPager); pPager->nRec = 0; | > | | | | | | > | 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 | sqlite3PagerUnrefNotNull(p); } } #endif pagerFreeBitvecs(pPager); pPager->nRec = 0; if( rc==SQLITE_OK ){ if( pagerFlushOnCommit(pPager, bCommit) ){ sqlite3PcacheCleanAll(pPager->pPCache); }else{ sqlite3PcacheClearWritable(pPager->pPCache); } sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); } if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE ** lock held on the database file. */ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); |
︙ | ︙ | |||
2416 2417 2418 2419 2420 2421 2422 | assert( isSavepnt ); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 ); pPager->doNotSpill |= SPILLFLAG_ROLLBACK; rc = sqlite3PagerGet(pPager, pgno, &pPg, 1); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; if( rc!=SQLITE_OK ) return rc; | < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > | 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 | assert( isSavepnt ); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 ); pPager->doNotSpill |= SPILLFLAG_ROLLBACK; rc = sqlite3PagerGet(pPager, pgno, &pPg, 1); assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 ); pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK; if( rc!=SQLITE_OK ) return rc; sqlite3PcacheMakeDirty(pPg); } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3PagerRollback(). */ void *pData; pData = pPg->pData; memcpy(pData, (u8*)aData, pPager->pageSize); pPager->xReiniter(pPg); /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But ** that call was dangerous and had no detectable benefit since the cache ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so ** has been removed. */ pager_set_pagehash(pPg); /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); } |
︙ | ︙ | |||
6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 | ** ** The overlying software layer calls this routine when all of the data ** on the given page is unused. The pager marks the page as clean so ** that it does not get written to disk. ** ** Tests show that this optimization can quadruple the speed of large ** DELETE operations. */ void sqlite3PagerDontWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; | > > > > > > | > | 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 | ** ** The overlying software layer calls this routine when all of the data ** on the given page is unused. The pager marks the page as clean so ** that it does not get written to disk. ** ** Tests show that this optimization can quadruple the speed of large ** DELETE operations. ** ** This optimization cannot be used with a temp-file, as the page may ** have been dirty at the start of the transaction. In that case, if ** memory pressure forces page pPg out of the cache, the data does need ** to be written out to disk so that it may be read back in if the ** current transaction is rolled back. */ void sqlite3PagerDontWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){ PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager))); IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) pPg->flags |= PGHDR_DONT_WRITE; pPg->flags &= ~PGHDR_WRITEABLE; testcase( pPg->flags & PGHDR_NEED_SYNC ); pager_set_pagehash(pPg); } } /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at |
︙ | ︙ | |||
6359 6360 6361 6362 6363 6364 6365 | ); assert( assert_pager_state(pPager) ); /* If a prior error occurred, report that error again. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* Provide the ability to easily simulate an I/O error during testing */ | | | | 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 | ); assert( assert_pager_state(pPager) ); /* If a prior error occurred, report that error again. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* Provide the ability to easily simulate an I/O error during testing */ if( sqlite3FaultSim(400) ) return SQLITE_IOERR; PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", pPager->zFilename, zMaster, pPager->dbSize)); /* If no database changes have been made, return early. */ if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK; assert( MEMDB==0 || pPager->tempFile ); assert( isOpen(pPager->fd) || pPager->tempFile ); if( 0==pagerFlushOnCommit(pPager, 1) ){ /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is mostly a no-op. However, any ** backup in progress needs to be restarted. */ sqlite3BackupRestart(pPager->pBackup); }else{ if( pagerUseWal(pPager) ){ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); |
︙ | ︙ | |||
6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 | || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); /* In order to be able to rollback, an in-memory database must journal ** the page we are moving from. */ if( pPager->tempFile ){ rc = sqlite3PagerWrite(pPg); if( rc ) return rc; } /* If the page being moved is dirty and has not been saved by the latest ** savepoint, then save the current contents of the page into the | > | 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 | || pPager->eState==PAGER_WRITER_DBMOD ); assert( assert_pager_state(pPager) ); /* In order to be able to rollback, an in-memory database must journal ** the page we are moving from. */ assert( pPager->tempFile || !MEMDB ); if( pPager->tempFile ){ rc = sqlite3PagerWrite(pPg); if( rc ) return rc; } /* If the page being moved is dirty and has not been saved by the latest ** savepoint, then save the current contents of the page into the |
︙ | ︙ | |||
7068 7069 7070 7071 7072 7073 7074 | sqlite3PcacheMove(pPg, pgno); sqlite3PcacheMakeDirty(pPg); /* For an in-memory database, make sure the original page continues ** to exist, in case the transaction needs to roll back. Use pPgOld ** as the original page since it has already been allocated. */ | | < | 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 | sqlite3PcacheMove(pPg, pgno); sqlite3PcacheMakeDirty(pPg); /* For an in-memory database, make sure the original page continues ** to exist, in case the transaction needs to roll back. Use pPgOld ** as the original page since it has already been allocated. */ if( pPager->tempFile && pPgOld ){ sqlite3PcacheMove(pPgOld, origPgno); sqlite3PagerUnrefNotNull(pPgOld); } if( needSyncPgno ){ /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. |
︙ | ︙ | |||
7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 | ** Unless this is an in-memory or temporary database, clear the pager cache. */ void sqlite3PagerClearCache(Pager *pPager){ assert( MEMDB==0 || pPager->tempFile ); if( pPager->tempFile==0 ) pager_reset(pPager); } #endif #ifndef SQLITE_OMIT_WAL /* ** This function is called when the user invokes "PRAGMA wal_checkpoint", ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() ** or wal_blocking_checkpoint() API functions. ** | > | 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 | ** Unless this is an in-memory or temporary database, clear the pager cache. */ void sqlite3PagerClearCache(Pager *pPager){ assert( MEMDB==0 || pPager->tempFile ); if( pPager->tempFile==0 ) pager_reset(pPager); } #endif #ifndef SQLITE_OMIT_WAL /* ** This function is called when the user invokes "PRAGMA wal_checkpoint", ** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint() ** or wal_blocking_checkpoint() API functions. ** |
︙ | ︙ | |||
7550 7551 7552 7553 7554 7555 7556 7557 | ** is empty, return 0. */ int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif | < | 7540 7541 7542 7543 7544 7545 7546 7547 7548 | ** is empty, return 0. */ int sqlite3PagerWalFramesize(Pager *pPager){ assert( pPager->eState>=PAGER_READER ); return sqlite3WalFramesize(pPager->pWal); } #endif #endif /* SQLITE_OMIT_DISKIO */ |
Changes to src/pager.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. */ | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. */ #ifndef SQLITE_PAGER_H #define SQLITE_PAGER_H /* ** Default maximum size for persistent journal files. A negative ** value means no limit. This value may be overridden using the ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". */ #ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT |
︙ | ︙ | |||
200 201 202 203 204 205 206 | sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); sqlite3_file *sqlite3PagerJrnlFile(Pager*); const char *sqlite3PagerJournalname(Pager*); void *sqlite3PagerTempSpace(Pager*); int sqlite3PagerIsMemdb(Pager*); void sqlite3PagerCacheStat(Pager *, int, int, int *); | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); sqlite3_file *sqlite3PagerJrnlFile(Pager*); const char *sqlite3PagerJournalname(Pager*); void *sqlite3PagerTempSpace(Pager*); int sqlite3PagerIsMemdb(Pager*); void sqlite3PagerCacheStat(Pager *, int, int, int *); void sqlite3PagerClearCache(Pager*); int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); void sqlite3PagerRekey(DbPage*, Pgno, u16); |
︙ | ︙ | |||
239 240 241 242 243 244 245 | void disable_simulated_io_errors(void); void enable_simulated_io_errors(void); #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif | | | 239 240 241 242 243 244 245 246 | void disable_simulated_io_errors(void); void enable_simulated_io_errors(void); #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif #endif /* SQLITE_PAGER_H */ |
Changes to src/parse.y.
︙ | ︙ | |||
312 313 314 315 316 317 318 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} | | > | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | // In addition to the type name, we also care about the primary key and // UNIQUE constraints. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);} ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} // The optional AUTOINCREMENT keyword |
︙ | ︙ | |||
361 362 363 364 365 366 367 | conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). | | > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E.pExpr);} tcons ::= FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); } |
︙ | ︙ | |||
1144 1145 1146 1147 1148 1149 1150 | } expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0); sqlite3PExprAddSelect(pParse, A.pExpr, Y); exprNot(pParse, N, &A); A.zEnd = &E.z[E.n]; } | | > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 | } expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] { A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0); sqlite3PExprAddSelect(pParse, A.pExpr, Y); exprNot(pParse, N, &A); A.zEnd = &E.z[E.n]; } expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] { SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E); A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0); sqlite3PExprAddSelect(pParse, A.pExpr, pSelect); exprNot(pParse, N, &A); A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n]; } expr(A) ::= EXISTS(B) LP select(Y) RP(E). { Expr *p; |
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | exprlist(A) ::= nexprlist(A). exprlist(A) ::= . {A = 0;} nexprlist(A) ::= nexprlist(A) COMMA expr(Y). {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);} nexprlist(A) ::= expr(Y). {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/} ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, | > > > > > > > > > | | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | exprlist(A) ::= nexprlist(A). exprlist(A) ::= . {A = 0;} nexprlist(A) ::= nexprlist(A) COMMA expr(Y). {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);} nexprlist(A) ::= expr(Y). {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/} %ifndef SQLITE_OMIT_SUBQUERY /* A paren_exprlist is an optional expression list contained inside ** of parenthesis */ %type paren_exprlist {ExprList*} %destructor paren_exprlist {sqlite3ExprListDelete(pParse->db, $$);} paren_exprlist(A) ::= . {A = 0;} paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;} %endif SQLITE_OMIT_SUBQUERY ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, &S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF); } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} |
︙ | ︙ |
Changes to src/pcache.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file implements that page cache. */ #include "sqliteInt.h" /* | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < > > > > | > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | ** ************************************************************************* ** This file implements that page cache. */ #include "sqliteInt.h" /* ** A complete page cache is an instance of this structure. Every ** entry in the cache holds a single page of the database file. The ** btree layer only operates on the cached copy of the database pages. ** ** A page cache entry is "clean" if it exactly matches what is currently ** on disk. A page is "dirty" if it has been modified and needs to be ** persisted to disk. ** ** pDirty, pDirtyTail, pSynced: ** All dirty pages are linked into the doubly linked list using ** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order ** such that p was added to the list more recently than p->pDirtyNext. ** PCache.pDirty points to the first (newest) element in the list and ** pDirtyTail to the last (oldest). ** ** The PCache.pSynced variable is used to optimize searching for a dirty ** page to eject from the cache mid-transaction. It is better to eject ** a page that does not require a journal sync than one that does. ** Therefore, pSynced is maintained to that it *almost* always points ** to either the oldest page in the pDirty/pDirtyTail list that has a ** clear PGHDR_NEED_SYNC flag or to a page that is older than this one ** (so that the right page to eject can be found by following pDirtyPrev ** pointers). */ struct PCache { PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */ PgHdr *pSynced; /* Last synced page in dirty page list */ int nRefSum; /* Sum of ref counts over all pages */ int szCache; /* Configured cache size */ int szSpill; /* Size before spilling occurs */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ u8 bPurgeable; /* True if pages are on backing store */ u8 eCreate; /* eCreate value for for xFetch() */ int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */ void *pStress; /* Argument to xStress */ sqlite3_pcache *pCache; /* Pluggable cache module */ }; /********************************** Test and Debug Logic **********************/ /* ** Debug tracing macros. Enable by by changing the "0" to "1" and ** recompiling. ** ** When sqlite3PcacheTrace is 1, single line trace messages are issued. ** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries ** is displayed for many operations, resulting in a lot of output. */ #if defined(SQLITE_DEBUG) && 0 int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} void pcacheDump(PCache *pCache){ int N; int i, j; sqlite3_pcache_page *pLower; PgHdr *pPg; unsigned char *a; if( sqlite3PcacheTrace<2 ) return; if( pCache->pCache==0 ) return; N = sqlite3PcachePagecount(pCache); if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; for(i=1; i<=N; i++){ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); if( pLower==0 ) continue; pPg = (PgHdr*)pLower->pExtra; printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); a = (unsigned char *)pLower->pBuf; for(j=0; j<12; j++) printf("%02x", a[j]); printf("\n"); if( pPg->pPage==0 ){ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); } } } #else # define pcacheTrace(X) # define pcacheDump(X) #endif /* ** Check invariants on a PgHdr entry. Return true if everything is OK. ** Return false if any invariant is violated. ** ** This routine is for use inside of assert() statements only. For ** example: ** ** assert( sqlite3PcachePageSanity(pPg) ); */ #if SQLITE_DEBUG int sqlite3PcachePageSanity(PgHdr *pPg){ PCache *pCache; assert( pPg!=0 ); assert( pPg->pgno>0 ); /* Page number is 1 or more */ pCache = pPg->pCache; assert( pCache!=0 ); /* Every page has an associated PCache */ if( pPg->flags & PGHDR_CLEAN ){ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ assert( pCache->pDirtyTail!=pPg ); } /* WRITEABLE pages must also be DIRTY */ if( pPg->flags & PGHDR_WRITEABLE ){ assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ } /* NEED_SYNC can be set independently of WRITEABLE. This can happen, ** for example, when using the sqlite3PagerDontWrite() optimization: ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK. ** (2) Page X moved to freelist, WRITEABLE is cleared ** (3) Page X reused, WRITEABLE is set again ** If NEED_SYNC had been cleared in step 2, then it would not be reset ** in step 3, and page might be written into the database without first ** syncing the rollback journal, which might cause corruption on a power ** loss. ** ** Another example is when the database page size is smaller than the ** disk sector size. When any page of a sector is journalled, all pages ** in that sector are marked NEED_SYNC even if they are still CLEAN, just ** in case they are later modified, since all pages in the same sector ** must be journalled and synced before any of those pages can be safely ** written. */ return 1; } #endif /* SQLITE_DEBUG */ /********************************** Linked List Management ********************/ /* Allowed values for second argument to pcacheManageDirtyList() */ #define PCACHE_DIRTYLIST_REMOVE 1 /* Remove pPage from dirty list */ #define PCACHE_DIRTYLIST_ADD 2 /* Add pPage to the dirty list */ #define PCACHE_DIRTYLIST_FRONT 3 /* Move pPage to the front of the list */ /* ** Manage pPage's participation on the dirty list. Bits of the addRemove ** argument determines what operation to do. The 0x01 bit means first ** remove pPage from the dirty list. The 0x02 means add pPage back to ** the dirty list. Doing both moves pPage to the front of the dirty list. */ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){ PCache *p = pPage->pCache; pcacheTrace(("%p.DIRTYLIST.%s %d\n", p, addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT", pPage->pgno)); if( addRemove & PCACHE_DIRTYLIST_REMOVE ){ assert( pPage->pDirtyNext || pPage==p->pDirtyTail ); assert( pPage->pDirtyPrev || pPage==p->pDirty ); /* Update the PCache1.pSynced variable if necessary. */ if( p->pSynced==pPage ){ p->pSynced = pPage->pDirtyPrev; } if( pPage->pDirtyNext ){ pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev; }else{ assert( pPage==p->pDirtyTail ); p->pDirtyTail = pPage->pDirtyPrev; } if( pPage->pDirtyPrev ){ pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext; }else{ /* If there are now no dirty pages in the cache, set eCreate to 2. ** This is an optimization that allows sqlite3PcacheFetch() to skip ** searching for a dirty page to eject from the cache when it might ** otherwise have to. */ assert( pPage==p->pDirty ); p->pDirty = pPage->pDirtyNext; assert( p->bPurgeable || p->eCreate==2 ); if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/ assert( p->bPurgeable==0 || p->eCreate==1 ); p->eCreate = 2; } } pPage->pDirtyNext = 0; pPage->pDirtyPrev = 0; } if( addRemove & PCACHE_DIRTYLIST_ADD ){ |
︙ | ︙ | |||
90 91 92 93 94 95 96 | p->pDirtyTail = pPage; if( p->bPurgeable ){ assert( p->eCreate==2 ); p->eCreate = 1; } } p->pDirty = pPage; | > > > > > > | > > > > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | p->pDirtyTail = pPage; if( p->bPurgeable ){ assert( p->eCreate==2 ); p->eCreate = 1; } } p->pDirty = pPage; /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set ** pSynced to point to it. Checking the NEED_SYNC flag is an ** optimization, as if pSynced points to a page with the NEED_SYNC ** flag set sqlite3PcacheFetchStress() searches through all newer ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */ if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/ ){ p->pSynced = pPage; } } pcacheDump(p); } /* ** Wrapper around the pluggable caches xUnpin method. If the cache is ** being used for an in-memory database, this function is a no-op. */ static void pcacheUnpin(PgHdr *p){ if( p->pCache->bPurgeable ){ pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno)); sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0); pcacheDump(p->pCache); } } /* ** Compute the number of pages of cache requested. p->szCache is the ** cache size requested by the "PRAGMA cache_size" statement. */ |
︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | p->szExtra = szExtra; p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; p->szSpill = 1; return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ | > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | p->szExtra = szExtra; p->bPurgeable = bPurgeable; p->eCreate = 2; p->xStress = xStress; p->pStress = pStress; p->szCache = 100; p->szSpill = 1; pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable)); return sqlite3PcacheSetPageSize(p, szPage); } /* ** Change the page size for PCache object. The caller must ensure that there ** are no outstanding page references when this function is called. */ |
︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 206 207 | if( pNew==0 ) return SQLITE_NOMEM_BKPT; sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); if( pCache->pCache ){ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } pCache->pCache = pNew; pCache->szPage = szPage; } return SQLITE_OK; } /* ** Try to obtain a page from the cache. ** | > | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | if( pNew==0 ) return SQLITE_NOMEM_BKPT; sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache)); if( pCache->pCache ){ sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } pCache->pCache = pNew; pCache->szPage = szPage; pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage)); } return SQLITE_OK; } /* ** Try to obtain a page from the cache. ** |
︙ | ︙ | |||
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | */ sqlite3_pcache_page *sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ int createFlag /* If true, create page if it does not exist already */ ){ int eCreate; assert( pCache!=0 ); assert( pCache->pCache!=0 ); assert( createFlag==3 || createFlag==0 ); assert( pgno>0 ); /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) ** 1 Allocate a new page if doing so is inexpensive. ** (createFlag==1 AND bPurgeable AND pDirty) ** 2 Allocate a new page even it doing so is difficult. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); | > > | > > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | */ sqlite3_pcache_page *sqlite3PcacheFetch( PCache *pCache, /* Obtain the page from this cache */ Pgno pgno, /* Page number to obtain */ int createFlag /* If true, create page if it does not exist already */ ){ int eCreate; sqlite3_pcache_page *pRes; assert( pCache!=0 ); assert( pCache->pCache!=0 ); assert( createFlag==3 || createFlag==0 ); assert( pgno>0 ); assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) ); /* eCreate defines what to do if the page does not exist. ** 0 Do not allocate a new page. (createFlag==0) ** 1 Allocate a new page if doing so is inexpensive. ** (createFlag==1 AND bPurgeable AND pDirty) ** 2 Allocate a new page even it doing so is difficult. ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, createFlag?" create":"",pRes)); return pRes; } /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new ** page because no clean pages are available for reuse and the cache ** size limit has been reached, then this routine can be invoked to ** try harder to allocate a page. This routine might invoke the stress |
︙ | ︙ | |||
272 273 274 275 276 277 278 | if( pCache->eCreate==2 ) return 0; if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ /* Find a dirty page to write-out and recycle. First try to find a ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. | | > > > > > > | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | if( pCache->eCreate==2 ) return 0; if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ /* Find a dirty page to write-out and recycle. First try to find a ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC ** cleared), but if that is not possible settle for any other ** unreferenced dirty page. ** ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC ** flag is currently referenced, then the following may leave pSynced ** set incorrectly (pointing to other than the LRU page with NEED_SYNC ** cleared). This is Ok, as pSynced is just an optimization. */ for(pPg=pCache->pSynced; pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); pPg=pPg->pDirtyPrev ); pCache->pSynced = pPg; if( !pPg ){ for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); } if( pPg ){ int rc; #ifdef SQLITE_LOG_CACHE_SPILL sqlite3_log(SQLITE_FULL, "spill page %d making room for %d - cache used: %d/%d", pPg->pgno, pgno, sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno)); rc = pCache->xStress(pCache->pStress, pPg); pcacheDump(pCache); if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ return rc; } } } *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; |
︙ | ︙ | |||
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | pPgHdr = (PgHdr *)pPage->pExtra; if( !pPgHdr->pPage ){ return pcacheFetchFinishWithInit(pCache, pgno, pPage); } pCache->nRefSum++; pPgHdr->nRef++; return pPgHdr; } /* ** Decrement the reference count on a page. If the page is clean and the ** reference count drops to 0, then it is made eligible for recycling. */ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); p->pCache->nRefSum--; if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); | > | | > > > > > > | > > > | > > > > | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | pPgHdr = (PgHdr *)pPage->pExtra; if( !pPgHdr->pPage ){ return pcacheFetchFinishWithInit(pCache, pgno, pPage); } pCache->nRefSum++; pPgHdr->nRef++; assert( sqlite3PcachePageSanity(pPgHdr) ); return pPgHdr; } /* ** Decrement the reference count on a page. If the page is clean and the ** reference count drops to 0, then it is made eligible for recycling. */ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){ assert( p->nRef>0 ); p->pCache->nRefSum--; if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/ /* Move the page to the head of the dirty list. If p->pDirtyPrev==0, ** then page p is already at the head of the dirty list and the ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE ** tag above. */ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } } /* ** Increase the reference count of a supplied page by 1. */ void sqlite3PcacheRef(PgHdr *p){ assert(p->nRef>0); assert( sqlite3PcachePageSanity(p) ); p->nRef++; p->pCache->nRefSum++; } /* ** Drop a page from the cache. There must be exactly one reference to the ** page. This function deletes that reference, so after it returns the ** page pointed to by p is invalid. */ void sqlite3PcacheDrop(PgHdr *p){ assert( p->nRef==1 ); assert( sqlite3PcachePageSanity(p) ); if( p->flags&PGHDR_DIRTY ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); } p->pCache->nRefSum--; sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1); } /* ** Make sure the page is marked as dirty. If it isn't dirty already, ** make it so. */ void sqlite3PcacheMakeDirty(PgHdr *p){ assert( p->nRef>0 ); assert( sqlite3PcachePageSanity(p) ); if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_CLEAN ){ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } assert( sqlite3PcachePageSanity(p) ); } } /* ** Make sure the page is marked as clean. If it isn't clean already, ** make it so. */ void sqlite3PcacheMakeClean(PgHdr *p){ assert( sqlite3PcachePageSanity(p) ); if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){ assert( (p->flags & PGHDR_CLEAN)==0 ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE); p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE); p->flags |= PGHDR_CLEAN; pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno)); assert( sqlite3PcachePageSanity(p) ); if( p->nRef==0 ){ pcacheUnpin(p); } } } /* ** Make every page in the cache clean. */ void sqlite3PcacheCleanAll(PCache *pCache){ PgHdr *p; pcacheTrace(("%p.CLEAN-ALL\n",pCache)); while( (p = pCache->pDirty)!=0 ){ sqlite3PcacheMakeClean(p); } } /* ** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages. */ void sqlite3PcacheClearWritable(PCache *pCache){ PgHdr *p; pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache)); for(p=pCache->pDirty; p; p=p->pDirtyNext){ p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE); } pCache->pSynced = pCache->pDirtyTail; } /* |
︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | /* ** Change the page number of page p to newPgno. */ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; assert( p->nRef>0 ); assert( newPgno>0 ); sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } /* ** Drop every cache entry whose page number is greater than "pgno". The ** caller must ensure that there are no outstanding references to any pages ** other than page 1 with a page number greater than pgno. ** ** If there is a reference to page 1 and the pgno parameter passed to this ** function is 0, then the data area associated with page 1 is zeroed, but ** the page object is not dropped. */ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ if( pCache->pCache ){ PgHdr *p; PgHdr *pNext; for(p=pCache->pDirty; p; p=pNext){ pNext = p->pDirtyNext; /* This routine never gets call with a positive pgno except right ** after sqlite3PcacheCleanAll(). So if there are dirty pages, ** it must be that pgno==0. */ assert( p->pgno>0 ); | > > > | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | /* ** Change the page number of page p to newPgno. */ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; assert( p->nRef>0 ); assert( newPgno>0 ); assert( sqlite3PcachePageSanity(p) ); pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } /* ** Drop every cache entry whose page number is greater than "pgno". The ** caller must ensure that there are no outstanding references to any pages ** other than page 1 with a page number greater than pgno. ** ** If there is a reference to page 1 and the pgno parameter passed to this ** function is 0, then the data area associated with page 1 is zeroed, but ** the page object is not dropped. */ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){ if( pCache->pCache ){ PgHdr *p; PgHdr *pNext; pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno)); for(p=pCache->pDirty; p; p=pNext){ pNext = p->pDirtyNext; /* This routine never gets call with a positive pgno except right ** after sqlite3PcacheCleanAll(). So if there are dirty pages, ** it must be that pgno==0. */ assert( p->pgno>0 ); |
︙ | ︙ | |||
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | } /* ** Close a cache. */ void sqlite3PcacheClose(PCache *pCache){ assert( pCache->pCache!=0 ); sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } /* ** Discard the contents of the cache. */ void sqlite3PcacheClear(PCache *pCache){ sqlite3PcacheTruncate(pCache, 0); } /* ** Merge two lists of pages connected by pDirty and in pgno order. | > | | > > > > > > > > | | < < < < < < | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | } /* ** Close a cache. */ void sqlite3PcacheClose(PCache *pCache){ assert( pCache->pCache!=0 ); pcacheTrace(("%p.CLOSE\n",pCache)); sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache); } /* ** Discard the contents of the cache. */ void sqlite3PcacheClear(PCache *pCache){ sqlite3PcacheTruncate(pCache, 0); } /* ** Merge two lists of pages connected by pDirty and in pgno order. ** Do not bother fixing the pDirtyPrev pointers. */ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){ PgHdr result, *pTail; pTail = &result; assert( pA!=0 && pB!=0 ); for(;;){ if( pA->pgno<pB->pgno ){ pTail->pDirty = pA; pTail = pA; pA = pA->pDirty; if( pA==0 ){ pTail->pDirty = pB; break; } }else{ pTail->pDirty = pB; pTail = pB; pB = pB->pDirty; if( pB==0 ){ pTail->pDirty = pA; break; } } } return result.pDirty; } /* ** Sort the list of pages in accending order by pgno. Pages are ** connected by pDirty pointers. The pDirtyPrev pointers are |
︙ | ︙ | |||
589 590 591 592 593 594 595 | ** the input list. But that is impossible. */ a[i] = pcacheMergeDirtyList(a[i], p); } } p = a[0]; for(i=1; i<N_SORT_BUCKET; i++){ | > | | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 | ** the input list. But that is impossible. */ a[i] = pcacheMergeDirtyList(a[i], p); } } p = a[0]; for(i=1; i<N_SORT_BUCKET; i++){ if( a[i]==0 ) continue; p = p ? pcacheMergeDirtyList(p, a[i]) : a[i]; } return p; } /* ** Return a list of all dirty pages in the cache, sorted by page number. */ |
︙ | ︙ |
Changes to src/pcache.h.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** Every page in the cache is controlled by an instance of the following ** structure. */ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** Every page in the cache is controlled by an instance of the following ** structure. */ struct PgHdr { sqlite3_pcache_page *pPage; /* Pcache object page handle */ void *pData; /* Page data */ void *pExtra; /* Extra content */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; /* Hash of page content */ #endif u16 flags; /* PGHDR flags defined below */ |
︙ | ︙ | |||
47 48 49 50 51 52 53 | /* Bit values for PgHdr.flags */ #define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ #define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ #define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before ** writing this page to the database */ | < | | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | /* Bit values for PgHdr.flags */ #define PGHDR_CLEAN 0x001 /* Page not on the PCache.pDirty list */ #define PGHDR_DIRTY 0x002 /* Page is on the PCache.pDirty list */ #define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */ #define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before ** writing this page to the database */ #define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */ #define PGHDR_MMAP 0x020 /* This is an mmap page object */ #define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */ /* Initialize and shutdown the page cache subsystem */ int sqlite3PcacheInitialize(void); void sqlite3PcacheShutdown(void); /* Page cache buffer management: ** These routines implement SQLITE_CONFIG_PAGECACHE. |
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 | #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This ** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif /* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit ** the total number of pages cached by purgeable pager-caches to the sum ** of the suggested cache-sizes. */ | > > > > > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This ** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif #if defined(SQLITE_DEBUG) /* Check invariants on a PgHdr object */ int sqlite3PcachePageSanity(PgHdr*); #endif /* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit ** the total number of pages cached by purgeable pager-caches to the sum ** of the suggested cache-sizes. */ |
︙ | ︙ |
Changes to src/pcache1.c.
︙ | ︙ | |||
628 629 630 631 632 633 634 | ** ** The PCache mutex must be held when this function is called. */ static void pcache1TruncateUnsafe( PCache1 *pCache, /* The cache to truncate */ unsigned int iLimit /* Drop pages with this pgno or larger */ ){ | | | > > > > > > > > > > > > > | > > > | > > | > > | | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | ** ** The PCache mutex must be held when this function is called. */ static void pcache1TruncateUnsafe( PCache1 *pCache, /* The cache to truncate */ unsigned int iLimit /* Drop pages with this pgno or larger */ ){ TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */ unsigned int h, iStop; assert( sqlite3_mutex_held(pCache->pGroup->mutex) ); assert( pCache->iMaxKey >= iLimit ); assert( pCache->nHash > 0 ); if( pCache->iMaxKey - iLimit < pCache->nHash ){ /* If we are just shaving the last few pages off the end of the ** cache, then there is no point in scanning the entire hash table. ** Only scan those hash slots that might contain pages that need to ** be removed. */ h = iLimit % pCache->nHash; iStop = pCache->iMaxKey % pCache->nHash; TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */ }else{ /* This is the general case where many pages are being removed. ** It is necessary to scan the entire hash table */ h = pCache->nHash/2; iStop = h - 1; } for(;;){ PgHdr1 **pp; PgHdr1 *pPage; assert( h<pCache->nHash ); pp = &pCache->apHash[h]; while( (pPage = *pp)!=0 ){ if( pPage->iKey>=iLimit ){ pCache->nPage--; *pp = pPage->pNext; if( !pPage->isPinned ) pcache1PinPage(pPage); pcache1FreePage(pPage); }else{ pp = &pPage->pNext; TESTONLY( if( nPage>=0 ) nPage++; ) } } if( h==iStop ) break; h = (h+1) % pCache->nHash; } assert( nPage<0 || pCache->nPage==(unsigned)nPage ); } /******************************************************************************/ /******** sqlite3_pcache Methods **********************************************/ /* ** Implementation of the sqlite3_pcache.xInit method. |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | ** Destroy a cache allocated using pcache1Create(). */ static void pcache1Destroy(sqlite3_pcache *p){ PCache1 *pCache = (PCache1 *)p; PGroup *pGroup = pCache->pGroup; assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); pcache1EnterMutex(pGroup); | | | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | ** Destroy a cache allocated using pcache1Create(). */ static void pcache1Destroy(sqlite3_pcache *p){ PCache1 *pCache = (PCache1 *)p; PGroup *pGroup = pCache->pGroup; assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) ); pcache1EnterMutex(pGroup); if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0); assert( pGroup->nMaxPage >= pCache->nMax ); pGroup->nMaxPage -= pCache->nMax; assert( pGroup->nMinPage >= pCache->nMin ); pGroup->nMinPage -= pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pcache1EnforceMaxPage(pCache); pcache1LeaveMutex(pGroup); |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 | if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; } /* Many of the flag-pragmas modify the code generated by the SQL ** compiler (eg. count_changes). So add an opcode to expire all ** compiled SQL statements after modifying a pragma value. */ sqlite3VdbeAddOp0(v, OP_Expire); setAllPagerFlags(db); } break; } #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS |
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 | ** name: Column name ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | ** name: Column name ** type: Column declaration type. ** notnull: True if 'NOT NULL' is part of column declaration ** dflt_value: The default value for the column, if any. */ case PragTyp_TABLE_INFO: if( zRight ){ Table *pTab; pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb); if( pTab ){ static const char *azCol[] = { "cid", "name", "type", "notnull", "dflt_value", "pk" }; int i, k; int nHidden = 0; Column *pCol; |
︙ | ︙ | |||
1330 1331 1332 1333 1334 1335 1336 | if( pParent && pIdx==0 ){ int iKey = pFK->aCol[0].iFrom; assert( iKey>=0 && iKey<pTab->nCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); | < < | | 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 | if( pParent && pIdx==0 ){ int iKey = pFK->aCol[0].iFrom; assert( iKey>=0 && iKey<pTab->nCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); } sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else{ for(j=0; j<pFK->nCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | */ #include "sqliteInt.h" /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ | | | | | | | | | | | | | | | | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | */ #include "sqliteInt.h" /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */ #define etFLOAT 1 /* Floating point. %f */ #define etEXP 2 /* Exponentional notation. %e and %E */ #define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ #define etSIZE 4 /* Return number of characters processed so far. %n */ #define etSTRING 5 /* Strings. %s */ #define etDYNSTRING 6 /* Dynamically allocated strings. %z */ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ #define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */ #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', NULL pointers replaced by SQL NULL. %Q */ #define etTOKEN 11 /* a pointer to a Token structure */ #define etSRCLIST 12 /* a pointer to a SrcList */ #define etPOINTER 13 /* The %p conversion */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etINVALID 16 /* Any unrecognized conversion type */ /* ** An "etByte" is an 8-bit unsigned value. */ typedef unsigned char etByte; |
︙ | ︙ | |||
185 186 187 188 189 190 191 | etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ etByte flag_altform2; /* True if "!" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ etByte done; /* Loop termination flag */ etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ u8 useIntern; /* Ok to use internal conversions (ex: %T) */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
714 715 716 717 718 719 720 | notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr); } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; | | > > > > | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 | notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr); } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; }else if( no_such_func && pParse->db->init.busy==0 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION && pParse->explain==0 #endif ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); pNC->nErr++; } |
︙ | ︙ | |||
759 760 761 762 763 764 765 766 767 768 769 770 771 772 | if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); } } break; } case TK_VARIABLE: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; | > | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); pNC->ncFlags |= NC_VarSelect; } } break; } case TK_VARIABLE: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; |
︙ | ︙ |
Changes to src/rowset.c.
︙ | ︙ | |||
238 239 240 241 242 243 244 | struct RowSetEntry *pA, /* First sorted list to be merged */ struct RowSetEntry *pB /* Second sorted list to be merged */ ){ struct RowSetEntry head; struct RowSetEntry *pTail; pTail = &head; | | > | | > | > > | | > | | < | | < < < < < < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | struct RowSetEntry *pA, /* First sorted list to be merged */ struct RowSetEntry *pB /* Second sorted list to be merged */ ){ struct RowSetEntry head; struct RowSetEntry *pTail; pTail = &head; assert( pA!=0 && pB!=0 ); for(;;){ assert( pA->pRight==0 || pA->v<=pA->pRight->v ); assert( pB->pRight==0 || pB->v<=pB->pRight->v ); if( pA->v<=pB->v ){ if( pA->v<pB->v ) pTail = pTail->pRight = pA; pA = pA->pRight; if( pA==0 ){ pTail->pRight = pB; break; } }else{ pTail = pTail->pRight = pB; pB = pB->pRight; if( pB==0 ){ pTail->pRight = pA; break; } } } return head.pRight; } /* ** Sort all elements on the list of RowSetEntry objects into order of ** increasing v. |
︙ | ︙ | |||
282 283 284 285 286 287 288 | for(i=0; aBucket[i]; i++){ pIn = rowSetEntryMerge(aBucket[i], pIn); aBucket[i] = 0; } aBucket[i] = pIn; pIn = pNext; } | | | > | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | for(i=0; aBucket[i]; i++){ pIn = rowSetEntryMerge(aBucket[i], pIn); aBucket[i] = 0; } aBucket[i] = pIn; pIn = pNext; } pIn = aBucket[0]; for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){ if( aBucket[i]==0 ) continue; pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i]; } return pIn; } /* ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects. |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 | int nOBSat; /* Number of ORDER BY terms satisfied by indices */ int iECursor; /* Cursor number for the sorter */ int regReturn; /* Register holding block-output return address */ int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure ** itself only if bFree is true. */ | > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | int nOBSat; /* Number of ORDER BY terms satisfied by indices */ int iECursor; /* Cursor number for the sorter */ int regReturn; /* Register holding block-output return address */ int labelBkOut; /* Start label for the block-output subroutine */ int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */ int labelDone; /* Jump here when done, ex: LIMIT reached */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */ }; #define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */ /* ** Delete all the content of a Select structure. Deallocate the structure ** itself only if bFree is true. */ |
︙ | ︙ | |||
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | op = OP_SorterInsert; }else{ op = OP_IdxInsert; } sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( iLimit ){ int addr; addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); sqlite3VdbeJumpHere(v, addr); } } /* ** Add code to implement the OFFSET */ | > > > > > > > > > > > > > > > > > > > > > | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | op = OP_SorterInsert; }else{ op = OP_IdxInsert; } sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord); if( iLimit ){ int addr; int r1 = 0; /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit ** register is initialized with value of LIMIT+OFFSET.) After the sorter ** fills up, delete the least entry in the sorter after each insert. ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */ addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor); if( pSort->bOrderedInnerLoop ){ r1 = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1); VdbeComment((v, "seq")); } sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor); if( pSort->bOrderedInnerLoop ){ /* If the inner loop is driven by an index such that values from ** the same iteration of the inner loop are in sorted order, then ** immediately jump to the next iteration of an inner loop if the ** entry from the current iteration does not fit into the top ** LIMIT+OFFSET entries of the sorter. */ int iBrk = sqlite3VdbeCurrentAddr(v) + 2; sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); VdbeCoverage(v); } sqlite3VdbeJumpHere(v, addr); } } /* ** Add code to implement the OFFSET */ |
︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 | /* ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1); | | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | /* ** Allocate a KeyInfo object sufficient for an index of N key columns and ** X extra columns. */ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ int nExtra = (N+X)*(sizeof(CollSeq*)+1); KeyInfo *p = sqlite3DbMallocRaw(db, sizeof(KeyInfo) + nExtra); if( p ){ p->aSortOrder = (u8*)&p->aColl[N+X]; p->nField = (u16)N; p->nXField = (u16)X; p->enc = ENC(db); p->db = db; p->nRef = 1; |
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | /* ** Deallocate a KeyInfo object */ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; | | | 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 | /* ** Deallocate a KeyInfo object */ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ) sqlite3DbFree(p->db, p); } } /* ** Make a new pointer to a KeyInfo object */ KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){ |
︙ | ︙ | |||
5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 | p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral | > | 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 | p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo); if( sSort.nOBSat==sSort.pOrderBy->nExpr ){ sSort.pOrderBy = 0; } } /* If sorting index that was created by a prior OP_OpenEphemeral ** instruction ended up not being needed, then change the OP_OpenEphemeral |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
2539 2540 2541 2542 2543 2544 2545 | } return f; } /* ** A routine for handling output from sqlite3_trace(). */ | | > > > > > > > > > | 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 | } return f; } /* ** A routine for handling output from sqlite3_trace(). */ static int sql_trace_callback( unsigned mType, void *pArg, void *pP, void *pX ){ FILE *f = (FILE*)pArg; UNUSED_PARAMETER(mType); UNUSED_PARAMETER(pP); if( f ){ const char *z = (const char*)pX; int i = (int)strlen(z); while( i>0 && z[i-1]==';' ){ i--; } utf8_printf(f, "%.*s;\n", i, z); } return 0; } /* ** A no-op routine that runs with the ".breakpoint" doc-command. This is ** a useful spot to set a debugger breakpoint. */ static void test_breakpoint(void){ |
︙ | ︙ | |||
2942 2943 2944 2945 2946 2947 2948 | sqlite3_finalize(pStmt); return res; } /* ** Convert a 2-byte or 4-byte big-endian integer into a native integer */ | | | | 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 | sqlite3_finalize(pStmt); return res; } /* ** Convert a 2-byte or 4-byte big-endian integer into a native integer */ static unsigned int get2byteInt(unsigned char *a){ return (a[0]<<8) + a[1]; } static unsigned int get4byteInt(unsigned char *a){ return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; } /* ** Implementation of the ".info" command. ** ** Return 1 on error, 2 to exit, and 0 otherwise. |
︙ | ︙ | |||
4651 4652 4653 4654 4655 4656 4657 | rc = 1; goto meta_command_exit; } output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ | | | | 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 | rc = 1; goto meta_command_exit; } output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1]); #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( p->traceOut==0 ){ sqlite3_trace_v2(p->db, 0, 0, 0); }else{ sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut); } #endif }else #if SQLITE_USER_AUTHENTICATION if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ if( nArg<2 ){ |
︙ | ︙ | |||
5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 | const char *zSize; sqlite3_int64 szHeap; zSize = cmdline_option_value(argc, argv, ++i); szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #endif }else if( strcmp(z,"-scratch")==0 ){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz>400000 ) sz = 400000; if( sz<2500 ) sz = 2500; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); | > > | 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 | const char *zSize; sqlite3_int64 szHeap; zSize = cmdline_option_value(argc, argv, ++i); szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #else (void)cmdline_option_value(argc, argv, ++i); #endif }else if( strcmp(z,"-scratch")==0 ){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz>400000 ) sz = 400000; if( sz<2500 ) sz = 2500; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are supposed to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ** on how SQLite interfaces are supposed to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ #ifndef SQLITE3_H #define SQLITE3_H #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus extern "C" { |
︙ | ︙ | |||
50 51 52 53 54 55 56 57 | #endif #ifndef SQLITE_API # define SQLITE_API #endif #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif #ifndef SQLITE_STDCALL | > > > | > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #endif #ifndef SQLITE_API # define SQLITE_API #endif #ifndef SQLITE_CDECL # define SQLITE_CDECL #endif #ifndef SQLITE_APICALL # define SQLITE_APICALL #endif #ifndef SQLITE_STDCALL # define SQLITE_STDCALL SQLITE_APICALL #endif #ifndef SQLITE_CALLBACK # define SQLITE_CALLBACK #endif #ifndef SQLITE_SYSAPI # define SQLITE_SYSAPI #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications ** should not use deprecated interfaces - they are supported for backwards ** compatibility only. Application writers should be aware that |
︙ | ︙ | |||
502 503 504 505 506 507 508 509 510 511 512 513 514 515 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | ** at the internal representation of an [sqlite3_mutex]. It only ** deals with pointers to the [sqlite3_mutex] object. ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. | > > > > > > > > > > | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | ** at the internal representation of an [sqlite3_mutex]. It only ** deals with pointers to the [sqlite3_mutex] object. ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: Loadable Extension Thunk ** ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. |
︙ | ︙ | |||
1935 1936 1937 1938 1939 1940 1941 | ** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt> ** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. ** There should be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is | | | 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 | ** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt> ** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()] ** interface independently of the [load_extension()] SQL function. ** The [sqlite3_enable_load_extension()] API enables or disables both the ** C-API [sqlite3_load_extension()] and the SQL function [load_extension()]. ** There should be two additional arguments. ** When the first argument to this interface is 1, then only the C-API is ** enabled and the SQL function remains disabled. If the first argument to ** this interface is 0, then both the C-API and the SQL function are disabled. ** If the first argument is -1, then no changes are made to state of either the ** C-API or the SQL function. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface ** is disabled or enabled following this call. The second parameter may ** be a NULL pointer, in which case the new setting is not reported back. |
︙ | ︙ | |||
2228 2229 2230 2231 2232 2233 2234 | ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ | | | 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 | ** database connection that invoked the busy handler. In other words, ** the busy handler is not reentrant. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*); /* ** CAPI3REF: Set A Busy Timeout ** METHOD: sqlite3 ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler |
︙ | ︙ | |||
2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 | #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the | > > > | 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 | #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** METHOD: sqlite3 ** ** These routines are deprecated. Use the [sqlite3_trace_v2()] interface ** instead of the routines described here. ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the |
︙ | ︙ | |||
2775 2776 2777 2778 2779 2780 2781 | ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 | ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); /* ** CAPI3REF: SQL Trace Event Codes ** KEYWORDS: SQLITE_TRACE ** ** These constants identify classes of events that can be monitored ** using the [sqlite3_trace_v2()] tracing logic. The third argument ** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of ** the following constants. ^The first argument to the trace callback ** is one of the following constants. ** ** New tracing constants may be added in future releases. ** ** ^A trace callback has four arguments: xCallback(T,C,P,X). ** ^The T argument is one of the integer type codes above. ** ^The C argument is a copy of the context pointer passed in as the ** fourth argument to [sqlite3_trace_v2()]. ** The P and X arguments are pointers whose meanings depend on T. ** ** <dl> ** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt> ** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement ** first begins running and possibly at other times during the ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which ** is the unexpanded SQL text of the prepared statement or an SQL comment ** that indicates the invocation of a trigger. ^The callback can compute ** the same text that would have been returned by the legacy [sqlite3_trace()] ** interface by using the X argument when X begins with "--" and invoking ** [sqlite3_expanded_sql(P)] otherwise. ** ** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt> ** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument points to a 64-bit integer which is the estimated of ** the number of nanosecond that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt> ** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared ** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. ** ** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt> ** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database ** connection closes. ** ^The P argument is a pointer to the [database connection] object ** and the X argument is unused. ** </dl> */ #define SQLITE_TRACE_STMT 0x01 #define SQLITE_TRACE_PROFILE 0x02 #define SQLITE_TRACE_ROW 0x04 #define SQLITE_TRACE_CLOSE 0x08 /* ** CAPI3REF: SQL Trace Hook ** METHOD: sqlite3 ** ** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback ** function X against [database connection] D, using property mask M ** and context pointer P. ^If the X callback is ** NULL or if the M mask is zero, then tracing is disabled. The ** M argument should be the bitwise OR-ed combination of ** zero or more [SQLITE_TRACE] constants. ** ** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides ** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2(). ** ** ^The X callback is invoked whenever any of the events identified by ** mask M occur. ^The integer return value from the callback is currently ** ignored, though this may change in future releases. Callback ** implementations should return zero to ensure future compatibility. ** ** ^A trace callback is invoked with four arguments: callback(T,C,P,X). ** ^The T argument is one of the [SQLITE_TRACE] ** constants to indicate why the callback was invoked. ** ^The C argument is a copy of the context pointer. ** The P and X arguments are pointers whose meanings depend on T. ** ** The sqlite3_trace_v2() interface is intended to replace the legacy ** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which ** are deprecated. */ int sqlite3_trace_v2( sqlite3*, unsigned uMask, int(*xCallback)(unsigned,void*,void*,void*), void *pCtx ); /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to |
︙ | ︙ | |||
3397 3398 3399 3400 3401 3402 3403 | const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** | | | | > > > > > > > > > > > > > > > > > > > > > > > > | 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 | const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); /* ** CAPI3REF: Retrieving Statement SQL ** METHOD: sqlite3_stmt ** ** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8 ** SQL text used to create [prepared statement] P if P was ** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 ** and parameter :xyz is unbound, then sqlite3_sql() will return ** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() ** will return "SELECT 2345,NULL".)^ ** ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory ** is available to hold the result, or if the result would exceed the ** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. ** ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** ** ^The string returned by sqlite3_sql(P) is managed by SQLite and is ** automatically freed when the prepared statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** METHOD: sqlite3_stmt ** ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to |
︙ | ︙ | |||
4559 4560 4561 4562 4563 4564 4565 | ** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or ** NULL if the metadata has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including: <ul> | | | | | > | | | 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 | ** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or ** NULL if the metadata has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including: <ul> ** <li> ^(when the corresponding function parameter changes)^, or ** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement)^, or ** <li> ^(when sqlite3_set_auxdata() is invoked again on the same ** parameter)^, or ** <li> ^(during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs.)^ </ul> ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after ** sqlite3_set_auxdata() has been called. |
︙ | ︙ | |||
5391 5392 5393 5394 5395 5396 5397 | ** information about column C of table T in database D ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a | | | 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 | ** information about column C of table T in database D ** on [database connection] X.)^ ^The sqlite3_table_column_metadata() ** interface returns SQLITE_OK and fills in the non-NULL pointers in ** the final five arguments with appropriate values if the specified ** column exists. ^The sqlite3_table_column_metadata() interface returns ** SQLITE_ERROR and if the specified column does not exist. ** ^If the column-name parameter to sqlite3_table_column_metadata() is a ** NULL pointer, then this routine simply checks for the existence of the ** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it ** does not. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^(The second parameter is either the name of the database ** (i.e. "main", "temp", or an attached database) containing the specified ** table or NULL.)^ ^If it is NULL, then all attached databases are searched |
︙ | ︙ | |||
5525 5526 5527 5528 5529 5530 5531 | ** ^Extension loading is off by default. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. | | | | | 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 | ** ^Extension loading is off by default. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. ** ** ^This interface enables or disables both the C-API ** [sqlite3_load_extension()] and the SQL function [load_extension()]. ** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..) ** to enable or disable only the C-API.)^ ** ** <b>Security warning:</b> It is recommended that extension loading ** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method ** rather than this interface, so the [load_extension()] SQL function ** remains disabled. This will prevent SQL injections from giving attackers ** access to extension loading capabilities. */ int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that ** xEntryPoint() is the entry point for a statically linked [SQLite extension] ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects an integer result as if the signature of the ** entry point where as follows: ** ** <blockquote><pre> ** int xEntryPoint( ** sqlite3 *db, ** const char **pzErrMsg, ** const struct sqlite3_api_routines *pThunk |
︙ | ︙ | |||
5572 5573 5574 5575 5576 5577 5578 | ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** ** See also: [sqlite3_reset_auto_extension()] ** and [sqlite3_cancel_auto_extension()] */ | | | | 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 | ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** ** See also: [sqlite3_reset_auto_extension()] ** and [sqlite3_cancel_auto_extension()] */ int sqlite3_auto_extension(void(*xEntryPoint)(void)); /* ** CAPI3REF: Cancel Automatic Extension Loading ** ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the ** initialization routine X that was registered using a prior call to ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] ** routine returns 1 if initialization routine X was successfully ** unregistered and it returns 0 if X was not on the list of initialization ** routines. */ int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void)); /* ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ |
︙ | ︙ | |||
6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 | ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> ** <dd>This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> ** <dd>This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. | > > > > > > > > > > > > | 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 | ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> ** <dd>This parameter returns the approximate number of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]] ** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt> ** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a ** pager cache is shared between two or more connections the bytes of heap ** memory used by that pager cache is divided evenly between the attached ** connections.)^ In other words, if none of the pager caches associated ** with the database connection are shared, this request returns the same ** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are ** shared, the value returned by this call will be smaller than that returned ** by DBSTATUS_CACHE_USED. ^The highwater mark associated with ** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> ** <dd>This parameter returns the approximate number of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. |
︙ | ︙ | |||
6817 6818 6819 6820 6821 6822 6823 | #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 | > | | 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 | #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_CACHE_USED_SHARED 11 #define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** METHOD: sqlite3_stmt ** ** ^(Each prepared statement maintains various |
︙ | ︙ | |||
7973 7974 7975 7976 7977 7978 7979 | ** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate ** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID] ** tables. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants | | | 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 | ** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate ** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID] ** tables. ** ** ^The second parameter to the preupdate callback is a pointer to ** the [database connection] that registered the preupdate hook. ** ^The third parameter to the preupdate callback is one of the constants ** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the ** kind of update operation that is about to occur. ** ^(The fourth parameter to the preupdate callback is the name of the ** database within the database connection that is being modified. This ** will be "main" for the main database or "temp" for TEMP tables or ** the name given after the AS keyword in the [ATTACH] statement for attached ** databases.)^ ** ^The fifth parameter to the preupdate callback is the name of the |
︙ | ︙ | |||
8200 8201 8202 8203 8204 8205 8206 | #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif | | | 8355 8356 8357 8358 8359 8360 8361 8362 | #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ | | | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ #ifndef SQLITE3EXT_H #define SQLITE3EXT_H #include "sqlite3.h" /* ** The following structure holds pointers to all of the SQLite API ** routines. ** ** WARNING: In order to maintain backwards compatibility, add new ** interfaces to the end of this structure only. If you insert new ** interfaces in the middle of this structure, then older different |
︙ | ︙ | |||
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | void (*result_subtype)(sqlite3_context*,unsigned int); /* Version 3.10.0 and later */ int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); /* Version 3.12.0 and later */ int (*system_errno)(sqlite3*); }; /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that | > > > > > > > > > > > > > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | void (*result_subtype)(sqlite3_context*,unsigned int); /* Version 3.10.0 and later */ int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); int (*strlike)(const char*,const char*,unsigned int); int (*db_cacheflush)(sqlite3*); /* Version 3.12.0 and later */ int (*system_errno)(sqlite3*); /* Version 3.14.0 and later */ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); char *(*expanded_sql)(sqlite3_stmt*); }; /* ** This is the function signature used for all extension entry points. It ** is also defined in the file "loadext.c". */ typedef int (*sqlite3_loadext_entry)( sqlite3 *db, /* Handle to the database. */ char **pzErrMsg, /* Used to set error string on failure. */ const sqlite3_api_routines *pThunk /* Extension API function pointers. */ ); /* ** The following macros redefine the API routines so that they are ** redirected through the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file ** (part of the main SQLite library - not an extension) so that |
︙ | ︙ | |||
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | #define sqlite3_result_subtype sqlite3_api->result_subtype /* Version 3.10.0 and later */ #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush /* Version 3.12.0 and later */ #define sqlite3_system_errno sqlite3_api->system_errno #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif | > > > | | 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | #define sqlite3_result_subtype sqlite3_api->result_subtype /* Version 3.10.0 and later */ #define sqlite3_status64 sqlite3_api->status64 #define sqlite3_strlike sqlite3_api->strlike #define sqlite3_db_cacheflush sqlite3_api->db_cacheflush /* Version 3.12.0 and later */ #define sqlite3_system_errno sqlite3_api->system_errno /* Version 3.14.0 and later */ #define sqlite3_trace_v2 sqlite3_api->trace_v2 #define sqlite3_expanded_sql sqlite3_api->expanded_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ # define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif #endif /* SQLITE3EXT_H */ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ #ifndef SQLITEINT_H #define SQLITEINT_H /* Special Comments: ** ** Some comments have special meaning to the tools that measure test ** coverage: ** ** NO_TEST - The branches on this line are not |
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** if it did occur. ** ** In all cases, the special comment must be enclosed in the usual ** slash-asterisk...asterisk-slash comment marks, with no spaces between the ** asterisks and the comment text. */ /* ** Make sure that rand_s() is available on Windows systems with MSVC 2005 ** or higher. */ #if defined(_MSC_VER) && _MSC_VER>=1400 # define _CRT_RAND_S #endif | > > > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | ** if it did occur. ** ** In all cases, the special comment must be enclosed in the usual ** slash-asterisk...asterisk-slash comment marks, with no spaces between the ** asterisks and the comment text. */ /* ** Make sure the Tcl calling convention macro is defined. This macro is ** only used by test code and Tcl integration code. */ #ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI #endif /* ** Make sure that rand_s() is available on Windows systems with MSVC 2005 ** or higher. */ #if defined(_MSC_VER) && _MSC_VER>=1400 # define _CRT_RAND_S #endif |
︙ | ︙ | |||
222 223 224 225 226 227 228 | /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | /* ** Make sure that the compiler intrinsics we desire are enabled when ** compiling with an appropriate version of MSVC unless prevented by ** the SQLITE_DISABLE_INTRINSIC define. */ #if !defined(SQLITE_DISABLE_INTRINSIC) # if defined(_MSC_VER) && _MSC_VER>=1400 # if !defined(_WIN32_WCE) # include <intrin.h> # pragma intrinsic(_byteswap_ushort) # pragma intrinsic(_byteswap_ulong) # pragma intrinsic(_ReadWriteBarrier) # else # include <cmnintrin.h> |
︙ | ︙ | |||
407 408 409 410 411 412 413 | ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ | | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code they specify will ** not be counted as untested code. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) |
︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*, const char*); #else typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*); #endif /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ | > > > > > > > > > | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*, const char*); #else typedef int (*sqlite3_xauth)(void*,int,const char*,const char*,const char*, const char*); #endif #ifndef SQLITE_OMIT_DEPRECATED /* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing ** in the style of sqlite3_trace() */ #define SQLITE_TRACE_LEGACY 0x80 #else #define SQLITE_TRACE_LEGACY 0 #endif /* SQLITE_OMIT_DEPRECATED */ /* ** Each database connection is an instance of the following structure. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ struct Vdbe *pVdbe; /* List of active virtual machines */ |
︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | u8 mallocFailed; /* True if we have seen a malloc failure */ u8 bBenignMalloc; /* Do not require OOMs if true */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ int newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ u8 imposterTable; /* Building an imposter table */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ | > | | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | u8 mallocFailed; /* True if we have seen a malloc failure */ u8 bBenignMalloc; /* Do not require OOMs if true */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 mTrace; /* zero or more SQLITE_TRACE flags */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */ struct sqlite3InitInfo { /* Information used during initialization */ int newTnum; /* Rootpage of table being initialized */ u8 iDb; /* Which db file is being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ u8 imposterTable; /* Building an imposter table */ } init; int nVdbeActive; /* Number of VDBEs currently running */ int nVdbeRead; /* Number of active VDBEs that read or write */ int nVdbeWrite; /* Number of active VDBEs that read and write */ int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nVDestroy; /* Number of active OP_VDestroy operations */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ int (*xTrace)(u32,void*,void*,void*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ |
︙ | ︙ | |||
2482 2483 2484 2485 2486 2487 2488 | char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { | | | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 | char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { u8 jointype; /* Type of join between this table and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ } fg; |
︙ | ︙ | |||
2528 2529 2530 2531 2532 2533 2534 | ** Value constraints (enforced via assert()): ** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ | > | | < | < | | | | | | > > | > | 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 | ** Value constraints (enforced via assert()): ** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ #define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ #define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */ #define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of ** the OR optimization */ #define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */ #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ #define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ /* 0x1000 not currently used */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ /* Allowed return values from sqlite3WhereIsDistinct() */ #define WHERE_DISTINCT_NOOP 0 /* DISTINCT keyword not used */ #define WHERE_DISTINCT_UNIQUE 1 /* No duplicates */ #define WHERE_DISTINCT_ORDERED 2 /* All duplicates are adjacent */ #define WHERE_DISTINCT_UNORDERED 3 /* Duplicates are scattered */ |
︙ | ︙ | |||
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 | */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ #define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** ** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. | > | 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 | */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ #define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. ** ** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0. |
︙ | ︙ | |||
3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 | NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ int *aiCol; /* array of column indexes */ } u; }; /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); | > | 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 | NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ SrcList *pSrcList; /* FROM clause */ struct SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ } u; }; /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); |
︙ | ︙ | |||
3424 3425 3426 3427 3428 3429 3430 | # define sqlite3StackFree(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif | > > > | | > | | | 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 | # define sqlite3StackFree(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif /* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they ** are, disable MEMSYS3 */ #ifdef SQLITE_ENABLE_MEMSYS5 const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); #undef SQLITE_ENABLE_MEMSYS3 #endif #ifdef SQLITE_ENABLE_MEMSYS3 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); #endif #ifndef SQLITE_MUTEX_OMIT sqlite3_mutex_methods const *sqlite3DefaultMutex(void); sqlite3_mutex_methods const *sqlite3NoopMutex(void); sqlite3_mutex *sqlite3MutexAlloc(int); |
︙ | ︙ | |||
3611 3612 3613 3614 3615 3616 3617 | void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); | | | > | 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 | void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int, u8); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); int sqlite3WhereOrderedInnerLoop(WhereInfo*); int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */ #define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */ #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ |
︙ | ︙ | |||
3664 3665 3666 3667 3668 3669 3670 | #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); | > > | | > | 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 | #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); #define LOCATE_VIEW 0x01 #define LOCATE_NOERR 0x02 Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*, int); int sqlite3ExprListCompare(ExprList*, ExprList*, int); int sqlite3ExprImpliesExpr(Expr*, Expr*, int); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_OMIT_BUILTIN_TEST void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); #endif void sqlite3RollbackAll(sqlite3*,int); |
︙ | ︙ | |||
4228 4229 4230 4231 4232 4233 4234 | int sqlite3ThreadJoin(SQLiteThread*, void**); #endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) int sqlite3DbstatRegister(sqlite3*); #endif | | | 4258 4259 4260 4261 4262 4263 4264 4265 | int sqlite3ThreadJoin(SQLiteThread*, void**); #endif #if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST) int sqlite3DbstatRegister(sqlite3*); #endif #endif /* SQLITEINT_H */ |
Changes to src/status.c.
︙ | ︙ | |||
154 155 156 157 158 159 160 | wsdStat.mxValue[op] = wsdStat.nowValue[op]; } sqlite3_mutex_leave(pMutex); (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | wsdStat.mxValue[op] = wsdStat.nowValue[op]; } sqlite3_mutex_leave(pMutex); (void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */ return SQLITE_OK; } int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ sqlite3_int64 iCur = 0, iHwtr = 0; int rc; #ifdef SQLITE_ENABLE_API_ARMOR if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT; #endif rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag); if( rc==0 ){ *pCurrent = (int)iCur; |
︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | } /* ** Return an approximation for the amount of memory currently used ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. */ case SQLITE_DBSTATUS_CACHE_USED: { int totalUsed = 0; int i; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); | > | > > > > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | } /* ** Return an approximation for the amount of memory currently used ** by all pagers associated with the given database connection. The ** highwater mark is meaningless and is returned as zero. */ case SQLITE_DBSTATUS_CACHE_USED_SHARED: case SQLITE_DBSTATUS_CACHE_USED: { int totalUsed = 0; int i; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ){ Pager *pPager = sqlite3BtreePager(pBt); int nByte = sqlite3PagerMemUsed(pPager); if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){ nByte = nByte / sqlite3BtreeConnectionCount(pBt); } totalUsed += nByte; } } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; *pHighwater = 0; break; } |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** SQLite. This option implies -DSQLITE_TCLMD5. */ /* ** If requested, include the SQLite compiler options file for MSVC. */ #if defined(INCLUDE_MSVC_H) | | > > > | > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ** SQLite. This option implies -DSQLITE_TCLMD5. */ /* ** If requested, include the SQLite compiler options file for MSVC. */ #if defined(INCLUDE_MSVC_H) # include "msvc.h" #endif #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include <errno.h> /* ** Some additional include files are needed if this file is not ** appended to the amalgamation. */ #ifndef SQLITE_AMALGAMATION |
︙ | ︙ | |||
129 130 131 132 133 134 135 136 137 138 139 140 141 142 | */ struct SqliteDb { sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ Tcl_Interp *interp; /* The interpreter used for this database */ char *zBusy; /* The busy callback routine */ char *zCommit; /* The commit hook callback routine */ char *zTrace; /* The trace callback routine */ char *zProfile; /* The profile callback routine */ char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ | > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | */ struct SqliteDb { sqlite3 *db; /* The "real" database structure. MUST BE FIRST */ Tcl_Interp *interp; /* The interpreter used for this database */ char *zBusy; /* The busy callback routine */ char *zCommit; /* The commit hook callback routine */ char *zTrace; /* The trace callback routine */ char *zTraceV2; /* The trace_v2 callback routine */ char *zProfile; /* The profile callback routine */ char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ |
︙ | ︙ | |||
188 189 190 191 192 193 194 | static void closeIncrblobChannels(SqliteDb *pDb){ IncrblobChannel *p; IncrblobChannel *pNext; for(p=pDb->pIncrblob; p; p=pNext){ pNext = p->pNext; | | > | > > | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | static void closeIncrblobChannels(SqliteDb *pDb){ IncrblobChannel *p; IncrblobChannel *pNext; for(p=pDb->pIncrblob; p; p=pNext){ pNext = p->pNext; /* Note: Calling unregister here call Tcl_Close on the incrblob channel, ** which deletes the IncrblobChannel structure at *p. So do not ** call Tcl_Free() here. */ Tcl_UnregisterChannel(pDb->interp, p->channel); } } /* ** Close an incremental blob channel. */ static int SQLITE_TCLAPI incrblobClose( ClientData instanceData, Tcl_Interp *interp ){ IncrblobChannel *p = (IncrblobChannel *)instanceData; int rc = sqlite3_blob_close(p->pBlob); sqlite3 *db = p->pDb->db; /* Remove the channel from the SqliteDb.pIncrblob list. */ if( p->pNext ){ p->pNext->pPrev = p->pPrev; |
︙ | ︙ | |||
228 229 230 231 232 233 234 | } return TCL_OK; } /* ** Read data from an incremental blob channel. */ | | | | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | } return TCL_OK; } /* ** Read data from an incremental blob channel. */ static int SQLITE_TCLAPI incrblobInput( ClientData instanceData, char *buf, int bufSize, int *errorCodePtr ){ IncrblobChannel *p = (IncrblobChannel *)instanceData; int nRead = bufSize; /* Number of bytes to read */ int nBlob; /* Total size of the blob */ int rc; /* sqlite error code */ |
︙ | ︙ | |||
260 261 262 263 264 265 266 | p->iSeek += nRead; return nRead; } /* ** Write data to an incremental blob channel. */ | | | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | p->iSeek += nRead; return nRead; } /* ** Write data to an incremental blob channel. */ static int SQLITE_TCLAPI incrblobOutput( ClientData instanceData, CONST char *buf, int toWrite, int *errorCodePtr ){ IncrblobChannel *p = (IncrblobChannel *)instanceData; int nWrite = toWrite; /* Number of bytes to write */ int nBlob; /* Total size of the blob */ int rc; /* sqlite error code */ |
︙ | ︙ | |||
293 294 295 296 297 298 299 | p->iSeek += nWrite; return nWrite; } /* ** Seek an incremental blob channel. */ | | | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | p->iSeek += nWrite; return nWrite; } /* ** Seek an incremental blob channel. */ static int SQLITE_TCLAPI incrblobSeek( ClientData instanceData, long offset, int seekMode, int *errorCodePtr ){ IncrblobChannel *p = (IncrblobChannel *)instanceData; switch( seekMode ){ |
︙ | ︙ | |||
319 320 321 322 323 324 325 | default: assert(!"Bad seekMode"); } return p->iSeek; } | > | > > | > | > > > | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | default: assert(!"Bad seekMode"); } return p->iSeek; } static void SQLITE_TCLAPI incrblobWatch( ClientData instanceData, int mode ){ /* NO-OP */ } static int SQLITE_TCLAPI incrblobHandle( ClientData instanceData, int dir, ClientData *hPtr ){ return TCL_ERROR; } static Tcl_ChannelType IncrblobChannelType = { "incrblob", /* typeName */ TCL_CHANNEL_VERSION_2, /* version */ incrblobClose, /* closeProc */ |
︙ | ︙ | |||
348 349 350 351 352 353 354 | 0, /* wideSeekProc */ }; /* ** Create a new incrblob channel. */ static int createIncrblobChannel( | | | | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | 0, /* wideSeekProc */ }; /* ** Create a new incrblob channel. */ static int createIncrblobChannel( Tcl_Interp *interp, SqliteDb *pDb, const char *zDb, const char *zTable, const char *zColumn, sqlite_int64 iRow, int isReadonly ){ IncrblobChannel *p; sqlite3 *db = pDb->db; sqlite3_blob *pBlob; int rc; |
︙ | ︙ | |||
434 435 436 437 438 439 440 | */ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ SqlFunc *p, *pNew; int nName = strlen30(zName); pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName+1); | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | */ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){ SqlFunc *p, *pNew; int nName = strlen30(zName); pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 ); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName+1); for(p=pDb->pFunc; p; p=p->pNext){ if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){ Tcl_Free((char*)pNew); return p; } } pNew->interp = pDb->interp; pNew->pDb = pDb; |
︙ | ︙ | |||
481 482 483 484 485 486 487 | pDb->stmtList = 0; } /* ** TCL calls this procedure when an sqlite3 database command is ** deleted. */ | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | pDb->stmtList = 0; } /* ** TCL calls this procedure when an sqlite3 database command is ** deleted. */ static void SQLITE_TCLAPI DbDeleteCmd(void *db){ SqliteDb *pDb = (SqliteDb*)db; flushStmtCache(pDb); closeIncrblobChannels(pDb); sqlite3_close(pDb->db); while( pDb->pFunc ){ SqlFunc *pFunc = pDb->pFunc; pDb->pFunc = pFunc->pNext; |
︙ | ︙ | |||
504 505 506 507 508 509 510 511 512 513 514 515 516 517 | } if( pDb->zBusy ){ Tcl_Free(pDb->zBusy); } if( pDb->zTrace ){ Tcl_Free(pDb->zTrace); } if( pDb->zProfile ){ Tcl_Free(pDb->zProfile); } if( pDb->zAuth ){ Tcl_Free(pDb->zAuth); } if( pDb->zNull ){ | > > > | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | } if( pDb->zBusy ){ Tcl_Free(pDb->zBusy); } if( pDb->zTrace ){ Tcl_Free(pDb->zTrace); } if( pDb->zTraceV2 ){ Tcl_Free(pDb->zTraceV2); } if( pDb->zProfile ){ Tcl_Free(pDb->zProfile); } if( pDb->zAuth ){ Tcl_Free(pDb->zAuth); } if( pDb->zNull ){ |
︙ | ︙ | |||
582 583 584 585 586 587 588 589 590 591 592 593 594 595 | Tcl_DStringAppend(&str, pDb->zTrace, -1); Tcl_DStringAppendElement(&str, zSql); Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); Tcl_ResetResult(pDb->interp); } #endif #ifndef SQLITE_OMIT_TRACE /* ** This routine is called by the SQLite profile handler after a statement ** SQL has executed. The TCL script in pDb->zProfile is evaluated. */ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | Tcl_DStringAppend(&str, pDb->zTrace, -1); Tcl_DStringAppendElement(&str, zSql); Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); Tcl_ResetResult(pDb->interp); } #endif #ifndef SQLITE_OMIT_TRACE /* ** This routine is called by the SQLite trace_v2 handler whenever a new ** supported event is generated. Unsupported event types are ignored. ** The TCL script in pDb->zTraceV2 is executed, with the arguments for ** the event appended to it (as list elements). */ static int DbTraceV2Handler( unsigned type, /* One of the SQLITE_TRACE_* event types. */ void *cd, /* The original context data pointer. */ void *pd, /* Primary event data, depends on event type. */ void *xd /* Extra event data, depends on event type. */ ){ SqliteDb *pDb = (SqliteDb*)cd; Tcl_Obj *pCmd; switch( type ){ case SQLITE_TRACE_STMT: { sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; char *zSql = (char *)xd; pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewStringObj(zSql, -1)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); Tcl_ResetResult(pDb->interp); break; } case SQLITE_TRACE_PROFILE: { sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; sqlite3_int64 ns = (sqlite3_int64)xd; pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewWideIntObj((Tcl_WideInt)ns)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); Tcl_ResetResult(pDb->interp); break; } case SQLITE_TRACE_ROW: { sqlite3_stmt *pStmt = (sqlite3_stmt *)pd; pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewWideIntObj((Tcl_WideInt)pStmt)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); Tcl_ResetResult(pDb->interp); break; } case SQLITE_TRACE_CLOSE: { sqlite3 *db = (sqlite3 *)pd; pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(pDb->interp, pCmd, Tcl_NewWideIntObj((Tcl_WideInt)db)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); Tcl_ResetResult(pDb->interp); break; } } return SQLITE_OK; } #endif #ifndef SQLITE_OMIT_TRACE /* ** This routine is called by the SQLite profile handler after a statement ** SQL has executed. The TCL script in pDb->zProfile is evaluated. */ static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){ |
︙ | ︙ | |||
633 634 635 636 637 638 639 | } } /* ** This procedure handles wal_hook callbacks. */ static int DbWalHandler( | | | | | | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 | } } /* ** This procedure handles wal_hook callbacks. */ static int DbWalHandler( void *clientData, sqlite3 *db, const char *zDb, int nEntry ){ int ret = SQLITE_OK; Tcl_Obj *p; SqliteDb *pDb = (SqliteDb*)clientData; Tcl_Interp *interp = pDb->interp; assert(pDb->pWalHook); assert( db==pDb->db ); p = Tcl_DuplicateObj(pDb->pWalHook); Tcl_IncrRefCount(p); Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1)); Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry)); if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret) ){ Tcl_BackgroundError(interp); } Tcl_DecrRefCount(p); return ret; |
︙ | ︙ | |||
691 692 693 694 695 696 697 | #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Pre-update hook callback. */ static void DbPreUpdateHandler( | | | | | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | #endif #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Pre-update hook callback. */ static void DbPreUpdateHandler( void *p, sqlite3 *db, int op, const char *zDb, const char *zTbl, sqlite_int64 iKey1, sqlite_int64 iKey2 ){ SqliteDb *pDb = (SqliteDb *)p; Tcl_Obj *pCmd; static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; |
︙ | ︙ | |||
723 724 725 726 727 728 729 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ static void DbUpdateHandler( | | | | | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | Tcl_ListObjAppendElement(0, pCmd, Tcl_NewWideIntObj(iKey2)); Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ static void DbUpdateHandler( void *p, int op, const char *zDb, const char *zTbl, sqlite_int64 rowid ){ SqliteDb *pDb = (SqliteDb *)p; Tcl_Obj *pCmd; static const char *azStr[] = {"DELETE", "INSERT", "UPDATE"}; assert( (SQLITE_DELETE-1)/9 == 0 ); |
︙ | ︙ | |||
811 812 813 814 815 816 817 | rc = Tcl_EvalObjEx(p->interp, pCmd, 0); Tcl_DecrRefCount(pCmd); }else{ /* If there are arguments to the function, make a shallow copy of the ** script object, lappend the arguments, then evaluate the copy. ** ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. | | | | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | rc = Tcl_EvalObjEx(p->interp, pCmd, 0); Tcl_DecrRefCount(pCmd); }else{ /* If there are arguments to the function, make a shallow copy of the ** script object, lappend the arguments, then evaluate the copy. ** ** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated. ** The new Tcl_Obj contains pointers to the original list elements. ** That way, when Tcl_EvalObjv() is run and shimmers the first element ** of the list to tclCmdNameType, that alternate representation will ** be preserved and reused on the next invocation. */ Tcl_Obj **aArg; int nArg; if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); return; } pCmd = Tcl_NewListObj(nArg, aArg); Tcl_IncrRefCount(pCmd); for(i=0; i<argc; i++){ sqlite3_value *pIn = argv[i]; Tcl_Obj *pVal; /* Set pVal to contain the i'th column of this row. */ switch( sqlite3_value_type(pIn) ){ case SQLITE_BLOB: { int bytes = sqlite3_value_bytes(pIn); pVal = Tcl_NewByteArrayObj(sqlite3_value_blob(pIn), bytes); break; } |
︙ | ︙ | |||
862 863 864 865 866 867 868 | pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); break; } } rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); if( rc ){ Tcl_DecrRefCount(pCmd); | | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 | pVal = Tcl_NewStringObj((char *)sqlite3_value_text(pIn), bytes); break; } } rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal); if( rc ){ Tcl_DecrRefCount(pCmd); sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); return; } } if( !p->useEvalObjv ){ /* Tcl_EvalObjEx() will automatically call Tcl_EvalObjv() if pCmd ** is a list without a string representation. To prevent this from ** happening, make sure pCmd has a valid string representation */ Tcl_GetString(pCmd); } rc = Tcl_EvalObjEx(p->interp, pCmd, TCL_EVAL_DIRECT); Tcl_DecrRefCount(pCmd); } if( rc && rc!=TCL_RETURN ){ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ |
︙ | ︙ | |||
979 980 981 982 983 984 985 | Tcl_DStringAppendElement(&str, zCode); Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); #ifdef SQLITE_USER_AUTHENTICATION Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); | | | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 | Tcl_DStringAppendElement(&str, zCode); Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); #ifdef SQLITE_USER_AUTHENTICATION Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : ""); #endif rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY"; if( strcmp(zReply,"SQLITE_OK")==0 ){ rc = SQLITE_OK; }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ rc = SQLITE_DENY; |
︙ | ︙ | |||
1050 1051 1052 1053 1054 1055 1056 | ** This function is part of the implementation of the command: ** ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT ** ** It is invoked after evaluating the script SCRIPT to commit or rollback ** the transaction or savepoint opened by the [transaction] command. */ | | | | | | 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | ** This function is part of the implementation of the command: ** ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT ** ** It is invoked after evaluating the script SCRIPT to commit or rollback ** the transaction or savepoint opened by the [transaction] command. */ static int SQLITE_TCLAPI DbTransPostCmd( ClientData data[], /* data[0] is the Sqlite3Db* for $db */ Tcl_Interp *interp, /* Tcl interpreter */ int result /* Result of evaluating SCRIPT */ ){ static const char *const azEnd[] = { "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ }; SqliteDb *pDb = (SqliteDb*)data[0]; int rc = result; const char *zEnd; pDb->nTransaction--; zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; pDb->disableAuth++; if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, ** that an IO-error has occurred. In either case, throw a Tcl exception ** and try to rollback the transaction. ** ** But it could also be that the user executed one or more BEGIN, ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing ** this method's logic. Not clear how this would be best handled. */ if( rc!=TCL_ERROR ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; return rc; } /* ** Unless SQLITE_TEST is defined, this function is a simple wrapper around ** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either ** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending ** on whether or not the [db_use_legacy_prepare] command has been used to ** configure the connection. */ static int dbPrepare( SqliteDb *pDb, /* Database object */ const char *zSql, /* SQL to compile */ sqlite3_stmt **ppStmt, /* OUT: Prepared statement */ const char **pzOut /* OUT: Pointer to next SQL statement */ |
︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 | /* Trim spaces from the start of zSql and calculate the remaining length. */ while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } nSql = strlen30(zSql); for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ int n = pPreStmt->nSql; | | | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | /* Trim spaces from the start of zSql and calculate the remaining length. */ while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; } nSql = strlen30(zSql); for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ int n = pPreStmt->nSql; if( nSql>=n && memcmp(pPreStmt->zSql, zSql, n)==0 && (zSql[n]==0 || zSql[n-1]==';') ){ pStmt = pPreStmt->pStmt; *pzOut = &zSql[pPreStmt->nSql]; /* When a prepared statement is found, unlink it from the |
︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 | pDb->stmtLast = pPreStmt->pPrev; } pDb->nStmt--; nVar = sqlite3_bind_parameter_count(pStmt); break; } } | | | 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 | pDb->stmtLast = pPreStmt->pPrev; } pDb->nStmt--; nVar = sqlite3_bind_parameter_count(pStmt); break; } } /* If no prepared statement was found. Compile the SQL text. Also allocate ** a new SqlPreparedStmt structure. */ if( pPreStmt==0 ){ int nByte; if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(pDb->db), -1)); |
︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 | } #endif } assert( pPreStmt ); assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); | | | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 | } #endif } assert( pPreStmt ); assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); /* Bind values to parameters that begin with $ or : */ for(i=1; i<=nVar; i++){ const char *zVar = sqlite3_bind_parameter_name(pStmt, i); if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); if( pVar ){ int n; u8 *data; |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | if( pDb->stmtLast==0 ){ assert( pDb->nStmt==0 ); pDb->stmtLast = pPreStmt; }else{ assert( pDb->nStmt>0 ); } pDb->nStmt++; | | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | if( pDb->stmtLast==0 ){ assert( pDb->nStmt==0 ); pDb->stmtLast = pPreStmt; }else{ assert( pDb->nStmt>0 ); } pDb->nStmt++; /* If we have too many statement in cache, remove the surplus from ** the end of the cache list. */ while( pDb->nStmt>pDb->maxStmt ){ SqlPreparedStmt *pLast = pDb->stmtLast; pDb->stmtLast = pLast->pPrev; pDb->stmtLast->pNext = 0; pDb->nStmt--; dbFreeStmt(pLast); |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | /* ** Initialize a DbEvalContext structure. ** ** If pArray is not NULL, then it contains the name of a Tcl array ** variable. The "*" member of this array is set to a list containing ** the names of the columns returned by the statement as part of each | | | | 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 | /* ** Initialize a DbEvalContext structure. ** ** If pArray is not NULL, then it contains the name of a Tcl array ** variable. The "*" member of this array is set to a list containing ** the names of the columns returned by the statement as part of each ** call to dbEvalStep(), in order from left to right. e.g. if the names ** of the returned columns are a, b and c, it does the equivalent of the ** tcl command: ** ** set ${pArray}(*) {a b c} */ static void dbEvalInit( DbEvalContext *p, /* Pointer to structure to initialize */ SqliteDb *pDb, /* Database handle */ |
︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 | if( rcs!=SQLITE_OK ){ /* If a run-time error occurs, report the error and stop reading ** the SQL. */ dbReleaseStmt(pDb, pPreStmt, 1); #if SQLITE_TEST if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ /* If the runtime error was an SQLITE_SCHEMA, and the database | | | 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | if( rcs!=SQLITE_OK ){ /* If a run-time error occurs, report the error and stop reading ** the SQL. */ dbReleaseStmt(pDb, pPreStmt, 1); #if SQLITE_TEST if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){ /* If the runtime error was an SQLITE_SCHEMA, and the database ** handle is configured to use the legacy sqlite3_prepare() ** interface, retry prepare()/step() on the same SQL statement. ** This only happens once. If there is a second SQLITE_SCHEMA ** error, the error will be returned to the caller. */ p->zSql = zPrevSql; continue; } #endif |
︙ | ︙ | |||
1576 1577 1578 1579 1580 1581 1582 | # define SQLITE_TCL_NRE 1 static int DbUseNre(void){ int major, minor; Tcl_GetVersion(&major, &minor, 0, 0); return( (major==8 && minor>=6) || major>8 ); } #else | | | | | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 | # define SQLITE_TCL_NRE 1 static int DbUseNre(void){ int major, minor; Tcl_GetVersion(&major, &minor, 0, 0); return( (major==8 && minor>=6) || major>8 ); } #else /* ** Compiling using headers earlier than 8.6. In this case NR cannot be ** used, so DbUseNre() to always return zero. Add #defines for the other ** Tcl_NRxxx() functions to prevent them from causing compilation errors, ** even though the only invocations of them are within conditional blocks ** of the form: ** ** if( DbUseNre() ) { ... } */ # define SQLITE_TCL_NRE 0 # define DbUseNre() 0 # define Tcl_NRAddCallback(a,b,c,d,e,f) (void)0 # define Tcl_NREvalObj(a,b,c) 0 # define Tcl_NRCreateCommand(a,b,c,d,e,f) (void)0 #endif /* ** This function is part of the implementation of the command: ** ** $db eval SQL ?ARRAYNAME? SCRIPT */ static int SQLITE_TCLAPI DbEvalNextCmd( ClientData data[], /* data[0] is the (DbEvalContext*) */ Tcl_Interp *interp, /* Tcl interpreter */ int result /* Result so far */ ){ int rc = result; /* Return code */ /* The first element of the data[] array is a pointer to a DbEvalContext |
︙ | ︙ | |||
1626 1627 1628 1629 1630 1631 1632 | if( pArray==0 ){ Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); }else{ Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); } } | | | | 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | if( pArray==0 ){ Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); }else{ Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); } } /* The required interpreter variables are now populated with the data ** from the current row. If using NRE, schedule callbacks to evaluate ** script pScript, then to invoke this function again to fetch the next ** row (or clean up if there is no next row or the script throws an ** exception). After scheduling the callbacks, return control to the ** caller. ** ** If not using NRE, evaluate pScript directly and continue with the ** next iteration of this while(...) loop. */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); return Tcl_NREvalObj(interp, pScript, 0); |
︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 | Tcl_ResetResult(interp); rc = TCL_OK; } return rc; } /* | | | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 | Tcl_ResetResult(interp); rc = TCL_OK; } return rc; } /* ** This function is used by the implementations of the following database ** handle sub-commands: ** ** $db update_hook ?SCRIPT? ** $db wal_hook ?SCRIPT? ** $db commit_hook ?SCRIPT? ** $db preupdate hook ?SCRIPT? */ |
︙ | ︙ | |||
1707 1708 1709 1710 1711 1712 1713 | ** sqlite3 db1 "my_database" ** db1 close ** ** The first command opens a connection to the "my_database" database ** and calls that connection "db1". The second command causes this ** subroutine to be invoked. */ | > > | > > > | | > | | | > | 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 | ** sqlite3 db1 "my_database" ** db1 close ** ** The first command opens a connection to the "my_database" database ** and calls that connection "db1". The second command causes this ** subroutine to be invoked. */ static int SQLITE_TCLAPI DbObjCmd( void *cd, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { "authorizer", "backup", "busy", "cache", "changes", "close", "collate", "collation_needed", "commit_hook", "complete", "copy", "enable_load_extension", "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "nullvalue", "onecolumn", "preupdate", "profile", "progress", "rekey", "restore", "rollback_hook", "status", "timeout", "total_changes", "trace", "trace_v2", "transaction", "unlock_notify", "update_hook", "version", "wal_hook", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BACKUP, DB_BUSY, DB_CACHE, DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY, DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK, }; /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } |
︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 | } }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ if( objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "size n"); return TCL_ERROR; }else{ if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ | | | | | 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 | } }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ if( objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "size n"); return TCL_ERROR; }else{ if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ Tcl_AppendResult( interp, "cannot convert \"", Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0); return TCL_ERROR; }else{ if( n<0 ){ flushStmtCache( pDb ); n = 0; }else if( n>MAX_PREPARED_STMTS ){ n = MAX_PREPARED_STMTS; } pDb->maxStmt = n; } } }else{ Tcl_AppendResult( interp, "bad option \"", Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", (char*)0); return TCL_ERROR; } break; } /* $db changes ** ** Return the number of rows that were modified, inserted, or deleted by ** the most recent INSERT, UPDATE or DELETE statement, not including ** any changes made by trigger programs. */ case DB_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; |
︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 | pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); if( pCollate==0 ) return TCL_ERROR; pCollate->interp = interp; pCollate->pNext = pDb->pCollate; pCollate->zScript = (char*)&pCollate[1]; pDb->pCollate = pCollate; memcpy(pCollate->zScript, zScript, nScript+1); | | | 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 | pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); if( pCollate==0 ) return TCL_ERROR; pCollate->interp = interp; pCollate->pNext = pDb->pCollate; pCollate->zScript = (char*)&pCollate[1]; pDb->pCollate = pCollate; memcpy(pCollate->zScript, zScript, nScript+1); if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, pCollate, tclSqlCollate) ){ Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); return TCL_ERROR; } break; } |
︙ | ︙ | |||
2122 2123 2124 2125 2126 2127 2128 | int lineno = 0; /* Line number of input file */ char zLineNum[80]; /* Line number print buffer */ Tcl_Obj *pResult; /* interp result */ const char *zSep; const char *zNull; if( objc<5 || objc>7 ){ | | | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 | int lineno = 0; /* Line number of input file */ char zLineNum[80]; /* Line number print buffer */ Tcl_Obj *pResult; /* interp result */ const char *zSep; const char *zNull; if( objc<5 || objc>7 ){ Tcl_WrongNumArgs(interp, 2, objv, "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); return TCL_ERROR; } if( objc>=6 ){ zSep = Tcl_GetStringFromObj(objv[5], 0); }else{ zSep = "\t"; |
︙ | ︙ | |||
2151 2152 2153 2154 2155 2156 2157 | return TCL_ERROR; } if(strcmp(zConflict, "rollback") != 0 && strcmp(zConflict, "abort" ) != 0 && strcmp(zConflict, "fail" ) != 0 && strcmp(zConflict, "ignore" ) != 0 && strcmp(zConflict, "replace" ) != 0 ) { | | | 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 | return TCL_ERROR; } if(strcmp(zConflict, "rollback") != 0 && strcmp(zConflict, "abort" ) != 0 && strcmp(zConflict, "fail" ) != 0 && strcmp(zConflict, "ignore" ) != 0 && strcmp(zConflict, "replace" ) != 0 ) { Tcl_AppendResult(interp, "Error: \"", zConflict, "\", conflict-algorithm must be one of: rollback, " "abort, fail, ignore, or replace", (char*)0); return TCL_ERROR; } zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); if( zSql==0 ){ Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0); |
︙ | ︙ | |||
2240 2241 2242 2243 2244 2245 2246 | } zCommit = "ROLLBACK"; break; } for(i=0; i<nCol; i++){ /* check for null data, if so, bind as null */ if( (nNull>0 && strcmp(azCol[i], zNull)==0) | | | 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 | } zCommit = "ROLLBACK"; break; } for(i=0; i<nCol; i++){ /* check for null data, if so, bind as null */ if( (nNull>0 && strcmp(azCol[i], zNull)==0) || strlen30(azCol[i])==0 ){ sqlite3_bind_null(pStmt, i+1); }else{ sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); } } sqlite3_step(pStmt); |
︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 | /* ** $db exists $sql ** $db onecolumn $sql ** ** The onecolumn method is the equivalent of: ** lindex [$db eval $sql] 0 */ | | > | | > | | 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 | /* ** $db exists $sql ** $db onecolumn $sql ** ** The onecolumn method is the equivalent of: ** lindex [$db eval $sql] 0 */ case DB_EXISTS: case DB_ONECOLUMN: { Tcl_Obj *pResult = 0; DbEvalContext sEval; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } dbEvalInit(&sEval, pDb, objv[2], 0); rc = dbEvalStep(&sEval); if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ pResult = dbEvalColumnValue(&sEval, 0); }else if( rc==TCL_BREAK ){ Tcl_ResetResult(interp); } }else if( rc==TCL_BREAK || rc==TCL_OK ){ pResult = Tcl_NewBooleanObj(rc==TCL_OK); } dbEvalFinalize(&sEval); if( pResult ) Tcl_SetObjResult(interp, pResult); if( rc==TCL_BREAK ){ rc = TCL_OK; } break; } /* ** $db eval $sql ?array? ?{ ...code... }? ** ** The SQL statement in $sql is evaluated. For each row, the values are ** placed in elements of the array named "array" and ...code... is executed. ** If "array" and "code" are omitted, then no callback is every invoked. ** If "array" is an empty string, then the values are placed in variables |
︙ | ︙ | |||
2391 2392 2393 2394 2395 2396 2397 | Tcl_Obj *pScript; if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){ pArray = objv[3]; } pScript = objv[objc-1]; Tcl_IncrRefCount(pScript); | | | 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 | Tcl_Obj *pScript; if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){ pArray = objv[3]; } pScript = objv[objc-1]; Tcl_IncrRefCount(pScript); p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); dbEvalInit(p, pDb, objv[2], pArray); cd2[0] = (void *)p; cd2[1] = (void *)pScript; rc = DbEvalNextCmd(cd2, interp, TCL_OK); } |
︙ | ︙ | |||
2438 2439 2440 2441 2442 2443 2444 | return TCL_ERROR; } i++; }else if( n>2 && strncmp(z, "-deterministic",n)==0 ){ flags |= SQLITE_DETERMINISTIC; }else{ | | | 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 | return TCL_ERROR; } i++; }else if( n>2 && strncmp(z, "-deterministic",n)==0 ){ flags |= SQLITE_DETERMINISTIC; }else{ Tcl_AppendResult(interp, "bad option \"", z, "\": must be -argcount or -deterministic", 0 ); return TCL_ERROR; } } pScript = objv[objc-1]; |
︙ | ︙ | |||
2547 2548 2549 2550 2551 2552 2553 | } } Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); break; } /* | | | 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 | } } Tcl_SetObjResult(interp, Tcl_NewStringObj(pDb->zNull, -1)); break; } /* ** $db last_insert_rowid ** ** Return an integer which is the ROWID for the most recent insert. */ case DB_LAST_INSERT_ROWID: { Tcl_Obj *pResult; Tcl_WideInt rowid; if( objc!=2 ){ |
︙ | ︙ | |||
2569 2570 2571 2572 2573 2574 2575 | } /* ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. */ /* $db progress ?N CALLBACK? | | | 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 | } /* ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. */ /* $db progress ?N CALLBACK? ** ** Invoke the given callback every N virtual machine opcodes while executing ** queries. */ case DB_PROGRESS: { if( objc==2 ){ if( pDb->zProgress ){ Tcl_AppendResult(interp, pDb->zProgress, (char*)0); |
︙ | ︙ | |||
2676 2677 2678 2679 2680 2681 2682 | } #endif break; } /* $db restore ?DATABASE? FILENAME ** | | | 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 | } #endif break; } /* $db restore ?DATABASE? FILENAME ** ** Open a database file named FILENAME. Transfer the content ** of FILENAME into the local database DATABASE (default: "main"). */ case DB_RESTORE: { const char *zSrcFile; const char *zDestDb; sqlite3 *pSrc; sqlite3_backup *pBackup; |
︙ | ︙ | |||
2737 2738 2739 2740 2741 2742 2743 | sqlite3_close(pSrc); break; } /* ** $db status (step|sort|autoindex) ** | | | | | | | | 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 | sqlite3_close(pSrc); break; } /* ** $db status (step|sort|autoindex) ** ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or ** SQLITE_STMTSTATUS_SORT for the most recent eval. */ case DB_STATUS: { int v; const char *zOp; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)"); return TCL_ERROR; } zOp = Tcl_GetString(objv[2]); if( strcmp(zOp, "step")==0 ){ v = pDb->nStep; }else if( strcmp(zOp, "sort")==0 ){ v = pDb->nSort; }else if( strcmp(zOp, "autoindex")==0 ){ v = pDb->nIndex; }else{ Tcl_AppendResult(interp, "bad argument: should be autoindex, step, or sort", (char*)0); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); break; } /* ** $db timeout MILLESECONDS ** ** Delay for the number of milliseconds specified when a file is locked. */ case DB_TIMEOUT: { int ms; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; sqlite3_busy_timeout(pDb->db, ms); break; } /* ** $db total_changes ** ** Return the number of rows that were modified, inserted, or deleted ** since the database handle was created. */ case DB_TOTAL_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; |
︙ | ︙ | |||
2824 2825 2826 2827 2828 2829 2830 | zTrace = Tcl_GetStringFromObj(objv[2], &len); if( zTrace && len>0 ){ pDb->zTrace = Tcl_Alloc( len + 1 ); memcpy(pDb->zTrace, zTrace, len+1); }else{ pDb->zTrace = 0; } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 | zTrace = Tcl_GetStringFromObj(objv[2], &len); if( zTrace && len>0 ){ pDb->zTrace = Tcl_Alloc( len + 1 ); memcpy(pDb->zTrace, zTrace, len+1); }else{ pDb->zTrace = 0; } #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) \ && !defined(SQLITE_OMIT_DEPRECATED) if( pDb->zTrace ){ pDb->interp = interp; sqlite3_trace(pDb->db, DbTraceHandler, pDb); }else{ sqlite3_trace(pDb->db, 0, 0); } #endif } break; } /* $db trace_v2 ?CALLBACK? ?MASK? ** ** Make arrangements to invoke the CALLBACK routine for each trace event ** matching the mask that is generated. The parameters are appended to ** CALLBACK before it is executed. */ case DB_TRACE_V2: { if( objc>4 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?"); return TCL_ERROR; }else if( objc==2 ){ if( pDb->zTraceV2 ){ Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0); } }else{ char *zTraceV2; int len; Tcl_WideInt wMask = 0; if( objc==4 ){ static const char *TTYPE_strs[] = { "statement", "profile", "row", "close", 0 }; enum TTYPE_enum { TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE }; int i; if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){ return TCL_ERROR; } for(i=0; i<len; i++){ Tcl_Obj *pObj; int ttype; if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){ return TCL_ERROR; } if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type", 0, &ttype)!=TCL_OK ){ Tcl_WideInt wType; Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); Tcl_IncrRefCount(pError); if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){ Tcl_DecrRefCount(pError); wMask |= wType; }else{ Tcl_SetObjResult(interp, pError); Tcl_DecrRefCount(pError); return TCL_ERROR; } }else{ switch( (enum TTYPE_enum)ttype ){ case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break; case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break; case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break; case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break; } } } }else{ wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */ } if( pDb->zTraceV2 ){ Tcl_Free(pDb->zTraceV2); } zTraceV2 = Tcl_GetStringFromObj(objv[2], &len); if( zTraceV2 && len>0 ){ pDb->zTraceV2 = Tcl_Alloc( len + 1 ); memcpy(pDb->zTraceV2, zTraceV2, len+1); }else{ pDb->zTraceV2 = 0; } #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) if( pDb->zTraceV2 ){ pDb->interp = interp; sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb); }else{ sqlite3_trace_v2(pDb->db, 0, 0, 0); } #endif } break; } /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT ** ** Start a new transaction (if we are not already in the midst of a |
︙ | ︙ | |||
2888 2889 2890 2891 2892 2893 2894 | return TCL_ERROR; } pDb->nTransaction++; /* If using NRE, schedule a callback to invoke the script pScript, then ** a second callback to commit (or rollback) the transaction or savepoint ** opened above. If not using NRE, evaluate the script directly, then | | | 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 | return TCL_ERROR; } pDb->nTransaction++; /* If using NRE, schedule a callback to invoke the script pScript, then ** a second callback to commit (or rollback) the transaction or savepoint ** opened above. If not using NRE, evaluate the script directly, then ** call function DbTransPostCmd() to commit (or rollback) the transaction ** or savepoint. */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0); (void)Tcl_NREvalObj(interp, pScript, 0); }else{ rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); } |
︙ | ︙ | |||
2919 2920 2921 2922 2923 2924 2925 | void (*xNotify)(void **, int) = 0; void *pNotifyArg = 0; if( pDb->pUnlockNotify ){ Tcl_DecrRefCount(pDb->pUnlockNotify); pDb->pUnlockNotify = 0; } | | | | 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 | void (*xNotify)(void **, int) = 0; void *pNotifyArg = 0; if( pDb->pUnlockNotify ){ Tcl_DecrRefCount(pDb->pUnlockNotify); pDb->pUnlockNotify = 0; } if( objc==3 ){ xNotify = DbUnlockNotify; pNotifyArg = (void *)pDb; pDb->pUnlockNotify = objv[2]; Tcl_IncrRefCount(pDb->pUnlockNotify); } if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } } #endif break; |
︙ | ︙ | |||
3025 3026 3027 3028 3029 3030 3031 | } /* ** $db wal_hook ?script? ** $db update_hook ?script? ** $db rollback_hook ?script? */ | | | | | | 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 | } /* ** $db wal_hook ?script? ** $db update_hook ?script? ** $db rollback_hook ?script? */ case DB_WAL_HOOK: case DB_UPDATE_HOOK: case DB_ROLLBACK_HOOK: { /* set ppHook to point at pUpdateHook or pRollbackHook, depending on ** whether [$db update_hook] or [$db rollback_hook] was invoked. */ Tcl_Obj **ppHook = 0; if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook; if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook; if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook; if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); return TCL_ERROR; } |
︙ | ︙ | |||
3063 3064 3065 3066 3067 3068 3069 | } #if SQLITE_TCL_NRE /* ** Adaptor that provides an objCmd interface to the NRE-enabled ** interface implementation. */ | | | 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 | } #if SQLITE_TCL_NRE /* ** Adaptor that provides an objCmd interface to the NRE-enabled ** interface implementation. */ static int SQLITE_TCLAPI DbObjCmdAdaptor( void *cd, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); } |
︙ | ︙ | |||
3088 3089 3090 3091 3092 3093 3094 | ** database connection. This command creates a new command named ** DBNAME that is used to control that connection. The database ** connection is deleted when the DBNAME command is deleted. ** ** The second argument is the name of the database file. ** */ | > > | > > > | 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 | ** database connection. This command creates a new command named ** DBNAME that is used to control that connection. The database ** connection is deleted when the DBNAME command is deleted. ** ** The second argument is the name of the database file. ** */ static int SQLITE_TCLAPI DbMain( void *cd, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ SqliteDb *p; const char *zArg; char *zErrMsg; int i; const char *zFile; const char *zVfs = 0; int flags; |
︙ | ︙ | |||
3192 3193 3194 3195 3196 3197 3198 | } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; } } if( objc<3 || (objc&1)!=1 ){ | | | 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 | } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; } } if( objc<3 || (objc&1)!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) " ?-key CODECKEY?" #endif ); return TCL_ERROR; |
︙ | ︙ | |||
3484 3485 3486 3487 3488 3489 3490 | ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ | | | 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 | ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ static void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) |
︙ | ︙ | |||
3530 3531 3532 3533 3534 3535 3536 | /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* | | | 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 | /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ |
︙ | ︙ | |||
3606 3607 3608 3609 3610 3611 3612 | j += 5; } zDigest[j] = 0; } /* ** A TCL command for md5. The argument is the text to be hashed. The | | > > | > > > | > > > > | > | | | 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 | j += 5; } zDigest[j] = 0; } /* ** A TCL command for md5. The argument is the text to be hashed. The ** Result is the hash in base64. */ static int SQLITE_TCLAPI md5_cmd( void*cd, Tcl_Interp *interp, int argc, const char **argv ){ MD5Context ctx; unsigned char digest[16]; char zBuf[50]; void (*converter)(unsigned char*, char*); if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], " TEXT\"", (char*)0); return TCL_ERROR; } MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); MD5Final(digest, &ctx); converter = (void(*)(unsigned char*,char*))cd; converter(digest, zBuf); Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** A TCL command to take the md5 hash of a file. The argument is the ** name of the file. */ static int SQLITE_TCLAPI md5file_cmd( void*cd, Tcl_Interp *interp, int argc, const char **argv ){ FILE *in; MD5Context ctx; void (*converter)(unsigned char*, char*); unsigned char digest[16]; char zBuf[10240]; if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], " FILENAME\"", (char*)0); return TCL_ERROR; } in = fopen(argv[1],"rb"); if( in==0 ){ Tcl_AppendResult(interp,"unable to open file \"", argv[1], "\" for reading", (char*)0); return TCL_ERROR; } MD5Init(&ctx); for(;;){ int n; n = (int)fread(zBuf, 1, sizeof(zBuf), in); |
︙ | ︙ | |||
3712 3713 3714 3715 3716 3717 3718 | unsigned char digest[16]; char zBuf[33]; p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); MD5DigestToBase16(digest, zBuf); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } | | > > > > | | 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 | unsigned char digest[16]; char zBuf[33]; p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); MD5DigestToBase16(digest, zBuf); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } int Md5_Register( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pThunk ){ int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, md5step, md5finalize); sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */ return rc; } #endif /* defined(SQLITE_TEST) */ |
︙ | ︙ | |||
3760 3761 3762 3763 3764 3765 3766 | #endif #if TCLSH==2 static const char *tclsh_main_loop(void); #endif #ifdef SQLITE_TEST static void init_all(Tcl_Interp *); | | | 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 | #endif #if TCLSH==2 static const char *tclsh_main_loop(void); #endif #ifdef SQLITE_TEST static void init_all(Tcl_Interp *); static int SQLITE_TCLAPI init_all_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Interp *slave; |
︙ | ︙ | |||
3790 3791 3792 3793 3794 3795 3796 | ** Tclcmd: db_use_legacy_prepare DB BOOLEAN ** ** The first argument to this command must be a database command created by ** [sqlite3]. If the second argument is true, then the handle is configured ** to use the sqlite3_prepare_v2() function to prepare statements. If it ** is false, sqlite3_prepare(). */ | | | 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 | ** Tclcmd: db_use_legacy_prepare DB BOOLEAN ** ** The first argument to this command must be a database command created by ** [sqlite3]. If the second argument is true, then the handle is configured ** to use the sqlite3_prepare_v2() function to prepare statements. If it ** is false, sqlite3_prepare(). */ static int SQLITE_TCLAPI db_use_legacy_prepare_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_CmdInfo cmdInfo; SqliteDb *pDb; |
︙ | ︙ | |||
3827 3828 3829 3830 3831 3832 3833 | /* ** Tclcmd: db_last_stmt_ptr DB ** ** If the statement cache associated with database DB is not empty, ** return the text representation of the most recently used statement ** handle. */ | | | 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 | /* ** Tclcmd: db_last_stmt_ptr DB ** ** If the statement cache associated with database DB is not empty, ** return the text representation of the most recently used statement ** handle. */ static int SQLITE_TCLAPI db_last_stmt_ptr( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); Tcl_CmdInfo cmdInfo; |
︙ | ︙ | |||
3864 3865 3866 3867 3868 3869 3870 | } #endif /* SQLITE_TEST */ /* ** Configure the interpreter passed as the first argument to have access ** to the commands and linked variables that make up: ** | | | 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 | } #endif /* SQLITE_TEST */ /* ** Configure the interpreter passed as the first argument to have access ** to the commands and linked variables that make up: ** ** * the [sqlite3] extension itself, ** ** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and ** ** * If SQLITE_TEST is set, the various test interfaces used by the Tcl ** test suite. */ static void init_all(Tcl_Interp *interp){ |
︙ | ︙ | |||
3952 3953 3954 3955 3956 3957 3958 | Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); | | | 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 | Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); |
︙ | ︙ | |||
3996 3997 3998 3999 4000 4001 4002 | /* Needed for the setrlimit() system call on unix */ #if defined(unix) #include <sys/resource.h> #endif #define TCLSH_MAIN main /* Needed to fake out mktclapp */ | | | 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 | /* Needed for the setrlimit() system call on unix */ #if defined(unix) #include <sys/resource.h> #endif #define TCLSH_MAIN main /* Needed to fake out mktclapp */ int SQLITE_CDECL TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; #if !defined(_WIN32_WCE) if( getenv("BREAK") ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | */ #include "sqliteInt.h" #if SQLITE_OS_WIN # include "os_win.h" #endif #include "vdbeInt.h" | > > > | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | */ #include "sqliteInt.h" #if SQLITE_OS_WIN # include "os_win.h" #endif #include "vdbeInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> /* ** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine ** can extract the sqlite3* pointer from an existing Tcl SQLite |
︙ | ︙ | |||
71 72 73 74 75 76 77 | /* ** A TCL command that returns the address of the sqlite* pointer ** for an sqlite connection instance. Bad things happen if the ** input is not an sqlite connection. */ | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | /* ** A TCL command that returns the address of the sqlite* pointer ** for an sqlite connection instance. Bad things happen if the ** input is not an sqlite connection. */ static int SQLITE_TCLAPI get_sqlite_pointer( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct SqliteDb *p; Tcl_CmdInfo cmdInfo; |
︙ | ︙ | |||
217 218 219 220 221 222 223 | /* ** Usage: io_trace FILENAME ** ** Turn I/O tracing on or off. If FILENAME is not an empty string, ** I/O tracing begins going into FILENAME. If FILENAME is an empty ** string, I/O tracing is turned off. */ | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | /* ** Usage: io_trace FILENAME ** ** Turn I/O tracing on or off. If FILENAME is not an empty string, ** I/O tracing begins going into FILENAME. If FILENAME is an empty ** string, I/O tracing is turned off. */ static int SQLITE_TCLAPI test_io_trace( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) if( argc!=2 ){ |
︙ | ︙ | |||
258 259 260 261 262 263 264 | ** Usage: clang_sanitize_address ** ** Returns true if the program was compiled using clang with the ** -fsanitize=address switch on the command line. False otherwise. ** ** Also return true if the OMIT_MISUSE environment variable exists. */ | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | ** Usage: clang_sanitize_address ** ** Returns true if the program was compiled using clang with the ** -fsanitize=address switch on the command line. False otherwise. ** ** Also return true if the OMIT_MISUSE environment variable exists. */ static int SQLITE_TCLAPI clang_sanitize_address( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int res = 0; #if defined(__has_feature) |
︙ | ︙ | |||
285 286 287 288 289 290 291 | /* ** Usage: sqlite3_exec_printf DB FORMAT STRING ** ** Invoke the sqlite3_exec_printf() interface using the open database ** DB. The SQL is the string FORMAT. The format string should contain ** one %s or %q. STRING is the value inserted into %s or %q. */ | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | /* ** Usage: sqlite3_exec_printf DB FORMAT STRING ** ** Invoke the sqlite3_exec_printf() interface using the open database ** DB. The SQL is the string FORMAT. The format string should contain ** one %s or %q. STRING is the value inserted into %s or %q. */ static int SQLITE_TCLAPI test_exec_printf( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; Tcl_DString str; |
︙ | ︙ | |||
323 324 325 326 327 328 329 | /* ** Usage: sqlite3_exec_hex DB HEX ** ** Invoke the sqlite3_exec() on a string that is obtained by translating ** HEX into ASCII. Most characters are translated as is. %HH becomes ** a hex character. */ | | | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | /* ** Usage: sqlite3_exec_hex DB HEX ** ** Invoke the sqlite3_exec() on a string that is obtained by translating ** HEX into ASCII. Most characters are translated as is. %HH becomes ** a hex character. */ static int SQLITE_TCLAPI test_exec_hex( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; Tcl_DString str; |
︙ | ︙ | |||
369 370 371 372 373 374 375 | /* ** Usage: db_enter DB ** db_leave DB ** ** Enter or leave the mutex on a database connection. */ | | | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | /* ** Usage: db_enter DB ** db_leave DB ** ** Enter or leave the mutex on a database connection. */ static int SQLITE_TCLAPI db_enter( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sqlite3_mutex_enter(db->mutex); return TCL_OK; } static int SQLITE_TCLAPI db_leave( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; if( argc!=2 ){ |
︙ | ︙ | |||
407 408 409 410 411 412 413 | } /* ** Usage: sqlite3_exec DB SQL ** ** Invoke the sqlite3_exec interface using the open database DB */ | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | } /* ** Usage: sqlite3_exec DB SQL ** ** Invoke the sqlite3_exec interface using the open database DB */ static int SQLITE_TCLAPI test_exec( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; Tcl_DString str; |
︙ | ︙ | |||
454 455 456 457 458 459 460 | /* ** Usage: sqlite3_exec_nr DB SQL ** ** Invoke the sqlite3_exec interface using the open database DB. Discard ** all results */ | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | /* ** Usage: sqlite3_exec_nr DB SQL ** ** Invoke the sqlite3_exec interface using the open database DB. Discard ** all results */ static int SQLITE_TCLAPI test_exec_nr( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
481 482 483 484 485 486 487 | /* ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... ** ** Test the %z format of sqlite_mprintf(). Use multiple mprintf() calls to ** concatenate arg0 through argn using separator as the separator. ** Return the result. */ | | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | /* ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... ** ** Test the %z format of sqlite_mprintf(). Use multiple mprintf() calls to ** concatenate arg0 through argn using separator as the separator. ** Return the result. */ static int SQLITE_TCLAPI test_mprintf_z( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *zResult = 0; int i; |
︙ | ︙ | |||
504 505 506 507 508 509 510 | /* ** Usage: sqlite3_mprintf_n_test STRING ** ** Test the %n format of sqlite_mprintf(). Return the length of the ** input string. */ | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | /* ** Usage: sqlite3_mprintf_n_test STRING ** ** Test the %n format of sqlite_mprintf(). Return the length of the ** input string. */ static int SQLITE_TCLAPI test_mprintf_n( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *zStr; int n = 0; |
︙ | ︙ | |||
528 529 530 531 532 533 534 | ** Test the of sqlite3_snprintf() routine. SIZE is the size of the ** output buffer in bytes. The maximum size is 100. FORMAT is the ** format string. INT is a single integer argument. The FORMAT ** string must require no more than this one integer argument. If ** You pass in a format string that requires more than one argument, ** bad things will happen. */ | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | ** Test the of sqlite3_snprintf() routine. SIZE is the size of the ** output buffer in bytes. The maximum size is 100. FORMAT is the ** format string. INT is a single integer argument. The FORMAT ** string must require no more than this one integer argument. If ** You pass in a format string that requires more than one argument, ** bad things will happen. */ static int SQLITE_TCLAPI test_snprintf_int( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char zStr[100]; int n = atoi(argv[1]); |
︙ | ︙ | |||
554 555 556 557 558 559 560 | /* ** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts? ** ** Invoke the sqlite3_get_table_printf() interface using the open database ** DB. The SQL is the string FORMAT. The format string should contain ** one %s or %q. STRING is the value inserted into %s or %q. */ | | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | /* ** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts? ** ** Invoke the sqlite3_get_table_printf() interface using the open database ** DB. The SQL is the string FORMAT. The format string should contain ** one %s or %q. STRING is the value inserted into %s or %q. */ static int SQLITE_TCLAPI test_get_table_printf( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; Tcl_DString str; |
︙ | ︙ | |||
617 618 619 620 621 622 623 | /* ** Usage: sqlite3_last_insert_rowid DB ** ** Returns the integer ROWID of the most recent insert. */ | | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | /* ** Usage: sqlite3_last_insert_rowid DB ** ** Returns the integer ROWID of the most recent insert. */ static int SQLITE_TCLAPI test_last_rowid( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; char zBuf[30]; |
︙ | ︙ | |||
641 642 643 644 645 646 647 | } /* ** Usage: sqlite3_key DB KEY ** ** Set the codec key. */ | | | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | } /* ** Usage: sqlite3_key DB KEY ** ** Set the codec key. */ static int SQLITE_TCLAPI test_key( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) sqlite3 *db; |
︙ | ︙ | |||
669 670 671 672 673 674 675 | } /* ** Usage: sqlite3_rekey DB KEY ** ** Change the codec key. */ | | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | } /* ** Usage: sqlite3_rekey DB KEY ** ** Change the codec key. */ static int SQLITE_TCLAPI test_rekey( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ #ifdef SQLITE_HAS_CODEC sqlite3 *db; |
︙ | ︙ | |||
697 698 699 700 701 702 703 | } /* ** Usage: sqlite3_close DB ** ** Closes the database opened by sqlite3_open. */ | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | } /* ** Usage: sqlite3_close DB ** ** Closes the database opened by sqlite3_open. */ static int SQLITE_TCLAPI sqlite_test_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
721 722 723 724 725 726 727 | } /* ** Usage: sqlite3_close_v2 DB ** ** Closes the database opened by sqlite3_open. */ | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | } /* ** Usage: sqlite3_close_v2 DB ** ** Closes the database opened by sqlite3_open. */ static int SQLITE_TCLAPI sqlite_test_close_v2( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 | ** The effect is similar to trying to use the same database connection from ** two threads at the same time. ** ** The original motivation for this routine was to be able to call the ** sqlite3_create_function function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ | | | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 | ** The effect is similar to trying to use the same database connection from ** two threads at the same time. ** ** The original motivation for this routine was to be able to call the ** sqlite3_create_function function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ static int SQLITE_TCLAPI test_create_function( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | ** This routine was later extended to test the use of sqlite3_result_error() ** within aggregate functions. ** ** Later: It is now also extended to register the aggregate function ** "legacy_count()" with the supplied database handle. This is used ** to test the deprecated sqlite3_aggregate_count() API. */ | | | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | ** This routine was later extended to test the use of sqlite3_result_error() ** within aggregate functions. ** ** Later: It is now also extended to register the aggregate function ** "legacy_count()" with the supplied database handle. This is used ** to test the deprecated sqlite3_aggregate_count() API. */ static int SQLITE_TCLAPI test_create_aggregate( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 | ** Usage: printf TEXT ** ** Send output to printf. Use this rather than puts to merge the output ** in the correct sequence with debugging printfs inserted into C code. ** Puts uses a separate buffer and debugging statements will be out of ** sequence if it is used. */ | | | 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 | ** Usage: printf TEXT ** ** Send output to printf. Use this rather than puts to merge the output ** in the correct sequence with debugging printfs inserted into C code. ** Puts uses a separate buffer and debugging statements will be out of ** sequence if it is used. */ static int SQLITE_TCLAPI test_printf( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | /* ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three integer arguments */ | | | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 | /* ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three integer arguments */ static int SQLITE_TCLAPI sqlite3_mprintf_int( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | } /* ** Usage: sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three 64-bit integer arguments */ | | | 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 | } /* ** Usage: sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three 64-bit integer arguments */ static int SQLITE_TCLAPI sqlite3_mprintf_int64( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int i; sqlite_int64 a[3]; |
︙ | ︙ | |||
1285 1286 1287 1288 1289 1290 1291 | /* ** Usage: sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three long integer arguments. This might be the ** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on ** platform. */ | | | 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 | /* ** Usage: sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three long integer arguments. This might be the ** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on ** platform. */ static int SQLITE_TCLAPI sqlite3_mprintf_long( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int i; long int a[3]; |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 | } /* ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ | | | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 | } /* ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ static int SQLITE_TCLAPI sqlite3_mprintf_str( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; |
︙ | ︙ | |||
1343 1344 1345 1346 1347 1348 1349 | } /* ** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ | | | 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 | } /* ** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ static int SQLITE_TCLAPI sqlite3_snprintf_str( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; int n; |
︙ | ︙ | |||
1377 1378 1379 1380 1381 1382 1383 | } /* ** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE ** ** Call mprintf with two integer arguments and one double argument */ | | | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | } /* ** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE ** ** Call mprintf with two integer arguments and one double argument */ static int SQLITE_TCLAPI sqlite3_mprintf_double( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; double r; |
︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 | /* ** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ | | | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 | /* ** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ static int SQLITE_TCLAPI sqlite3_mprintf_scaled( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int i; double r[2]; |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | /* ** Usage: sqlite3_mprintf_stronly FORMAT STRING ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | /* ** Usage: sqlite3_mprintf_stronly FORMAT STRING ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ static int SQLITE_TCLAPI sqlite3_mprintf_stronly( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *z; if( argc!=3 ){ |
︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 | /* ** Usage: sqlite3_mprintf_hexdouble FORMAT HEX ** ** Call mprintf with a single double argument which is derived from the ** hexadecimal encoding of an IEEE double. */ | | | 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 | /* ** Usage: sqlite3_mprintf_hexdouble FORMAT HEX ** ** Call mprintf with a single double argument which is derived from the ** hexadecimal encoding of an IEEE double. */ static int SQLITE_TCLAPI sqlite3_mprintf_hexdouble( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *z; double r; |
︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 | } /* ** Usage: sqlite3_enable_shared_cache ?BOOLEAN? ** */ #if !defined(SQLITE_OMIT_SHARED_CACHE) | | | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | } /* ** Usage: sqlite3_enable_shared_cache ?BOOLEAN? ** */ #if !defined(SQLITE_OMIT_SHARED_CACHE) static int SQLITE_TCLAPI test_enable_shared( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int rc; int enable; |
︙ | ︙ | |||
1532 1533 1534 1535 1536 1537 1538 | /* ** Usage: sqlite3_extended_result_codes DB BOOLEAN ** */ | | | 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 | /* ** Usage: sqlite3_extended_result_codes DB BOOLEAN ** */ static int SQLITE_TCLAPI test_extended_result_codes( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int enable; sqlite3 *db; |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | return TCL_OK; } /* ** Usage: sqlite3_libversion_number ** */ | | | | 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | return TCL_OK; } /* ** Usage: sqlite3_libversion_number ** */ static int SQLITE_TCLAPI test_libversion_number( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_libversion_number())); return TCL_OK; } /* ** Usage: sqlite3_table_column_metadata DB dbname tblname colname ** */ static int SQLITE_TCLAPI test_table_column_metadata( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDb; |
︙ | ︙ | |||
1620 1621 1622 1623 1624 1625 1626 | Tcl_SetObjResult(interp, pRet); return TCL_OK; } #ifndef SQLITE_OMIT_INCRBLOB | | | 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 | Tcl_SetObjResult(interp, pRet); return TCL_OK; } #ifndef SQLITE_OMIT_INCRBLOB static int SQLITE_TCLAPI blobHandleFromObj( Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3_blob **ppBlob ){ char *z; int n; |
︙ | ︙ | |||
1649 1650 1651 1652 1653 1654 1655 | instanceData = Tcl_GetChannelInstanceData(channel); *ppBlob = *((sqlite3_blob **)instanceData); } return TCL_OK; } | | | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 | instanceData = Tcl_GetChannelInstanceData(channel); *ppBlob = *((sqlite3_blob **)instanceData); } return TCL_OK; } static int SQLITE_TCLAPI test_blob_reopen( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_WideInt iRowid; sqlite3_blob *pBlob; |
︙ | ︙ | |||
1725 1726 1727 1728 1729 1730 1731 | ){ Tcl_BackgroundError(p->interp); } Tcl_DecrRefCount(pScript); return iRes; } | | | 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | ){ Tcl_BackgroundError(p->interp); } Tcl_DecrRefCount(pScript); return iRes; } static int SQLITE_TCLAPI test_create_collation_v2( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ TestCollationX *p; sqlite3 *db; |
︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 | if( p->pFunc ) Tcl_DecrRefCount(p->pFunc); if( p->pStep ) Tcl_DecrRefCount(p->pStep); if( p->pFinal ) Tcl_DecrRefCount(p->pFinal); if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy); sqlite3_free(p); } | | | 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 | if( p->pFunc ) Tcl_DecrRefCount(p->pFunc); if( p->pStep ) Tcl_DecrRefCount(p->pStep); if( p->pFinal ) Tcl_DecrRefCount(p->pFinal); if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy); sqlite3_free(p); } static int SQLITE_TCLAPI test_create_function_v2( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The invoking TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zFunc; |
︙ | ︙ | |||
1888 1889 1890 1891 1892 1893 1894 | } return TCL_OK; } /* ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC? */ | | | 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 | } return TCL_OK; } /* ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC? */ static int SQLITE_TCLAPI test_load_extension( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_CmdInfo cmdInfo; sqlite3 *db; |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | return rc; } /* ** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF */ | | | 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 | return rc; } /* ** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF */ static int SQLITE_TCLAPI test_enable_load( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_CmdInfo cmdInfo; sqlite3 *db; |
︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 | /* ** Usage: sqlite_abort ** ** Shutdown the process immediately. This is not a clean shutdown. ** This command is used to test the recoverability of a database in ** the event of a program crash. */ | | | 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 | /* ** Usage: sqlite_abort ** ** Shutdown the process immediately. This is not a clean shutdown. ** This command is used to test the recoverability of a database in ** the event of a program crash. */ static int SQLITE_TCLAPI sqlite_abort( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ #if defined(_MSC_VER) /* We do this, otherwise the test will halt with a popup message |
︙ | ︙ | |||
2051 2052 2053 2054 2055 2056 2057 | } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ | | | 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 | } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ static int SQLITE_TCLAPI test_register_func( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 | } /* ** Usage: sqlite3_finalize STMT ** ** Finalize a statement handle. */ | | | 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 | } /* ** Usage: sqlite3_finalize STMT ** ** Finalize a statement handle. */ static int SQLITE_TCLAPI test_finalize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
2112 2113 2114 2115 2116 2117 2118 | } /* ** Usage: sqlite3_stmt_status STMT CODE RESETFLAG ** ** Get the value of a status counter from a statement. */ | | | 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | } /* ** Usage: sqlite3_stmt_status STMT CODE RESETFLAG ** ** Get the value of a status counter from a statement. */ static int SQLITE_TCLAPI test_stmt_status( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int iValue; int i, op = 0, resetFlag; |
︙ | ︙ | |||
2157 2158 2159 2160 2161 2162 2163 | return TCL_OK; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Usage: sqlite3_stmt_scanstatus STMT IDX */ | | | 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 | return TCL_OK; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Usage: sqlite3_stmt_scanstatus STMT IDX */ static int SQLITE_TCLAPI test_stmt_scanstatus( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; /* First argument */ int idx; /* Second argument */ |
︙ | ︙ | |||
2207 2208 2209 2210 2211 2212 2213 | } return TCL_OK; } /* ** Usage: sqlite3_stmt_scanstatus_reset STMT */ | | | 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 | } return TCL_OK; } /* ** Usage: sqlite3_stmt_scanstatus_reset STMT */ static int SQLITE_TCLAPI test_stmt_scanstatus_reset( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; /* First argument */ if( objc!=2 ){ |
︙ | ︙ | |||
2230 2231 2232 2233 2234 2235 2236 | #ifdef SQLITE_ENABLE_SQLLOG /* ** Usage: sqlite3_config_sqllog ** ** Zero the SQLITE_CONFIG_SQLLOG configuration */ | | | | | 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 | #ifdef SQLITE_ENABLE_SQLLOG /* ** Usage: sqlite3_config_sqllog ** ** Zero the SQLITE_CONFIG_SQLLOG configuration */ static int SQLITE_TCLAPI test_config_sqllog( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0); return TCL_OK; } #endif /* ** Usage: vfs_current_time_int64 ** ** Return the value returned by the default VFS's xCurrentTimeInt64 method. */ static int SQLITE_TCLAPI vfsCurrentTimeInt64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ i64 t; sqlite3_vfs *pVfs = sqlite3_vfs_find(0); if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } pVfs->xCurrentTimeInt64(pVfs, &t); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t)); return TCL_OK; } #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_get DB DBNAME */ static int SQLITE_TCLAPI test_snapshot_get( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
2306 2307 2308 2309 2310 2311 2312 | } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT */ | | | 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 | } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT */ static int SQLITE_TCLAPI test_snapshot_open( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
2338 2339 2340 2341 2342 2343 2344 | } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_free SNAPSHOT */ | | | | 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 | } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_free SNAPSHOT */ static int SQLITE_TCLAPI test_snapshot_free( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_snapshot *pSnapshot; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT"); return TCL_ERROR; } pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); sqlite3_snapshot_free(pSnapshot); return TCL_OK; } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* ** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2 */ static int SQLITE_TCLAPI test_snapshot_cmp( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int res; sqlite3_snapshot *p1; |
︙ | ︙ | |||
2385 2386 2387 2388 2389 2390 2391 | #endif /* SQLITE_ENABLE_SNAPSHOT */ /* ** Usage: sqlite3_next_stmt DB STMT ** ** Return the next statment in sequence after STMT. */ | | | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 | #endif /* SQLITE_ENABLE_SNAPSHOT */ /* ** Usage: sqlite3_next_stmt DB STMT ** ** Return the next statment in sequence after STMT. */ static int SQLITE_TCLAPI test_next_stmt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; sqlite3 *db = 0; |
︙ | ︙ | |||
2417 2418 2419 2420 2421 2422 2423 | /* ** Usage: sqlite3_stmt_readonly STMT ** ** Return true if STMT is a NULL pointer or a pointer to a statement ** that is guaranteed to leave the database unmodified. */ | | | 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 | /* ** Usage: sqlite3_stmt_readonly STMT ** ** Return true if STMT is a NULL pointer or a pointer to a statement ** that is guaranteed to leave the database unmodified. */ static int SQLITE_TCLAPI test_stmt_readonly( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
2444 2445 2446 2447 2448 2449 2450 | /* ** Usage: sqlite3_stmt_busy STMT ** ** Return true if STMT is a non-NULL pointer to a statement ** that has been stepped but not to completion. */ | | | 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 | /* ** Usage: sqlite3_stmt_busy STMT ** ** Return true if STMT is a non-NULL pointer to a statement ** that has been stepped but not to completion. */ static int SQLITE_TCLAPI test_stmt_busy( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
2470 2471 2472 2473 2474 2475 2476 | } /* ** Usage: uses_stmt_journal STMT ** ** Return true if STMT uses a statement journal. */ | | | 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 | } /* ** Usage: uses_stmt_journal STMT ** ** Return true if STMT uses a statement journal. */ static int SQLITE_TCLAPI uses_stmt_journal( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
2496 2497 2498 2499 2500 2501 2502 | /* ** Usage: sqlite3_reset STMT ** ** Reset a statement handle. */ | | | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 | /* ** Usage: sqlite3_reset STMT ** ** Reset a statement handle. */ static int SQLITE_TCLAPI test_reset( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
2531 2532 2533 2534 2535 2536 2537 | } /* ** Usage: sqlite3_expired STMT ** ** Return TRUE if a recompilation of the statement is recommended. */ | | | 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 | } /* ** Usage: sqlite3_expired STMT ** ** Return TRUE if a recompilation of the statement is recommended. */ static int SQLITE_TCLAPI test_expired( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_DEPRECATED sqlite3_stmt *pStmt; |
︙ | ︙ | |||
2555 2556 2557 2558 2559 2560 2561 | } /* ** Usage: sqlite3_transfer_bindings FROMSTMT TOSTMT ** ** Transfer all bindings from FROMSTMT over to TOSTMT */ | | | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 | } /* ** Usage: sqlite3_transfer_bindings FROMSTMT TOSTMT ** ** Transfer all bindings from FROMSTMT over to TOSTMT */ static int SQLITE_TCLAPI test_transfer_bind( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_DEPRECATED sqlite3_stmt *pStmt1, *pStmt2; |
︙ | ︙ | |||
2582 2583 2584 2585 2586 2587 2588 | /* ** Usage: sqlite3_changes DB ** ** Return the number of changes made to the database by the last SQL ** execution. */ | | | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | /* ** Usage: sqlite3_changes DB ** ** Return the number of changes made to the database by the last SQL ** execution. */ static int SQLITE_TCLAPI test_changes( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ |
︙ | ︙ | |||
2617 2618 2619 2620 2621 2622 2623 | ** string. VALUE is the new value. If FLAGS=="null" then VALUE is ** ignored and the value is set to NULL. If FLAGS=="static" then ** the value is set to the value of a static variable named ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy ** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored ** an a 10-byte blob "abc\000xyz\000pq" is inserted. */ | | | 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 | ** string. VALUE is the new value. If FLAGS=="null" then VALUE is ** ignored and the value is set to NULL. If FLAGS=="static" then ** the value is set to the value of a static variable named ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy ** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored ** an a 10-byte blob "abc\000xyz\000pq" is inserted. */ static int SQLITE_TCLAPI test_bind( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
2739 2740 2741 2742 2743 2744 2745 | sqlite3EndBenignMalloc(); Tcl_EvalObjEx(i, pX, 0); Tcl_DecrRefCount(pX); Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res); return res; } | | | 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 | sqlite3EndBenignMalloc(); Tcl_EvalObjEx(i, pX, 0); Tcl_DecrRefCount(pX); Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res); return res; } static int SQLITE_TCLAPI test_collate( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int val; |
︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 | int nB, const void *zB ){ int nCmp = (nA>nB ? nB : nA); int res = memcmp(zA, zB, nCmp); if( res==0 ) res = nA - nB; return res; } | | | 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 | int nB, const void *zB ){ int nCmp = (nA>nB ? nB : nA); int res = memcmp(zA, zB, nCmp); if( res==0 ) res = nA - nB; return res; } static int SQLITE_TCLAPI test_utf16bin_collate( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
2870 2871 2872 2873 2874 2875 2876 | sqlite3_create_collation( db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func); } /* ** Usage: add_test_collate_needed DB */ | | | 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 | sqlite3_create_collation( db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func); } /* ** Usage: add_test_collate_needed DB */ static int SQLITE_TCLAPI test_collate_needed( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
2921 2922 2923 2924 2925 2926 2927 | if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++; rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ rc = nKey1 - nKey2; } return rc; } | | | 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 | if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++; rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ rc = nKey1 - nKey2; } return rc; } static int SQLITE_TCLAPI add_alignment_test_collations( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc>=2 ){ |
︙ | ︙ | |||
3039 3040 3041 3042 3043 3044 3045 | sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal), -1, SQLITE_TRANSIENT); sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal), -1, SQLITE_TRANSIENT); sqlite3ValueFree(pVal); } #endif /* SQLITE_OMIT_UTF16 */ | | | 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 | sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal), -1, SQLITE_TRANSIENT); sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal), -1, SQLITE_TRANSIENT); sqlite3ValueFree(pVal); } #endif /* SQLITE_OMIT_UTF16 */ static int SQLITE_TCLAPI test_function( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; |
︙ | ︙ | |||
3084 3085 3086 3087 3088 3089 3090 | ** Usage: sqlite3_test_errstr <err code> ** ** Test that the english language string equivalents for sqlite error codes ** are sane. The parameter is an integer representing an sqlite error code. ** The result is a list of two elements, the string representation of the ** error code and the english language explanation. */ | | | 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 | ** Usage: sqlite3_test_errstr <err code> ** ** Test that the english language string equivalents for sqlite error codes ** are sane. The parameter is an integer representing an sqlite error code. ** The result is a list of two elements, the string representation of the ** error code and the english language explanation. */ static int SQLITE_TCLAPI test_errstr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *zCode; int i; |
︙ | ︙ | |||
3117 3118 3119 3120 3121 3122 3123 | ** In the TCL test script, we can add code like this: ** ** if {$i==1485} breakpoint ** ** Then run testfixture in the debugger and wait for the breakpoint to ** fire. Then additional breakpoints can be set to trace down the bug. */ | | | | 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 | ** In the TCL test script, we can add code like this: ** ** if {$i==1485} breakpoint ** ** Then run testfixture in the debugger and wait for the breakpoint to ** fire. Then additional breakpoints can be set to trace down the bug. */ static int SQLITE_TCLAPI test_breakpoint( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ return TCL_OK; /* Do nothing */ } /* ** Usage: sqlite3_bind_zeroblob STMT IDX N ** ** Test the sqlite3_bind_zeroblob interface. STMT is a prepared statement. ** IDX is the index of a wildcard in the prepared statement. This command ** binds a N-byte zero-filled BLOB to the wildcard. */ static int SQLITE_TCLAPI test_bind_zeroblob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3169 3170 3171 3172 3173 3174 3175 | /* ** Usage: sqlite3_bind_zeroblob64 STMT IDX N ** ** Test the sqlite3_bind_zeroblob64 interface. STMT is a prepared statement. ** IDX is the index of a wildcard in the prepared statement. This command ** binds a N-byte zero-filled BLOB to the wildcard. */ | | | 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 | /* ** Usage: sqlite3_bind_zeroblob64 STMT IDX N ** ** Test the sqlite3_bind_zeroblob64 interface. STMT is a prepared statement. ** IDX is the index of a wildcard in the prepared statement. This command ** binds a N-byte zero-filled BLOB to the wildcard. */ static int SQLITE_TCLAPI test_bind_zeroblob64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3206 3207 3208 3209 3210 3211 3212 | /* ** Usage: sqlite3_bind_int STMT N VALUE ** ** Test the sqlite3_bind_int interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 32-bit integer VALUE to that wildcard. */ | | | 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 | /* ** Usage: sqlite3_bind_int STMT N VALUE ** ** Test the sqlite3_bind_int interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 32-bit integer VALUE to that wildcard. */ static int SQLITE_TCLAPI test_bind_int( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 | if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_int64 STMT N VALUE ** ** Test the sqlite3_bind_int64 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 | if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: intarray_addr INT ... ** ** Return the address of a C-language array of 32-bit integers. ** ** Space to hold the array is obtained from malloc(). Call this procedure once ** with no arguments in order to release memory. Each call to this procedure ** overwrites the previous array. */ static int SQLITE_TCLAPI test_intarray_addr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; static int *p = 0; sqlite3_free(p); p = 0; if( objc>1 ){ p = sqlite3_malloc( sizeof(p[0])*(objc-1) ); if( p==0 ) return TCL_ERROR; for(i=0; i<objc-1; i++){ if( Tcl_GetIntFromObj(interp, objv[1+i], &p[i]) ){ sqlite3_free(p); p = 0; return TCL_ERROR; } } } Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p)); return TCL_OK; } /* ** Usage: intarray_addr INT ... ** ** Return the address of a C-language array of 32-bit integers. ** ** Space to hold the array is obtained from malloc(). Call this procedure once ** with no arguments in order to release memory. Each call to this procedure ** overwrites the previous array. */ static int SQLITE_TCLAPI test_int64array_addr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; static sqlite3_int64 *p = 0; sqlite3_free(p); p = 0; if( objc>1 ){ p = sqlite3_malloc( sizeof(p[0])*(objc-1) ); if( p==0 ) return TCL_ERROR; for(i=0; i<objc-1; i++){ Tcl_WideInt v; if( Tcl_GetWideIntFromObj(interp, objv[1+i], &v) ){ sqlite3_free(p); p = 0; return TCL_ERROR; } p[i] = v; } } Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p)); return TCL_OK; } /* ** Usage: doublearray_addr INT ... ** ** Return the address of a C-language array of doubles. ** ** Space to hold the array is obtained from malloc(). Call this procedure once ** with no arguments in order to release memory. Each call to this procedure ** overwrites the previous array. */ static int SQLITE_TCLAPI test_doublearray_addr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; static double *p = 0; sqlite3_free(p); p = 0; if( objc>1 ){ p = sqlite3_malloc( sizeof(p[0])*(objc-1) ); if( p==0 ) return TCL_ERROR; for(i=0; i<objc-1; i++){ if( Tcl_GetDoubleFromObj(interp, objv[1+i], &p[i]) ){ sqlite3_free(p); p = 0; return TCL_ERROR; } } } Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p)); return TCL_OK; } /* ** Usage: textarray_addr TEXT ... ** ** Return the address of a C-language array of strings. ** ** Space to hold the array is obtained from malloc(). Call this procedure once ** with no arguments in order to release memory. Each call to this procedure ** overwrites the previous array. */ static int SQLITE_TCLAPI test_textarray_addr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; static int n = 0; static char **p = 0; for(i=0; i<n; i++) sqlite3_free(p[i]); sqlite3_free(p); p = 0; if( objc>1 ){ p = sqlite3_malloc( sizeof(p[0])*(objc-1) ); if( p==0 ) return TCL_ERROR; for(i=0; i<objc-1; i++){ p[i] = sqlite3_mprintf("%s", Tcl_GetString(objv[1+i])); } } n = objc-1; Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p)); return TCL_OK; } /* ** Usage: sqlite3_bind_int64 STMT N VALUE ** ** Test the sqlite3_bind_int64 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ static int SQLITE_TCLAPI test_bind_int64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3282 3283 3284 3285 3286 3287 3288 | /* ** Usage: sqlite3_bind_double STMT N VALUE ** ** Test the sqlite3_bind_double interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ | | | 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 | /* ** Usage: sqlite3_bind_double STMT N VALUE ** ** Test the sqlite3_bind_double interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ static int SQLITE_TCLAPI test_bind_double( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3358 3359 3360 3361 3362 3363 3364 | /* ** Usage: sqlite3_bind_null STMT N ** ** Test the sqlite3_bind_null interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a NULL to the wildcard. */ | | | 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 | /* ** Usage: sqlite3_bind_null STMT N ** ** Test the sqlite3_bind_null interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a NULL to the wildcard. */ static int SQLITE_TCLAPI test_bind_null( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3394 3395 3396 3397 3398 3399 3400 | ** Usage: sqlite3_bind_text STMT N STRING BYTES ** ** Test the sqlite3_bind_text interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-8 string STRING to the wildcard. The string is BYTES bytes ** long. */ | | | 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 | ** Usage: sqlite3_bind_text STMT N STRING BYTES ** ** Test the sqlite3_bind_text interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-8 string STRING to the wildcard. The string is BYTES bytes ** long. */ static int SQLITE_TCLAPI test_bind_text( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; |
︙ | ︙ | |||
3435 3436 3437 3438 3439 3440 3441 | ** Usage: sqlite3_bind_text16 ?-static? STMT N STRING BYTES ** ** Test the sqlite3_bind_text16 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-16 string STRING to the wildcard. The string is BYTES bytes ** long. */ | | | 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 | ** Usage: sqlite3_bind_text16 ?-static? STMT N STRING BYTES ** ** Test the sqlite3_bind_text16 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-16 string STRING to the wildcard. The string is BYTES bytes ** long. */ static int SQLITE_TCLAPI test_bind_text16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; |
︙ | ︙ | |||
3483 3484 3485 3486 3487 3488 3489 | /* ** Usage: sqlite3_bind_blob ?-static? STMT N DATA BYTES ** ** Test the sqlite3_bind_blob interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a BLOB to the wildcard. The BLOB is BYTES bytes in size. */ | | | | > > > > > > > > > | | 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 | /* ** Usage: sqlite3_bind_blob ?-static? STMT N DATA BYTES ** ** Test the sqlite3_bind_blob interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a BLOB to the wildcard. The BLOB is BYTES bytes in size. */ static int SQLITE_TCLAPI test_bind_blob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int len, idx; int bytes; char *value; int rc; sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT; if( objc!=5 && objc!=6 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0); return TCL_ERROR; } if( objc==6 ){ xDestructor = SQLITE_STATIC; objv++; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; if( bytes>len ){ char zBuf[200]; sqlite3_snprintf(sizeof(zBuf), zBuf, "cannot use %d blob bytes, have %d", bytes, len); Tcl_AppendResult(interp, zBuf, -1); return TCL_ERROR; } rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_parameter_count STMT ** ** Return the number of wildcards in the given statement. */ static int SQLITE_TCLAPI test_bind_parameter_count( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
3550 3551 3552 3553 3554 3555 3556 | /* ** Usage: sqlite3_bind_parameter_name STMT N ** ** Return the name of the Nth wildcard. The first wildcard is 1. ** An empty string is returned if N is out of range or if the wildcard ** is nameless. */ | | | 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 | /* ** Usage: sqlite3_bind_parameter_name STMT N ** ** Return the name of the Nth wildcard. The first wildcard is 1. ** An empty string is returned if N is out of range or if the wildcard ** is nameless. */ static int SQLITE_TCLAPI test_bind_parameter_name( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int i; |
︙ | ︙ | |||
3577 3578 3579 3580 3581 3582 3583 | /* ** Usage: sqlite3_bind_parameter_index STMT NAME ** ** Return the index of the wildcard called NAME. Return 0 if there is ** no such wildcard. */ | | | 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 | /* ** Usage: sqlite3_bind_parameter_index STMT NAME ** ** Return the index of the wildcard called NAME. Return 0 if there is ** no such wildcard. */ static int SQLITE_TCLAPI test_bind_parameter_index( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
3602 3603 3604 3605 3606 3607 3608 | return TCL_OK; } /* ** Usage: sqlite3_clear_bindings STMT ** */ | | | | 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 | return TCL_OK; } /* ** Usage: sqlite3_clear_bindings STMT ** */ static int SQLITE_TCLAPI test_clear_bindings( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt))); return TCL_OK; } /* ** Usage: sqlite3_sleep MILLISECONDS */ static int SQLITE_TCLAPI test_sleep( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ms; |
︙ | ︙ | |||
3647 3648 3649 3650 3651 3652 3653 | /* ** Usage: sqlite3_extended_errcode DB ** ** Return the string representation of the most recent sqlite3_* API ** error code. e.g. "SQLITE_ERROR". */ | | | 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 | /* ** Usage: sqlite3_extended_errcode DB ** ** Return the string representation of the most recent sqlite3_* API ** error code. e.g. "SQLITE_ERROR". */ static int SQLITE_TCLAPI test_ex_errcode( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
3674 3675 3676 3677 3678 3679 3680 | /* ** Usage: sqlite3_errcode DB ** ** Return the string representation of the most recent sqlite3_* API ** error code. e.g. "SQLITE_ERROR". */ | | | 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 | /* ** Usage: sqlite3_errcode DB ** ** Return the string representation of the most recent sqlite3_* API ** error code. e.g. "SQLITE_ERROR". */ static int SQLITE_TCLAPI test_errcode( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
3700 3701 3702 3703 3704 3705 3706 | /* ** Usage: sqlite3_errmsg DB ** ** Returns the UTF-8 representation of the error message string for the ** most recent sqlite3_* API call. */ | | | 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 | /* ** Usage: sqlite3_errmsg DB ** ** Returns the UTF-8 representation of the error message string for the ** most recent sqlite3_* API call. */ static int SQLITE_TCLAPI test_errmsg( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zErr; |
︙ | ︙ | |||
3729 3730 3731 3732 3733 3734 3735 | ** Usage: test_errmsg16 DB ** ** Returns the UTF-16 representation of the error message string for the ** most recent sqlite3_* API call. This is a byte array object at the TCL ** level, and it includes the 0x00 0x00 terminator bytes at the end of the ** UTF-16 string. */ | | | 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 | ** Usage: test_errmsg16 DB ** ** Returns the UTF-16 representation of the error message string for the ** most recent sqlite3_* API call. This is a byte array object at the TCL ** level, and it includes the 0x00 0x00 terminator bytes at the end of the ** UTF-16 string. */ static int SQLITE_TCLAPI test_errmsg16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; |
︙ | ︙ | |||
3766 3767 3768 3769 3770 3771 3772 | ** Usage: sqlite3_prepare DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ | | | 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 | ** Usage: sqlite3_prepare DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ static int SQLITE_TCLAPI test_prepare( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zSql; |
︙ | ︙ | |||
3823 3824 3825 3826 3827 3828 3829 | ** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ | | | 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 | ** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ static int SQLITE_TCLAPI test_prepare_v2( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zSql; |
︙ | ︙ | |||
3891 3892 3893 3894 3895 3896 3897 | /* ** Usage: sqlite3_prepare_tkt3134 DB ** ** Generate a prepared statement for a zero-byte string as a test ** for ticket #3134. The string should be preceded by a zero byte. */ | | | 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 | /* ** Usage: sqlite3_prepare_tkt3134 DB ** ** Generate a prepared statement for a zero-byte string as a test ** for ticket #3134. The string should be preceded by a zero byte. */ static int SQLITE_TCLAPI test_prepare_tkt3134( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; static const char zSql[] = "\000SELECT 1"; |
︙ | ︙ | |||
3934 3935 3936 3937 3938 3939 3940 | ** Usage: sqlite3_prepare16 DB sql bytes tailvar ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ | | | 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 | ** Usage: sqlite3_prepare16 DB sql bytes tailvar ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ static int SQLITE_TCLAPI test_prepare16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; |
︙ | ︙ | |||
3994 3995 3996 3997 3998 3999 4000 | ** Usage: sqlite3_prepare16_v2 DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ | | | 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 | ** Usage: sqlite3_prepare16_v2 DB sql bytes ?tailvar? ** ** Compile up to <bytes> bytes of the supplied SQL string <sql> using ** database handle <DB>. The parameter <tailval> is the name of a global ** variable that is set to the unused portion of <sql> (if any). A ** STMT handle is returned. */ static int SQLITE_TCLAPI test_prepare16_v2( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; |
︙ | ︙ | |||
4049 4050 4051 4052 4053 4054 4055 | #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_open filename ?options-list? */ | | | 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 | #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_open filename ?options-list? */ static int SQLITE_TCLAPI test_open( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; sqlite3 *db; |
︙ | ︙ | |||
4076 4077 4078 4079 4080 4081 4082 | Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: sqlite3_open_v2 FILENAME FLAGS VFS */ | | | 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 | Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: sqlite3_open_v2 FILENAME FLAGS VFS */ static int SQLITE_TCLAPI test_open_v2( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; const char *zVfs; |
︙ | ︙ | |||
4146 4147 4148 4149 4150 4151 4152 | Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: sqlite3_open16 filename options */ | | | 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 | Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: sqlite3_open16 filename options */ static int SQLITE_TCLAPI test_open16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 const void *zFilename; |
︙ | ︙ | |||
4178 4179 4180 4181 4182 4183 4184 | /* ** Usage: sqlite3_complete16 <UTF-16 string> ** ** Return 1 if the supplied argument is a complete SQL statement, or zero ** otherwise. */ | | | 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 | /* ** Usage: sqlite3_complete16 <UTF-16 string> ** ** Return 1 if the supplied argument is a complete SQL statement, or zero ** otherwise. */ static int SQLITE_TCLAPI test_complete16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #if !defined(SQLITE_OMIT_COMPLETE) && !defined(SQLITE_OMIT_UTF16) char *zBuf; |
︙ | ︙ | |||
4203 4204 4205 4206 4207 4208 4209 | } /* ** Usage: sqlite3_step STMT ** ** Advance the statement to the next row. */ | | | 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 | } /* ** Usage: sqlite3_step STMT ** ** Advance the statement to the next row. */ static int SQLITE_TCLAPI test_step( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
4226 4227 4228 4229 4230 4231 4232 | rc = sqlite3_step(pStmt); /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } | | > > > > > > > > > > > > > > > > > > > > | | 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 | rc = sqlite3_step(pStmt); /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } static int SQLITE_TCLAPI test_sql( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE); return TCL_OK; } static int SQLITE_TCLAPI test_ex_sql( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; char *z; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; z = sqlite3_expanded_sql(pStmt); Tcl_SetResult(interp, z, TCL_VOLATILE); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_column_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int SQLITE_TCLAPI test_column_count( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
4274 4275 4276 4277 4278 4279 4280 | } /* ** Usage: sqlite3_column_type STMT column ** ** Return the type of the data in column 'column' of the current row. */ | | | 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 | } /* ** Usage: sqlite3_column_type STMT column ** ** Return the type of the data in column 'column' of the current row. */ static int SQLITE_TCLAPI test_column_type( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4323 4324 4325 4326 4327 4328 4329 | /* ** Usage: sqlite3_column_int64 STMT column ** ** Return the data in column 'column' of the current row cast as an ** wide (64-bit) integer. */ | | | 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 | /* ** Usage: sqlite3_column_int64 STMT column ** ** Return the data in column 'column' of the current row cast as an ** wide (64-bit) integer. */ static int SQLITE_TCLAPI test_column_int64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4350 4351 4352 4353 4354 4355 4356 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal)); return TCL_OK; } /* ** Usage: sqlite3_column_blob STMT column */ | | | 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal)); return TCL_OK; } /* ** Usage: sqlite3_column_blob STMT column */ static int SQLITE_TCLAPI test_column_blob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4382 4383 4384 4385 4386 4387 4388 | } /* ** Usage: sqlite3_column_double STMT column ** ** Return the data in column 'column' of the current row cast as a double. */ | | | 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 | } /* ** Usage: sqlite3_column_double STMT column ** ** Return the data in column 'column' of the current row cast as a double. */ static int SQLITE_TCLAPI test_column_double( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4411 4412 4413 4414 4415 4416 4417 | } /* ** Usage: sqlite3_data_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ | | | 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 | } /* ** Usage: sqlite3_data_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int SQLITE_TCLAPI test_data_count( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
4438 4439 4440 4441 4442 4443 4444 | /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ | | | 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 | /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ static int SQLITE_TCLAPI test_stmt_utf8( void * clientData, /* Pointer to SQLite API function to be invoke */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4465 4466 4467 4468 4469 4470 4471 | zRet = xFunc(pStmt, col); if( zRet ){ Tcl_SetResult(interp, (char *)zRet, 0); } return TCL_OK; } | | | 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 | zRet = xFunc(pStmt, col); if( zRet ){ Tcl_SetResult(interp, (char *)zRet, 0); } return TCL_OK; } static int SQLITE_TCLAPI test_global_recover( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_DEPRECATED int rc; |
︙ | ︙ | |||
4490 4491 4492 4493 4494 4495 4496 | /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ | | | 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 | /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ static int SQLITE_TCLAPI test_stmt_utf16( void * clientData, /* Pointer to SQLite API function to be invoked */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; |
︙ | ︙ | |||
4534 4535 4536 4537 4538 4539 4540 | ** Usage: sqlite3_column_int STMT column ** ** Usage: sqlite3_column_bytes STMT column ** ** Usage: sqlite3_column_bytes16 STMT column ** */ | | | 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 | ** Usage: sqlite3_column_int STMT column ** ** Usage: sqlite3_column_bytes STMT column ** ** Usage: sqlite3_column_bytes16 STMT column ** */ static int SQLITE_TCLAPI test_stmt_int( void * clientData, /* Pointer to SQLite API function to be invoked */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; |
︙ | ︙ | |||
4563 4564 4565 4566 4567 4568 4569 | } /* ** Usage: sqlite_set_magic DB MAGIC-NUMBER ** ** Set the db->magic value. This is used to test error recovery logic. */ | | | 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 | } /* ** Usage: sqlite_set_magic DB MAGIC-NUMBER ** ** Set the db->magic value. This is used to test error recovery logic. */ static int SQLITE_TCLAPI sqlite_set_magic( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; if( argc!=3 ){ |
︙ | ︙ | |||
4595 4596 4597 4598 4599 4600 4601 | } /* ** Usage: sqlite3_interrupt DB ** ** Trigger an interrupt on DB */ | | | 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 | } /* ** Usage: sqlite3_interrupt DB ** ** Trigger an interrupt on DB */ static int SQLITE_TCLAPI test_interrupt( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; if( argc!=2 ){ |
︙ | ︙ | |||
4636 4637 4638 4639 4640 4641 4642 | } /* ** Usage: sqlite3_stack_used DB SQL ** ** Try to measure the amount of stack space used by a call to sqlite3_exec */ | | | 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 | } /* ** Usage: sqlite3_stack_used DB SQL ** ** Try to measure the amount of stack space used by a call to sqlite3_exec */ static int SQLITE_TCLAPI test_stack_used( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; int i; |
︙ | ︙ | |||
4664 4665 4666 4667 4668 4669 4670 | /* ** Usage: sqlite_delete_function DB function-name ** ** Delete the user function 'function-name' from database handle DB. It ** is assumed that the user function was created as UTF8, any number of ** arguments (the way the TCL interface does it). */ | | | 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 | /* ** Usage: sqlite_delete_function DB function-name ** ** Delete the user function 'function-name' from database handle DB. It ** is assumed that the user function was created as UTF8, any number of ** arguments (the way the TCL interface does it). */ static int SQLITE_TCLAPI delete_function( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
4690 4691 4692 4693 4694 4695 4696 | /* ** Usage: sqlite_delete_collation DB collation-name ** ** Delete the collation sequence 'collation-name' from database handle ** DB. It is assumed that the collation sequence was created as UTF8 (the ** way the TCL interface does it). */ | | | 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 | /* ** Usage: sqlite_delete_collation DB collation-name ** ** Delete the collation sequence 'collation-name' from database handle ** DB. It is assumed that the collation sequence was created as UTF8 (the ** way the TCL interface does it). */ static int SQLITE_TCLAPI delete_collation( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
4715 4716 4717 4718 4719 4720 4721 | /* ** Usage: sqlite3_get_autocommit DB ** ** Return true if the database DB is currently in auto-commit mode. ** Return false if not. */ | | | 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 | /* ** Usage: sqlite3_get_autocommit DB ** ** Return true if the database DB is currently in auto-commit mode. ** Return false if not. */ static int SQLITE_TCLAPI get_autocommit( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ char zBuf[30]; sqlite3 *db; |
︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 | /* ** Usage: sqlite3_busy_timeout DB MS ** ** Set the busy timeout. This is more easily done using the timeout ** method of the TCL interface. But we need a way to test the case ** where it returns SQLITE_MISUSE. */ | | | 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 | /* ** Usage: sqlite3_busy_timeout DB MS ** ** Set the busy timeout. This is more easily done using the timeout ** method of the TCL interface. But we need a way to test the case ** where it returns SQLITE_MISUSE. */ static int SQLITE_TCLAPI test_busy_timeout( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ int rc, ms; sqlite3 *db; |
︙ | ︙ | |||
4767 4768 4769 4770 4771 4772 4773 | /* ** Usage: tcl_variable_type VARIABLENAME ** ** Return the name of the internal representation for the ** value of the given variable. */ | | | 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 | /* ** Usage: tcl_variable_type VARIABLENAME ** ** Return the name of the internal representation for the ** value of the given variable. */ static int SQLITE_TCLAPI tcl_variable_type( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj *pVar; if( objc!=2 ){ |
︙ | ︙ | |||
4793 4794 4795 4796 4797 4798 4799 | /* ** Usage: sqlite3_release_memory ?N? ** ** Attempt to release memory currently held but not actually required. ** The integer N is the number of bytes we are trying to release. The ** return value is the amount of memory actually released. */ | | | 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 | /* ** Usage: sqlite3_release_memory ?N? ** ** Attempt to release memory currently held but not actually required. ** The integer N is the number of bytes we are trying to release. The ** return value is the amount of memory actually released. */ static int SQLITE_TCLAPI test_release_memory( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO) int N; |
︙ | ︙ | |||
4824 4825 4826 4827 4828 4829 4830 | /* ** Usage: sqlite3_db_release_memory DB ** ** Attempt to release memory currently held by database DB. Return the ** result code (which in the current implementation is always zero). */ | | | 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 | /* ** Usage: sqlite3_db_release_memory DB ** ** Attempt to release memory currently held by database DB. Return the ** result code (which in the current implementation is always zero). */ static int SQLITE_TCLAPI test_db_release_memory( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
4847 4848 4849 4850 4851 4852 4853 | } /* ** Usage: sqlite3_db_cacheflush DB ** ** Attempt to flush any dirty pages to disk. */ | | | 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 | } /* ** Usage: sqlite3_db_cacheflush DB ** ** Attempt to flush any dirty pages to disk. */ static int SQLITE_TCLAPI test_db_cacheflush( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
4875 4876 4877 4878 4879 4880 4881 | } /* ** Usage: sqlite3_system_errno DB ** ** Return the low-level system errno value. */ | | | 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 | } /* ** Usage: sqlite3_system_errno DB ** ** Return the low-level system errno value. */ static int SQLITE_TCLAPI test_system_errno( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int iErrno; |
︙ | ︙ | |||
4898 4899 4900 4901 4902 4903 4904 | } /* ** Usage: sqlite3_db_filename DB DBNAME ** ** Return the name of a file associated with a database. */ | | | 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 | } /* ** Usage: sqlite3_db_filename DB DBNAME ** ** Return the name of a file associated with a database. */ static int SQLITE_TCLAPI test_db_filename( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zDbName; |
︙ | ︙ | |||
4922 4923 4924 4925 4926 4927 4928 | /* ** Usage: sqlite3_db_readonly DB DBNAME ** ** Return 1 or 0 if DBNAME is readonly or not. Return -1 if DBNAME does ** not exist. */ | | | 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 | /* ** Usage: sqlite3_db_readonly DB DBNAME ** ** Return 1 or 0 if DBNAME is readonly or not. Return -1 if DBNAME does ** not exist. */ static int SQLITE_TCLAPI test_db_readonly( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zDbName; |
︙ | ︙ | |||
4947 4948 4949 4950 4951 4952 4953 | /* ** Usage: sqlite3_soft_heap_limit ?N? ** ** Query or set the soft heap limit for the current thread. The ** limit is only changed if the N is present. The previous limit ** is returned. */ | | | 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 | /* ** Usage: sqlite3_soft_heap_limit ?N? ** ** Query or set the soft heap limit for the current thread. The ** limit is only changed if the N is present. The previous limit ** is returned. */ static int SQLITE_TCLAPI test_soft_heap_limit( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_int64 amt; Tcl_WideInt N = -1; |
︙ | ︙ | |||
4972 4973 4974 4975 4976 4977 4978 | } /* ** Usage: sqlite3_thread_cleanup ** ** Call the sqlite3_thread_cleanup API. */ | | | | 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 | } /* ** Usage: sqlite3_thread_cleanup ** ** Call the sqlite3_thread_cleanup API. */ static int SQLITE_TCLAPI test_thread_cleanup( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_DEPRECATED sqlite3_thread_cleanup(); #endif return TCL_OK; } /* ** Usage: sqlite3_pager_refcounts DB ** ** Return a list of numbers which are the PagerRefcount for all ** pagers on each database connection. */ static int SQLITE_TCLAPI test_pager_refcounts( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int i; |
︙ | ︙ | |||
5036 5037 5038 5039 5040 5041 5042 | ** TCL build to see whether or not it supports 64-bit integers. It ** returns TRUE if it does and FALSE if not. ** ** This command is used to warn users that their TCL build is defective ** and that the errors they are seeing in the test scripts might be ** a result of their defective TCL rather than problems in SQLite. */ | | | 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 | ** TCL build to see whether or not it supports 64-bit integers. It ** returns TRUE if it does and FALSE if not. ** ** This command is used to warn users that their TCL build is defective ** and that the errors they are seeing in the test scripts might be ** a result of their defective TCL rather than problems in SQLite. */ static int SQLITE_TCLAPI working_64bit_int( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_Obj *pTestObj; int working = 0; |
︙ | ︙ | |||
5061 5062 5063 5064 5065 5066 5067 | ** tclcmd: vfs_unlink_test ** ** This TCL command unregisters the primary VFS and then registers ** it back again. This is used to test the ability to register a ** VFS when none are previously registered, and the ability to ** unregister the only available VFS. Ticket #2738 */ | | | 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 | ** tclcmd: vfs_unlink_test ** ** This TCL command unregisters the primary VFS and then registers ** it back again. This is used to test the ability to register a ** VFS when none are previously registered, and the ability to ** unregister the only available VFS. Ticket #2738 */ static int SQLITE_TCLAPI vfs_unlink_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; sqlite3_vfs *pMain; |
︙ | ︙ | |||
5163 5164 5165 5166 5167 5168 5169 | /* ** tclcmd: vfs_initfail_test ** ** This TCL command attempts to vfs_find and vfs_register when the ** sqlite3_initialize() interface is failing. All calls should fail. */ | | | 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 | /* ** tclcmd: vfs_initfail_test ** ** This TCL command attempts to vfs_find and vfs_register when the ** sqlite3_initialize() interface is failing. All calls should fail. */ static int SQLITE_TCLAPI vfs_initfail_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_vfs one; one.zName = "__one"; |
︙ | ︙ | |||
5191 5192 5193 5194 5195 5196 5197 | static int nVfs = 0; /* ** tclcmd: vfs_unregister_all ** ** Unregister all VFSes. */ | | | 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 | static int nVfs = 0; /* ** tclcmd: vfs_unregister_all ** ** Unregister all VFSes. */ static int SQLITE_TCLAPI vfs_unregister_all( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; for(i=0; i<ArraySize(apVfs); i++){ |
︙ | ︙ | |||
5213 5214 5215 5216 5217 5218 5219 | /* ** tclcmd: vfs_reregister_all ** ** Restore all VFSes that were removed using vfs_unregister_all. Taking ** care to put the linked list back together in the same order as it was ** in before vfs_unregister_all was invoked. */ | | | | 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 | /* ** tclcmd: vfs_reregister_all ** ** Restore all VFSes that were removed using vfs_unregister_all. Taking ** care to put the linked list back together in the same order as it was ** in before vfs_unregister_all was invoked. */ static int SQLITE_TCLAPI vfs_reregister_all( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; for(i=nVfs-1; i>=0; i--){ sqlite3_vfs_register(apVfs[i], 1); } return TCL_OK; } /* ** tclcmd: file_control_test DB ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the same. */ static int SQLITE_TCLAPI file_control_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int iArg = 0; sqlite3 *db; |
︙ | ︙ | |||
5268 5269 5270 5271 5272 5273 5274 | /* ** tclcmd: file_control_lasterrno_test DB ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_LAST_ERRNO verb. */ | | | 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 | /* ** tclcmd: file_control_lasterrno_test DB ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_LAST_ERRNO verb. */ static int SQLITE_TCLAPI file_control_lasterrno_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int iArg = 0; sqlite3 *db; |
︙ | ︙ | |||
5306 5307 5308 5309 5310 5311 5312 | /* ** tclcmd: file_control_chunksize_test DB DBNAME SIZE ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. */ | | | 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 | /* ** tclcmd: file_control_chunksize_test DB DBNAME SIZE ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. */ static int SQLITE_TCLAPI file_control_chunksize_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int nSize; /* New chunk size */ char *zDb; /* Db name ("main", "temp" etc.) */ |
︙ | ︙ | |||
5343 5344 5345 5346 5347 5348 5349 | /* ** tclcmd: file_control_sizehint_test DB DBNAME SIZE ** ** This TCL command runs the sqlite3_file_control interface ** with SQLITE_FCNTL_SIZE_HINT */ | | | 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 | /* ** tclcmd: file_control_sizehint_test DB DBNAME SIZE ** ** This TCL command runs the sqlite3_file_control interface ** with SQLITE_FCNTL_SIZE_HINT */ static int SQLITE_TCLAPI file_control_sizehint_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_WideInt nSize; /* Hinted size */ char *zDb; /* Db name ("main", "temp" etc.) */ |
︙ | ︙ | |||
5381 5382 5383 5384 5385 5386 5387 | /* ** tclcmd: file_control_lockproxy_test DB PWD ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. */ | | | 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 | /* ** tclcmd: file_control_lockproxy_test DB PWD ** ** This TCL command runs the sqlite3_file_control interface and ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and ** SQLITE_SET_LOCKPROXYFILE verbs. */ static int SQLITE_TCLAPI file_control_lockproxy_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; |
︙ | ︙ | |||
5451 5452 5453 5454 5455 5456 5457 | #if SQLITE_OS_WIN /* ** tclcmd: file_control_win32_av_retry DB NRETRY DELAY ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_WIN32_AV_RETRY opcode. */ | | | 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 | #if SQLITE_OS_WIN /* ** tclcmd: file_control_win32_av_retry DB NRETRY DELAY ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_WIN32_AV_RETRY opcode. */ static int SQLITE_TCLAPI file_control_win32_av_retry( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5484 5485 5486 5487 5488 5489 5490 | /* ** tclcmd: file_control_win32_set_handle DB HANDLE ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode. */ | | | 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 | /* ** tclcmd: file_control_win32_set_handle DB HANDLE ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode. */ static int SQLITE_TCLAPI file_control_win32_set_handle( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5520 5521 5522 5523 5524 5525 5526 | /* ** tclcmd: file_control_persist_wal DB PERSIST-FLAG ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_PERSIST_WAL opcode. */ | | | 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 | /* ** tclcmd: file_control_persist_wal DB PERSIST-FLAG ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_PERSIST_WAL opcode. */ static int SQLITE_TCLAPI file_control_persist_wal( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5552 5553 5554 5555 5556 5557 5558 | /* ** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode. */ | | | 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 | /* ** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG ** ** This TCL command runs the sqlite3_file_control interface with ** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode. */ static int SQLITE_TCLAPI file_control_powersafe_overwrite( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5584 5585 5586 5587 5588 5589 5590 | /* ** tclcmd: file_control_vfsname DB ?AUXDB? ** ** Return a string that describes the stack of VFSes. */ | | | 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 | /* ** tclcmd: file_control_vfsname DB ?AUXDB? ** ** Return a string that describes the stack of VFSes. */ static int SQLITE_TCLAPI file_control_vfsname( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDbName = "main"; |
︙ | ︙ | |||
5616 5617 5618 5619 5620 5621 5622 | } /* ** tclcmd: file_control_tempfilename DB ?AUXDB? ** ** Return a string that is a temporary filename */ | | | 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 | } /* ** tclcmd: file_control_tempfilename DB ?AUXDB? ** ** Return a string that is a temporary filename */ static int SQLITE_TCLAPI file_control_tempfilename( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDbName = "main"; |
︙ | ︙ | |||
5649 5650 5651 5652 5653 5654 5655 | /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ | | | 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 | /* ** tclcmd: sqlite3_vfs_list ** ** Return a tcl list containing the names of all registered vfs's. */ static int SQLITE_TCLAPI vfs_list( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_vfs *pVfs; Tcl_Obj *pRet = Tcl_NewObj(); |
︙ | ︙ | |||
5674 5675 5676 5677 5678 5679 5680 | /* ** tclcmd: sqlite3_limit DB ID VALUE ** ** This TCL command runs the sqlite3_limit interface and ** verifies correct operation of the same. */ | | | 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 | /* ** tclcmd: sqlite3_limit DB ID VALUE ** ** This TCL command runs the sqlite3_limit interface and ** verifies correct operation of the same. */ static int SQLITE_TCLAPI test_limit( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5737 5738 5739 5740 5741 5742 5743 | /* ** tclcmd: save_prng_state ** ** Save the state of the pseudo-random number generator. ** At the same time, verify that sqlite3_test_control works even when ** called with an out-of-range opcode. */ | | | | | | | | 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 | /* ** tclcmd: save_prng_state ** ** Save the state of the pseudo-random number generator. ** At the same time, verify that sqlite3_test_control works even when ** called with an out-of-range opcode. */ static int SQLITE_TCLAPI save_prng_state( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int rc = sqlite3_test_control(9999); assert( rc==0 ); rc = sqlite3_test_control(-1); assert( rc==0 ); sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SAVE); return TCL_OK; } /* ** tclcmd: restore_prng_state */ static int SQLITE_TCLAPI restore_prng_state( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESTORE); return TCL_OK; } /* ** tclcmd: reset_prng_state */ static int SQLITE_TCLAPI reset_prng_state( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET); return TCL_OK; } /* ** tclcmd: database_may_be_corrupt ** ** Indicate that database files might be corrupt. In other words, set the normal ** state of operation. */ static int SQLITE_TCLAPI database_may_be_corrupt( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0); return TCL_OK; } /* ** tclcmd: database_never_corrupt ** ** Indicate that database files are always well-formed. This enables extra assert() ** statements that test conditions that are always true for well-formed databases. */ static int SQLITE_TCLAPI database_never_corrupt( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1); return TCL_OK; } /* ** tclcmd: pcache_stats */ static int SQLITE_TCLAPI test_pcache_stats( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int nMin; int nMax; |
︙ | ︙ | |||
5851 5852 5853 5854 5855 5856 5857 | } #endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */ /* ** tclcmd: sqlite3_unlock_notify db */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | | | 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 | } #endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */ /* ** tclcmd: sqlite3_unlock_notify db */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY static int SQLITE_TCLAPI test_unlock_notify( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
5877 5878 5879 5880 5881 5882 5883 | return TCL_OK; } #endif /* ** tclcmd: sqlite3_wal_checkpoint db ?NAME? */ | | | 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 | return TCL_OK; } #endif /* ** tclcmd: sqlite3_wal_checkpoint db ?NAME? */ static int SQLITE_TCLAPI test_wal_checkpoint( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zDb = 0; sqlite3 *db; |
︙ | ︙ | |||
5921 5922 5923 5924 5925 5926 5927 | ** ** Otherwise, this command returns a list of three integers. The first integer ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers ** are the values returned via the output parameters by wal_checkpoint_v2() - ** the number of frames in the log and the number of frames in the log ** that have been checkpointed. */ | | | 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 | ** ** Otherwise, this command returns a list of three integers. The first integer ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers ** are the values returned via the output parameters by wal_checkpoint_v2() - ** the number of frames in the log and the number of frames in the log ** that have been checkpointed. */ static int SQLITE_TCLAPI test_wal_checkpoint_v2( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zDb = 0; sqlite3 *db; |
︙ | ︙ | |||
5977 5978 5979 5980 5981 5982 5983 | return TCL_OK; } /* ** tclcmd: sqlite3_wal_autocheckpoint db VALUE */ | | | 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 | return TCL_OK; } /* ** tclcmd: sqlite3_wal_autocheckpoint db VALUE */ static int SQLITE_TCLAPI test_wal_autocheckpoint( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ | |||
6028 6029 6030 6031 6032 6033 6034 | Tcl_ListObjAppendElement( 0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1) ); Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1)); Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); Tcl_DecrRefCount(pNew); } | | | 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 | Tcl_ListObjAppendElement( 0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1) ); Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1)); Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); Tcl_DecrRefCount(pNew); } static int SQLITE_TCLAPI test_sqlite3_log( ClientData clientData, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ if( objc>2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SCRIPT"); |
︙ | ︙ | |||
6059 6060 6061 6062 6063 6064 6065 | /* ** tcl_objproc COMMANDNAME ARGS... ** ** Run a TCL command using its objProc interface. Throw an error if ** the command has no objProc interface. */ | | | 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 | /* ** tcl_objproc COMMANDNAME ARGS... ** ** Run a TCL command using its objProc interface. Throw an error if ** the command has no objProc interface. */ static int SQLITE_TCLAPI runAsObjProc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_CmdInfo cmdInfo; if( objc<2 ){ |
︙ | ︙ | |||
6122 6123 6124 6125 6126 6127 6128 | printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail); } return sqlite3_finalize(pExplain); } | | | 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 | printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail); } return sqlite3_finalize(pExplain); } static int SQLITE_TCLAPI test_print_eqp( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; sqlite3_stmt *pStmt; |
︙ | ︙ | |||
6150 6151 6152 6153 6154 6155 6156 | return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** sqlite3_test_control VERB ARGS... */ | | | 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 | return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** sqlite3_test_control VERB ARGS... */ static int SQLITE_TCLAPI test_test_control( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct Verb { const char *zName; |
︙ | ︙ | |||
6229 6230 6231 6232 6233 6234 6235 | return TCL_OK; } #if SQLITE_OS_UNIX #include <sys/time.h> #include <sys/resource.h> | | | 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 | return TCL_OK; } #if SQLITE_OS_UNIX #include <sys/time.h> #include <sys/resource.h> static int SQLITE_TCLAPI test_getrusage( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char buf[1024]; struct rusage r; |
︙ | ︙ | |||
6272 6273 6274 6275 6276 6277 6278 | #if SQLITE_OS_WIN #include <process.h> /* ** The background thread that does file locking. */ | | | 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 | #if SQLITE_OS_WIN #include <process.h> /* ** The background thread that does file locking. */ static void SQLITE_CDECL win32_file_locker(void *pAppData){ struct win32FileLocker *p = (struct win32FileLocker*)pAppData; if( p->evName ){ HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName); if ( ev ){ SetEvent(ev); CloseHandle(ev); } |
︙ | ︙ | |||
6303 6304 6305 6306 6307 6308 6309 | #if SQLITE_OS_WIN /* ** lock_win32_file FILENAME DELAY1 DELAY2 ** ** Get an exclusive manditory lock on file for DELAY2 milliseconds. ** Wait DELAY1 milliseconds before acquiring the lock. */ | | | 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 | #if SQLITE_OS_WIN /* ** lock_win32_file FILENAME DELAY1 DELAY2 ** ** Get an exclusive manditory lock on file for DELAY2 milliseconds. ** Wait DELAY1 milliseconds before acquiring the lock. */ static int SQLITE_TCLAPI win32_file_lock( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 }; const char *zFilename; |
︙ | ︙ | |||
6367 6368 6369 6370 6371 6372 6373 | /* ** exists_win32_path PATH ** ** Returns non-zero if the specified path exists, whose fully qualified name ** may exceed 260 characters if it is prefixed with "\\?\". */ | | | 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 | /* ** exists_win32_path PATH ** ** Returns non-zero if the specified path exists, whose fully qualified name ** may exceed 260 characters if it is prefixed with "\\?\". */ static int SQLITE_TCLAPI win32_exists_path( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "PATH"); |
︙ | ︙ | |||
6389 6390 6391 6392 6393 6394 6395 | /* ** find_win32_file PATTERN ** ** Returns a list of entries in a directory that match the specified pattern, ** whose fully qualified name may exceed 248 characters if it is prefixed with ** "\\?\". */ | | | 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 | /* ** find_win32_file PATTERN ** ** Returns a list of entries in a directory that match the specified pattern, ** whose fully qualified name may exceed 248 characters if it is prefixed with ** "\\?\". */ static int SQLITE_TCLAPI win32_find_file( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ HANDLE hFindFile = INVALID_HANDLE_VALUE; WIN32_FIND_DATAW findData; |
︙ | ︙ | |||
6434 6435 6436 6437 6438 6439 6440 | /* ** delete_win32_file FILENAME ** ** Deletes the specified file, whose fully qualified name may exceed 260 ** characters if it is prefixed with "\\?\". */ | | | 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 | /* ** delete_win32_file FILENAME ** ** Deletes the specified file, whose fully qualified name may exceed 260 ** characters if it is prefixed with "\\?\". */ static int SQLITE_TCLAPI win32_delete_file( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
︙ | ︙ | |||
6458 6459 6460 6461 6462 6463 6464 | /* ** make_win32_dir DIRECTORY ** ** Creates the specified directory, whose fully qualified name may exceed 248 ** characters if it is prefixed with "\\?\". */ | | | 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 | /* ** make_win32_dir DIRECTORY ** ** Creates the specified directory, whose fully qualified name may exceed 248 ** characters if it is prefixed with "\\?\". */ static int SQLITE_TCLAPI win32_mkdir( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); |
︙ | ︙ | |||
6482 6483 6484 6485 6486 6487 6488 | /* ** remove_win32_dir DIRECTORY ** ** Removes the specified directory, whose fully qualified name may exceed 248 ** characters if it is prefixed with "\\?\". */ | | | 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 | /* ** remove_win32_dir DIRECTORY ** ** Removes the specified directory, whose fully qualified name may exceed 248 ** characters if it is prefixed with "\\?\". */ static int SQLITE_TCLAPI win32_rmdir( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); |
︙ | ︙ | |||
6509 6510 6511 6512 6513 6514 6515 | /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. ** OPT is the name of the optimization to be disabled. */ | | | 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 | /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. ** OPT is the name of the optimization to be disabled. */ static int SQLITE_TCLAPI optimization_control( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; sqlite3 *db; |
︙ | ︙ | |||
6566 6567 6568 6569 6570 6571 6572 | } return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); return TCL_OK; } | < | > > > > | 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 | } return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); return TCL_OK; } /* ** load_static_extension DB NAME ... ** ** Load one or more statically linked extensions. */ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "carray", sqlite3_carray_init }, { "closure", sqlite3_closure_init }, { "csv", sqlite3_csv_init }, { "eval", sqlite3_eval_init }, { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, |
︙ | ︙ | |||
6646 6647 6648 6649 6650 6651 6652 | return TCL_OK; } /* ** sorter_test_fakeheap BOOL ** */ | | | 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 | return TCL_OK; } /* ** sorter_test_fakeheap BOOL ** */ static int SQLITE_TCLAPI sorter_test_fakeheap( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int bArg; if( objc!=2 ){ |
︙ | ︙ | |||
6686 6687 6688 6689 6690 6691 6692 | ** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, ** check that the leftmost and rightmost columns returned are both integers, ** and that both contain the same value. ** ** Then execute statement $SQL2. Check that the statement returns the same ** set of integers in the same order as in the previous step (using $SQL1). */ | | | | | 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 | ** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, ** check that the leftmost and rightmost columns returned are both integers, ** and that both contain the same value. ** ** Then execute statement $SQL2. Check that the statement returns the same ** set of integers in the same order as in the previous step (using $SQL1). */ static int SQLITE_TCLAPI sorter_test_sort4_helper( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zSql1; const char *zSql2; int nStep; int iStep; unsigned int iCksum1 = 0; unsigned int iCksum2 = 0; int rc; int iB; sqlite3 *db; sqlite3_stmt *pStmt; if( objc!=5 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2"); |
︙ | ︙ | |||
6724 6725 6726 6727 6728 6729 6730 | for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){ int a = sqlite3_column_int(pStmt, 0); if( a!=sqlite3_column_int(pStmt, iB) ){ Tcl_AppendResult(interp, "data error: (a!=b)", 0); return TCL_ERROR; } | | | | 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 | for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){ int a = sqlite3_column_int(pStmt, 0); if( a!=sqlite3_column_int(pStmt, iB) ){ Tcl_AppendResult(interp, "data error: (a!=b)", 0); return TCL_ERROR; } iCksum1 += (iCksum1 << 3) + (unsigned int)a; } rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_OK ) goto sql_error; rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0); if( rc!=SQLITE_OK ) goto sql_error; for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){ int a = sqlite3_column_int(pStmt, 0); iCksum2 += (iCksum2 << 3) + (unsigned int)a; } rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_OK ) goto sql_error; if( iCksum1!=iCksum2 ){ Tcl_AppendResult(interp, "checksum mismatch", 0); return TCL_ERROR; |
︙ | ︙ | |||
6755 6756 6757 6758 6759 6760 6761 | #ifdef SQLITE_USER_AUTHENTICATION #include "sqlite3userauth.h" /* ** tclcmd: sqlite3_user_authenticate DB USERNAME PASSWORD */ | | | 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 | #ifdef SQLITE_USER_AUTHENTICATION #include "sqlite3userauth.h" /* ** tclcmd: sqlite3_user_authenticate DB USERNAME PASSWORD */ static int SQLITE_TCLAPI test_user_authenticate( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zUser = 0; char *zPasswd = 0; |
︙ | ︙ | |||
6786 6787 6788 6789 6790 6791 6792 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_add DB USERNAME PASSWORD ISADMIN */ | | | 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_add DB USERNAME PASSWORD ISADMIN */ static int SQLITE_TCLAPI test_user_add( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zUser = 0; char *zPasswd = 0; |
︙ | ︙ | |||
6819 6820 6821 6822 6823 6824 6825 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_change DB USERNAME PASSWORD ISADMIN */ | | | 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_change DB USERNAME PASSWORD ISADMIN */ static int SQLITE_TCLAPI test_user_change( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zUser = 0; char *zPasswd = 0; |
︙ | ︙ | |||
6852 6853 6854 6855 6856 6857 6858 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_delete DB USERNAME */ | | | 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 | } #endif /* SQLITE_USER_AUTHENTICATION */ #ifdef SQLITE_USER_AUTHENTICATION /* ** tclcmd: sqlite3_user_delete DB USERNAME */ static int SQLITE_TCLAPI test_user_delete( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ char *zUser = 0; sqlite3 *db; |
︙ | ︙ | |||
6889 6890 6891 6892 6893 6894 6895 | ** ** TYPE BEHAVIOR ** 1 Overflow a signed integer ** 2 Jump based on an uninitialized variable ** 3 Read after free ** 4 Panic */ | | | 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 | ** ** TYPE BEHAVIOR ** 1 Overflow a signed integer ** 2 Jump based on an uninitialized variable ** 3 Read after free ** 4 Panic */ static int SQLITE_TCLAPI test_bad_behavior( ClientData clientData, /* Pointer to an integer containing zero */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int iType; int xyz; |
︙ | ︙ | |||
6939 6940 6941 6942 6943 6944 6945 | } /* ** tclcmd: register_dbstat_vtab DB ** ** Cause the dbstat virtual table to be available on the connection DB */ | | | 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 | } /* ** tclcmd: register_dbstat_vtab DB ** ** Cause the dbstat virtual table to be available on the connection DB */ static int SQLITE_TCLAPI test_register_dbstat_vtab( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_OMIT_VIRTUALTABLE Tcl_AppendResult(interp, "dbstat not available because of " |
︙ | ︙ | |||
6973 6974 6975 6976 6977 6978 6979 | } /* ** tclcmd: sqlite3_db_config DB SETTING VALUE ** ** Invoke sqlite3_db_config() for one of the setting values. */ | | | 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 | } /* ** tclcmd: sqlite3_db_config DB SETTING VALUE ** ** Invoke sqlite3_db_config() for one of the setting values. */ static int SQLITE_TCLAPI test_sqlite3_db_config( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static const struct { const char *zName; |
︙ | ︙ | |||
7030 7031 7032 7033 7034 7035 7036 | extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE extern int sqlite3_hostid_num; #endif extern int sqlite3_max_blobsize; | | | 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 | extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE extern int sqlite3_hostid_num; #endif extern int sqlite3_max_blobsize; extern int SQLITE_TCLAPI sqlite3BtreeSharedCacheReport(void*, Tcl_Interp*,int,Tcl_Obj*CONST*); static int iZero = 0; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "db_enter", (Tcl_CmdProc*)db_enter }, |
︙ | ︙ | |||
7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 | Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "sqlite3_db_config", test_sqlite3_db_config, 0 }, { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "register_dbstat_vtab", test_register_dbstat_vtab }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, { "sqlite3_bind_zeroblob64", test_bind_zeroblob64, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_null", test_bind_null ,0 }, { "sqlite3_bind_text", test_bind_text ,0 }, | > > > > | 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 | Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "sqlite3_db_config", test_sqlite3_db_config, 0 }, { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "register_dbstat_vtab", test_register_dbstat_vtab }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "intarray_addr", test_intarray_addr, 0 }, { "int64array_addr", test_int64array_addr, 0 }, { "doublearray_addr", test_doublearray_addr, 0 }, { "textarray_addr", test_textarray_addr, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, { "sqlite3_bind_zeroblob64", test_bind_zeroblob64, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_null", test_bind_null ,0 }, { "sqlite3_bind_text", test_bind_text ,0 }, |
︙ | ︙ | |||
7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 | { "sqlite3_stmt_status", test_stmt_status ,0 }, { "sqlite3_reset", test_reset ,0 }, { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, | > | 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 | { "sqlite3_stmt_status", test_stmt_status ,0 }, { "sqlite3_reset", test_reset ,0 }, { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_expanded_sql", test_ex_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, |
︙ | ︙ |
Changes to src/test2.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" | > > > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <ctype.h> extern const char *sqlite3ErrName(int); /* |
︙ | ︙ | |||
34 35 36 37 38 39 40 | } /* ** Usage: pager_open FILENAME N-PAGE ** ** Open a new pager */ | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | } /* ** Usage: pager_open FILENAME N-PAGE ** ** Open a new pager */ static int SQLITE_TCLAPI pager_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ u32 pageSize; Pager *pPager; |
︙ | ︙ | |||
71 72 73 74 75 76 77 | } /* ** Usage: pager_close ID ** ** Close the given pager. */ | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | } /* ** Usage: pager_close ID ** ** Close the given pager. */ static int SQLITE_TCLAPI pager_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
98 99 100 101 102 103 104 | } /* ** Usage: pager_rollback ID ** ** Rollback changes */ | | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | } /* ** Usage: pager_rollback ID ** ** Rollback changes */ static int SQLITE_TCLAPI pager_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
125 126 127 128 129 130 131 | } /* ** Usage: pager_commit ID ** ** Commit all changes */ | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | } /* ** Usage: pager_commit ID ** ** Commit all changes */ static int SQLITE_TCLAPI pager_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
157 158 159 160 161 162 163 | } /* ** Usage: pager_stmt_begin ID ** ** Start a new checkpoint. */ | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | } /* ** Usage: pager_stmt_begin ID ** ** Start a new checkpoint. */ static int SQLITE_TCLAPI pager_stmt_begin( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
184 185 186 187 188 189 190 | } /* ** Usage: pager_stmt_rollback ID ** ** Rollback changes to a checkpoint */ | | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | } /* ** Usage: pager_stmt_rollback ID ** ** Rollback changes to a checkpoint */ static int SQLITE_TCLAPI pager_stmt_rollback( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
212 213 214 215 216 217 218 | } /* ** Usage: pager_stmt_commit ID ** ** Commit changes to a checkpoint */ | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | } /* ** Usage: pager_stmt_commit ID ** ** Commit changes to a checkpoint */ static int SQLITE_TCLAPI pager_stmt_commit( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int rc; |
︙ | ︙ | |||
239 240 241 242 243 244 245 | } /* ** Usage: pager_stats ID ** ** Return pager statistics. */ | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | } /* ** Usage: pager_stats ID ** ** Return pager statistics. */ static int SQLITE_TCLAPI pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int i, *a; |
︙ | ︙ | |||
272 273 274 275 276 277 278 | } /* ** Usage: pager_pagecount ID ** ** Return the size of the database file. */ | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | } /* ** Usage: pager_pagecount ID ** ** Return the size of the database file. */ static int SQLITE_TCLAPI pager_pagecount( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; |
︙ | ︙ | |||
298 299 300 301 302 303 304 | } /* ** Usage: page_get ID PGNO ** ** Return a pointer to a page from the database. */ | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | } /* ** Usage: page_get ID PGNO ** ** Return a pointer to a page from the database. */ static int SQLITE_TCLAPI page_get( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; |
︙ | ︙ | |||
335 336 337 338 339 340 341 | /* ** Usage: page_lookup ID PGNO ** ** Return a pointer to a page if the page is already in cache. ** If not in cache, return an empty string. */ | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | /* ** Usage: page_lookup ID PGNO ** ** Return a pointer to a page if the page is already in cache. ** If not in cache, return an empty string. */ static int SQLITE_TCLAPI page_lookup( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; char zBuf[100]; |
︙ | ︙ | |||
363 364 365 366 367 368 369 | } return TCL_OK; } /* ** Usage: pager_truncate ID PGNO */ | | | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | } return TCL_OK; } /* ** Usage: pager_truncate ID PGNO */ static int SQLITE_TCLAPI pager_truncate( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Pager *pPager; int pgno; |
︙ | ︙ | |||
388 389 390 391 392 393 394 | /* ** Usage: page_unref PAGE ** ** Drop a pointer to a page. */ | | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | /* ** Usage: page_unref PAGE ** ** Drop a pointer to a page. */ static int SQLITE_TCLAPI page_unref( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ DbPage *pPage; if( argc!=2 ){ |
︙ | ︙ | |||
410 411 412 413 414 415 416 | } /* ** Usage: page_read PAGE ** ** Return the content of a page */ | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | } /* ** Usage: page_read PAGE ** ** Return the content of a page */ static int SQLITE_TCLAPI page_read( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; DbPage *pPage; |
︙ | ︙ | |||
434 435 436 437 438 439 440 | } /* ** Usage: page_number PAGE ** ** Return the page number for a page. */ | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | } /* ** Usage: page_number PAGE ** ** Return the page number for a page. */ static int SQLITE_TCLAPI page_number( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; DbPage *pPage; |
︙ | ︙ | |||
458 459 460 461 462 463 464 | } /* ** Usage: page_write PAGE DATA ** ** Write something into a page. */ | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | } /* ** Usage: page_write PAGE DATA ** ** Write something into a page. */ static int SQLITE_TCLAPI page_write( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ DbPage *pPage; char *pData; |
︙ | ︙ | |||
494 495 496 497 498 499 500 | ** ** Write a few bytes at the N megabyte point of FILENAME. This will ** create a large file. If the file was a valid SQLite database, then ** the next time the database is opened, SQLite will begin allocating ** new pages after N. If N is 2096 or bigger, this will test the ** ability of SQLite to write to large files. */ | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | ** ** Write a few bytes at the N megabyte point of FILENAME. This will ** create a large file. If the file was a valid SQLite database, then ** the next time the database is opened, SQLite will begin allocating ** new pages after N. If N is 2096 or bigger, this will test the ** ability of SQLite to write to large files. */ static int SQLITE_TCLAPI fake_big_file( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ sqlite3_vfs *pVfs; sqlite3_file *fd = 0; |
︙ | ︙ | |||
547 548 549 550 551 552 553 | /* ** test_control_pending_byte PENDING_BYTE ** ** Set the PENDING_BYTE using the sqlite3_test_control() interface. */ | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | /* ** test_control_pending_byte PENDING_BYTE ** ** Set the PENDING_BYTE using the sqlite3_test_control() interface. */ static int SQLITE_TCLAPI testPendingByte( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int pbyte; int rc; |
︙ | ︙ | |||
612 613 614 615 616 617 618 | /* ** sqlite3_test_control_fault_install SCRIPT ** ** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim() ** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the ** empty string, cancel the sqlite3FaultSim() callback. */ | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | /* ** sqlite3_test_control_fault_install SCRIPT ** ** Arrange to invoke SCRIPT with the integer argument to sqlite3FaultSim() ** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the ** empty string, cancel the sqlite3FaultSim() callback. */ static int SQLITE_TCLAPI faultInstallCmd( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ const char *zScript; int nScript; |
︙ | ︙ | |||
655 656 657 658 659 660 661 | /* ** sqlite3BitvecBuiltinTest SIZE PROGRAM ** ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control. ** See comments on sqlite3BitvecBuiltinTest() for additional information. */ | | | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | /* ** sqlite3BitvecBuiltinTest SIZE PROGRAM ** ** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control. ** See comments on sqlite3BitvecBuiltinTest() for additional information. */ static int SQLITE_TCLAPI testBitvecBuiltinTest( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int sz, rc; int nProg = 0; |
︙ | ︙ |
Changes to src/test3.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "btreeInt.h" | > > > | > | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "btreeInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> extern const char *sqlite3ErrName(int); /* ** A bogus sqlite3 connection structure for use in the btree ** tests. */ static sqlite3 sDb; static int nRefSqlite3 = 0; /* ** Usage: btree_open FILENAME NCACHE ** ** Open a new database */ static int SQLITE_TCLAPI btree_open( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc, nCache; |
︙ | ︙ | |||
75 76 77 78 79 80 81 | } /* ** Usage: btree_close ID ** ** Close the given database. */ | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | } /* ** Usage: btree_close ID ** ** Close the given database. */ static int SQLITE_TCLAPI btree_close( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; |
︙ | ︙ | |||
110 111 112 113 114 115 116 | /* ** Usage: btree_begin_transaction ID ** ** Start a new transaction */ | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /* ** Usage: btree_begin_transaction ID ** ** Start a new transaction */ static int SQLITE_TCLAPI btree_begin_transaction( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; |
︙ | ︙ | |||
139 140 141 142 143 144 145 | } /* ** Usage: btree_pager_stats ID ** ** Returns pager statistics */ | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | } /* ** Usage: btree_pager_stats ID ** ** Returns pager statistics */ static int SQLITE_TCLAPI btree_pager_stats( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int i; |
︙ | ︙ | |||
189 190 191 192 193 194 195 | } /* ** Usage: btree_cursor ID TABLENUM WRITEABLE ** ** Create a new cursor. Return the ID for the cursor. */ | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | } /* ** Usage: btree_cursor ID TABLENUM WRITEABLE ** ** Create a new cursor. Return the ID for the cursor. */ static int SQLITE_TCLAPI btree_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int iTable; |
︙ | ︙ | |||
238 239 240 241 242 243 244 | } /* ** Usage: btree_close_cursor ID ** ** Close a cursor opened using btree_cursor. */ | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | } /* ** Usage: btree_close_cursor ID ** ** Close a cursor opened using btree_cursor. */ static int SQLITE_TCLAPI btree_close_cursor( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; Btree *pBt; |
︙ | ︙ | |||
275 276 277 278 279 280 281 | /* ** Usage: btree_next ID ** ** Move the cursor to the next entry in the table. Return 0 on success ** or 1 if the cursor was already on the last entry in the table or if ** the table is empty. */ | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | /* ** Usage: btree_next ID ** ** Move the cursor to the next entry in the table. Return 0 on success ** or 1 if the cursor was already on the last entry in the table or if ** the table is empty. */ static int SQLITE_TCLAPI btree_next( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; |
︙ | ︙ | |||
310 311 312 313 314 315 316 | /* ** Usage: btree_first ID ** ** Move the cursor to the first entry in the table. Return 0 if the ** cursor was left point to something and 1 if the table is empty. */ | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | /* ** Usage: btree_first ID ** ** Move the cursor to the first entry in the table. Return 0 if the ** cursor was left point to something and 1 if the table is empty. */ static int SQLITE_TCLAPI btree_first( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; |
︙ | ︙ | |||
345 346 347 348 349 350 351 | /* ** Usage: btree_eof ID ** ** Return TRUE if the given cursor is not pointing at a valid entry. ** Return FALSE if the cursor does point to a valid entry. */ | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | /* ** Usage: btree_eof ID ** ** Return TRUE if the given cursor is not pointing at a valid entry. ** Return FALSE if the cursor does point to a valid entry. */ static int SQLITE_TCLAPI btree_eof( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; int rc; |
︙ | ︙ | |||
374 375 376 377 378 379 380 | } /* ** Usage: btree_payload_size ID ** ** Return the number of bytes of payload */ | | | < < < < < < < < | < | | | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | } /* ** Usage: btree_payload_size ID ** ** Return the number of bytes of payload */ static int SQLITE_TCLAPI btree_payload_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ BtCursor *pCur; u32 n; char zBuf[50]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); n = sqlite3BtreePayloadSize(pCur); sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } /* ** usage: varint_test START MULTIPLIER COUNT INCREMENT ** ** This command tests the putVarint() and getVarint() ** routines, both for accuracy and for speed. ** ** An integer is written using putVarint() and read back with ** getVarint() and varified to be unchanged. This repeats COUNT ** times. The first integer is START*MULTIPLIER. Each iteration ** increases the integer by INCREMENT. ** ** This command returns nothing if it works. It returns an error message ** if something goes wrong. */ static int SQLITE_TCLAPI btree_varint_test( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ u32 start, mult, count, incr; u64 in, out; |
︙ | ︙ | |||
505 506 507 508 509 510 511 | ** ** This command returns the btree handle for the main database associated ** with the database-handle passed as the argument. Example usage: ** ** sqlite3 db test.db ** set bt [btree_from_db db] */ | | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | ** ** This command returns the btree handle for the main database associated ** with the database-handle passed as the argument. Example usage: ** ** sqlite3 db test.db ** set bt [btree_from_db db] */ static int SQLITE_TCLAPI btree_from_db( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ char zBuf[100]; Tcl_CmdInfo info; |
︙ | ︙ | |||
545 546 547 548 549 550 551 | } /* ** Usage: btree_ismemdb ID ** ** Return true if the B-Tree is currently stored entirely in memory. */ | | | 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | } /* ** Usage: btree_ismemdb ID ** ** Return true if the B-Tree is currently stored entirely in memory. */ static int SQLITE_TCLAPI btree_ismemdb( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int res; |
︙ | ︙ | |||
576 577 578 579 580 581 582 | } /* ** usage: btree_set_cache_size ID NCACHE ** ** Set the size of the cache used by btree $ID. */ | | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | } /* ** usage: btree_set_cache_size ID NCACHE ** ** Set the size of the cache used by btree $ID. */ static int SQLITE_TCLAPI btree_set_cache_size( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int nCache; Btree *pBt; |
︙ | ︙ | |||
606 607 608 609 610 611 612 | } /* ** usage: btree_insert CSR ?KEY? VALUE ** ** Set the size of the cache used by btree $ID. */ | | | < < < > | > | | > | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | } /* ** usage: btree_insert CSR ?KEY? VALUE ** ** Set the size of the cache used by btree $ID. */ static int SQLITE_TCLAPI btree_insert( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ){ BtCursor *pCur; int rc; BtreePayload x; if( objc!=4 && objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); return TCL_ERROR; } memset(&x, 0, sizeof(x)); if( objc==4 ){ if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR; x.nKey = rc; x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData); }else{ x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc); x.nKey = rc; } pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); sqlite3_mutex_enter(pCur->pBtree->db->mutex); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeInsert(pCur, &x, 0, 0); sqlite3BtreeLeave(pCur->pBtree); sqlite3_mutex_leave(pCur->pBtree->db->mutex); Tcl_ResetResult(interp); if( rc ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; |
︙ | ︙ |
Changes to src/test4.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the SQLite library in a multithreaded environment. */ #include "sqliteInt.h" | > > > | > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the SQLite library in a multithreaded environment. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #if SQLITE_OS_UNIX && SQLITE_THREADSAFE #include <stdlib.h> #include <string.h> #include <pthread.h> #include <sched.h> #include <ctype.h> |
︙ | ︙ | |||
117 118 119 120 121 122 123 | /* ** Usage: thread_create NAME FILENAME ** ** NAME should be an upper case letter. Start the thread running with ** an open connection to the given database. */ | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /* ** Usage: thread_create NAME FILENAME ** ** NAME should be an upper case letter. Start the thread running with ** an open connection to the given database. */ static int SQLITE_TCLAPI tcl_thread_create( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; pthread_t x; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | } /* ** Usage: thread_wait ID ** ** Wait on thread ID to reach its idle state. */ | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | } /* ** Usage: thread_wait ID ** ** Wait on thread ID to reach its idle state. */ static int SQLITE_TCLAPI tcl_thread_wait( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
210 211 212 213 214 215 216 | /* ** Usage: thread_halt ID ** ** Cause a thread to shut itself down. Wait for the shutdown to be ** completed. If ID is "*" then stop all threads. */ | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | /* ** Usage: thread_halt ID ** ** Cause a thread to shut itself down. Wait for the shutdown to be ** completed. If ID is "*" then stop all threads. */ static int SQLITE_TCLAPI tcl_thread_halt( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
245 246 247 248 249 250 251 | /* ** Usage: thread_argc ID ** ** Wait on the most recent thread_step to complete, then return the ** number of columns in the result set. */ | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | /* ** Usage: thread_argc ID ** ** Wait on the most recent thread_step to complete, then return the ** number of columns in the result set. */ static int SQLITE_TCLAPI tcl_thread_argc( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; char zBuf[100]; |
︙ | ︙ | |||
277 278 279 280 281 282 283 | /* ** Usage: thread_argv ID N ** ** Wait on the most recent thread_step to complete, then return the ** value of the N-th columns in the result set. */ | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | /* ** Usage: thread_argv ID N ** ** Wait on the most recent thread_step to complete, then return the ** value of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_thread_argv( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; |
︙ | ︙ | |||
313 314 315 316 317 318 319 | /* ** Usage: thread_colname ID N ** ** Wait on the most recent thread_step to complete, then return the ** name of the N-th columns in the result set. */ | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | /* ** Usage: thread_colname ID N ** ** Wait on the most recent thread_step to complete, then return the ** name of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_thread_colname( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; |
︙ | ︙ | |||
349 350 351 352 353 354 355 | /* ** Usage: thread_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ | | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | /* ** Usage: thread_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ static int SQLITE_TCLAPI tcl_thread_result( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; const char *zName; |
︙ | ︙ | |||
381 382 383 384 385 386 387 | /* ** Usage: thread_error ID ** ** Wait on the most recent operation to complete, then return the ** error string. */ | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | /* ** Usage: thread_error ID ** ** Wait on the most recent operation to complete, then return the ** error string. */ static int SQLITE_TCLAPI tcl_thread_error( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
426 427 428 429 430 431 432 | } /* ** Usage: thread_compile ID SQL ** ** Compile a new virtual machine. */ | | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | } /* ** Usage: thread_compile ID SQL ** ** Compile a new virtual machine. */ static int SQLITE_TCLAPI tcl_thread_compile( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=3 ){ |
︙ | ︙ | |||
479 480 481 482 483 484 485 | } /* ** Usage: thread_step ID ** ** Advance the virtual machine by one step */ | | | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 | } /* ** Usage: thread_step ID ** ** Advance the virtual machine by one step */ static int SQLITE_TCLAPI tcl_thread_step( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ |
︙ | ︙ | |||
521 522 523 524 525 526 527 | } /* ** Usage: thread_finalize ID ** ** Finalize the virtual machine. */ | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | } /* ** Usage: thread_finalize ID ** ** Finalize the virtual machine. */ static int SQLITE_TCLAPI tcl_thread_finalize( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ |
︙ | ︙ | |||
552 553 554 555 556 557 558 | } /* ** Usage: thread_swap ID ID ** ** Interchange the sqlite* pointer between two threads. */ | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | } /* ** Usage: thread_swap ID ID ** ** Interchange the sqlite* pointer between two threads. */ static int SQLITE_TCLAPI tcl_thread_swap( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i, j; sqlite3 *temp; |
︙ | ︙ | |||
592 593 594 595 596 597 598 | /* ** Usage: thread_db_get ID ** ** Return the database connection pointer for the given thread. Then ** remove the pointer from the thread itself. Afterwards, the thread ** can be stopped and the connection can be used by the main thread. */ | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | /* ** Usage: thread_db_get ID ** ** Return the database connection pointer for the given thread. Then ** remove the pointer from the thread itself. Afterwards, the thread ** can be stopped and the connection can be used by the main thread. */ static int SQLITE_TCLAPI tcl_thread_db_get( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; char zBuf[100]; |
︙ | ︙ | |||
623 624 625 626 627 628 629 | return TCL_OK; } /* ** Usage: thread_db_put ID DB ** */ | | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | return TCL_OK; } /* ** Usage: thread_db_put ID DB ** */ static int SQLITE_TCLAPI tcl_thread_db_put( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); |
︙ | ︙ | |||
655 656 657 658 659 660 661 | /* ** Usage: thread_stmt_get ID ** ** Return the database stmt pointer for the given thread. Then ** remove the pointer from the thread itself. */ | | | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | /* ** Usage: thread_stmt_get ID ** ** Return the database stmt pointer for the given thread. Then ** remove the pointer from the thread itself. */ static int SQLITE_TCLAPI tcl_thread_stmt_get( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; char zBuf[100]; |
︙ | ︙ |
Changes to src/test5.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. Specifically, the code in this file ** is used for testing the SQLite routines for converting between ** the various supported unicode encodings. */ #include "sqliteInt.h" #include "vdbeInt.h" | > > > | > | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. Specifically, the code in this file ** is used for testing the SQLite routines for converting between ** the various supported unicode encodings. */ #include "sqliteInt.h" #include "vdbeInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> /* ** The first argument is a TCL UTF-8 string. Return the byte array ** object with the encoded representation of the string, including ** the NULL terminator. */ static int SQLITE_TCLAPI binarize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int len; char *bytes; |
︙ | ︙ | |||
50 51 52 53 54 55 56 | ** sqlite3_value_text(), on a value that contains a UTF-8 string. The idea ** is to figure out whether or not it is a problem to use sqlite3_value ** structures with collation sequence functions. ** ** If <do-calls> is 0, then the calls to sqlite3_value_text() are not ** actually made. */ | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ** sqlite3_value_text(), on a value that contains a UTF-8 string. The idea ** is to figure out whether or not it is a problem to use sqlite3_value ** structures with collation sequence functions. ** ** If <do-calls> is 0, then the calls to sqlite3_value_text() are not ** actually made. */ static int SQLITE_TCLAPI test_value_overhead( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int do_calls; int repeat_count; |
︙ | ︙ | |||
114 115 116 117 118 119 120 | return pEnc->enc; } /* ** Usage: test_translate <string/blob> <from enc> <to enc> ?<transient>? ** */ | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | return pEnc->enc; } /* ** Usage: test_translate <string/blob> <from enc> <to enc> ?<transient>? ** */ static int SQLITE_TCLAPI test_translate( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ u8 enc_from; u8 enc_to; |
︙ | ︙ | |||
178 179 180 181 182 183 184 | /* ** Usage: translate_selftest ** ** Call sqlite3UtfSelfTest() to run the internal tests for unicode ** translation. If there is a problem an assert() will fail. **/ void sqlite3UtfSelfTest(void); | | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | /* ** Usage: translate_selftest ** ** Call sqlite3UtfSelfTest() to run the internal tests for unicode ** translation. If there is a problem an assert() will fail. **/ void sqlite3UtfSelfTest(void); static int SQLITE_TCLAPI test_translate_selftest( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3UtfSelfTest(); |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqliteInt.h" | > > > | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */ /* #define TRACE_CRASHTEST */ typedef struct CrashFile CrashFile; typedef struct CrashGlobal CrashGlobal; |
︙ | ︙ | |||
211 212 213 214 215 216 217 | sqlite3_randomness(sizeof(int), &iFinal); iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite; for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--; pFinal = pWrite; } #ifdef TRACE_CRASHTEST | > | > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | sqlite3_randomness(sizeof(int), &iFinal); iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite; for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--; pFinal = pWrite; } #ifdef TRACE_CRASHTEST if( pFile ){ printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a")); } #endif ppPtr = &g.pWriteList; for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){ sqlite3_file *pRealFile = pWrite->pFile->pRealFile; /* (eAction==1) -> write block out normally, |
︙ | ︙ | |||
794 795 796 797 798 799 800 801 802 803 804 805 806 807 | } if( setSectorsize ){ *piSectorSize = iSectorSize; } return TCL_OK; } /* ** tclcmd: sqlite_crash_enable ENABLE ** ** Parameter ENABLE must be a boolean value. If true, then the "crash" ** vfs is added to the system. If false, it is removed. */ | > > > > > > > > > > > > > > > > > > > > > | | 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | } if( setSectorsize ){ *piSectorSize = iSectorSize; } return TCL_OK; } /* ** tclcmd: sqlite3_crash_now ** ** Simulate a crash immediately. This function does not return ** (writeListSync() calls exit(-1)). */ static int SQLITE_TCLAPI crashNowCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } writeListSync(0, 1); assert( 0 ); return TCL_OK; } /* ** tclcmd: sqlite_crash_enable ENABLE ** ** Parameter ENABLE must be a boolean value. If true, then the "crash" ** vfs is added to the system. If false, it is removed. */ static int SQLITE_TCLAPI crashEnableCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int isEnable; static sqlite3_vfs crashVfs = { |
︙ | ︙ | |||
876 877 878 879 880 881 882 | ** "atomic64K", "sequential" and "safe_append". ** ** Example: ** ** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1 ** */ | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | ** "atomic64K", "sequential" and "safe_append". ** ** Example: ** ** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1 ** */ static int SQLITE_TCLAPI crashParamsObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int iDelay; const char *zCrashFile; |
︙ | ︙ | |||
923 924 925 926 927 928 929 | sqlite3CrashTestEnable = 1; return TCL_OK; error: return TCL_ERROR; } | | | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | sqlite3CrashTestEnable = 1; return TCL_OK; error: return TCL_ERROR; } static int SQLITE_TCLAPI devSymObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void devsym_register(int iDeviceChar, int iSectorSize); |
︙ | ︙ | |||
946 947 948 949 950 951 952 | return TCL_OK; } /* ** tclcmd: unregister_devsim */ | | | | 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | return TCL_OK; } /* ** tclcmd: unregister_devsim */ static int SQLITE_TCLAPI dsUnregisterObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void devsym_unregister(void); if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } devsym_unregister(); return TCL_OK; } /* ** tclcmd: register_jt_vfs ?-default? PARENT-VFS */ static int SQLITE_TCLAPI jtObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int jt_register(char *, int); char *zParent = 0; |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | return TCL_OK; } /* ** tclcmd: unregister_jt_vfs */ | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | return TCL_OK; } /* ** tclcmd: unregister_jt_vfs */ static int SQLITE_TCLAPI jtUnregisterObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void jt_unregister(void); |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | /* ** This procedure registers the TCL procedures defined in this file. */ int Sqlitetest6_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ | > | 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 | /* ** This procedure registers the TCL procedures defined in this file. */ int Sqlitetest6_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_DISKIO Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0); Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0); Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ |
Changes to src/test7.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the client/server version of the SQLite library. ** Derived from test4.c. */ #include "sqliteInt.h" | > > > | > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the client/server version of the SQLite library. ** Derived from test4.c. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* ** This test only works on UNIX with a SQLITE_THREADSAFE build that includes ** the SQLITE_SERVER option. */ #if defined(SQLITE_SERVER) && !defined(SQLITE_OMIT_SHARED_CACHE) && \ SQLITE_OS_UNIX && SQLITE_THREADSAFE |
︙ | ︙ | |||
145 146 147 148 149 150 151 | /* ** Usage: client_create NAME FILENAME ** ** NAME should be an upper case letter. Start the thread running with ** an open connection to the given database. */ | | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /* ** Usage: client_create NAME FILENAME ** ** NAME should be an upper case letter. Start the thread running with ** an open connection to the given database. */ static int SQLITE_TCLAPI tcl_client_create( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; pthread_t x; |
︙ | ︙ | |||
198 199 200 201 202 203 204 | } /* ** Usage: client_wait ID ** ** Wait on thread ID to reach its idle state. */ | | | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | } /* ** Usage: client_wait ID ** ** Wait on thread ID to reach its idle state. */ static int SQLITE_TCLAPI tcl_client_wait( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
242 243 244 245 246 247 248 | /* ** Usage: client_halt ID ** ** Cause a client thread to shut itself down. Wait for the shutdown to be ** completed. If ID is "*" then stop all client threads. */ | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | /* ** Usage: client_halt ID ** ** Cause a client thread to shut itself down. Wait for the shutdown to be ** completed. If ID is "*" then stop all client threads. */ static int SQLITE_TCLAPI tcl_client_halt( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
290 291 292 293 294 295 296 | /* ** Usage: client_argc ID ** ** Wait on the most recent client_step to complete, then return the ** number of columns in the result set. */ | | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | /* ** Usage: client_argc ID ** ** Wait on the most recent client_step to complete, then return the ** number of columns in the result set. */ static int SQLITE_TCLAPI tcl_client_argc( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; char zBuf[100]; |
︙ | ︙ | |||
322 323 324 325 326 327 328 | /* ** Usage: client_argv ID N ** ** Wait on the most recent client_step to complete, then return the ** value of the N-th columns in the result set. */ | | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | /* ** Usage: client_argv ID N ** ** Wait on the most recent client_step to complete, then return the ** value of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_client_argv( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; |
︙ | ︙ | |||
358 359 360 361 362 363 364 | /* ** Usage: client_colname ID N ** ** Wait on the most recent client_step to complete, then return the ** name of the N-th columns in the result set. */ | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | /* ** Usage: client_colname ID N ** ** Wait on the most recent client_step to complete, then return the ** name of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_client_colname( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; |
︙ | ︙ | |||
396 397 398 399 400 401 402 | /* ** Usage: client_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ | | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | /* ** Usage: client_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ static int SQLITE_TCLAPI tcl_client_result( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; const char *zName; |
︙ | ︙ | |||
428 429 430 431 432 433 434 | /* ** Usage: client_error ID ** ** Wait on the most recent operation to complete, then return the ** error string. */ | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | /* ** Usage: client_error ID ** ** Wait on the most recent operation to complete, then return the ** error string. */ static int SQLITE_TCLAPI tcl_client_error( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; |
︙ | ︙ | |||
473 474 475 476 477 478 479 | } /* ** Usage: client_compile ID SQL ** ** Compile a new virtual machine. */ | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | } /* ** Usage: client_compile ID SQL ** ** Compile a new virtual machine. */ static int SQLITE_TCLAPI tcl_client_compile( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=3 ){ |
︙ | ︙ | |||
526 527 528 529 530 531 532 | } /* ** Usage: client_step ID ** ** Advance the virtual machine by one step */ | | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | } /* ** Usage: client_step ID ** ** Advance the virtual machine by one step */ static int SQLITE_TCLAPI tcl_client_step( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ |
︙ | ︙ | |||
568 569 570 571 572 573 574 | } /* ** Usage: client_finalize ID ** ** Finalize the virtual machine. */ | | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | } /* ** Usage: client_finalize ID ** ** Finalize the virtual machine. */ static int SQLITE_TCLAPI tcl_client_finalize( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ |
︙ | ︙ | |||
612 613 614 615 616 617 618 | } /* ** Usage: client_reset ID ** ** Finalize the virtual machine. */ | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | } /* ** Usage: client_reset ID ** ** Finalize the virtual machine. */ static int SQLITE_TCLAPI tcl_client_reset( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ |
︙ | ︙ | |||
643 644 645 646 647 648 649 | } /* ** Usage: client_swap ID ID ** ** Interchange the sqlite* pointer between two threads. */ | | | 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | } /* ** Usage: client_swap ID ID ** ** Interchange the sqlite* pointer between two threads. */ static int SQLITE_TCLAPI tcl_client_swap( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i, j; sqlite3 *temp; |
︙ | ︙ |
Changes to src/test8.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" | > > > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct echo_vtab echo_vtab; typedef struct echo_cursor echo_cursor; |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | static void moduleDestroy(void *p){ sqlite3_free(p); } /* ** Register the echo virtual table module. */ | | | 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | static void moduleDestroy(void *p){ sqlite3_free(p); } /* ** Register the echo virtual table module. */ static int SQLITE_TCLAPI register_echo_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int rc; sqlite3 *db; |
︙ | ︙ | |||
1389 1390 1391 1392 1393 1394 1395 | } /* ** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl: ** ** sqlite3_declare_vtab DB SQL */ | | | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 | } /* ** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl: ** ** sqlite3_declare_vtab DB SQL */ static int SQLITE_TCLAPI declare_vtab( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; |
︙ | ︙ |
Changes to src/test9.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file contains obscure tests of the C-interface required ** for completeness. Test code is written in C for these cases ** as there is not much point in binding to Tcl. */ #include "sqliteInt.h" | > > > | > | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ************************************************************************* ** ** This file contains obscure tests of the C-interface required ** for completeness. Test code is written in C for these cases ** as there is not much point in binding to Tcl. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> /* ** c_collation_test */ static int SQLITE_TCLAPI c_collation_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ const char *zErrFunction = "N/A"; sqlite3 *db; |
︙ | ︙ | |||
59 60 61 62 63 64 65 | Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, 0); return TCL_ERROR; } /* ** c_realloc_test */ | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | Tcl_AppendResult(interp, "Error testing function: ", zErrFunction, 0); return TCL_ERROR; } /* ** c_realloc_test */ static int SQLITE_TCLAPI c_realloc_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ void *p; const char *zErrFunction = "N/A"; |
︙ | ︙ | |||
100 101 102 103 104 105 106 | return TCL_ERROR; } /* ** c_misuse_test */ | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | return TCL_ERROR; } /* ** c_misuse_test */ static int SQLITE_TCLAPI c_misuse_test( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ const char *zErrFunction = "N/A"; sqlite3 *db = 0; |
︙ | ︙ |
Changes to src/test_async.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file contains a binding of the asynchronous IO extension interface ** (defined in ext/async/sqlite3async.h) to Tcl. */ #define TCL_THREADS | > > > | > > > > | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ************************************************************************* ** ** This file contains a binding of the asynchronous IO extension interface ** (defined in ext/async/sqlite3async.h) to Tcl. */ #define TCL_THREADS #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #ifdef SQLITE_ENABLE_ASYNCIO #include "sqlite3async.h" #include "sqlite3.h" #include <assert.h> /* From main.c */ extern const char *sqlite3ErrName(int); struct TestAsyncGlobal { int isInstalled; /* True when async VFS is installed */ } testasync_g = { 0 }; TCL_DECLARE_MUTEX(testasync_g_writerMutex); /* ** sqlite3async_initialize PARENT-VFS ISDEFAULT */ static int SQLITE_TCLAPI testAsyncInit( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zParent; int isDefault; |
︙ | ︙ | |||
65 66 67 68 69 70 71 | } return TCL_OK; } /* ** sqlite3async_shutdown */ | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | } return TCL_OK; } /* ** sqlite3async_shutdown */ static int SQLITE_TCLAPI testAsyncShutdown( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3async_shutdown(); return TCL_OK; |
︙ | ︙ | |||
89 90 91 92 93 94 95 | } /* ** sqlite3async_start ** ** Start a new writer thread. */ | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | } /* ** sqlite3async_start ** ** Start a new writer thread. */ static int SQLITE_TCLAPI testAsyncStart( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ volatile int isStarted = 0; ClientData threadData = (ClientData)&isStarted; |
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** sqlite3async_wait ** ** Wait for the current writer thread to terminate. ** ** If the current writer thread is set to run forever then this ** command would block forever. To prevent that, an error is returned. */ | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ** sqlite3async_wait ** ** Wait for the current writer thread to terminate. ** ** If the current writer thread is set to run forever then this ** command would block forever. To prevent that, an error is returned. */ static int SQLITE_TCLAPI testAsyncWait( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int eCond; if( objc!=1 ){ |
︙ | ︙ | |||
147 148 149 150 151 152 153 | Tcl_MutexUnlock(&testasync_g_writerMutex); return TCL_OK; } /* ** sqlite3async_control OPTION ?VALUE? */ | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | Tcl_MutexUnlock(&testasync_g_writerMutex); return TCL_OK; } /* ** sqlite3async_control OPTION ?VALUE? */ static int SQLITE_TCLAPI testAsyncControl( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = SQLITE_OK; int aeOpt[] = { SQLITEASYNC_HALT, SQLITEASYNC_DELAY, SQLITEASYNC_LOCKFILES }; |
︙ | ︙ |
Changes to src/test_autoext.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 August 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. */ | > > > | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* ** 2006 August 23 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. */ #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include "sqlite3ext.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_EXTENSION_INIT1 /* ** The sqr() SQL function returns the square of its input value. |
︙ | ︙ | |||
83 84 85 86 87 88 89 | } /* ** tclcmd: sqlite3_auto_extension_sqr ** ** Register the "sqr" extension to be loaded automatically. */ | | | | | | | | | | | | | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | } /* ** tclcmd: sqlite3_auto_extension_sqr ** ** Register the "sqr" extension to be loaded automatically. */ static int SQLITE_TCLAPI autoExtSqrObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_auto_extension((void(*)(void))sqr_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } /* ** tclcmd: sqlite3_cancel_auto_extension_sqr ** ** Unregister the "sqr" extension. */ static int SQLITE_TCLAPI cancelAutoExtSqrObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_cancel_auto_extension((void(*)(void))sqr_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } /* ** tclcmd: sqlite3_auto_extension_cube ** ** Register the "cube" extension to be loaded automatically. */ static int SQLITE_TCLAPI autoExtCubeObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_auto_extension((void(*)(void))cube_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } /* ** tclcmd: sqlite3_cancel_auto_extension_cube ** ** Unregister the "cube" extension. */ static int SQLITE_TCLAPI cancelAutoExtCubeObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_cancel_auto_extension((void(*)(void))cube_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } /* ** tclcmd: sqlite3_auto_extension_broken ** ** Register the broken extension to be loaded automatically. */ static int SQLITE_TCLAPI autoExtBrokenObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_auto_extension((void(*)(void))broken_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } /* ** tclcmd: sqlite3_cancel_auto_extension_broken ** ** Unregister the broken extension. */ static int SQLITE_TCLAPI cancelAutoExtBrokenObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = sqlite3_cancel_auto_extension((void(*)(void))broken_init); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return SQLITE_OK; } #endif /* SQLITE_OMIT_LOAD_EXTENSION */ /* ** tclcmd: sqlite3_reset_auto_extension ** ** Reset all auto-extensions */ static int SQLITE_TCLAPI resetAutoExtObjCmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_reset_auto_extension(); return SQLITE_OK; |
︙ | ︙ |
Changes to src/test_backup.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_backup() interface. ** */ | > > > | > > > > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_backup() interface. ** */ #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include "sqlite3.h" #include <assert.h> /* These functions are implemented in main.c. */ extern const char *sqlite3ErrName(int); /* These functions are implemented in test1.c. */ extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); static int SQLITE_TCLAPI backupTestCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ enum BackupSubCommandEnum { BACKUP_STEP, BACKUP_FINISH, BACKUP_REMAINING, BACKUP_PAGECOUNT |
︙ | ︙ | |||
94 95 96 97 98 99 100 | Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_backup_pagecount(p))); break; } return TCL_OK; } | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_backup_pagecount(p))); break; } return TCL_OK; } static void SQLITE_TCLAPI backupTestFinish(ClientData clientData){ sqlite3_backup *pBackup = (sqlite3_backup *)clientData; sqlite3_backup_finish(pBackup); } /* ** sqlite3_backup CMDNAME DESTHANDLE DESTNAME SRCHANDLE SRCNAME ** */ static int SQLITE_TCLAPI backupTestInit( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ sqlite3_backup *pBackup; sqlite3 *pDestDb; |
︙ | ︙ |
Changes to src/test_bestindex.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** for the current scan. The leftmost column returned by the SELECT is assumed ** to contain the rowid. Other columns must follow, in order from left to ** right. */ #include "sqliteInt.h" | > > > | > | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | ** for the current scan. The leftmost column returned by the SELECT is assumed ** to contain the rowid. Other columns must follow, in order from left to ** right. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct tcl_vtab tcl_vtab; typedef struct tcl_cursor tcl_cursor; /* |
︙ | ︙ | |||
175 176 177 178 179 180 181 | int rc = SQLITE_OK; if( argc!=4 ){ *pzErr = sqlite3_mprintf("wrong number of arguments"); return SQLITE_ERROR; } | | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | int rc = SQLITE_OK; if( argc!=4 ){ *pzErr = sqlite3_mprintf("wrong number of arguments"); return SQLITE_ERROR; } zCmd = sqlite3_malloc64(strlen(argv[3])+1); pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab)); if( zCmd && pTab ){ memcpy(zCmd, argv[3], strlen(argv[3])+1); tclDequote(zCmd); memset(pTab, 0, sizeof(tcl_vtab)); pTab->pCmd = Tcl_NewStringObj(zCmd, -1); pTab->interp = interp; |
︙ | ︙ | |||
559 560 561 562 563 564 565 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ | | | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ static int SQLITE_TCLAPI register_tcl_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ |
︙ | ︙ |
Changes to src/test_blob.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** */ #include "sqliteInt.h" | > > > | > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <assert.h> #ifndef SQLITE_OMIT_INCRBLOB /* These functions are implemented in main.c. */ extern const char *sqlite3ErrName(int); |
︙ | ︙ | |||
91 92 93 94 95 96 97 | } /* ** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME ** ** Tcl test harness for the sqlite3_blob_open() function. */ | | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | } /* ** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME ** ** Tcl test harness for the sqlite3_blob_open() function. */ static int SQLITE_TCLAPI test_blob_open( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* Calling TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDb; |
︙ | ︙ | |||
142 143 144 145 146 147 148 | return TCL_OK; } /* ** sqlite3_blob_close HANDLE */ | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | return TCL_OK; } /* ** sqlite3_blob_close HANDLE */ static int SQLITE_TCLAPI test_blob_close( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int rc; |
︙ | ︙ | |||
170 171 172 173 174 175 176 | } return TCL_OK; } /* ** sqlite3_blob_bytes HANDLE */ | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | } return TCL_OK; } /* ** sqlite3_blob_bytes HANDLE */ static int SQLITE_TCLAPI test_blob_bytes( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int nByte; |
︙ | ︙ | |||
206 207 208 209 210 211 212 | ** blob handle. ** ** On success, a byte-array object containing the read data is ** returned. On failure, the interpreter result is set to the ** text representation of the returned error code (i.e. "SQLITE_NOMEM") ** and a Tcl exception is thrown. */ | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | ** blob handle. ** ** On success, a byte-array object containing the read data is ** returned. On failure, the interpreter result is set to the ** text representation of the returned error code (i.e. "SQLITE_NOMEM") ** and a Tcl exception is thrown. */ static int SQLITE_TCLAPI test_blob_read( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int nByte; |
︙ | ︙ | |||
258 259 260 261 262 263 264 | ** to write the DATA byte-array to the underlying SQLite blob handle. ** at offset OFFSET. ** ** On success, an empty string is returned. On failure, the interpreter ** result is set to the text representation of the returned error code ** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. */ | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | ** to write the DATA byte-array to the underlying SQLite blob handle. ** at offset OFFSET. ** ** On success, an empty string is returned. On failure, the interpreter ** result is set to the text representation of the returned error code ** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. */ static int SQLITE_TCLAPI test_blob_write( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int iOffset; |
︙ | ︙ |
Changes to src/test_btree.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "btreeInt.h" | > > > | > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "btreeInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* ** Usage: sqlite3_shared_cache_report ** ** Return a list of file that are shared and the number of ** references to each file. */ int SQLITE_TCLAPI sqlite3BtreeSharedCacheReport( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_SHARED_CACHE extern BtShared *sqlite3SharedCacheList; |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "sqliteLimit.h" #include "sqliteInt.h" #if SQLITE_OS_WIN # include "os_win.h" #endif | > > > | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include "sqliteLimit.h" #include "sqliteInt.h" #if SQLITE_OS_WIN # include "os_win.h" #endif #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> /* ** Macro to stringify the results of the evaluation a pre-processor ** macro. i.e. so that STRINGVALUE(SQLITE_NOMEM) -> "7". */ |
︙ | ︙ |
Changes to src/test_demovfs.c.
︙ | ︙ | |||
637 638 639 640 641 642 643 | } #endif /* !defined(SQLITE_TEST) || SQLITE_OS_UNIX */ #ifdef SQLITE_TEST | > > > | > > > > | | | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | } #endif /* !defined(SQLITE_TEST) || SQLITE_OS_UNIX */ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #if SQLITE_OS_UNIX static int SQLITE_TCLAPI register_demovfs( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_vfs_register(sqlite3_demovfs(), 1); return TCL_OK; } static int SQLITE_TCLAPI unregister_demovfs( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_vfs_unregister(sqlite3_demovfs()); return TCL_OK; |
︙ | ︙ |
Changes to src/test_fs.c.
︙ | ︙ | |||
58 59 60 61 62 63 64 | ** contents of the file-system, starting at "/". To restrict the search ** space, the virtual table supports LIKE and GLOB constraints on the ** 'path' column. For example: ** ** SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%' */ #include "sqliteInt.h" | > > > | > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | ** contents of the file-system, starting at "/". To restrict the search ** space, the virtual table supports LIKE and GLOB constraints on the ** 'path' column. For example: ** ** SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%' */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> |
︙ | ︙ | |||
867 868 869 870 871 872 873 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ | | | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ static int SQLITE_TCLAPI register_fs_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ |
︙ | ︙ |
Changes to src/test_func.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. */ #include "sqlite3.h" | > > > | > < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. */ #include "sqlite3.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqliteInt.h" #include "vdbeInt.h" /* ** Allocate nByte bytes of space using sqlite3_malloc(). If the ** allocation fails, call sqlite3_result_error_nomem() to notify ** the database handle that malloc() has failed. */ static void *testContextMalloc(sqlite3_context *context, int nByte){ |
︙ | ︙ | |||
636 637 638 639 640 641 642 | int argc, sqlite3_value **argv ){ sqlite3_result_value(context, argv[0]); sqlite3_result_subtype(context, (unsigned int)sqlite3_value_int(argv[1])); } | | > > > > | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | int argc, sqlite3_value **argv ){ sqlite3_result_value(context, argv[0]); sqlite3_result_subtype(context, (unsigned int)sqlite3_value_int(argv[1])); } static int registerTestFunctions( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pThunk ){ static const struct { char *zName; signed char nArg; unsigned int eTextRep; /* 1: UTF-16. 0: UTF-8 */ void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { { "randstr", 2, SQLITE_UTF8, randStr }, |
︙ | ︙ | |||
685 686 687 688 689 690 691 | /* ** TCLCMD: autoinstall_test_functions ** ** Invoke this TCL command to use sqlite3_auto_extension() to cause ** the standard set of test functions to be loaded into each new ** database connection. */ | | | | | | | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | /* ** TCLCMD: autoinstall_test_functions ** ** Invoke this TCL command to use sqlite3_auto_extension() to cause ** the standard set of test functions to be loaded into each new ** database connection. */ static int SQLITE_TCLAPI autoinstall_test_funcs( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *); int rc = sqlite3_auto_extension((void(*)(void))registerTestFunctions); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension((void(*)(void))Md5_Register); } Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** A bogus step function and finalizer function. */ static void tStep(sqlite3_context *a, int b, sqlite3_value **c){} static void tFinal(sqlite3_context *a){} /* ** tclcmd: abuse_create_function ** ** Make various calls to sqlite3_create_function that do not have valid ** parameters. Verify that the error condition is detected and reported. */ static int SQLITE_TCLAPI abuse_create_function( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); sqlite3 *db; |
︙ | ︙ | |||
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | return TCL_OK; abuse_err: Tcl_AppendResult(interp, "sqlite3_create_function abused test failed", (char*)0); return TCL_ERROR; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_func_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "autoinstall_test_functions", autoinstall_test_funcs }, { "abuse_create_function", abuse_create_function }, }; int i; | > | | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | return TCL_OK; abuse_err: Tcl_AppendResult(interp, "sqlite3_create_function abused test failed", (char*)0); return TCL_ERROR; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_func_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "autoinstall_test_functions", autoinstall_test_funcs }, { "abuse_create_function", abuse_create_function }, }; int i; extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *); for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } sqlite3_initialize(); sqlite3_auto_extension((void(*)(void))registerTestFunctions); sqlite3_auto_extension((void(*)(void))Md5_Register); return TCL_OK; } |
Changes to src/test_hexio.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** database files and displaying the content of those files as ** hexadecimal. We could, in theory, use the built-in "binary" ** command of TCL to do a lot of this, but there are some issues ** with historical versions of the "binary" command. So it seems ** easier and safer to build our own mechanism. */ #include "sqliteInt.h" | > > > | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** database files and displaying the content of those files as ** hexadecimal. We could, in theory, use the built-in "binary" ** command of TCL to do a lot of this, but there are some issues ** with historical versions of the "binary" command. So it seems ** easier and safer to build our own mechanism. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <assert.h> /* ** Convert binary to hex. The input zBuf[] contains N bytes of |
︙ | ︙ | |||
90 91 92 93 94 95 96 | /* ** Usage: hexio_read FILENAME OFFSET AMT ** ** Read AMT bytes from file FILENAME beginning at OFFSET from the ** beginning of the file. Convert that information to hexadecimal ** and return the resulting HEX string. */ | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | /* ** Usage: hexio_read FILENAME OFFSET AMT ** ** Read AMT bytes from file FILENAME beginning at OFFSET from the ** beginning of the file. Convert that information to hexadecimal ** and return the resulting HEX string. */ static int SQLITE_TCLAPI hexio_read( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int offset; int amt, got; |
︙ | ︙ | |||
140 141 142 143 144 145 146 | /* ** Usage: hexio_write FILENAME OFFSET DATA ** ** Write DATA into file FILENAME beginning at OFFSET from the ** beginning of the file. DATA is expressed in hexadecimal. */ | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | /* ** Usage: hexio_write FILENAME OFFSET DATA ** ** Write DATA into file FILENAME beginning at OFFSET from the ** beginning of the file. DATA is expressed in hexadecimal. */ static int SQLITE_TCLAPI hexio_write( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int offset; int nIn, nOut, written; |
︙ | ︙ | |||
188 189 190 191 192 193 194 | /* ** USAGE: hexio_get_int HEXDATA ** ** Interpret the HEXDATA argument as a big-endian integer. Return ** the value of that integer. HEXDATA can contain between 2 and 8 ** hexadecimal digits. */ | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | /* ** USAGE: hexio_get_int HEXDATA ** ** Interpret the HEXDATA argument as a big-endian integer. Return ** the value of that integer. HEXDATA can contain between 2 and 8 ** hexadecimal digits. */ static int SQLITE_TCLAPI hexio_get_int( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int val; int nIn, nOut; |
︙ | ︙ | |||
228 229 230 231 232 233 234 | /* ** USAGE: hexio_render_int16 INTEGER ** ** Render INTEGER has a 16-bit big-endian integer in hexadecimal. */ | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | /* ** USAGE: hexio_render_int16 INTEGER ** ** Render INTEGER has a 16-bit big-endian integer in hexadecimal. */ static int SQLITE_TCLAPI hexio_render_int16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int val; unsigned char aNum[10]; |
︙ | ︙ | |||
255 256 257 258 259 260 261 | /* ** USAGE: hexio_render_int32 INTEGER ** ** Render INTEGER has a 32-bit big-endian integer in hexadecimal. */ | | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | /* ** USAGE: hexio_render_int32 INTEGER ** ** Render INTEGER has a 32-bit big-endian integer in hexadecimal. */ static int SQLITE_TCLAPI hexio_render_int32( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int val; unsigned char aNum[10]; |
︙ | ︙ | |||
285 286 287 288 289 290 291 | /* ** USAGE: utf8_to_utf8 HEX ** ** The argument is a UTF8 string represented in hexadecimal. ** The UTF8 might not be well-formed. Run this string through ** sqlite3Utf8to8() convert it back to hex and return the result. */ | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | /* ** USAGE: utf8_to_utf8 HEX ** ** The argument is a UTF8 string represented in hexadecimal. ** The UTF8 might not be well-formed. Run this string through ** sqlite3Utf8to8() convert it back to hex and return the result. */ static int SQLITE_TCLAPI utf8_to_utf8( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifdef SQLITE_DEBUG int n; |
︙ | ︙ | |||
336 337 338 339 340 341 342 | /* ** USAGE: read_fts3varint BLOB VARNAME ** ** Read a varint from the start of BLOB. Set variable VARNAME to contain ** the interpreted value. Return the number of bytes of BLOB consumed. */ | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | /* ** USAGE: read_fts3varint BLOB VARNAME ** ** Read a varint from the start of BLOB. Set variable VARNAME to contain ** the interpreted value. Return the number of bytes of BLOB consumed. */ static int SQLITE_TCLAPI read_fts3varint( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nBlob; unsigned char *zBlob; |
︙ | ︙ |
Changes to src/test_init.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | ** of those subsystems that were initialized, and ** 3) A subsequent call to sqlite3_initialize() attempts to initialize ** the remaining, uninitialized, subsystems. */ #include "sqliteInt.h" #include <string.h> | > > > | > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ** of those subsystems that were initialized, and ** 3) A subsequent call to sqlite3_initialize() attempts to initialize ** the remaining, uninitialized, subsystems. */ #include "sqliteInt.h" #include <string.h> #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif static struct Wrapped { sqlite3_pcache_methods2 pcache; sqlite3_mem_methods mem; sqlite3_mutex_methods mutex; int mem_init; /* True if mem subsystem is initalized */ |
︙ | ︙ | |||
180 181 182 183 184 185 186 | sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem); sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache); sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods); sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods); sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods); } | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem); sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache); sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods); sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods); sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods); } static int SQLITE_TCLAPI init_wrapper_install( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; installInitWrappers(); |
︙ | ︙ | |||
204 205 206 207 208 209 210 | Tcl_AppendResult(interp, "Unknown argument: \"", z, "\""); return TCL_ERROR; } } return TCL_OK; } | | | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | Tcl_AppendResult(interp, "Unknown argument: \"", z, "\""); return TCL_ERROR; } } return TCL_OK; } static int SQLITE_TCLAPI init_wrapper_uninstall( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } sqlite3_shutdown(); sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex); sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem); sqlite3_config(SQLITE_CONFIG_PCACHE2, &wrapped.pcache); return TCL_OK; } static int SQLITE_TCLAPI init_wrapper_clear( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } wrapped.mem_fail = 0; wrapped.mutex_fail = 0; wrapped.pcache_fail = 0; return TCL_OK; } static int SQLITE_TCLAPI init_wrapper_query( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_Obj *pRet; |
︙ | ︙ |
Changes to src/test_intarray.c.
︙ | ︙ | |||
266 267 268 269 270 271 272 | } /***************************************************************************** ** Everything below is interface for testing this module. */ #ifdef SQLITE_TEST | > > > | > > > > | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | } /***************************************************************************** ** Everything below is interface for testing this module. */ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif /* ** Routines to encode and decode pointers */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern void *sqlite3TestTextToPtr(const char*); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*); extern const char *sqlite3ErrName(int); /* ** sqlite3_intarray_create DB NAME ** ** Invoke the sqlite3_intarray_create interface. A string that becomes ** the first parameter to sqlite3_intarray_bind. */ static int SQLITE_TCLAPI test_intarray_create( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zName; |
︙ | ︙ | |||
318 319 320 321 322 323 324 | } /* ** sqlite3_intarray_bind INTARRAY ?VALUE ...? ** ** Invoke the sqlite3_intarray_bind interface on the given array of integers. */ | | | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | } /* ** sqlite3_intarray_bind INTARRAY ?VALUE ...? ** ** Invoke the sqlite3_intarray_bind interface on the given array of integers. */ static int SQLITE_TCLAPI test_intarray_bind( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_intarray *pArray; int rc = SQLITE_OK; |
︙ | ︙ |
Changes to src/test_intarray.h.
︙ | ︙ | |||
71 72 73 74 75 76 77 | ** The intarray object is automatically destroyed when its corresponding ** virtual table is dropped. Since the virtual tables are created in the ** TEMP database, they are automatically dropped when the database connection ** closes so the application does not normally need to take any special ** action to free the intarray objects. */ #include "sqlite3.h" | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | ** The intarray object is automatically destroyed when its corresponding ** virtual table is dropped. Since the virtual tables are created in the ** TEMP database, they are automatically dropped when the database connection ** closes so the application does not normally need to take any special ** action to free the intarray objects. */ #include "sqlite3.h" #ifndef SQLITE_INTARRAY_H #define SQLITE_INTARRAY_H /* ** Make sure we can call this stuff from C++. */ #ifdef __cplusplus extern "C" { #endif |
︙ | ︙ | |||
121 122 123 124 125 126 127 | sqlite3_int64 *aElements, /* Content of the intarray */ void (*xFree)(void*) /* How to dispose of the intarray when done */ ); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif | | | 121 122 123 124 125 126 127 128 | sqlite3_int64 *aElements, /* Content of the intarray */ void (*xFree)(void*) /* How to dispose of the intarray when done */ ); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE_INTARRAY_H */ |
Changes to src/test_malloc.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. */ #include "sqliteInt.h" | > > > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** ************************************************************************* ** ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <assert.h> /* ** This structure is used to encapsulate the global state variables used ** by malloc() fault simulation. |
︙ | ︙ | |||
302 303 304 305 306 307 308 | } /* ** Usage: sqlite3_malloc NBYTES ** ** Raw test interface for sqlite3_malloc(). */ | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | } /* ** Usage: sqlite3_malloc NBYTES ** ** Raw test interface for sqlite3_malloc(). */ static int SQLITE_TCLAPI test_malloc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nByte; void *p; |
︙ | ︙ | |||
327 328 329 330 331 332 333 | } /* ** Usage: sqlite3_realloc PRIOR NBYTES ** ** Raw test interface for sqlite3_realloc(). */ | | | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | } /* ** Usage: sqlite3_realloc PRIOR NBYTES ** ** Raw test interface for sqlite3_realloc(). */ static int SQLITE_TCLAPI test_realloc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nByte; void *pPrior, *p; |
︙ | ︙ | |||
356 357 358 359 360 361 362 | } /* ** Usage: sqlite3_free PRIOR ** ** Raw test interface for sqlite3_free(). */ | | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | } /* ** Usage: sqlite3_free PRIOR ** ** Raw test interface for sqlite3_free(). */ static int SQLITE_TCLAPI test_free( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *pPrior; if( objc!=2 ){ |
︙ | ︙ | |||
387 388 389 390 391 392 393 | /* ** Usage: memset ADDRESS SIZE HEX ** ** Set a chunk of memory (obtained from malloc, probably) to a ** specified hex pattern. */ | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | /* ** Usage: memset ADDRESS SIZE HEX ** ** Set a chunk of memory (obtained from malloc, probably) to a ** specified hex pattern. */ static int SQLITE_TCLAPI test_memset( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *p; int size, n, i; |
︙ | ︙ | |||
433 434 435 436 437 438 439 | } /* ** Usage: memget ADDRESS SIZE ** ** Return memory as hexadecimal text. */ | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | } /* ** Usage: memget ADDRESS SIZE ** ** Return memory as hexadecimal text. */ static int SQLITE_TCLAPI test_memget( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *p; int size, n; |
︙ | ︙ | |||
480 481 482 483 484 485 486 | } /* ** Usage: sqlite3_memory_used ** ** Raw test interface for sqlite3_memory_used(). */ | | | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | } /* ** Usage: sqlite3_memory_used ** ** Raw test interface for sqlite3_memory_used(). */ static int SQLITE_TCLAPI test_memory_used( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sqlite3_memory_used())); return TCL_OK; } /* ** Usage: sqlite3_memory_highwater ?RESETFLAG? ** ** Raw test interface for sqlite3_memory_highwater(). */ static int SQLITE_TCLAPI test_memory_highwater( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int resetFlag = 0; if( objc!=1 && objc!=2 ){ |
︙ | ︙ | |||
520 521 522 523 524 525 526 | /* ** Usage: sqlite3_memdebug_backtrace DEPTH ** ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined ** then this routine is a no-op. */ | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | /* ** Usage: sqlite3_memdebug_backtrace DEPTH ** ** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined ** then this routine is a no-op. */ static int SQLITE_TCLAPI test_memdebug_backtrace( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int depth; if( objc!=2 ){ |
︙ | ︙ | |||
546 547 548 549 550 551 552 | } /* ** Usage: sqlite3_memdebug_dump FILENAME ** ** Write a summary of unfreed memory to FILENAME. */ | | | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | } /* ** Usage: sqlite3_memdebug_dump FILENAME ** ** Write a summary of unfreed memory to FILENAME. */ static int SQLITE_TCLAPI test_memdebug_dump( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
︙ | ︙ | |||
571 572 573 574 575 576 577 | } /* ** Usage: sqlite3_memdebug_malloc_count ** ** Return the total number of times malloc() has been called. */ | | | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | } /* ** Usage: sqlite3_memdebug_malloc_count ** ** Return the total number of times malloc() has been called. */ static int SQLITE_TCLAPI test_memdebug_malloc_count( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nMalloc = -1; if( objc!=1 ){ |
︙ | ︙ | |||
611 612 613 614 615 616 617 | ** ** Each call to this routine overrides the prior counter value. ** This routine returns the number of simulated failures that have ** happened since the previous call to this routine. ** ** To disable simulated failures, use a COUNTER of -1. */ | | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | ** ** Each call to this routine overrides the prior counter value. ** This routine returns the number of simulated failures that have ** happened since the previous call to this routine. ** ** To disable simulated failures, use a COUNTER of -1. */ static int SQLITE_TCLAPI test_memdebug_fail( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ii; int iFail; |
︙ | ︙ | |||
677 678 679 680 681 682 683 | /* ** Usage: sqlite3_memdebug_pending ** ** Return the number of malloc() calls that will succeed before a ** simulated failure occurs. A negative return value indicates that ** no malloc() failure is scheduled. */ | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | /* ** Usage: sqlite3_memdebug_pending ** ** Return the number of malloc() calls that will succeed before a ** simulated failure occurs. A negative return value indicates that ** no malloc() failure is scheduled. */ static int SQLITE_TCLAPI test_memdebug_pending( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nPending; if( objc!=1 ){ |
︙ | ︙ | |||
710 711 712 713 714 715 716 | ** Set a title string stored with each allocation. The TITLE is ** typically the name of the test that was running when the ** allocation occurred. The TITLE is stored with the allocation ** and can be used to figure out which tests are leaking memory. ** ** Each title overwrite the previous. */ | | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 | ** Set a title string stored with each allocation. The TITLE is ** typically the name of the test that was running when the ** allocation occurred. The TITLE is stored with the allocation ** and can be used to figure out which tests are leaking memory. ** ** Each title overwrite the previous. */ static int SQLITE_TCLAPI test_memdebug_settitle( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_memdebug_title_count++; if( objc!=2 ){ |
︙ | ︙ | |||
791 792 793 794 795 796 797 | MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); Tcl_Free((char *)pLog); } Tcl_DeleteHashTable(&aMallocLog); Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS); } | | | 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry); Tcl_Free((char *)pLog); } Tcl_DeleteHashTable(&aMallocLog); Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS); } static int SQLITE_TCLAPI test_memdebug_log( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static int isInit = 0; int iSub; |
︙ | ︙ | |||
889 890 891 892 893 894 895 | ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. ** The buffer is static and is of limited size. N might be ** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. */ | | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | ** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH. ** The buffer is static and is of limited size. N might be ** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. */ static int SQLITE_TCLAPI test_config_scratch( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int sz, N, rc; Tcl_Obj *pResult; |
︙ | ︙ | |||
929 930 931 932 933 934 935 | ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. ** The buffer is static and is of limited size. N might be ** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. */ | | | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | ** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE. ** The buffer is static and is of limited size. N might be ** adjusted downward as needed to accommodate the requested size. ** The revised value of N is returned. ** ** A negative SIZE causes the buffer pointer to be NULL. */ static int SQLITE_TCLAPI test_config_pagecache( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int sz, N; Tcl_Obj *pRes; |
︙ | ︙ | |||
972 973 974 975 976 977 978 | ** Set up the alternative test page cache. Install if INSTALL_FLAG is ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive ** which determines the chance of discarding a page when unpinned. 100 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator ** seed. */ | | | 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | ** Set up the alternative test page cache. Install if INSTALL_FLAG is ** true and uninstall (reverting to the default page cache) if INSTALL_FLAG ** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive ** which determines the chance of discarding a page when unpinned. 100 ** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator ** seed. */ static int SQLITE_TCLAPI test_alt_pcache( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int installFlag; int discardChance = 0; |
︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 | } /* ** Usage: sqlite3_config_memstatus BOOLEAN ** ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. */ | | | | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | } /* ** Usage: sqlite3_config_memstatus BOOLEAN ** ** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS. */ static int SQLITE_TCLAPI test_config_memstatus( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int enable, rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN"); return TCL_ERROR; } if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ) return TCL_ERROR; rc = sqlite3_config(SQLITE_CONFIG_MEMSTATUS, enable); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_config_lookaside SIZE COUNT ** */ static int SQLITE_TCLAPI test_config_lookaside( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int sz, cnt; Tcl_Obj *pRet; |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | /* ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT ** ** There are two static buffers with BUFID 1 and 2. Each static buffer ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL ** which will cause sqlite3_db_config() to allocate space on its own. */ | | | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 | /* ** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT ** ** There are two static buffers with BUFID 1 and 2. Each static buffer ** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL ** which will cause sqlite3_db_config() to allocate space on its own. */ static int SQLITE_TCLAPI test_db_config_lookaside( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; int sz, cnt; |
︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_config_heap NBYTE NMINALLOC */ | | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_config_heap NBYTE NMINALLOC */ static int SQLITE_TCLAPI test_config_heap( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static char *zBuf; /* Use this memory */ int nByte; /* Size of buffer to pass to sqlite3_config() */ |
︙ | ︙ | |||
1140 1141 1142 1143 1144 1145 1146 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_config_heap_size NBYTE */ | | | 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_config_heap_size NBYTE */ static int SQLITE_TCLAPI test_config_heap_size( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nByte; /* Size to pass to sqlite3_config() */ int rc; /* Return code of sqlite3_config() */ |
︙ | ︙ | |||
1170 1171 1172 1173 1174 1175 1176 | /* ** Usage: sqlite3_config_error [DB] ** ** Invoke sqlite3_config() or sqlite3_db_config() with invalid ** opcodes and verify that they return errors. */ | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 | /* ** Usage: sqlite3_config_error [DB] ** ** Invoke sqlite3_config() or sqlite3_db_config() with invalid ** opcodes and verify that they return errors. */ static int SQLITE_TCLAPI test_config_error( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**); |
︙ | ︙ | |||
1208 1209 1210 1211 1212 1213 1214 | /* ** Usage: sqlite3_config_uri BOOLEAN ** ** Enables or disables interpretation of URI parameters by default using ** SQLITE_CONFIG_URI. */ | | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 | /* ** Usage: sqlite3_config_uri BOOLEAN ** ** Enables or disables interpretation of URI parameters by default using ** SQLITE_CONFIG_URI. */ static int SQLITE_TCLAPI test_config_uri( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; int bOpenUri; |
︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 | /* ** Usage: sqlite3_config_cis BOOLEAN ** ** Enables or disables the use of the covering-index scan optimization. ** SQLITE_CONFIG_COVERING_INDEX_SCAN. */ | | | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | /* ** Usage: sqlite3_config_cis BOOLEAN ** ** Enables or disables the use of the covering-index scan optimization. ** SQLITE_CONFIG_COVERING_INDEX_SCAN. */ static int SQLITE_TCLAPI test_config_cis( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; int bUseCis; |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | } /* ** Usage: sqlite3_config_pmasz INTEGER ** ** Set the minimum PMA size. */ | | | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 | } /* ** Usage: sqlite3_config_pmasz INTEGER ** ** Set the minimum PMA size. */ static int SQLITE_TCLAPI test_config_pmasz( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; int iPmaSz; |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME ** ** Write a summary of unfreed memsys3 allocations to FILENAME. */ | | | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 | /* ** Usage: sqlite3_dump_memsys3 FILENAME ** sqlite3_dump_memsys5 FILENAME ** ** Write a summary of unfreed memsys3 allocations to FILENAME. */ static int SQLITE_TCLAPI test_dump_memsys3( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 | /* ** Usage: sqlite3_status OPCODE RESETFLAG ** ** Return a list of three elements which are the sqlite3_status() return ** code, the current value, and the high-water mark value. */ | | | 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 | /* ** Usage: sqlite3_status OPCODE RESETFLAG ** ** Return a list of three elements which are the sqlite3_status() return ** code, the current value, and the high-water mark value. */ static int SQLITE_TCLAPI test_status( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; int i, op = 0, resetFlag; |
︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 | /* ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG ** ** Return a list of three elements which are the sqlite3_db_status() return ** code, the current value, and the high-water mark value. */ | | | 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | /* ** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG ** ** Return a list of three elements which are the sqlite3_db_status() return ** code, the current value, and the high-water mark value. */ static int SQLITE_TCLAPI test_db_status( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc, iValue, mxValue; int i, op = 0, resetFlag; |
︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 | { "STMT_USED", SQLITE_DBSTATUS_STMT_USED }, { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT }, { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE }, { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }, { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT }, { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS }, { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE }, | | > | 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | { "STMT_USED", SQLITE_DBSTATUS_STMT_USED }, { "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT }, { "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE }, { "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL }, { "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT }, { "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS }, { "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE }, { "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS }, { "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED }, }; Tcl_Obj *pResult; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB PARAMETER RESETFLAG"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** install_malloc_faultsim BOOLEAN */ | | | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** install_malloc_faultsim BOOLEAN */ static int SQLITE_TCLAPI test_install_malloc_faultsim( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; int isInstall; |
︙ | ︙ | |||
1472 1473 1474 1475 1476 1477 1478 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_install_memsys3 */ | | | | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_install_memsys3 */ static int SQLITE_TCLAPI test_install_memsys3( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = SQLITE_MISUSE; #ifdef SQLITE_ENABLE_MEMSYS3 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3()); #endif Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } static int SQLITE_TCLAPI test_vfs_oom_test( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ extern int sqlite3_memdebug_vfs_oom_test; if( objc>2 ){ |
︙ | ︙ |
Changes to src/test_multiplex.c.
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | gMultiplex.sIoMethodsV2.iVersion = 2; gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap; gMultiplex.sIoMethodsV2.xShmLock = multiplexShmLock; gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier; gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap; sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault); | | | 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 | gMultiplex.sIoMethodsV2.iVersion = 2; gMultiplex.sIoMethodsV2.xShmMap = multiplexShmMap; gMultiplex.sIoMethodsV2.xShmLock = multiplexShmLock; gMultiplex.sIoMethodsV2.xShmBarrier = multiplexShmBarrier; gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap; sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault); sqlite3_auto_extension((void(*)(void))multiplexFuncInit); return SQLITE_OK; } /* ** CAPI: Shutdown the multiplex system - sqlite3_multiplex_shutdown() ** |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | sqlite3_vfs_unregister(&gMultiplex.sThisVfs); memset(&gMultiplex, 0, sizeof(gMultiplex)); return rc; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST | > > > | > > > > | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | sqlite3_vfs_unregister(&gMultiplex.sThisVfs); memset(&gMultiplex, 0, sizeof(gMultiplex)); return rc; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif extern const char *sqlite3ErrName(int); /* ** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT */ static int SQLITE_TCLAPI test_multiplex_initialize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zName; /* Name of new multiplex VFS */ int makeDefault; /* True to make the new VFS the default */ |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_shutdown */ | | | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_shutdown */ static int SQLITE_TCLAPI test_multiplex_shutdown( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; /* Value returned by multiplex_shutdown() */ |
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 | return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_dump */ | | | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | return TCL_OK; } /* ** tclcmd: sqlite3_multiplex_dump */ static int SQLITE_TCLAPI test_multiplex_dump( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj *pResult; Tcl_Obj *pGroupTerm; |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE? */ | | | 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE? */ static int SQLITE_TCLAPI test_multiplex_control( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; /* Return code from file_control() */ int idx; /* Index in aSub[] */ |
︙ | ︙ |
Changes to src/test_multiplex.h.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ** This particular shim enforces a multiplex system on DB files. ** This shim shards/partitions a single DB file into smaller ** "chunks" such that the total DB file size may exceed the maximum ** file size of the underlying file system. ** */ | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** This particular shim enforces a multiplex system on DB files. ** This shim shards/partitions a single DB file into smaller ** "chunks" such that the total DB file size may exceed the maximum ** file size of the underlying file system. ** */ #ifndef SQLITE_TEST_MULTIPLEX_H #define SQLITE_TEST_MULTIPLEX_H /* ** CAPI: File-control Operations Supported by Multiplex VFS ** ** Values interpreted by the xFileControl method of a Multiplex VFS db file-handle. ** ** MULTIPLEX_CTRL_ENABLE: |
︙ | ︙ | |||
92 93 94 95 96 97 98 | */ extern int sqlite3_multiplex_shutdown(int eForce); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif | | | 92 93 94 95 96 97 98 99 | */ extern int sqlite3_multiplex_shutdown(int eForce); #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE_TEST_MULTIPLEX_H */ |
Changes to src/test_mutex.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_mutex interfaces. */ | > > > | > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_mutex interfaces. */ #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include "sqlite3.h" #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include <string.h> #define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1) |
︙ | ︙ | |||
148 149 150 151 152 153 154 | assert( g.isInit ); g.m.xMutexLeave(p->pReal); } /* ** sqlite3_shutdown */ | | | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | assert( g.isInit ); g.m.xMutexLeave(p->pReal); } /* ** sqlite3_shutdown */ static int SQLITE_TCLAPI test_shutdown( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_shutdown(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_initialize */ static int SQLITE_TCLAPI test_initialize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_initialize(); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** install_mutex_counters BOOLEAN */ static int SQLITE_TCLAPI test_install_mutex_counters( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = SQLITE_OK; int isInstall; |
︙ | ︙ | |||
251 252 253 254 255 256 257 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** read_mutex_counters */ | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_OK; } /* ** read_mutex_counters */ static int SQLITE_TCLAPI test_read_mutex_counters( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj *pRet; int ii; |
︙ | ︙ | |||
280 281 282 283 284 285 286 | return TCL_OK; } /* ** clear_mutex_counters */ | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | return TCL_OK; } /* ** clear_mutex_counters */ static int SQLITE_TCLAPI test_clear_mutex_counters( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ii; |
︙ | ︙ | |||
304 305 306 307 308 309 310 | } /* ** Create and free a mutex. Return the mutex pointer. The pointer ** will be invalid since the mutex has already been freed. The ** return pointer just checks to see if the mutex really was allocated. */ | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | } /* ** Create and free a mutex. Return the mutex pointer. The pointer ** will be invalid since the mutex has already been freed. The ** return pointer just checks to see if the mutex really was allocated. */ static int SQLITE_TCLAPI test_alloc_mutex( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #if SQLITE_THREADSAFE sqlite3_mutex *p = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
︙ | ︙ | |||
331 332 333 334 335 336 337 | ** ** SQLITE_CONFIG_SINGLETHREAD ** SQLITE_CONFIG_MULTITHREAD ** SQLITE_CONFIG_SERIALIZED ** ** Or OPTION can be an raw integer. */ | | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | ** ** SQLITE_CONFIG_SINGLETHREAD ** SQLITE_CONFIG_MULTITHREAD ** SQLITE_CONFIG_SERIALIZED ** ** Or OPTION can be an raw integer. */ static int SQLITE_TCLAPI test_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct ConfigOption { const char *zName; |
︙ | ︙ | |||
393 394 395 396 397 398 399 | if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){ return 0; } assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE ); return counterMutexAlloc(iMutex); } | | | | | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){ return 0; } assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE ); return counterMutexAlloc(iMutex); } static int SQLITE_TCLAPI test_enter_static_mutex( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_mutex *pMutex; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "NAME"); return TCL_ERROR; } pMutex = getStaticMutexPointer(interp, objv[1]); if( !pMutex ){ return TCL_ERROR; } sqlite3_mutex_enter(pMutex); return TCL_OK; } static int SQLITE_TCLAPI test_leave_static_mutex( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_mutex *pMutex; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "NAME"); return TCL_ERROR; } pMutex = getStaticMutexPointer(interp, objv[1]); if( !pMutex ){ return TCL_ERROR; } sqlite3_mutex_leave(pMutex); return TCL_OK; } static int SQLITE_TCLAPI test_enter_db_mutex( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } db = getDbPointer(interp, objv[1]); if( !db ){ return TCL_ERROR; } sqlite3_mutex_enter(sqlite3_db_mutex(db)); return TCL_OK; } static int SQLITE_TCLAPI test_leave_db_mutex( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ |
︙ | ︙ |
Changes to src/test_osinst.c.
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 | /************************************************************************** *************************************************************************** ** Tcl interface starts here. */ #if defined(SQLITE_TEST) || defined(TCLSH) | > > > | > > > > | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 | /************************************************************************** *************************************************************************** ** Tcl interface starts here. */ #if defined(SQLITE_TEST) || defined(TCLSH) #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif static int SQLITE_TCLAPI test_vfslog( void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct SqliteDb { sqlite3 *db; }; sqlite3 *db; |
︙ | ︙ |
Changes to src/test_quota.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 | int nRef; /* Number of times this file is open */ int deleteOnClose; /* True to delete this file when it closes */ quotaFile *pNext, **ppPrev; /* Linked list of files in the same group */ }; /* ** An instance of the following object represents each open connection | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | int nRef; /* Number of times this file is open */ int deleteOnClose; /* True to delete this file when it closes */ quotaFile *pNext, **ppPrev; /* Linked list of files in the same group */ }; /* ** An instance of the following object represents each open connection ** to a file that participates in quota tracking. This object is a ** subclass of sqlite3_file. The sqlite3_file object for the underlying ** VFS is appended to this structure. */ struct quotaConn { sqlite3_file base; /* Base class - must be first */ quotaFile *pFile; /* The underlying file */ /* The underlying VFS sqlite3_file is appended to this object */ |
︙ | ︙ | |||
150 151 152 153 154 155 156 | sqlite3_vfs *pOrigVfs; /* The sThisVfs is the VFS structure used by this shim. It is initialized ** at start-time and thus does not require a mutex */ sqlite3_vfs sThisVfs; | | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | sqlite3_vfs *pOrigVfs; /* The sThisVfs is the VFS structure used by this shim. It is initialized ** at start-time and thus does not require a mutex */ sqlite3_vfs sThisVfs; /* The sIoMethods defines the methods used by sqlite3_file objects ** associated with this shim. It is initialized at start-time and does ** not require a mutex. ** ** When the underlying VFS is called to open a file, it might return ** either a version 1 or a version 2 sqlite3_file object. This shim ** has to create a wrapper sqlite3_file of the same version. Hence ** there are two I/O method structures, one for version 1 and the other ** for version 2. */ sqlite3_io_methods sIoMethodsV1; sqlite3_io_methods sIoMethodsV2; |
︙ | ︙ | |||
186 187 188 189 190 191 192 | /* ** Acquire and release the mutex used to serialize access to the ** list of quotaGroups. */ static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); } static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); } | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | /* ** Acquire and release the mutex used to serialize access to the ** list of quotaGroups. */ static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); } static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); } /* Count the number of open files in a quotaGroup */ static int quotaGroupOpenFileCount(quotaGroup *pGroup){ int N = 0; quotaFile *pFile = pGroup->pFiles; while( pFile ){ if( pFile->nRef ) N++; pFile = pFile->pNext; |
︙ | ︙ | |||
395 396 397 398 399 400 401 | if( zMbcs ){ WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0); } sqlite3_free(zTmpWide); return zMbcs; #else return (char*)zUtf8; /* No-op on unix */ | | | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | if( zMbcs ){ WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0); } sqlite3_free(zTmpWide); return zMbcs; #else return (char*)zUtf8; /* No-op on unix */ #endif } /* ** Deallocate any memory allocated by quota_utf8_to_mbcs(). */ static void quota_mbcs_free(char *zOld){ #if SQLITE_OS_WIN sqlite3_free(zOld); #else /* No-op on unix */ #endif } /************************* VFS Method Wrappers *****************************/ /* ** This is the xOpen method used for the "quota" VFS. ** ** Most of the work is done by the underlying original VFS. This method ** simply links the new file into the appropriate quota group if it is a ** file that needs to be tracked. */ static int quotaOpen( sqlite3_vfs *pVfs, /* The quota VFS */ const char *zName, /* Name of file to be opened */ sqlite3_file *pConn, /* Fill in this file descriptor */ int flags, /* Flags to control the opening */ int *pOutFlags /* Flags showing results of opening */ ){ int rc; /* Result code */ quotaConn *pQuotaOpen; /* The new quota file descriptor */ quotaFile *pFile; /* Corresponding quotaFile obj */ quotaGroup *pGroup; /* The group file belongs to */ sqlite3_file *pSubOpen; /* Real file descriptor */ sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */ /* If the file is not a main database file or a WAL, then use the |
︙ | ︙ | |||
484 485 486 487 488 489 490 | ** the set of files in the quota group. */ static int quotaDelete( sqlite3_vfs *pVfs, /* The quota VFS */ const char *zName, /* Name of file to be deleted */ int syncDir /* Do a directory sync after deleting */ ){ | | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | ** the set of files in the quota group. */ static int quotaDelete( sqlite3_vfs *pVfs, /* The quota VFS */ const char *zName, /* Name of file to be deleted */ int syncDir /* Do a directory sync after deleting */ ){ int rc; /* Result code */ quotaFile *pFile; /* Files in the quota */ quotaGroup *pGroup; /* The group file belongs to */ sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */ /* Do the actual file delete */ rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir); |
︙ | ︙ | |||
577 578 579 580 581 582 583 | if( pFile->iSize<iEnd ){ pGroup = pFile->pGroup; quotaEnter(); szNew = pGroup->iSize - pFile->iSize + iEnd; if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ if( pGroup->xCallback ){ | | | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | if( pFile->iSize<iEnd ){ pGroup = pFile->pGroup; quotaEnter(); szNew = pGroup->iSize - pFile->iSize + iEnd; if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ if( pGroup->xCallback ){ pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, pGroup->pArg); } if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ quotaLeave(); return SQLITE_FULL; } } |
︙ | ︙ | |||
734 735 736 737 738 739 740 | return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); } /************************** Public Interfaces *****************************/ /* ** Initialize the quota VFS shim. Use the VFS named zOrigVfsName ** as the VFS that does the actual work. Use the default if | | | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag); } /************************** Public Interfaces *****************************/ /* ** Initialize the quota VFS shim. Use the VFS named zOrigVfsName ** as the VFS that does the actual work. Use the default if ** zOrigVfsName==NULL. ** ** The quota VFS shim is named "quota". It will become the default ** VFS if makeDefault is non-zero. ** ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once ** during start-up. */ |
︙ | ︙ | |||
904 905 906 907 908 909 910 | zFull = &((char *)fd)[gQuota.sThisVfs.szOsFile]; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, gQuota.sThisVfs.mxPathname+1, zFull); } if( rc==SQLITE_OK ){ zFull[strlen(zFull)+1] = '\0'; | | | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 | zFull = &((char *)fd)[gQuota.sThisVfs.szOsFile]; rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename, gQuota.sThisVfs.mxPathname+1, zFull); } if( rc==SQLITE_OK ){ zFull[strlen(zFull)+1] = '\0'; rc = quotaOpen(&gQuota.sThisVfs, zFull, fd, SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB, &outFlags); if( rc==SQLITE_OK ){ fd->pMethods->xFileSize(fd, &iSize); fd->pMethods->xClose(fd); }else if( rc==SQLITE_CANTOPEN ){ quotaGroup *pGroup; quotaFile *pFile; |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | pFile = p->pFile; if( pFile && pFile->iSize<iEnd ){ quotaGroup *pGroup = pFile->pGroup; quotaEnter(); szNew = pGroup->iSize - pFile->iSize + iEnd; if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ if( pGroup->xCallback ){ | | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 | pFile = p->pFile; if( pFile && pFile->iSize<iEnd ){ quotaGroup *pGroup = pFile->pGroup; quotaEnter(); szNew = pGroup->iSize - pFile->iSize + iEnd; if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ if( pGroup->xCallback ){ pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew, pGroup->pArg); } if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){ iEnd = pGroup->iLimit - pGroup->iSize + pFile->iSize; nmemb = (size_t)((iEnd - iOfst)/size); iEnd = iOfst + size*nmemb; szNew = pGroup->iSize - pFile->iSize + iEnd; |
︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | /* ** Return the size of the file, as it is known to the quota subsystem. */ sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){ return p->pFile ? p->pFile->iSize : -1; } | | | 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 | /* ** Return the size of the file, as it is known to the quota subsystem. */ sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){ return p->pFile ? p->pFile->iSize : -1; } /* ** Determine the amount of data in bytes available for reading ** in the given file. */ long sqlite3_quota_file_available(quota_FILE *p){ FILE* f = p->f; long pos1, pos2; |
︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 | } } } quotaLeave(); sqlite3_free(zFull); return rc; } | | > > > | > > > > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 | } } } quotaLeave(); sqlite3_free(zFull); return rc; } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif /* ** Argument passed to a TCL quota-over-limit callback. */ typedef struct TclQuotaCallback TclQuotaCallback; struct TclQuotaCallback { Tcl_Interp *interp; /* Interpreter in which to run the script */ |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | sqlite3_free((char *)p); } } /* ** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT */ | | | 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | sqlite3_free((char *)p); } } /* ** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT */ static int SQLITE_TCLAPI test_quota_initialize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zName; /* Name of new quota VFS */ int makeDefault; /* True to make the new VFS the default */ |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_shutdown */ | | | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_shutdown */ static int SQLITE_TCLAPI test_quota_shutdown( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc; /* Value returned by quota_shutdown() */ |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT */ | | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT */ static int SQLITE_TCLAPI test_quota_set( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zPattern; /* File pattern to configure */ Tcl_WideInt iLimit; /* Initial quota in bytes */ |
︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file FILENAME */ | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file FILENAME */ static int SQLITE_TCLAPI test_quota_file( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; /* File pattern to configure */ int rc; /* Value returned by quota_file() */ |
︙ | ︙ | |||
1478 1479 1480 1481 1482 1483 1484 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_dump */ | | | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 | Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; } /* ** tclcmd: sqlite3_quota_dump */ static int SQLITE_TCLAPI test_quota_dump( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj *pResult; Tcl_Obj *pGroupTerm; |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fopen FILENAME MODE */ | | | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 | Tcl_SetObjResult(interp, pResult); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fopen FILENAME MODE */ static int SQLITE_TCLAPI test_quota_fopen( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; /* File pattern to configure */ const char *zMode; /* Mode string */ |
︙ | ︙ | |||
1556 1557 1558 1559 1560 1561 1562 | /* Defined in test1.c */ extern void *sqlite3TestTextToPtr(const char*); /* ** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM */ | | | 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 | /* Defined in test1.c */ extern void *sqlite3TestTextToPtr(const char*); /* ** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM */ static int SQLITE_TCLAPI test_quota_fread( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; char *zBuf; |
︙ | ︙ | |||
1590 1591 1592 1593 1594 1595 1596 | sqlite3_free(zBuf); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT */ | | | 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 | sqlite3_free(zBuf); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT */ static int SQLITE_TCLAPI test_quota_fwrite( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; char *zBuf; |
︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(got)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fclose HANDLE */ | | | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(got)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fclose HANDLE */ static int SQLITE_TCLAPI test_quota_fclose( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; int rc; |
︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC? */ | | | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC? */ static int SQLITE_TCLAPI test_quota_fflush( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; int rc; |
︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE */ | | | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE */ static int SQLITE_TCLAPI test_quota_fseek( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; int ofst; |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_rewind HANDLE */ | | | | | 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_rewind HANDLE */ static int SQLITE_TCLAPI test_quota_rewind( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); sqlite3_quota_rewind(p); return TCL_OK; } /* ** tclcmd: sqlite3_quota_ftell HANDLE */ static int SQLITE_TCLAPI test_quota_ftell( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; sqlite3_int64 x; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); x = sqlite3_quota_ftell(p); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_ftruncate HANDLE SIZE */ static int SQLITE_TCLAPI test_quota_ftruncate( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; sqlite3_int64 x; |
︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file_size HANDLE */ | | | | | 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 | Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file_size HANDLE */ static int SQLITE_TCLAPI test_quota_file_size( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; sqlite3_int64 x; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); x = sqlite3_quota_file_size(p); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file_truesize HANDLE */ static int SQLITE_TCLAPI test_quota_file_truesize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; sqlite3_int64 x; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } p = sqlite3TestTextToPtr(Tcl_GetString(objv[1])); x = sqlite3_quota_file_truesize(p); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x)); return TCL_OK; } /* ** tclcmd: sqlite3_quota_file_mtime HANDLE */ static int SQLITE_TCLAPI test_quota_file_mtime( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; time_t t; |
︙ | ︙ | |||
1834 1835 1836 1837 1838 1839 1840 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_remove FILENAME */ | | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 | return TCL_OK; } /* ** tclcmd: sqlite3_quota_remove FILENAME */ static int SQLITE_TCLAPI test_quota_remove( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; /* File pattern to configure */ int rc; |
︙ | ︙ | |||
1858 1859 1860 1861 1862 1863 1864 | /* ** tclcmd: sqlite3_quota_glob PATTERN TEXT ** ** Test the glob pattern matching. Return 1 if TEXT matches PATTERN ** and return 0 if it does not. */ | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 | /* ** tclcmd: sqlite3_quota_glob PATTERN TEXT ** ** Test the glob pattern matching. Return 1 if TEXT matches PATTERN ** and return 0 if it does not. */ static int SQLITE_TCLAPI test_quota_glob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zPattern; /* The glob pattern */ const char *zText; /* Text to compare agains the pattern */ |
︙ | ︙ | |||
1884 1885 1886 1887 1888 1889 1890 | /* ** tclcmd: sqlite3_quota_file_available HANDLE ** ** Return the number of bytes from the current file point to the end of ** the file. */ | | | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 | /* ** tclcmd: sqlite3_quota_file_available HANDLE ** ** Return the number of bytes from the current file point to the end of ** the file. */ static int SQLITE_TCLAPI test_quota_file_available( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; sqlite3_int64 x; |
︙ | ︙ | |||
1907 1908 1909 1910 1911 1912 1913 | } /* ** tclcmd: sqlite3_quota_ferror HANDLE ** ** Return true if the file handle is in the error state. */ | | | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 | } /* ** tclcmd: sqlite3_quota_ferror HANDLE ** ** Return true if the file handle is in the error state. */ static int SQLITE_TCLAPI test_quota_ferror( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ quota_FILE *p; int x; |
︙ | ︙ |
Changes to src/test_rtree.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. */ #include "sqlite3.h" | > > > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. */ #include "sqlite3.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* Solely for the UNUSED_PARAMETER() macro. */ #include "sqliteInt.h" #ifdef SQLITE_ENABLE_RTREE /* ** Type used to cache parameter information for the "circle" r-tree geometry |
︙ | ︙ | |||
349 350 351 352 353 354 355 | } /* END of implementation of "circle" geometry callback. ************************************************************************** *************************************************************************/ #include <assert.h> | > > > | > | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | } /* END of implementation of "circle" geometry callback. ************************************************************************** *************************************************************************/ #include <assert.h> #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif typedef struct Cube Cube; struct Cube { double x; double y; double z; double width; |
︙ | ︙ | |||
428 429 430 431 432 433 434 | *piRes = 1; } return SQLITE_OK; } #endif /* SQLITE_ENABLE_RTREE */ | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | *piRes = 1; } return SQLITE_OK; } #endif /* SQLITE_ENABLE_RTREE */ static int SQLITE_TCLAPI register_cube_geom( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_ENABLE_RTREE UNUSED_PARAMETER(clientData); |
︙ | ︙ | |||
456 457 458 459 460 461 462 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_rtree_geometry_callback(db, "cube", cube_geom, (void *)&gHere); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); #endif return TCL_OK; } | | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_rtree_geometry_callback(db, "cube", cube_geom, (void *)&gHere); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); #endif return TCL_OK; } static int SQLITE_TCLAPI register_circle_geom( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_ENABLE_RTREE UNUSED_PARAMETER(clientData); |
︙ | ︙ |
Changes to src/test_schema.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | ")" /* If SQLITE_TEST is defined this code is preprocessed for use as part ** of the sqlite test binary "testfixture". Otherwise it is preprocessed ** to be compiled into an sqlite dynamic extension. */ #ifdef SQLITE_TEST | | > > > | > | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ")" /* If SQLITE_TEST is defined this code is preprocessed for use as part ** of the sqlite test binary "testfixture". Otherwise it is preprocessed ** to be compiled into an sqlite dynamic extension. */ #ifdef SQLITE_TEST # include "sqliteInt.h" # if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" # else # include "tcl.h" # endif #else # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #endif #include <stdlib.h> #include <string.h> #include <assert.h> |
︙ | ︙ | |||
298 299 300 301 302 303 304 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the schema virtual table module. */ | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the schema virtual table module. */ static int SQLITE_TCLAPI register_schema_module( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ |
︙ | ︙ |
Changes to src/test_superlock.c.
︙ | ︙ | |||
252 253 254 255 256 257 258 | ************************************************************************** ************************************************************************** *************************************************************************/ #ifdef SQLITE_TEST | > > > | > > > > | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | ************************************************************************** ************************************************************************** *************************************************************************/ #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif struct InterpAndScript { Tcl_Interp *interp; Tcl_Obj *pScript; }; typedef struct InterpAndScript InterpAndScript; static void SQLITE_TCLAPI superunlock_del(ClientData cd){ sqlite3demo_superunlock((void *)cd); } static int SQLITE_TCLAPI superunlock_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); |
︙ | ︙ | |||
296 297 298 299 300 301 302 | return iVal; } /* ** Tclcmd: sqlite3demo_superlock CMDNAME PATH VFS BUSY-HANDLER-SCRIPT */ | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | return iVal; } /* ** Tclcmd: sqlite3demo_superlock CMDNAME PATH VFS BUSY-HANDLER-SCRIPT */ static int SQLITE_TCLAPI superlock_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ void *pLock; /* Lock context */ char *zPath; |
︙ | ︙ |
Changes to src/test_syscall.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 | ** If PGSZ is a power of two greater than 256, install a wrapper around ** OS function getpagesize() that reports the system page size as PGSZ. ** Or, if PGSZ is less than zero, remove any wrapper already installed. */ #include "sqliteInt.h" #include "sqlite3.h" | > > > | > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | ** If PGSZ is a power of two greater than 256, install a wrapper around ** OS function getpagesize() that reports the system page size as PGSZ. ** Or, if PGSZ is less than zero, remove any wrapper already installed. */ #include "sqliteInt.h" #include "sqlite3.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #include <assert.h> #if SQLITE_OS_UNIX /* From main.c */ |
︙ | ︙ | |||
414 415 416 417 418 419 420 | return MAP_FAILED; } va_start(ap, d); pArg = va_arg(ap, void *); return orig_mremap(a, b, c, d, pArg); } | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | return MAP_FAILED; } va_start(ap, d); pArg = va_arg(ap, void *); return orig_mremap(a, b, c, d, pArg); } static int SQLITE_TCLAPI test_syscall_install( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs; int nElem; |
︙ | ︙ | |||
450 451 452 453 454 455 456 | } aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno; } return TCL_OK; } | | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | } aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno; } return TCL_OK; } static int SQLITE_TCLAPI test_syscall_uninstall( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs; int i; |
︙ | ︙ | |||
474 475 476 477 478 479 480 | pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0); aSyscall[i].xOrig = 0; } } return TCL_OK; } | | | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0); aSyscall[i].xOrig = 0; } } return TCL_OK; } static int SQLITE_TCLAPI test_syscall_reset( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs; int i; |
︙ | ︙ | |||
512 513 514 515 516 517 518 | return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } | | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } static int SQLITE_TCLAPI test_syscall_exists( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs; sqlite3_syscall_ptr x; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pVfs = sqlite3_vfs_find(0); x = pVfs->xGetSystemCall(pVfs, Tcl_GetString(objv[2])); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(x!=0)); return TCL_OK; } static int SQLITE_TCLAPI test_syscall_fault( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int nCount = 0; int bPersist = 0; |
︙ | ︙ | |||
562 563 564 565 566 567 568 | Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail)); gSyscall.nCount = nCount; gSyscall.bPersist = bPersist; gSyscall.nFail = 0; return TCL_OK; } | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail)); gSyscall.nCount = nCount; gSyscall.bPersist = bPersist; gSyscall.nFail = 0; return TCL_OK; } static int SQLITE_TCLAPI test_syscall_errno( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int iCall; int iErrno; |
︙ | ︙ | |||
608 609 610 611 612 613 614 | ); if( rc!=TCL_OK ) return rc; aSyscall[iCall].custom_errno = aErrno[iErrno].i; return TCL_OK; } | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | ); if( rc!=TCL_OK ) return rc; aSyscall[iCall].custom_errno = aErrno[iErrno].i; return TCL_OK; } static int SQLITE_TCLAPI test_syscall_list( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zSys; sqlite3_vfs *pVfs; |
︙ | ︙ | |||
638 639 640 641 642 643 644 | } Tcl_SetObjResult(interp, pList); Tcl_DecrRefCount(pList); return TCL_OK; } | | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 | } Tcl_SetObjResult(interp, pList); Tcl_DecrRefCount(pList); return TCL_OK; } static int SQLITE_TCLAPI test_syscall_defaultvfs( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs; |
︙ | ︙ | |||
660 661 662 663 664 665 666 | return TCL_OK; } static int ts_getpagesize(void){ return gSyscall.pgsz; } | | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | return TCL_OK; } static int ts_getpagesize(void){ return gSyscall.pgsz; } static int SQLITE_TCLAPI test_syscall_pagesize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); int pgsz; |
︙ | ︙ | |||
695 696 697 698 699 700 701 | pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize ); } return TCL_OK; } | | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize ); } return TCL_OK; } static int SQLITE_TCLAPI test_syscall( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct SyscallCmd { const char *zName; |
︙ | ︙ |
Changes to src/test_tclvar.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** The emphasis of this file is a virtual table that provides ** access to TCL variables. */ #include "sqliteInt.h" | > > > | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** The emphasis of this file is a virtual table that provides ** access to TCL variables. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Characters that make up the idxStr created by xBestIndex for xFilter. |
︙ | ︙ | |||
403 404 405 406 407 408 409 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ static int SQLITE_TCLAPI register_tclvar_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int rc = TCL_OK; sqlite3 *db; |
︙ | ︙ |
Changes to src/test_thread.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. */ #include "sqliteInt.h" | > > > | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #if SQLITE_THREADSAFE #include <errno.h> #if !defined(_MSC_VER) #include <unistd.h> |
︙ | ︙ | |||
68 69 70 71 72 73 74 | extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); /* ** Handler for events of type EvalEvent. */ | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **); extern int sqlite3TestMakePointerStr(Tcl_Interp *, char *, void *); extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int); /* ** Handler for events of type EvalEvent. */ static int SQLITE_TCLAPI tclScriptEvent(Tcl_Event *evPtr, int flags){ int rc; EvalEvent *p = (EvalEvent *)evPtr; rc = Tcl_Eval(p->interp, p->zScript); if( rc!=TCL_OK ){ Tcl_BackgroundError(p->interp); } UNUSED_PARAMETER(flags); |
︙ | ︙ | |||
163 164 165 166 167 168 169 | ** Spawn a new thread with its own Tcl interpreter and run the ** specified SCRIPT(s) in it. The thread terminates after running ** the script. The result of the script is stored in the variable ** VARNAME. ** ** The caller can wait for the script to terminate using [vwait VARNAME]. */ | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | ** Spawn a new thread with its own Tcl interpreter and run the ** specified SCRIPT(s) in it. The thread terminates after running ** the script. The result of the script is stored in the variable ** VARNAME. ** ** The caller can wait for the script to terminate using [vwait VARNAME]. */ static int SQLITE_TCLAPI sqlthread_spawn( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_ThreadId x; SqlThread *pNew; |
︙ | ︙ | |||
216 217 218 219 220 221 222 | ** script back to the parent thread for execution. The result of ** evaluating the SCRIPT is returned. The parent thread must enter ** the event loop for this to work - otherwise the caller will ** block indefinitely. ** ** NOTE: At the moment, this doesn't work. FIXME. */ | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | ** script back to the parent thread for execution. The result of ** evaluating the SCRIPT is returned. The parent thread must enter ** the event loop for this to work - otherwise the caller will ** block indefinitely. ** ** NOTE: At the moment, this doesn't work. FIXME. */ static int SQLITE_TCLAPI sqlthread_parent( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ EvalEvent *pEvent; char *zMsg; |
︙ | ︙ | |||
261 262 263 264 265 266 267 | /* ** sqlthread open ** ** Open a database handle and return the string representation of ** the pointer value. */ | | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | /* ** sqlthread open ** ** Open a database handle and return the string representation of ** the pointer value. */ static int SQLITE_TCLAPI sqlthread_open( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p); const char *zFilename; sqlite3 *db; char zBuf[100]; extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); zFilename = Tcl_GetString(objv[2]); sqlite3_open(zFilename, &db); #ifdef SQLITE_HAS_CODEC |
︙ | ︙ | |||
295 296 297 298 299 300 301 | sqlite3_close(db); Tcl_AppendResult(interp, zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } #endif | | | | | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | sqlite3_close(db); Tcl_AppendResult(interp, zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } #endif Md5_Register(db, 0, 0); sqlite3_busy_handler(db, xBusy, 0); if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** sqlthread open ** ** Return the current thread-id (Tcl_GetCurrentThread()) cast to ** an integer. */ static int SQLITE_TCLAPI sqlthread_id( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_ThreadId id = Tcl_GetCurrentThread(); Tcl_SetObjResult(interp, Tcl_NewIntObj(SQLITE_PTR_TO_INT(id))); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); return TCL_OK; } /* ** Dispatch routine for the sub-commands of [sqlthread]. */ static int SQLITE_TCLAPI sqlthread_proc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct SubCommand { char *zName; |
︙ | ︙ | |||
377 378 379 380 381 382 383 | /* ** The [clock_seconds] command. This is more or less the same as the ** regular tcl [clock seconds], except that it is available in testfixture ** when linked against both Tcl 8.4 and 8.5. Because [clock seconds] is ** implemented as a script in Tcl 8.5, it is not usually available to ** testfixture. */ | | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | /* ** The [clock_seconds] command. This is more or less the same as the ** regular tcl [clock seconds], except that it is available in testfixture ** when linked against both Tcl 8.4 and 8.5. Because [clock seconds] is ** implemented as a script in Tcl 8.5, it is not usually available to ** testfixture. */ static int SQLITE_TCLAPI clock_seconds_proc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Time now; Tcl_GetTime(&now); |
︙ | ︙ | |||
539 540 541 542 543 544 545 | /* END_SQLITE_BLOCKING_STEP */ /* ** Usage: sqlite3_blocking_step STMT ** ** Advance the statement to the next row. */ | | | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | /* END_SQLITE_BLOCKING_STEP */ /* ** Usage: sqlite3_blocking_step STMT ** ** Advance the statement to the next row. */ static int SQLITE_TCLAPI blocking_step_proc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; |
︙ | ︙ | |||
565 566 567 568 569 570 571 | return TCL_OK; } /* ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar? ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar? */ | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | return TCL_OK; } /* ** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar? ** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar? */ static int SQLITE_TCLAPI blocking_prepare_v2_proc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zSql; |
︙ | ︙ |
Changes to src/test_vfs.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 | ** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname) ** -iversion INTEGER (Value for sqlite3_vfs.iVersion) */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqlite3.h" #include "sqliteInt.h" | > > > | > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname) ** -iversion INTEGER (Value for sqlite3_vfs.iVersion) */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqlite3.h" #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif typedef struct Testvfs Testvfs; typedef struct TestvfsShm TestvfsShm; typedef struct TestvfsBuffer TestvfsBuffer; typedef struct TestvfsFile TestvfsFile; typedef struct TestvfsFd TestvfsFd; |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 | } static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){ TestvfsFd *pFd = tvfsGetFd(pFile); return sqlite3OsUnfetch(pFd->pReal, iOfst, p); } | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | } static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){ TestvfsFd *pFd = tvfsGetFd(pFile); return sqlite3OsUnfetch(pFd->pReal, iOfst, p); } static int SQLITE_TCLAPI testvfs_obj_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Testvfs *p = (Testvfs *)cd; |
︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 | break; } } return TCL_OK; } | | | 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 | break; } } return TCL_OK; } static void SQLITE_TCLAPI testvfs_obj_del(ClientData cd){ Testvfs *p = (Testvfs *)cd; if( p->pScript ) Tcl_DecrRefCount(p->pScript); sqlite3_vfs_unregister(p->pVfs); ckfree((char *)p->pVfs); ckfree((char *)p); } |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 | ** When the xShmLock method is invoked by SQLite, the following script is ** run: ** ** SCRIPT xShmLock FILENAME ID LOCK ** ** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive" */ | | | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 | ** When the xShmLock method is invoked by SQLite, the following script is ** run: ** ** SCRIPT xShmLock FILENAME ID LOCK ** ** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive" */ static int SQLITE_TCLAPI testvfs_cmd( ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ static sqlite3_vfs tvfs_vfs = { 3, /* iVersion */ |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 | return SQLITE_NOMEM_BKPT; } assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->nzVar==0 ); assert( pParse->azVar==0 ); | | > | | | | | | > > > > > > > > > > > < < < < < < < < < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | return SQLITE_NOMEM_BKPT; } assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->nzVar==0 ); assert( pParse->azVar==0 ); while( 1 ){ assert( i>=0 ); if( zSql[i]!=0 ){ pParse->sLastToken.z = &zSql[i]; pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType); i += pParse->sLastToken.n; if( i>mxSqlLen ){ pParse->rc = SQLITE_TOOBIG; break; } }else{ /* Upon reaching the end of input, call the parser two more times ** with tokens TK_SEMI and 0, in that order. */ if( lastTokenParsed==TK_SEMI ){ tokenType = 0; }else if( lastTokenParsed==0 ){ break; }else{ tokenType = TK_SEMI; } } if( tokenType>=TK_SPACE ){ assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); if( db->u1.isInterrupted ){ pParse->rc = SQLITE_INTERRUPT; break; } if( tokenType==TK_ILLEGAL ){ sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &pParse->sLastToken); break; } }else{ sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); lastTokenParsed = tokenType; if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } } assert( nErr==0 ); pParse->zTail = &zSql[i]; #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(pEngine) ); sqlite3_mutex_leave(sqlite3MallocMutex()); #endif /* YYDEBUG */ |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
441 442 443 444 445 446 447 448 449 450 451 452 453 454 | case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); | > > > > > > | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); break; } #endif case TK_MATCH: { sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); sqlite3TreeViewExpr(pView, pExpr->pRight, 0); break; } default: { sqlite3TreeViewLine(pView, "op=%d", pExpr->op); break; } } if( zBinOp ){ sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
348 349 350 351 352 353 354 | #endif /* Begin the database scan */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); pWInfo = sqlite3WhereBegin( | | > | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | #endif /* Begin the database scan */ if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE, iIdxCur ); if( pWInfo==0 ) goto update_cleanup; okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); /* Remember the rowid of every item to be updated. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
117 118 119 120 121 122 123 | int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ char *zSql = 0; /* SQL statements */ int saved_flags; /* Saved value of the db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ | | | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ Btree *pTemp; /* The temporary database we vacuum into */ char *zSql = 0; /* SQL statements */ int saved_flags; /* Saved value of the db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ int nRes; /* Bytes of reserved space at the end of each page */ int nDb; /* Number of attached databases */ if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; } /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin; db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder); db->mTrace = 0; pMain = db->aDb[0].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a |
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | int nKey; char *zKey; sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ | > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | int nKey; char *zKey; sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif sqlite3BtreeSetCacheSize(pTemp, db->aDb[0].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Begin a transaction and take an exclusive lock on the main database ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, ** to ensure that we do not try to change the page-size on a WAL database. */ |
︙ | ︙ | |||
341 342 343 344 345 346 347 | rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1); end_of_vacuum: /* Restore the original value of db->flags */ db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1); end_of_vacuum: /* Restore the original value of db->flags */ db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->mTrace = saved_mTrace; sqlite3BtreeSetPageSize(pMain, -1, -1, 1); /* Currently there is an SQL level transaction open on the vacuum ** database. No locks are held on any other files (since the main file ** was committed at the btree level). So it safe to end the transaction ** by manually setting the autoCommit flag to true and detaching the ** vacuum database. The vacuum_db journal file is deleted when the pager |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
945 946 947 948 949 950 951 | ** omitted. ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { | < < | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 | ** omitted. ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { VdbeFrame *pFrame; int pcx; pcx = (int)(pOp - aOp); if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; |
︙ | ︙ | |||
975 976 977 978 979 980 981 982 983 984 985 | aMem = p->aMem; pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pcx; if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; | > < < < < < < < < | | | > | | | | 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | aMem = p->aMem; pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pcx; assert( pOp->p5>=0 && pOp->p5<=4 ); if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; testcase( pOp->p5==1 ); testcase( pOp->p5==2 ); testcase( pOp->p5==3 ); testcase( pOp->p5==4 ); sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); if( pOp->p4.z ){ p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); } }else{ sqlite3VdbeError(p, "%s", pOp->p4.z); } sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ); assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 ); rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; } goto vdbe_return; } |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | pOut = out2Prerelease(p, pOp); pOp->opcode = OP_String; pOp->p1 = sqlite3Strlen30(pOp->p4.z); #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); | < | < < > > | | > > | < | | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | pOut = out2Prerelease(p, pOp); pOp->opcode = OP_String; pOp->p1 = sqlite3Strlen30(pOp->p4.z); #ifndef SQLITE_OMIT_UTF16 if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); pOut->szMalloc = 0; pOut->flags |= MEM_Static; if( pOp->p4type==P4_DYNAMIC ){ sqlite3DbFree(db, pOp->p4.z); } pOp->p4type = P4_DYNAMIC; pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } testcase( rc==SQLITE_TOOBIG ); #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ } /* Opcode: String P1 P2 P3 P4 P5 ** Synopsis: r[P2]='P4' (len=P1) ** ** The string value P4 of length P1 (bytes) is stored in register P2. ** ** If P3 is not zero and the content of register P3 is equal to P5, then ** the datatype of the register P2 is converted to BLOB. The content is ** the same sequence of bytes, it is merely interpreted as a BLOB instead ** of a string, as if it had been CAST. In other words: ** ** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB) */ case OP_String: { /* out2 */ assert( pOp->p4.z!=0 ); pOut = out2Prerelease(p, pOp); pOut->flags = MEM_Str|MEM_Static|MEM_Term; pOut->z = pOp->p4.z; pOut->n = pOp->p1; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pOp->p3>0 ){ assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; } #endif break; } /* Opcode: Null P1 P2 P3 * * ** Synopsis: r[P2..P3]=NULL |
︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | Deephemeralize(&pMem[i]); assert( (pMem[i].flags & MEM_Ephem)==0 || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } | > > > > | 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | Deephemeralize(&pMem[i]); assert( (pMem[i].flags & MEM_Ephem)==0 || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 ); sqlite3VdbeMemNulTerminate(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; if( db->mTrace & SQLITE_TRACE_ROW ){ db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); } /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } |
︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 | }else{ /* Neither operand is NULL. Do a comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); } if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); | > > | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 | }else{ /* Neither operand is NULL. Do a comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); flags3 = pIn3->flags; } if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); |
︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 | ** ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { | < | 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 | ** ** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when ** the result is guaranteed to only be used as the argument of a length() ** or typeof() function, respectively. The loading of large blobs can be ** skipped for length() and all content loading can be skipped for typeof(). */ case OP_Column: { int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ BtCursor *pCrsr; /* The BTree cursor */ u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */ int len; /* The length of the serialized data for the column */ int i; /* Loop counter */ Mem *pDest; /* Where to write the extracted value */ |
︙ | ︙ | |||
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 | Mem *pReg; /* PseudoTable input register */ pC = p->apCsr[pOp->p1]; p2 = pOp->p2; /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pC!=0 ); assert( p2<pC->nField ); aOffset = pC->aOffset; assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); pCrsr = pC->uc.pCursor; | > < | < | < < < < < < < | < < < < | < | < | | | | | > | | > < > < < < | < > > > | 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 | Mem *pReg; /* PseudoTable input register */ pC = p->apCsr[pOp->p1]; p2 = pOp->p2; /* If the cursor cache is stale, bring it up-to-date */ rc = sqlite3VdbeCursorMoveto(&pC, &p2); if( rc ) goto abort_due_to_error; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pC!=0 ); assert( p2<pC->nField ); aOffset = pC->aOffset; assert( pC->eCurType!=CURTYPE_VTAB ); assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow ); assert( pC->eCurType!=CURTYPE_SORTER ); pCrsr = pC->uc.pCursor; if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/ if( pC->nullRow ){ if( pC->eCurType==CURTYPE_PSEUDO ){ assert( pC->uc.pseudoTableReg>0 ); pReg = &aMem[pC->uc.pseudoTableReg]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); pC->payloadSize = pC->szRow = avail = pReg->n; pC->aRow = (u8*)pReg->z; }else{ sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail); assert( avail<=65536 ); /* Maximum page size is 64KiB */ if( pC->payloadSize <= (u32)avail ){ pC->szRow = pC->payloadSize; }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; }else{ pC->szRow = avail; } } pC->cacheStatus = p->cacheCtr; pC->iHdrOffset = getVarint32(pC->aRow, offset); pC->nHdrParsed = 0; aOffset[0] = offset; if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/ /* pC->aRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be ** dynamically allocated. */ pC->aRow = 0; pC->szRow = 0; /* Make sure a corrupt database has not given us an oversize header. ** Do this now to avoid an oversize memory allocation. ** ** Type entries can be between 1 and 5 bytes each. But 4 and 5 byte ** types use so much data space that there can only be 4096 and 32 of ** them, respectively. So the maximum header length results from a ** 3-byte type for each of the maximum of 32768 columns plus three ** extra bytes for the header length itself. 32768*3 + 3 = 98307. */ if( offset > 98307 || offset > pC->payloadSize ){ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/ /* The following goto is an optimization. It can be omitted and ** everything will still work. But OP_Column is measurably faster ** by skipping the subsequent conditional, which is always true. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ goto op_column_read_header; } } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* If there is more header available for parsing in the record, try ** to extract additional fields up through the p2+1-th field */ if( pC->iHdrOffset<aOffset[0] ){ /* Make sure zData points to enough of the record to cover the header. */ if( pC->aRow==0 ){ memset(&sMem, 0, sizeof(sMem)); rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem); if( rc!=SQLITE_OK ) goto abort_due_to_error; zData = (u8*)sMem.z; }else{ zData = pC->aRow; } /* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */ op_column_read_header: i = pC->nHdrParsed; offset64 = aOffset[i]; zHdr = zData + pC->iHdrOffset; zEndHdr = zData + aOffset[0]; do{ if( (t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); offset64 += sqlite3VdbeSerialTypeLen(t); } pC->aType[i++] = t; aOffset[i] = (u32)(offset64 & 0xffffffff); }while( i<=p2 && zHdr<zEndHdr ); /* The record is corrupt if any of the following are true: ** (1) the bytes of the header extend past the declared header size ** (2) the entire header was used but not all data was used ** (3) the end of the data extends beyond the end of the record. */ if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize)) || (offset64 > pC->payloadSize) ){ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } pC->nHdrParsed = i; pC->iHdrOffset = (u32)(zHdr - zData); if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem); }else{ t = 0; } /* If after trying to extract new entries from the header, nHdrParsed is ** still not up to p2, that means that the record has fewer than p2 ** columns. So the result will be either the default value or a NULL. |
︙ | ︙ | |||
2579 2580 2581 2582 2583 2584 2585 | /* Extract the content for the p2+1-th column. Control can only ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2<pC->nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); | | > > < > > | 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 | /* Extract the content for the p2+1-th column. Control can only ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2<pC->nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( VdbeMemDynamic(pDest) ){ sqlite3VdbeMemSetNull(pDest); } assert( t==pC->aType[p2] ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ zData = pC->aRow + aOffset[p2]; if( t<12 ){ sqlite3VdbeSerialGet(zData, t, pDest); }else{ /* If the column value is a string, we need a persistent value, not ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). */ static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; pDest->n = len = (t-12)/2; pDest->enc = encoding; if( pDest->szMalloc < len+2 ){ pDest->flags = MEM_Null; if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; }else{ pDest->z = pDest->zMalloc; } memcpy(pDest->z, zData, len); pDest->z[len] = 0; pDest->z[len+1] = 0; pDest->flags = aFlag[t&1]; } }else{ pDest->enc = encoding; /* This branch happens only when content is on overflow pages */ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ /* Content is irrelevant for ** 1. the typeof() function, |
︙ | ︙ | |||
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 | }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > | 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 | }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; } break; } /* Opcode: SeekRowid P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). If register P3 does not contain an integer or if P1 does not ** contain a record with rowid P3 then jump immediately to P2. ** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain ** a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_NotExists opcode performs the same operation, but with OP_NotExists ** the P3 register must be guaranteed to contain an integer value. With this ** opcode, register P3 might not contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ /* Opcode: NotExists P1 P2 P3 * * ** Synopsis: intkey=r[P3] ** ** P1 is the index of a cursor open on an SQL table btree (with integer ** keys). P3 is an integer rowid. If P1 does not contain a record with ** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an ** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then ** leave the cursor pointing at that record and fall through to the next ** instruction. ** ** The OP_SeekRowid opcode performs the same operation but also allows the ** P3 register to contain a non-integer value, in which case the jump is ** always taken. This opcode requires that P3 always contain an integer. ** ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2; } /* Fall through into OP_NotExists */ case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = 0; #endif |
︙ | ︙ | |||
4198 4199 4200 4201 4202 4203 4204 | if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); | | < | 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 | if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; /* IMP: R-61914-48074 */ }else{ assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) ); v = sqlite3BtreeIntegerKey(pC->uc.pCursor); if( v>=MAX_ROWID ){ pC->useRandomRowid = 1; }else{ v++; /* IMP: R-29538-34987 */ } } } |
︙ | ︙ | |||
4282 4283 4284 4285 4286 4287 4288 | ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of | | > | > | 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 | ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of ** the last seek operation (OP_NotExists or OP_SeekRowid) was a success, ** then this ** operation will not attempt to find the appropriate row before doing ** the insert but will instead overwrite the row that the cursor is ** currently pointing to. Presumably, the prior OP_NotExists or ** OP_SeekRowid opcode ** has already positioned the cursor correctly. This is an optimization ** that boosts performance by avoiding redundant seeks. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode ** is part of an INSERT operation. The difference is only important to ** the update hook. |
︙ | ︙ | |||
4317 4318 4319 4320 4321 4322 4323 | ** This works exactly like OP_Insert except that the key is the ** integer value P3, not the value of the integer stored in register P3. */ case OP_Insert: case OP_InsertInt: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ | < < > | | | | | | > > | | > | < | | 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 | ** This works exactly like OP_Insert except that the key is the ** integer value P3, not the value of the integer stored in register P3. */ case OP_Insert: case OP_InsertInt: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ Table *pTab; /* Table structure - used by update and pre-update hooks */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ BtreePayload x; /* Payload to be inserted */ op = 0; pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable ); assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC ); REGISTER_TRACE(pOp->p2, pData); if( pOp->opcode==OP_Insert ){ pKey = &aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); x.nKey = pKey->u.i; }else{ assert( pOp->opcode==OP_InsertInt ); x.nKey = pOp->p3; } if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->isTable ); assert( pC->iDb>=0 ); zDb = db->aDb[pC->iDb].zName; pTab = pOp->p4.pTab; assert( HasRowid(pTab) ); op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT); }else{ pTab = 0; /* Not needed. Silence a comiler warning. */ zDb = 0; /* Not needed. Silence a compiler warning. */ } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update hook, if any */ if( db->xPreUpdateCallback && pOp->p4type==P4_TABLE && !(pOp->p5 & OPFLAG_ISUPDATE) ){ sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2); } #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = x.nKey; if( pData->flags & MEM_Null ){ x.pData = 0; x.nData = 0; }else{ assert( pData->flags & (MEM_Blob|MEM_Str) ); x.pData = pData->z; x.nData = pData->n; } seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ x.nZero = pData->u.nZero; }else{ x.nZero = 0; } x.pKey = 0; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, (pOp->p5 & OPFLAG_APPEND)!=0, seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; if( db->xUpdateCallback && op ){ db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey); } break; } /* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. |
︙ | ︙ | |||
4453 4454 4455 4456 4457 4458 4459 | assert( pC->deferredMoveto==0 ); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ | | < | | 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 | assert( pC->deferredMoveto==0 ); #ifdef SQLITE_DEBUG if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){ /* If p5 is zero, the seek operation that positioned the cursor prior to ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); assert( pC->movetoTarget==iKey ); } #endif /* If the update-hook or pre-update-hook will be invoked, set zDb to ** the name of the db to pass as to it. Also set local pTab to a copy ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set ** VdbeCursor.movetoTarget to the current rowid. */ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 ); assert( pOp->p4.pTab!=0 ); zDb = db->aDb[pC->iDb].zName; pTab = pOp->p4.pTab; if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor); } }else{ zDb = 0; /* Not needed. Silence a compiler warning. */ pTab = 0; /* Not needed. Silence a compiler warning. */ } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK |
︙ | ︙ | |||
4624 4625 4626 4627 4628 4629 4630 | ** of a real table, not a pseudo-table. */ case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; | < | > | < < | < < < < < < < < | | < | 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 | ** of a real table, not a pseudo-table. */ case OP_RowKey: case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; pOut = &aMem[pOp->p2]; memAboutToChange(p, pOut); /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( isSorter(pC)==0 ); assert( pC->isTable || pOp->opcode!=OP_RowData ); assert( pC->isTable==0 || pOp->opcode==OP_RowData ); assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. ** If this where not the case, on of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); #if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){ goto no_mem; } pOut->n = n; MemSetTypeFlag(pOut, MEM_Blob); |
︙ | ︙ | |||
4733 4734 4735 4736 4737 4738 4739 | assert( pC->uc.pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } | | < | 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 | assert( pC->uc.pCursor!=0 ); rc = sqlite3VdbeCursorRestore(pC); if( rc ) goto abort_due_to_error; if( pC->nullRow ){ pOut->flags = MEM_Null; break; } v = sqlite3BtreeIntegerKey(pC->uc.pCursor); } pOut->u.i = v; break; } /* Opcode: NullRow P1 * * * * ** |
︙ | ︙ | |||
5009 5010 5011 5012 5013 5014 5015 | ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; | | < | | > > > | | 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 | ** ** This instruction only works for indices. The equivalent instruction ** for tables is OP_Insert. */ case OP_SorterInsert: /* in2 */ case OP_IdxInsert: { /* in2 */ VdbeCursor *pC; BtreePayload x; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; if( pOp->opcode==OP_SorterInsert ){ rc = sqlite3VdbeSorterWrite(pC, pIn2); }else{ x.nKey = pIn2->n; x.pKey = pIn2->z; x.nData = 0; x.nZero = 0; x.pData = 0; rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, pOp->p3, ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) ); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } if( rc) goto abort_due_to_error; break; |
︙ | ︙ | |||
6002 6003 6004 6005 6006 6007 6008 | pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ) goto jump_to_p2; break; } | < < < < < < < < < < < < < < < | 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 | pIn1->u.i--; VdbeBranchTaken(pIn1->u.i==0, 2); if( pIn1->u.i==0 ) goto jump_to_p2; break; } /* Opcode: AggStep0 * P2 P3 P4 P5 ** Synopsis: accum=r[P3] step(r[P2@P5]) ** ** Execute the step function for an aggregate. The ** function has P5 arguments. P4 is a pointer to the FuncDef ** structure that specifies the function. Register P3 is the ** accumulator. |
︙ | ︙ | |||
6819 6820 6821 6822 6823 6824 6825 | ** the UTF-8 string contained in P4 is emitted on the trace callback. ** Or if P4 is blank, use the string returned by sqlite3_sql(). ** ** If P2 is not zero, jump to instruction P2. */ case OP_Init: { /* jump */ char *zTrace; | | > > > > > > > > > > | > > > | | | > > > > > | 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 | ** the UTF-8 string contained in P4 is emitted on the trace callback. ** Or if P4 is blank, use the string returned by sqlite3_sql(). ** ** If P2 is not zero, jump to instruction P2. */ case OP_Init: { /* jump */ char *zTrace; /* If the P4 argument is not NULL, then it must be an SQL comment string. ** The "--" string is broken up to prevent false-positives with srcck1.c. ** ** This assert() provides evidence for: ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that ** would have been returned by the legacy sqlite3_trace() interface by ** using the X argument when X begins with "--" and invoking ** sqlite3_expanded_sql(P) otherwise. */ assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 && !p->doingRerun && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){ #ifndef SQLITE_OMIT_DEPRECATED if( db->mTrace & SQLITE_TRACE_LEGACY ){ void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; char *z = sqlite3VdbeExpandSql(p, zTrace); x(db->pTraceArg, z); sqlite3_free(z); }else #endif { (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace); } } #ifdef SQLITE_USE_FCNTL_TRACE zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql); if( zTrace ){ int i; for(i=0; i<db->nDb; i++){ if( DbMaskTest(p->btreeMask, i)==0 ) continue; |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef SQLITE_VDBE_H #define SQLITE_VDBE_H #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ |
︙ | ︙ | |||
305 306 307 308 309 310 311 | #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif | | | 305 306 307 308 309 310 311 312 | #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif #endif /* SQLITE_VDBE_H */ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** This is the header file for information that is private to the ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ************************************************************************* ** This is the header file for information that is private to the ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ #ifndef SQLITE_VDBEINT_H #define SQLITE_VDBEINT_H /* ** The maximum number of times that a statement will try to reparse ** itself before giving up and returning SQLITE_SCHEMA. */ #ifndef SQLITE_MAX_SCHEMA_RETRY # define SQLITE_MAX_SCHEMA_RETRY 50 |
︙ | ︙ | |||
554 555 556 557 558 559 560 | int sqlite3VdbeMemExpandBlob(Mem *); #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) #else #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK #define ExpandBlob(P) SQLITE_OK #endif | | | 554 555 556 557 558 559 560 561 | int sqlite3VdbeMemExpandBlob(Mem *); #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) #else #define sqlite3VdbeMemExpandBlob(x) SQLITE_OK #define ExpandBlob(P) SQLITE_OK #endif #endif /* !defined(SQLITE_VDBEINT_H) */ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 63 | #ifndef SQLITE_OMIT_TRACE /* ** Invoke the profile callback. This routine is only called if we already ** know that the profile callback is defined and needs to be invoked. */ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; assert( p->startTime>0 ); | > | > > | > > > > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #ifndef SQLITE_OMIT_TRACE /* ** Invoke the profile callback. This routine is only called if we already ** know that the profile callback is defined and needs to be invoked. */ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ sqlite3_int64 iNow; sqlite3_int64 iElapse; assert( p->startTime>0 ); assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 ); assert( db->init.busy==0 ); assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } if( db->mTrace & SQLITE_TRACE_PROFILE ){ db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse); } p->startTime = 0; } /* ** The checkProfileCallback(DB,P) macro checks to see if a profile callback ** is needed, and it invokes the callback if it is needed. */ # define checkProfileCallback(DB,P) \ |
︙ | ︙ | |||
565 566 567 568 569 570 571 | } assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE | > | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | } assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0) && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ assert( p->startTime==0 ); } #endif db->nVdbeActive++; |
︙ | ︙ | |||
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 | return 0; } #endif v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized ** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure ** if successful, or a NULL pointer if an OOM error is encountered. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 | return 0; } #endif v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } /* ** Return the SQL associated with a prepared statement */ const char *sqlite3_sql(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe *)pStmt; return p ? p->zSql : 0; } /* ** Return the SQL associated with a prepared statement with ** bound parameters expanded. Space to hold the returned string is ** obtained from sqlite3_malloc(). The caller is responsible for ** freeing the returned string by passing it to sqlite3_free(). ** ** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of ** expanded bound parameters. */ char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #ifdef SQLITE_OMIT_TRACE return 0; #else char *z = 0; const char *zSql = sqlite3_sql(pStmt); if( zSql ){ Vdbe *p = (Vdbe *)pStmt; sqlite3_mutex_enter(p->db->mutex); z = sqlite3VdbeExpandSql(p, zSql); sqlite3_mutex_leave(p->db->mutex); } return z; #endif } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized ** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure ** if successful, or a NULL pointer if an OOM error is encountered. */ |
︙ | ︙ | |||
1646 1647 1648 1649 1650 1651 1652 | } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; | | < | 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | } /* If the old.* record has not yet been loaded into memory, do so now. */ if( p->pUnpacked==0 ){ u32 nRec; u8 *aRec; nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor); aRec = sqlite3DbMallocRaw(db, nRec); if( !aRec ) goto preupdate_old_out; rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec); if( rc==SQLITE_OK ){ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec); if( !p->pUnpacked ) rc = SQLITE_NOMEM; } |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 | if( !isPrepareV2 ) return; #endif assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); p->isPrepareV2 = (u8)isPrepareV2; } | < < < < < < < < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | if( !isPrepareV2 ) return; #endif assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); p->isPrepareV2 = (u8)isPrepareV2; } /* ** Swap all content between two VDBE structures. */ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp; char *zTmp; assert( pA->db==pB->db ); |
︙ | ︙ | |||
787 788 789 790 791 792 793 | /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ | | > > > > > > > > | | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | /* ** If the input FuncDef structure is ephemeral, then free it. If ** the FuncDef is not ephermal, then do nothing. */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFree(db, pDef); } } static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Delete a P4 value if necessary. */ static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc); sqlite3DbFree(db, p); } static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){ freeEphemeralFunction(db, p->pFunc); sqlite3DbFree(db, p); } static void freeP4(sqlite3 *db, int p4type, void *p4){ assert( db ); switch( p4type ){ case P4_FUNCCTX: { freeP4FuncCtx(db, (sqlite3_context*)p4); break; } case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { sqlite3DbFree(db, p4); break; |
︙ | ︙ | |||
833 834 835 836 837 838 839 | freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { if( db->pnBytesFreed==0 ){ sqlite3ValueFree((sqlite3_value*)p4); }else{ | | < < | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { if( db->pnBytesFreed==0 ){ sqlite3ValueFree((sqlite3_value*)p4); }else{ freeP4Mem(db, (Mem*)p4); } break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); break; } |
︙ | ︙ | |||
4325 4326 4327 4328 4329 4330 4331 | /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); | | < | 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 | /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ sqlite3VdbeMemInit(&m, db, 0); rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m); if( rc ){ return rc; |
︙ | ︙ | |||
4403 4404 4405 4406 4407 4408 4409 | int rc; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); | | < | 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 | int rc; BtCursor *pCur; Mem m; assert( pC->eCurType==CURTYPE_BTREE ); pCur = pC->uc.pCursor; assert( sqlite3BtreeCursorIsValid(pCur) ); nCellKey = sqlite3BtreePayloadSize(pCur); /* nCellKey will always be between 0 and 0xffffffff because of the way ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT_BKPT; } sqlite3VdbeMemInit(&m, db, 0); |
︙ | ︙ |
Changes to src/vdbeblob.c.
︙ | ︙ | |||
411 412 413 414 415 416 417 | ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | ** SQLITE_UPDATE where the PK columns do not change is handled in the ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually ** slightly more efficient). Since you cannot write to a PK column ** using the incremental-blob API, this works. For the sessions module ** anyhow. */ sqlite3_int64 iKey; iKey = sqlite3BtreeIntegerKey(p->pCsr); sqlite3VdbePreUpdateHook( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 ); } #endif rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
987 988 989 990 991 992 993 | assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); | < | < < < | 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | assert( sqlite3BtreeCursorIsValid(pCur) ); assert( !VdbeMemDynamic(pMem) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); if( offset+amt<=available ){ pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 | } return SQLITE_OK; } /* ** Merge the two sorted lists p1 and p2 into a single list. | < | | < | > > > > > > > > | | < > | | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 | } return SQLITE_OK; } /* ** Merge the two sorted lists p1 and p2 into a single list. */ static SorterRecord *vdbeSorterMerge( SortSubtask *pTask, /* Calling thread context */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2 /* Second list to merge */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; int bCached = 0; assert( p1!=0 && p2!=0 ); for(;;){ int res; res = pTask->xCompare( pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal ); if( res<=0 ){ *pp = p1; pp = &p1->u.pNext; p1 = p1->u.pNext; if( p1==0 ){ *pp = p2; break; } }else{ *pp = p2; pp = &p2->u.pNext; p2 = p2->u.pNext; bCached = 0; if( p2==0 ){ *pp = p1; break; } } } return pFinal; } /* ** Return the SorterCompare function to compare values collected by the ** sorter object passed as the only argument. */ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ |
︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | } }else{ pNext = p->u.pNext; } p->u.pNext = 0; for(i=0; aSlot[i]; i++){ | | > | | 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 | } }else{ pNext = p->u.pNext; } p->u.pNext = 0; for(i=0; aSlot[i]; i++){ p = vdbeSorterMerge(pTask, p, aSlot[i]); aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<64; i++){ if( aSlot[i]==0 ) continue; p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; } pList->pList = p; sqlite3_free(aSlot); assert( pTask->pUnpacked->errCode==SQLITE_OK || pTask->pUnpacked->errCode==SQLITE_NOMEM ); |
︙ | ︙ |
Changes to src/vdbetrace.c.
︙ | ︙ | |||
77 78 79 80 81 82 83 84 85 86 | int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ char zBase[100]; /* Initial working space */ db = p->db; | > > > | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | int idx = 0; /* Index of a host parameter */ int nextIndex = 1; /* Index of next ? host parameter */ int n; /* Length of a token prefix */ int nToken; /* Length of the parameter token */ int i; /* Loop counter */ Mem *pVar; /* Value of a host parameter */ StrAccum out; /* Accumulate the output here */ #ifndef SQLITE_OMIT_UTF16 Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */ #endif char zBase[100]; /* Initial working space */ db = p->db; sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); sqlite3StrAccumAppend(&out, "-- ", 3); assert( (zRawSql - zStart) > 0 ); |
︙ | ︙ | |||
131 132 133 134 135 136 137 | sqlite3XPrintf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3XPrintf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); | < | > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | sqlite3XPrintf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3XPrintf(&out, "%!.15g", pVar->u.r); }else if( pVar->flags & MEM_Str ){ int nOut; /* Number of bytes of the string text to include in output */ #ifndef SQLITE_OMIT_UTF16 u8 enc = ENC(db); if( enc!=SQLITE_UTF8 ){ memset(&utf8, 0, sizeof(utf8)); utf8.db = db; sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC); if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){ out.accError = STRACCUM_NOMEM; out.nAlloc = 0; } pVar = &utf8; } #endif nOut = pVar->n; #ifdef SQLITE_TRACE_SIZE_LIMIT if( nOut>SQLITE_TRACE_SIZE_LIMIT ){ nOut = SQLITE_TRACE_SIZE_LIMIT; |
︙ | ︙ | |||
178 179 180 181 182 183 184 185 186 187 188 | if( nOut<pVar->n ){ sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } return sqlite3StrAccumFinish(&out); } #endif /* #ifndef SQLITE_OMIT_TRACE */ | > | 183 184 185 186 187 188 189 190 191 192 193 194 | if( nOut<pVar->n ){ sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut); } #endif } } } if( out.accError ) sqlite3StrAccumReset(&out); return sqlite3StrAccumFinish(&out); } #endif /* #ifndef SQLITE_OMIT_TRACE */ |
Changes to src/vtab.c.
︙ | ︙ | |||
414 415 416 417 418 419 420 | zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); } |
︙ | ︙ | |||
750 751 752 753 754 755 756 | if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) && pParse->pNewTable && !db->mallocFailed && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ | > > | | > | | > > > > > > > > > > > | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr) && pParse->pNewTable && !db->mallocFailed && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ Table *pNew = pParse->pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; pTab->nCol = pNew->nCol; pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid); pNew->nCol = 0; pNew->aCol = 0; assert( pTab->pIndex==0 ); if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){ rc = SQLITE_ERROR; } pIdx = pNew->pIndex; if( pIdx ){ assert( pIdx->pNext==0 ); pTab->pIndex = pIdx; pNew->pIndex = 0; pIdx->pTable = pTab; } } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } |
︙ | ︙ | |||
789 790 791 792 793 794 795 | ** This call is a no-op if zTab is not a virtual table. */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); | | | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | ** This call is a no-op if zTab is not a virtual table. */ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } |
︙ | ︙ | |||
929 930 931 932 933 934 935 | ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); | | > > > | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 | ** sqlite3.aVTrans[] array. */ rc = growVTrans(db); if( rc==SQLITE_OK ){ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ int iSvpt = db->nStatement + db->nSavepoint; addToVTrans(db, pVTab); if( iSvpt && pModule->xSavepoint ){ pVTab->iSavepoint = iSvpt; rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1); } } } } return rc; } /* |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* | | < < | > > > > > < < | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ sqlite3OomFault(pToplevel->db); } } /* ** Check to see if virtual table module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE ** statement in order to come into existance. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same ** method can have an eponymous virtual table instance. */ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return 0; pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nRef = 1; pTab->pSchema = db->aDb[0].pSchema; pTab->tabFlags |= TF_Virtual; pTab->nModuleArg = 0; pTab->iPKey = -1; addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(db, pTab, 0); |
︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ | > | > | | | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 | /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( pTab!=0 ){ /* Mark the table as Ephemeral prior to deleting it, so that the ** sqlite3DeleteTable() routine will know that it is not stored in ** the schema. */ pTab->tabFlags |= TF_Ephemeral; sqlite3DeleteTable(db, pTab); pMod->pEpoTab = 0; } } /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 | ** needed and only the sync is done. If padding is needed, then the ** final frame is repeated (with its commit mark) until the next sector ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) return rc; iOffset += szFrame; nExtra++; } | > > > > > | | 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 | ** needed and only the sync is done. If padding is needed, then the ** final frame is repeated (with its commit mark) until the next sector ** boundary is crossed. Only the part of the WAL prior to the last ** sector boundary is synced; the part of the last frame that extends ** past the sector boundary is written after the sync. */ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ int bSync = 1; if( pWal->padToSectorBoundary ){ int sectorSize = sqlite3SectorSize(pWal->pWalFd); w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize; bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) return rc; iOffset += szFrame; nExtra++; } } if( bSync ){ assert( rc==SQLITE_OK ); rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK); } } /* If this frame set completes the first transaction in the WAL and ** if PRAGMA journal_size_limit is set, then truncate the WAL to the ** journal size limit, if possible. |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This header file defines the interface to the write-ahead logging ** system. Refer to the comments below and the header comment attached to ** the implementation of each function in log.c for further details. */ | | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ************************************************************************* ** This header file defines the interface to the write-ahead logging ** system. Refer to the comments below and the header comment attached to ** the implementation of each function in log.c for further details. */ #ifndef SQLITE_WAL_H #define SQLITE_WAL_H #include "sqliteInt.h" /* Additional values that can be added to the sync_flags argument of ** sqlite3WalFrames(): */ #define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */ |
︙ | ︙ | |||
148 149 150 151 152 153 154 | int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ | | | 148 149 150 151 152 153 154 155 | int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ |
Changes to src/walker.c.
︙ | ︙ | |||
37 38 39 40 41 42 43 | ** and WRC_Continue to continue. */ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); | < | | | | | | | | < | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | ** and WRC_Continue to continue. */ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){ int rc; testcase( ExprHasProperty(pExpr, EP_TokenOnly) ); testcase( ExprHasProperty(pExpr, EP_Reduced) ); rc = pWalker->xExprCallback(pWalker, pExpr); if( rc || ExprHasProperty(pExpr,EP_TokenOnly) ) return rc & WRC_Abort; if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else{ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } return WRC_Continue; } int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; } /* ** Call sqlite3WalkExpr() for every expression in list p or until |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /* ** Return TRUE if the WHERE clause returns rows in ORDER BY order. ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ assert( pWInfo->iContinue!=0 ); | > > > > > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /* ** Return TRUE if the WHERE clause returns rows in ORDER BY order. ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* ** Return TRUE if the innermost loop of the WHERE clause implementation ** returns rows in ORDER BY order for complete run of the inner loop. ** ** Across multiple iterations of outer loops, the output rows need not be ** sorted. As long as rows are sorted for just the innermost loop, this ** routine can return TRUE. */ int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){ return pWInfo->bOrderedInnerLoop; } /* ** Return the VDBE address or label to jump to in order to continue ** immediately with the next row of a WHERE clause. */ int sqlite3WhereContinueLabel(WhereInfo *pWInfo){ assert( pWInfo->iContinue!=0 ); |
︙ | ︙ | |||
257 258 259 260 261 262 263 | /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. ** ** The scanner will be searching the WHERE clause pWC. It will look ** for terms of the form "X <op> <expr>" where X is column iColumn of table | > > > | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. ** ** The scanner will be searching the WHERE clause pWC. It will look ** for terms of the form "X <op> <expr>" where X is column iColumn of table ** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx ** must be one of the indexes of table iCur. ** ** The <op> must be one of the operators described by opMask. ** ** If the search is for X and the WHERE clause contains terms of the ** form X=Y then this routine might also return terms of the form ** "Y <op> <expr>". The number of levels of transitivity is limited, ** but is enough to handle most commonly occurring SQL statements. ** ** If X is not the INTEGER PRIMARY KEY then X must be compatible with |
︙ | ︙ | |||
305 306 307 308 309 310 311 | pScan->nEquiv = 1; pScan->iEquiv = 1; return whereScanNext(pScan); } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" | | | | > | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | pScan->nEquiv = 1; pScan->iEquiv = 1; return whereScanNext(pScan); } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" ** where X is a reference to the iColumn of table iCur or of index pIdx ** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by ** the op parameter. Return a pointer to the term. Return 0 if not found. ** ** If pIdx!=0 then it must be one of the indexes of table iCur. ** Search for terms matching the iColumn-th column of pIdx ** rather than the iColumn-th column of table iCur. ** ** The term returned might by Y=<expr> if there is another constraint in ** the WHERE clause that specifies that X=Y. Any such constraints will be ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The ** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11 ** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10 |
︙ | ︙ | |||
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; sqlite3DebugPrintf( | > > > > > > > > > > | | > > > > > > > > > > > > | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; char zLeft[50]; memcpy(zType, "...", 4); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; if( pTerm->eOperator & WO_SINGLE ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x\n", iTerm, pTerm, zType, zLeft, pTerm->truthProb, pTerm->eOperator, pTerm->wtFlags); sqlite3TreeViewExpr(0, pTerm->pExpr, 0); } } #endif #ifdef WHERETRACE_ENABLED /* ** Show the complete content of a WhereClause */ void sqlite3WhereClausePrint(WhereClause *pWC){ int i; for(i=0; i<pWC->nTerm; i++){ whereTermPrint(&pWC->a[i], i); } } #endif #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ |
︙ | ︙ | |||
2627 2628 2629 2630 2631 2632 2633 | } rSize = pTab->nRowLogEst; rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ | | | 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 | } rSize = pTab->nRowLogEst; rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ |
︙ | ︙ | |||
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 | ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ pNew->rSetup = rLogSize + rSize + 4; if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 24; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; | > | 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 | ** those objects, since there is no opportunity to add schema ** indexes on subqueries and views. */ pNew->rSetup = rLogSize + rSize + 4; if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 24; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); if( pNew->rSetup<0 ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; |
︙ | ︙ | |||
2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 | m = pSrc->colUsed & ~columnsInIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) ){ pNew->iSortIdx = b ? iSortIdx : 0; /* The cost of visiting the index rows is N*K, where K is ** between 1.1 and 3.0, depending on the relative sizes of the | > | < > > > > > > > > > > > > > > > > > > > > > > > > | | 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | m = pSrc->colUsed & ~columnsInIndex(pProbe); pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) ){ pNew->iSortIdx = b ? iSortIdx : 0; /* The cost of visiting the index rows is N*K, where K is ** between 1.1 and 3.0, depending on the relative sizes of the ** index and table rows. */ pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow; if( m!=0 ){ /* If this is a non-covering index scan, add in the cost of ** doing table lookups. The cost will be 3x the number of ** lookups. Take into account WHERE clause terms that can be ** satisfied using just the index, and that do not require a ** table lookup. */ LogEst nLookup = rSize + 16; /* Base cost: N*3 */ int ii; int iCur = pSrc->iCursor; WhereClause *pWC2 = &pWInfo->sWC; for(ii=0; ii<pWC2->nTerm; ii++){ WhereTerm *pTerm = &pWC2->a[ii]; if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){ break; } /* pTerm can be evaluated using just the index. So reduce ** the expected number of table lookups accordingly */ if( pTerm->truthProb<=0 ){ nLookup += pTerm->truthProb; }else{ nLookup--; if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19; } } pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; } |
︙ | ︙ | |||
3104 3105 3106 3107 3108 3109 3110 | continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ | | < < | 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 | continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif |
︙ | ︙ | |||
3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 | pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mPrereq = mPrior; } priorJointype = pItem->fg.jointype; if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; p<pEnd; p++){ if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); | > | > > | 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 | pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mPrereq = mPrior; } priorJointype = pItem->fg.jointype; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; p<pEnd; p++){ if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ { rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; |
︙ | ︙ | |||
3242 3243 3244 3245 3246 3247 3248 | ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ | | > | 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 | ** the pOrderBy terms can be matched in any order. With ORDER BY, the ** pOrderBy terms must be matched in strict left-to-right order. */ static i8 wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */ WherePath *pPath, /* The WherePath to check */ u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */ u16 nLoop, /* Number of entries in pPath->aLoop[] */ WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */ ){ u8 revSet; /* True if rev is known */ u8 rev; /* Composite sort order */ u8 revIdx; /* Index sort order */ u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */ u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */ u8 isMatch; /* iColumn matches a term of the ORDER BY clause */ u16 eqOpMask; /* Allowed equality operators */ u16 nKeyCol; /* Number of key columns in pIndex */ u16 nColumn; /* Total number of ordered columns in the index */ u16 nOrderBy; /* Number terms in the ORDER BY clause */ int iLoop; /* Index of WhereLoop in pPath being processed */ int i, j; /* Loop counters */ int iCur; /* Cursor number for current WhereLoop */ int iColumn; /* A column number within table iCur */ |
︙ | ︙ | |||
3303 3304 3305 3306 3307 3308 3309 3310 3311 | nOrderBy = pOrderBy->nExpr; testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){ if( iLoop>0 ) ready |= pLoop->maskSelf; | > > > | > > > > | | 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 | nOrderBy = pOrderBy->nExpr; testcase( nOrderBy==BMS-1 ); if( nOrderBy>BMS-1 ) return 0; /* Cannot optimize overly large ORDER BYs */ isOrderDistinct = 1; obDone = MASKBIT(nOrderBy)-1; orderDistinctMask = 0; ready = 0; eqOpMask = WO_EQ | WO_IS | WO_ISNULL; if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN; for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){ if( iLoop>0 ) ready |= pLoop->maskSelf; if( iLoop<nLoop ){ pLoop = pPath->aLoop[iLoop]; if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue; }else{ pLoop = pLast; } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ if( pLoop->u.vtab.isOrdered ) obSat = obDone; break; } iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; /* Mark off any ORDER BY term X that is a column in the table of ** the current loop for which there is term in the WHERE ** clause of the form X IS NULL or X=? that reference only outer ** loops. */ for(i=0; i<nOrderBy; i++){ if( MASKBIT(i) & obSat ) continue; pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, eqOpMask, 0); if( pTerm==0 ) continue; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ const char *z1, *z2; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr); if( !pColl ) pColl = db->pDfltColl; z1 = pColl->zName; pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr); |
︙ | ︙ | |||
3363 3364 3365 3366 3367 3368 3369 | ** that are not constrained by == or IN. */ rev = revSet = 0; distinctColumns = 0; for(j=0; j<nColumn; j++){ u8 bOnce; /* True to run the ORDER BY search loop */ | | > > | | 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 | ** that are not constrained by == or IN. */ rev = revSet = 0; distinctColumns = 0; for(j=0; j<nColumn; j++){ u8 bOnce; /* True to run the ORDER BY search loop */ /* Skip over == and IS and ISNULL terms. ** (Also skip IN terms when doing WHERE_ORDERBY_LIMIT processing) */ if( j<pLoop->u.btree.nEq && pLoop->nSkip==0 && ((i = pLoop->aLTerm[j]->eOperator) & eqOpMask)!=0 ){ if( i & WO_ISNULL ){ testcase( isOrderDistinct ); isOrderDistinct = 0; } continue; } |
︙ | ︙ | |||
3890 3891 3892 3893 3894 3895 3896 | if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; | > | > > > > > > > | > > > | 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 | if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; pWInfo->revMask = pFrom->revLoop; if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 && (pFrom->aLoop[nLoop-1]->wsFlags & WHERE_ONEROW)==0 ){ Bitmask m = 0; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); if( rc==pWInfo->pOrderBy->nExpr ){ pWInfo->bOrderedInnerLoop = 1; pWInfo->revMask = m; } } } } if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP) && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0 ){ Bitmask revMask = 0; int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask |
︙ | ︙ | |||
3939 3940 3941 3942 3943 3944 3945 | WhereLoop *pLoop; int iCur; int j; Table *pTab; Index *pIdx; pWInfo = pBuilder->pWInfo; | | | 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 | WhereLoop *pLoop; int iCur; int j; Table *pTab; Index *pIdx; pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy ) return 0; iCur = pItem->iCursor; pWC = &pWInfo->sWC; |
︙ | ︙ | |||
4086 4087 4088 4089 4090 4091 4092 | ** ** pOrderBy is a pointer to the ORDER BY clause (or the GROUP BY clause ** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** The iIdxCur parameter is the cursor number of an index. If | | | | | | | 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 | ** ** pOrderBy is a pointer to the ORDER BY clause (or the GROUP BY clause ** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. ** ** The iIdxCur parameter is the cursor number of an index. If ** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index ** to use for OR clause processing. The WHERE clause should use this ** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is ** the first cursor in an array of cursors for all indices. iIdxCur should ** be used to compute the appropriate cursor depending on which index is ** used. */ WhereInfo *sqlite3WhereBegin( Parse *pParse, /* The parser context */ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */ Expr *pWhere, /* The WHERE clause */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number ** If WHERE_USE_LIMIT, then the limit amount */ ){ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Bitmask notReady; /* Cursors that are not yet positioned */ WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ WhereLoop *pLoop; /* Pointer to a single WhereLoop object */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */ assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 )); /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */ assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 || (wctrlFlags & WHERE_USE_LIMIT)==0 ); /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ |
︙ | ︙ | |||
4151 4152 4153 4154 4155 4156 4157 | testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); return 0; } /* This function normally generates a nested loop for all tables in | | | | 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 | testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); return 0; } /* This function normally generates a nested loop for all tables in ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should ** only generate code for the first table in pTabList and assume that ** any cursors associated with subsequent tables are uninitialized. */ nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc; /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. |
︙ | ︙ | |||
4231 4232 4233 4234 4235 4236 4237 | ** a table T, then X-1 is the bitmask for all other tables to the left of T. ** Knowing the bitmask for all tables to the left of a left join is ** important. Ticket #3015. ** ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the | | | 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 | ** a table T, then X-1 is the bitmask for all other tables to the left of T. ** Knowing the bitmask for all tables to the left of a left join is ** important. Ticket #3015. ** ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_OR_SUBCLAUSE flag is set. */ for(ii=0; ii<pTabList->nSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); } #ifdef SQLITE_DEBUG for(ii=0; ii<pTabList->nSrc; ii++){ |
︙ | ︙ | |||
4269 4270 4271 4272 4273 4274 4275 | sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ | < | < < | 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 | sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags); if( wctrlFlags & WHERE_USE_LIMIT ){ sqlite3DebugPrintf(", limit: %d", iAuxArg); } sqlite3DebugPrintf(")\n"); } if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ sqlite3WhereClausePrint(sWLB.pWC); } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; |
︙ | ︙ | |||
4414 4415 4416 4417 4418 4419 4420 | int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); }else if( IsVirtual(pTab) ){ /* noop */ }else #endif if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 | | | 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 | int iCur = pTabItem->iCursor; sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB); }else if( IsVirtual(pTab) ){ /* noop */ }else #endif if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ op = OP_OpenWrite; pWInfo->aiCurOnePass[0] = pTabItem->iCursor; }; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); assert( pTabItem->iCursor==pLevel->iTabCur ); |
︙ | ︙ | |||
4453 4454 4455 4456 4457 4458 4459 | if( pLoop->wsFlags & WHERE_INDEXED ){ Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; /* iAuxArg is always set if to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) | | | | | 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 | if( pLoop->wsFlags & WHERE_INDEXED ){ Index *pIx = pLoop->u.btree.pIndex; int iIndexCur; int op = OP_OpenRead; /* iAuxArg is always set if to a positive value if ONEPASS is possible */ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 ); if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx) && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ /* This is one term of an OR-optimization using the PRIMARY KEY of a ** WITHOUT ROWID table. No need for a separate index */ iIndexCur = pLevel->iTabCur; op = 0; }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ Index *pJ = pTabItem->pTab->pIndex; iIndexCur = iAuxArg; assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); while( ALWAYS(pJ) && pJ!=pIx ){ iIndexCur++; pJ = pJ->pNext; } op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ iIndexCur = iAuxArg; op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; } pLevel->iIdxCur = iIndexCur; assert( pIx->pSchema==pTab->pSchema ); assert( iIndexCur>=0 ); if( op ){ |
︙ | ︙ | |||
4533 4534 4535 4536 4537 4538 4539 | #endif addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; | | | 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 | #endif addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); return pWInfo; |
︙ | ︙ | |||
4603 4604 4605 4606 4607 4608 4609 | sqlite3VdbeGoto(v, pLevel->addrSkip); VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pLevel->addrLikeRep ){ | < < | < < < | | 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 | sqlite3VdbeGoto(v, pLevel->addrSkip); VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( pLevel->addrLikeRep ){ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1), pLevel->addrLikeRep); VdbeCoverage(v); } #endif if( pLevel->iLeftJoin ){ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || (pLoop->wsFlags & WHERE_INDEXED)!=0 ); |
︙ | ︙ | |||
4661 4662 4663 4664 4665 4666 4667 | translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization | | | | 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 | translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult, 0); continue; } /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors ** created for the ONEPASS optimization. */ if( (pTab->tabFlags & TF_Ephemeral)==0 && pTab->pSelect==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int ws = pLoop->wsFlags; if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
66 67 68 69 70 71 72 | int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on pWLoop->wsFlags */ struct { |
︙ | ︙ | |||
414 415 416 417 418 419 420 | LogEst nRowOut; /* Estimated number of output rows */ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ | | > > > > | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | LogEst nRowOut; /* Estimated number of output rows */ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ u8 nLevel; /* Number of nested loop */ u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED void sqlite3WhereClausePrint(WhereClause *pWC); #endif WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
122 123 124 125 126 127 128 | u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); |
︙ | ︙ | |||
556 557 558 559 560 561 562 | } *pzAff = zAff; return regBase; } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* | | | | > | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | } *pzAff = zAff; return regBase; } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS /* ** If the most recently coded instruction is a constant range constraint ** (a string literal) that originated from the LIKE optimization, then ** set P3 and P5 on the OP_String opcode so that the string will be cast ** to a BLOB at appropriate times. ** ** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range ** expression: "x>='ABC' AND x<'abd'". But this requires that the range ** scan loop run twice, once for strings and a second time for BLOBs. ** The OP_String opcodes on the second pass convert the upper and lower ** bound string constants to blobs. This routine makes the necessary changes ** to the OP_String opcodes for that to happen. ** ** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then ** only the one pass through the string space is required, so this routine ** becomes a no-op. */ static void whereLikeOptimizationStringFixup( Vdbe *v, /* prepared statement under construction */ WhereLevel *pLevel, /* The loop that contains the LIKE operator */ WhereTerm *pTerm /* The upper or lower bound just coded */ ){ if( pTerm->wtFlags & TERM_LIKEOPT ){ VdbeOp *pOp; assert( pLevel->iLikeRepCntr>0 ); pOp = sqlite3VdbeGetOp(v, -1); assert( pOp!=0 ); assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ } } #else # define whereLikeOptimizationStringFixup(A,B,C) #endif #ifdef SQLITE_ENABLE_CURSOR_HINTS |
︙ | ︙ | |||
618 619 620 621 622 623 624 625 626 627 628 629 630 631 | assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } return WRC_Continue; } /* ** This function is called on every node of an expression tree used as an ** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } return WRC_Continue; } /* ** Test whether or not expression pExpr, which was part of a WHERE clause, ** should be included in the cursor-hint for a table that is on the rhs ** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the ** expression is not suitable. ** ** An expression is unsuitable if it might evaluate to non NULL even if ** a TK_COLUMN node that does affect the value of the expression is set ** to NULL. For example: ** ** col IS NULL ** col IS NOT NULL ** coalesce(col, 1) ** CASE WHEN col THEN 0 ELSE 1 END */ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_IS || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE ){ pWalker->eCode = 1; }else if( pExpr->op==TK_FUNCTION ){ int d1; char d2[3]; if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){ pWalker->eCode = 1; } } return WRC_Continue; } /* ** This function is called on every node of an expression tree used as an ** argument to the OP_CursorHint instruction. If the node is a TK_COLUMN |
︙ | ︙ | |||
673 674 675 676 677 678 679 680 681 682 683 684 685 686 | return rc; } /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; | > | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | return rc; } /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( struct SrcList_item *pTabItem, /* FROM clause item */ WhereInfo *pWInfo, /* The where clause */ WhereLevel *pLevel, /* Which loop to provide hints for */ WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */ ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; |
︙ | ︙ | |||
703 704 705 706 707 708 709 | sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; /* Any terms specified as part of the ON(...) clause for any LEFT ** JOIN for which the current table is not the rhs are omitted ** from the cursor-hint. ** ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms ** that were specified as part of the WHERE clause must be excluded. ** This is to address the following: ** ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL; ** ** Say there is a single row in t2 that matches (t1.a=t2.b), but its ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is ** pushed down to the cursor, this row is filtered out, causing ** SQLite to synthesize a row of NULL values. Which does match the ** WHERE clause, and so the query returns a row. Which is incorrect. ** ** For the same reason, WHERE terms such as: ** ** WHERE 1 = (t2.c IS NULL) ** ** are also excluded. See codeCursorHintIsOrFunction() for details. */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; if( !ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable!=pTabItem->iCursor ){ sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintIsOrFunction; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } }else{ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize ** the cursor. These terms are not needed as hints for a pure range ** scan (that has no == terms) so omit them. */ if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){ for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){} if( j<pLoop->nLTerm ) continue; |
︙ | ︙ | |||
737 738 739 740 741 742 743 | sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } } #else | | | 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | sqlite3WalkExpr(&sWalker, pExpr); sqlite3VdbeAddOp4(v, OP_CursorHint, (sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0, (const char*)pExpr, P4_EXPR); } } #else # define codeCursorHint(A,B,C,D) /* No-op */ #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* ** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains ** a rowid value just read from cursor iIdxCur, open on index pIdx. This ** function generates code to do a deferred seek of cursor iCur to the ** rowid stored in register iRowid. |
︙ | ︙ | |||
771 772 773 774 775 776 777 | Parse *pParse = pWInfo->pParse; /* Parse context */ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); | | | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | Parse *pParse = pWInfo->pParse; /* Parse context */ Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */ assert( iIdxCur>0 ); assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 ); sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur); if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) && DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask) ){ int i; Table *pTab = pIdx->pTable; int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); if( ai ){ ai[0] = pTab->nCol; |
︙ | ︙ | |||
826 827 828 829 830 831 832 | pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 | | | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 | pLevel = &pWInfo->a[iLevel]; pLoop = pLevel->pWLoop; pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; iCur = pTabItem->iCursor; pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); bRev = (pWInfo->revMask>>iLevel)&1; omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0; VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); /* Create labels for the "break" and "continue" instructions ** for the current loop. Jump to addrBrk to break out of a loop. ** Jump to cont to go immediately to the next iteration of the ** loop. ** |
︙ | ︙ | |||
966 967 968 969 970 971 972 | assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; | < | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); iReleaseReg = ++pParse->nMem; iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg); VdbeCoverage(v); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 |
︙ | ︙ | |||
994 995 996 997 998 999 1000 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } | | | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } codeCursorHint(pTabItem, pWInfo, pLevel, pEnd); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ |
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = 1; #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ | | > > > > > < | | < | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ){ pRangeEnd = pLoop->aLTerm[j++]; nExtraReg = 1; #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){ assert( pRangeStart!=0 ); /* LIKE opt constraints */ assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */ pLevel->iLikeRepCntr = (u32)++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr); VdbeComment((v, "LIKE loop counter")); pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v); /* iLikeRepCntr actually stores 2x the counter register number. The ** bottom bit indicates whether the search order is ASC or DESC. */ testcase( bRev ); testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC ); assert( (bRev & ~1)==0 ); pLevel->iLikeRepCntr <<=1; pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC); } #endif if( pRangeStart==0 && (j = pIdx->aiColumn[nEq])>=0 && pIdx->pTable->aCol[j].notNull==0 ){ bSeekPastNull = 1; |
︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 | SWAP(u8, bSeekPastNull, bStopAtNull); } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ | | | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | SWAP(u8, bSeekPastNull, bStopAtNull); } /* Generate code to evaluate all constraint terms using == or IN ** and store the values of those terms in an array of registers ** starting at regBase. */ codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd); regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); if( zStartAff ) cEndAff = zStartAff[nEq]; addrNxt = pLevel->addrNxt; testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); |
︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 | } if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ zStartAff[nEq] = SQLITE_AFF_BLOB; } } nConstraint++; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); | > | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 | } if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ zStartAff[nEq] = SQLITE_AFF_BLOB; } } nConstraint++; testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); bSeekPastNull = 0; }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; } codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 | /* Seek the table cursor, if required */ disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ | | | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 | /* Seek the table cursor, if required */ disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); VdbeCoverage(v); }else{ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); |
︙ | ︙ | |||
1509 1510 1511 1512 1513 1514 1515 | } } /* Run a separate WHERE clause for each term of the OR clause. After ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ | | < < < | 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 | } } /* Run a separate WHERE clause for each term of the OR clause. After ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); for(ii=0; ii<pOrWc->nTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */ int jmp1 = 0; /* Address of jump operation */ if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){ |
︙ | ︙ | |||
1620 1621 1622 1623 1624 1625 1626 | assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; | < | 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 | assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex)) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); } |
︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 | static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); if( pTabItem->fg.isRecursive ){ /* Tables marked isRecursive have only a single row that is stored in ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ | | | 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 | static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); if( pTabItem->fg.isRecursive ){ /* Tables marked isRecursive have only a single row that is stored in ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ codeCursorHint(pTabItem, pWInfo, pLevel, 0); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } |
︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 | Expr *pE; int skipLikeAddr = 0; testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 | | > > > > > | > | | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | Expr *pE; int skipLikeAddr = 0; testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){ continue; } if( pTerm->wtFlags & TERM_LIKECOND ){ /* If the TERM_LIKECOND flag is set, that means that the range search ** is sufficient to guarantee that the LIKE operator is true, so we ** can skip the call to the like(A,B) function. But this only works ** for strings. So do not skip the call to the function on the pass ** that compares BLOBs. */ #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS continue; #else u32 x = pLevel->iLikeRepCntr; assert( x>0 ); skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1)); VdbeCoverage(v); #endif } sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
286 287 288 289 290 291 292 | ** ** If it is then return TRUE. If not, return FALSE. */ static int isMatchOfColumn( Expr *pExpr, /* Test this expression */ unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ ){ | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | ** ** If it is then return TRUE. If not, return FALSE. */ static int isMatchOfColumn( Expr *pExpr, /* Test this expression */ unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */ ){ static const struct Op2 { const char *zOp; unsigned char eOp2; } aOp[] = { { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } |
︙ | ︙ | |||
564 565 566 567 568 569 570 | sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); | | > > | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); sqlite3WhereExprAnalyze(pSrc, pAndWC); pAndWC->pOuter = pWC; if( !db->mallocFailed ){ for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) || pAndTerm->eOperator==WO_MATCH ){ b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } indexable &= b; } }else if( pOrTerm->wtFlags & TERM_COPIED ){ |
︙ | ︙ | |||
779 780 781 782 783 784 785 | && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); | < < | | | | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); zColl1 = pColl ? pColl->zName : 0; pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); zColl2 = pColl ? pColl->zName : 0; return sqlite3_stricmp(zColl1, zColl2)==0; } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression ** tree. */ |
︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_MATCH auxiliary term to the constraint set if the ** current expression is of the form: column MATCH expr. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Add a WO_MATCH auxiliary term to the constraint set if the ** current expression is of the form: column MATCH expr. ** This information is used by the xBestIndex methods of ** virtual tables. The native query optimizer does not attempt ** to do anything with MATCH functions. */ if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){ int idxNew; Expr *pRight, *pLeft; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; pRight = pExpr->x.pList->a[0].pExpr; pLeft = pExpr->x.pList->a[1].pExpr; |
︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 | /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ | | > | | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ mask = sqlite3WhereGetMask(pMaskSet, p->iTable); return mask; } assert( !ExprHasProperty(p, EP_TokenOnly) ); mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); if( ExprHasProperty(p, EP_xIsSelect) ){ mask |= exprSelectUsage(pMaskSet, p->x.pSelect); }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } return mask; |
︙ | ︙ |
Changes to test/alter3.test.
︙ | ︙ | |||
180 181 182 183 184 185 186 | ALTER TABLE t1 ADD c; SELECT * FROM t1; } } {1 100 {} 2 300 {}} if {!$has_codec} { do_test alter3-3.3 { get_file_format | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | ALTER TABLE t1 ADD c; SELECT * FROM t1; } } {1 100 {} 2 300 {}} if {!$has_codec} { do_test alter3-3.3 { get_file_format } {3} } ifcapable schema_version { do_test alter3-3.4 { execsql { PRAGMA schema_version; } } {11} |
︙ | ︙ | |||
216 217 218 219 220 221 222 | ALTER TABLE t1 ADD c DEFAULT 'hello world'; SELECT * FROM t1; } } {1 100 {hello world} 2 300 {hello world}} if {!$has_codec} { do_test alter3-4.3 { get_file_format | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | ALTER TABLE t1 ADD c DEFAULT 'hello world'; SELECT * FROM t1; } } {1 100 {hello world} 2 300 {hello world}} if {!$has_codec} { do_test alter3-4.3 { get_file_format } {3} } ifcapable schema_version { do_test alter3-4.4 { execsql { PRAGMA schema_version; } } {21} |
︙ | ︙ | |||
266 267 268 269 270 271 272 | PRAGMA aux.schema_version; } } {31} } if {!$has_codec} { do_test alter3-5.5 { list [get_file_format test2.db] [get_file_format] | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | PRAGMA aux.schema_version; } } {31} } if {!$has_codec} { do_test alter3-5.5 { list [get_file_format test2.db] [get_file_format] } {3 3} } do_test alter3-5.6 { execsql { ALTER TABLE aux.t1 ADD COLUMN d DEFAULT 1000; SELECT sql FROM aux.sqlite_master; } } {{CREATE TABLE t1(a,b, c VARCHAR(128), d DEFAULT 1000)}} |
︙ | ︙ | |||
343 344 345 346 347 348 349 | } {1} do_test alter3-7.2 { execsql { CREATE TABLE abc(a, b, c); ALTER TABLE abc ADD d DEFAULT NULL; } get_file_format | | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | } {1} do_test alter3-7.2 { execsql { CREATE TABLE abc(a, b, c); ALTER TABLE abc ADD d DEFAULT NULL; } get_file_format } {3} do_test alter3-7.3 { execsql { ALTER TABLE abc ADD e DEFAULT 10; } get_file_format } {3} do_test alter3-7.4 { execsql { ALTER TABLE abc ADD f DEFAULT NULL; } get_file_format } {3} do_test alter3-7.5 { execsql { VACUUM; } get_file_format } {1} } |
︙ | ︙ |
Changes to test/alter4.test.
︙ | ︙ | |||
350 351 352 353 354 355 356 357 358 | real 9.22337203685478e+18 } do_execsql_test alter4-9.3 { ALTER TABLE t5 ADD COLUMN c INTEGER DEFAULT (-(-9223372036854775808)); SELECT typeof(c), c FROM t5; } {real 9.22337203685478e+18} finish_test | > > > > > > > > > > > > > > > > > > > | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | real 9.22337203685478e+18 } do_execsql_test alter4-9.3 { ALTER TABLE t5 ADD COLUMN c INTEGER DEFAULT (-(-9223372036854775808)); SELECT typeof(c), c FROM t5; } {real 9.22337203685478e+18} # Confirm that doing an ALTER TABLE on a legacy format database # does not corrupt DESC indexes. # # Ticket https://www.sqlite.org/src/tktview/f68bf68513a1c # do_test alter4-10.1 { db close sqlite3 db :memory: db eval { PRAGMA legacy_file_format=on; CREATE TABLE t1(a,b,c); CREATE INDEX t1a ON t1(a DESC); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t1 VALUES(2,3,4); ALTER TABLE t1 ADD COLUMN d; PRAGMA integrity_check; } } {ok} finish_test |
Changes to test/auth2.test.
︙ | ︙ | |||
94 95 96 97 98 99 100 | SQLITE_CREATE_TABLE t2 {} main {} SQLITE_UPDATE sqlite_master type main {} SQLITE_UPDATE sqlite_master name main {} SQLITE_UPDATE sqlite_master tbl_name main {} SQLITE_UPDATE sqlite_master rootpage main {} SQLITE_UPDATE sqlite_master sql main {} SQLITE_READ sqlite_master ROWID main {} | < < < < < < < < < < < < | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | SQLITE_CREATE_TABLE t2 {} main {} SQLITE_UPDATE sqlite_master type main {} SQLITE_UPDATE sqlite_master name main {} SQLITE_UPDATE sqlite_master tbl_name main {} SQLITE_UPDATE sqlite_master rootpage main {} SQLITE_UPDATE sqlite_master sql main {} SQLITE_READ sqlite_master ROWID main {} } do_test auth2-2.2 { set ::authargs {} db eval { CREATE VIEW v2 AS SELECT x+y AS a, y+z AS b from t2; } set ::authargs } {SQLITE_INSERT sqlite_master {} main {} SQLITE_CREATE_VIEW v2 {} main {} SQLITE_UPDATE sqlite_master type main {} SQLITE_UPDATE sqlite_master name main {} SQLITE_UPDATE sqlite_master tbl_name main {} SQLITE_UPDATE sqlite_master rootpage main {} SQLITE_UPDATE sqlite_master sql main {} SQLITE_READ sqlite_master ROWID main {} } do_test auth2-2.3 { set ::authargs {} db eval { SELECT a, b FROM v2; } |
︙ | ︙ |
Changes to test/auth3.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test that the truncate optimization is disabled if the SQLITE_DELETE # authorization callback returns SQLITE_IGNORE. # | | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test that the truncate optimization is disabled if the SQLITE_DELETE # authorization callback returns SQLITE_IGNORE. # # Test that authorizer is disabled during schema parsing. set testdir [file dirname $argv0] source $testdir/tester.tcl # disable this test if the SQLITE_OMIT_AUTHORIZATION macro is # defined during compilation. if {[catch {db auth {}} msg]} { |
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 | } set sqlite_search_count 0 execsql { DELETE FROM t1; } set sqlite_search_count } {1} finish_test | > > > > > > > > > > > > > > > > > > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | } set sqlite_search_count 0 execsql { DELETE FROM t1; } set sqlite_search_count } {1} # 2016-07-28. A problem report from a private client complaining about # an authorizer failure during an ALTER TABLE. The solution (I think) is # to disable the authorizer during schema parsing. # proc auth {code args} { if {$code=="SQLITE_READ" && [regexp {DoNotRead} $args]} { return SQLITE_DENY } return SQLITE_OK } do_execsql_test auth3-3.0 { CREATE TEMPORARY TABLE TempTable ( key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL); ALTER TABLE TempTable RENAME TO DoNotRead; SELECT name FROM sqlite_temp_master; } {DoNotRead sqlite_autoindex_DoNotRead_1} finish_test |
Added test/bestindex3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | # 2016 May 29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix bestindex3 ifcapable !vtab { finish_test return } #------------------------------------------------------------------------- # Virtual table callback for a virtual table named $tbl. # # The table created is: # # "CREATE TABLE t1 (a, b, c)" # # This virtual table supports both LIKE and = operators on all columns. # proc vtab_cmd {bOmit method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { foreach {clist orderby mask} $args {} set ret [list] set use use if {$bOmit} {set use omit} for {set i 0} {$i < [llength $clist]} {incr i} { array unset C array set C [lindex $clist $i] if {$C(usable) && ($C(op)=="like" || $C(op)=="eq")} { lappend ret $use $i lappend ret idxstr lappend ret "[lindex {a b c} $C(column)] [string toupper $C(op)] ?" break } } if {$ret==""} { lappend ret cost 1000000 rows 1000000 } else { lappend ret cost 100 rows 10 } return $ret } xFilter { foreach {idxnum idxstr param} $args {} set where "" if {$bOmit && $idxstr != ""} { set where " WHERE [string map [list ? '$param' EQ =] $idxstr]" } return [list sql "SELECT rowid, * FROM ttt$where"] } } return "" } register_tcl_module db do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} } do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} } do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_eqp_test 1.4 { SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_execsql_test 1.5 { CREATE TABLE ttt(a, b, c); INSERT INTO ttt VALUES(1, 'two', 'three'); INSERT INTO ttt VALUES(2, 'one', 'two'); INSERT INTO ttt VALUES(3, 'three', 'one'); INSERT INTO ttt VALUES(4, 'y', 'one'); INSERT INTO ttt VALUES(5, 'x', 'two'); INSERT INTO ttt VALUES(6, 'y', 'three'); } foreach omit {0 1} { do_execsql_test 1.6.$omit.0 " DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING tcl('vtab_cmd $omit'); " do_execsql_test 1.6.$omit.1 { SELECT rowid FROM t1 WHERE c LIKE 'o%' } {3 4} do_execsql_test 1.6.$omit.2 { SELECT rowid FROM t1 WHERE c LIKE 'o%' OR b='y' } {3 4 6} do_execsql_test 1.6.$omit.3 { SELECT rowid FROM t1 WHERE c = 'three' OR c LIKE 'o%' } {1 6 3 4} } #------------------------------------------------------------------------- # Test the same pattern works with ordinary tables. # # This test does not work if the ICU extension is enabled. ICU overrides # LIKE - and this optimization only works with the built-in LIKE function. # ifcapable !icu { do_execsql_test 2.1 { CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT); CREATE INDEX t2x ON t2(x COLLATE nocase); CREATE INDEX t2y ON t2(y); } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)} 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } } #------------------------------------------------------------------------- # Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE # statement is currently ignored. # proc vvv_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a PRIMARY KEY, b, c)" } } } proc yyy_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b))" } } } do_execsql_test 3.1 { CREATE VIRTUAL TABLE t3 USING tcl('vvv_command') } do_execsql_test 3.2 { CREATE VIRTUAL TABLE t4 USING tcl('yyy_command') } finish_test |
Added test/collateB.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # 2016-07-01 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # Test cases for a crash bug. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test collateB-1.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY); CREATE TABLE t2(b INTEGER PRIMARY KEY, x1 INT COLLATE NOCASE); CREATE TABLE t3(x2 INT); SELECT * FROM t3, t2, t1 WHERE x2=b AND x1=a AND a=1; } {} do_execsql_test collateB-1.2 { INSERT INTO t1(a) VALUES(1),(2),(3); INSERT INTO t2(b,x1) VALUES(11,1),(22,2),(33,3); INSERT INTO t3(x2) VALUES(11),(22),(33); SELECT *,'|' FROM t3, t2, t1 WHERE x2=b AND x1=a AND a=1; } {11 11 1 1 |} do_execsql_test collateB-1.3 { SELECT *,'|' FROM t3, t1, t2 WHERE x2=b AND x1=a AND a=1; } {11 1 11 1 |} do_execsql_test collateB-1.4 { SELECT *,'|' FROM t2, t3, t1 WHERE x2=b AND x1=a AND a=1; } {11 1 11 1 |} do_execsql_test collateB-1.5 { SELECT *,'|' FROM t2, t1, t3 WHERE x2=b AND x1=a AND a=1; } {11 1 1 11 |} do_execsql_test collateB-1.6 { SELECT *,'|' FROM t1, t2, t3 WHERE x2=b AND x1=a AND a=1; } {1 11 1 11 |} do_execsql_test collateB-1.7 { SELECT *,'|' FROM t1, t2, t3 WHERE x2=b AND x1=a AND a=1; } {1 11 1 11 |} do_execsql_test collateB-1.12 { SELECT *,'|' FROM t3, t2, t1 WHERE b=x2 AND a=x1 AND 1=a; } {11 11 1 1 |} do_execsql_test collateB-1.13 { SELECT *,'|' FROM t3, t1, t2 WHERE b=x2 AND a=x1 AND 1=a; } {11 1 11 1 |} do_execsql_test collateB-1.14 { SELECT *,'|' FROM t2, t3, t1 WHERE b=x2 AND a=x1 AND 1=a; } {11 1 11 1 |} do_execsql_test collateB-1.15 { SELECT *,'|' FROM t2, t1, t3 WHERE b=x2 AND a=x1 AND 1=a; } {11 1 1 11 |} do_execsql_test collateB-1.16 { SELECT *,'|' FROM t1, t2, t3 WHERE b=x2 AND a=x1 AND 1=a; } {1 11 1 11 |} do_execsql_test collateB-1.17 { SELECT *,'|' FROM t1, t2, t3 WHERE b=x2 AND a=x1 AND 1=a; } {1 11 1 11 |} finish_test |
Added test/csv01.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # 2016-06-02 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for CSV virtual table. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix csv01 ifcapable !vtab||!cte { finish_test ; return } load_static_extension db csv do_execsql_test 1.0 { CREATE VIRTUAL TABLE temp.t1 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4 ); SELECT * FROM t1 WHERE c1=10; } {9 10 11 12} do_execsql_test 1.1 { SELECT * FROM t1 WHERE c1='10'; } {9 10 11 12} do_execsql_test 1.2 { SELECT rowid FROM t1; } {1 2 3 4} do_execsql_test 2.0 { DROP TABLE t1; CREATE VIRTUAL TABLE temp.t2 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema='CREATE TABLE t2(a INT, b TEXT, c REAL, d BLOB)' ); SELECT * FROM t2 WHERE a=9; } {9 10 11 12} do_execsql_test 2.1 { SELECT * FROM t2 WHERE b=10; } {9 10 11 12} do_execsql_test 2.2 { SELECT * FROM t2 WHERE c=11; } {9 10 11 12} do_execsql_test 2.3 { SELECT * FROM t2 WHERE d=12; } {} do_execsql_test 2.4 { SELECT * FROM t2 WHERE d='12'; } {9 10 11 12} do_execsql_test 2.5 { SELECT * FROM t2 WHERE a='9'; } {9 10 11 12} do_execsql_test 3.0 { DROP TABLE t2; CREATE VIRTUAL TABLE temp.t3 USING csv( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema= 'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID', testflags=1 ); SELECT a FROM t3 WHERE b=6 OR c=7 OR d=12 ORDER BY +a; } {5 9} do_execsql_test 3.1 { SELECT a FROM t3 WHERE +b=6 OR c=7 OR d=12 ORDER BY +a; } {5 9} # The rowid column is not visible on a WITHOUT ROWID virtual table do_catchsql_test 3.2 { SELECT rowid, a FROM t3; } {1 {no such column: rowid}} do_catchsql_test 4.0 { DROP TABLE t3; CREATE VIRTUAL TABLE temp.t4 USING csv_wr( data= '1,2,3,4 5,6,7,8 9,10,11,12 13,14,15,16 ', columns=4, schema= 'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID', testflags=1 ); } {1 {vtable constructor failed: t4}} finish_test |
Changes to test/ctime.test.
︙ | ︙ | |||
192 193 194 195 196 197 198 | PRAGMA compile_options; } ] set opts [ lindex $ans 1 ] set tc 1 foreach opt $opts { do_test ctime-2.5.$tc { set N [ expr {$tc-1} ] | | | > | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | PRAGMA compile_options; } ] set opts [ lindex $ans 1 ] set tc 1 foreach opt $opts { do_test ctime-2.5.$tc { set N [ expr {$tc-1} ] set ans1 [catch {db one { SELECT sqlite_compileoption_get($N); }} msg] lappend ans1 $msg set ans2 [ catchsql { SELECT sqlite_compileoption_used($opt); } ] list [ lindex $ans1 0 ] [ expr { [lindex $ans1 1]==$opt } ] \ [ expr { $ans2 } ] } {0 1 {0 1}} incr tc 1 |
︙ | ︙ |
Added test/cursorhint2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | # 2016 June 17 # # 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. The # focus is on testing that cursor-hints are correct for queries # involving LEFT JOIN. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix cursorhint2 ifcapable !cursorhints { finish_test return } proc extract_hints {sql} { db eval "SELECT tbl_name, rootpage FROM sqlite_master where rootpage" { set lookup($rootpage) $tbl_name } set ret [list] db eval "EXPLAIN $sql" a { switch -- $a(opcode) { OpenRead { set csr($a(p1)) $lookup($a(p2)) } CursorHint { lappend ret $csr($a(p1)) $a(p4) } } } set ret } proc do_extract_hints_test {tn sql ret} { uplevel [list do_test $tn [list extract_hints $sql] [list {*}$ret]] } do_execsql_test 1.0 { PRAGMA automatic_index = 0; CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); CREATE TABLE t3(e, f); } do_extract_hints_test 1.1 { SELECT * FROM t1 WHERE a=1; } { t1 EQ(c0,1) } do_extract_hints_test 1.2 { SELECT * FROM t1 CROSS JOIN t2 ON (a=c) WHERE d IS NULL; } { t2 {AND(ISNULL(c1),EQ(r[1],c0))} } do_extract_hints_test 1.3 { SELECT * FROM t1 LEFT JOIN t2 ON (a=c) WHERE d IS NULL; } { t2 {EQ(r[2],c0)} } do_extract_hints_test 1.4 { SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND a=10) WHERE d IS NULL; } { t2 {AND(EQ(r[2],c0),EQ(r[3],10))} } do_extract_hints_test 1.5 { SELECT * FROM t1 CROSS JOIN t2 ON (a=c AND a=10) WHERE d IS NULL; } { t1 EQ(c0,10) t2 {AND(ISNULL(c1),EQ(r[3],c0))} } do_extract_hints_test 1.6 { SELECT * FROM t1 LEFT JOIN t2 ON (a=c) LEFT JOIN t3 ON (d=f); } { t2 {EQ(r[2],c0)} t3 {EQ(r[6],c1)} } do_extract_hints_test 1.7 { SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND d=e) LEFT JOIN t3 ON (d=f); } { t2 {EQ(r[2],c0)} t3 {AND(EQ(r[6],c0),EQ(r[7],c1))} } #------------------------------------------------------------------------- # do_execsql_test 2.0 { CREATE TABLE x1(x, y); CREATE TABLE x2(a, b); } do_extract_hints_test 2.1 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NULL; } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.2 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS +NULL; } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.3 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = (b IS NULL) } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.4 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1) } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.5 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1) } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.6 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT NULL) } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.7 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT +NULL) } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.8 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NOT +NULL } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.9 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE CASE b WHEN 0 THEN 0 ELSE 1 END; } { x2 {EQ(c0,r[2])} } do_extract_hints_test 2.10 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b = 32+32 } { x2 {AND(EQ(c1,ADD(32,32)),EQ(c0,r[2]))} } do_extract_hints_test 2.11 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b LIKE 'abc%' } { x2 {AND(expr,EQ(c0,r[2]))} } do_extract_hints_test 2.11 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1) } { x2 {EQ(c0,r[2])} } finish_test |
Changes to test/dbstatus.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #*********************************************************************** # # Tests for the sqlite3_db_status() function # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !compound { finish_test return } # Memory statistics must be enabled for this test. db close sqlite3_shutdown sqlite3_config_memstatus 1 sqlite3_initialize sqlite3 db test.db # Make sure sqlite3_db_config() and sqlite3_db_status are working. # unset -nocomplain PAGESZ | > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #*********************************************************************** # # Tests for the sqlite3_db_status() function # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix dbstatus ifcapable !compound { finish_test return } # Memory statistics must be enabled for this test. db close sqlite3_shutdown sqlite3_config_memstatus 1 sqlite3_config_uri 1 sqlite3_initialize sqlite3 db test.db # Make sure sqlite3_db_config() and sqlite3_db_status are working. # unset -nocomplain PAGESZ |
︙ | ︙ | |||
63 64 65 66 67 68 69 | ifcapable stat4||stat3 { set STAT3 1 } else { set STAT3 0 } | < < < < < > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ifcapable stat4||stat3 { set STAT3 1 } else { set STAT3 0 } #--------------------------------------------------------------------------- # Run the dbstatus-2 and dbstatus-3 tests with several of different # lookaside buffer sizes. # foreach ::lookaside_buffer_size {0 64 120} { ifcapable malloc_usable_size break # Do not run any of these tests if there is SQL configured to run # as part of the [sqlite3] command. This prevents the script from # configuring the size of the lookaside buffer after [sqlite3] has # returned. if {[presql] != ""} break |
︙ | ︙ | |||
372 373 374 375 376 377 378 379 380 | do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1} } do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3] do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4] } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1} } do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3] do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4] } } #------------------------------------------------------------------------- # The following tests focus on DBSTATUS_CACHE_USED_SHARED # ifcapable shared_cache { if {[permutation]=="memsys3" || [permutation]=="memsys5" || $::tcl_platform(os)=="Linux"} { proc do_cacheused_test {tn db res} { set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0] set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0] set cu [lindex $cu 1] set pcu [lindex $pcu 1] uplevel [list do_test $tn [list list $cu $pcu] "#/$res/"] } reset_db sqlite3 db file:test.db?cache=shared do_execsql_test 4.0 { PRAGMA auto_vacuum=NONE; CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES(1, 2, 3); } do_cacheused_test 4.0.1 db { 4568 4568 } do_execsql_test 4.1 { CREATE TEMP TABLE tt(a, b, c); INSERT INTO tt VALUES(1, 2, 3); } do_cacheused_test 4.1.1 db { 9000 9000 } sqlite3 db2 file:test.db?cache=shared do_cacheused_test 4.2.1 db2 { 4568 2284 } do_cacheused_test 4.2.2 db { 9000 6716 } db close do_cacheused_test 4.2.3 db2 { 4568 4568 } sqlite3 db file:test.db?cache=shared do_cacheused_test 4.2.4 db2 { 4568 2284 } db2 close } } finish_test |
Changes to test/delete4.test.
︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 | INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1; INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1; INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1; PRAGMA reverse_unordered_selects = ON; DELETE FROM t1 WHERE b=2; SELECT a FROM t1 WHERE b=2; } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | INSERT INTO t1(a,b,c) SELECT a+2, 1, c FROM t1; INSERT INTO t1(a,b,c) SELECT a+10, 2, c FROM t1 WHERE b=1; INSERT INTO t1(a,b,c) SELECT a+20, 3, c FROM t1 WHERE b=1; PRAGMA reverse_unordered_selects = ON; DELETE FROM t1 WHERE b=2; SELECT a FROM t1 WHERE b=2; } {} # 2016-05-02 # Ticket https://www.sqlite.org/src/tktview/dc6ebeda93960877 # A subquery in the WHERE clause of a one-pass DELETE can cause an # incorrect answer. # db close forcedelete test.db sqlite3 db test.db do_execsql_test 6.0 { CREATE TABLE t2(x INT); INSERT INTO t2(x) VALUES(1),(2),(3),(4),(5); DELETE FROM t2 WHERE EXISTS(SELECT 1 FROM t2 AS v WHERE v.x=t2.x-1); SELECT x FROM t2; } {1} do_execsql_test 6.1 { DROP TABLE IF EXISTS t2; CREATE TABLE t2(x INT); INSERT INTO t2(x) VALUES(1),(2),(3),(4),(5); DELETE FROM t2 WHERE EXISTS(SELECT 1 FROM t2 AS v WHERE v.x=t2.x+1); SELECT x FROM t2; } {5} finish_test |
Changes to test/fts3conf.test.
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 | ROLLBACK TO abc; COMMIT; } do_execsql_test 4.2.2 { SELECT * FROM t01 WHERE t01 MATCH 'b'; INSERT INTO t01(t01) VALUES('integrity-check'); } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | ROLLBACK TO abc; COMMIT; } do_execsql_test 4.2.2 { SELECT * FROM t01 WHERE t01 MATCH 'b'; INSERT INTO t01(t01) VALUES('integrity-check'); } {} do_execsql_test 4.3.1 { CREATE VIRTUAL TABLE t02 USING fts4; INSERT INTO t01 VALUES('1 1 1'); INSERT INTO t02 VALUES('2 2 2'); BEGIN; SAVEPOINT abc; INSERT INTO t01 VALUES('a b c'); INSERT INTO t02 VALUES('a b c'); ROLLBACK TO abc; COMMIT; } do_execsql_test 4.3.2 { SELECT * FROM t01 WHERE t01 MATCH 'b'; INSERT INTO t01(t01) VALUES('integrity-check'); } {} do_execsql_test 4.4.1 { CREATE TABLE A(ID INTEGER PRIMARY KEY, AnotherID INTEGER, Notes TEXT); CREATE VIRTUAL TABLE AFTS USING FTS4 (Notes); CREATE TRIGGER A_DeleteTrigger AFTER DELETE ON A FOR EACH ROW BEGIN DELETE FROM AFTS WHERE rowid=OLD.ID; END; CREATE TABLE B(ID INTEGER PRIMARY KEY,Notes TEXT); CREATE VIRTUAL TABLE BFTS USING FTS3 (Notes); CREATE TRIGGER B_DeleteTrigger AFTER DELETE ON B FOR EACH ROW BEGIN DELETE FROM BFTS WHERE rowid=OLD.ID; END; } do_execsql_test 4.4.2 { BEGIN TRANSACTION; DELETE FROM A WHERE AnotherID=1; DELETE FROM B WHERE ID=1; COMMIT; } finish_test |
Changes to test/fts3expr.test.
︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 | do_test fts3expr-8.8 { test_fts3expr "(,(blah-),)" } {PHRASE 3 0 blah} set sqlite_fts3_enable_parentheses 0 do_test fts3expr-9.1 { test_fts3expr "f (e NEAR/2 a)" } {AND {PHRASE 3 0 f} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} finish_test | > > > > | 509 510 511 512 513 514 515 516 517 518 519 520 521 | do_test fts3expr-8.8 { test_fts3expr "(,(blah-),)" } {PHRASE 3 0 blah} set sqlite_fts3_enable_parentheses 0 do_test fts3expr-9.1 { test_fts3expr "f (e NEAR/2 a)" } {AND {PHRASE 3 0 f} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} do_test fts3expr-10.1 { test_fts3expr "abc *" } {PHRASE 3 0 abc} do_test fts3expr-10.2 { test_fts3expr "*" } {} do_test fts3expr-10.3 { test_fts3expr "abc*" } {PHRASE 3 0 abc+} finish_test |
Changes to test/fuzzcheck.c.
︙ | ︙ | |||
778 779 780 781 782 783 784 | */ static void showHelp(void){ printf("Usage: %s [options] SOURCE-DB ?ARGS...?\n", g.zArgv0); printf( "Read databases and SQL scripts from SOURCE-DB and execute each script against\n" "each database, checking for crashes and memory leaks.\n" "Options:\n" | | | | | | | | | | | | | | | | | | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | */ static void showHelp(void){ printf("Usage: %s [options] SOURCE-DB ?ARGS...?\n", g.zArgv0); printf( "Read databases and SQL scripts from SOURCE-DB and execute each script against\n" "each database, checking for crashes and memory leaks.\n" "Options:\n" " --cell-size-check Set the PRAGMA cell_size_check=ON\n" " --dbid N Use only the database where dbid=N\n" " --export-db DIR Write databases to files(s) in DIR. Works with --dbid\n" " --export-sql DIR Write SQL to file(s) in DIR. Also works with --sqlid\n" " --help Show this help text\n" " -q|--quiet Reduced output\n" " --limit-mem N Limit memory used by test SQLite instance to N bytes\n" " --limit-vdbe Panic if any test runs for more than 100,000 cycles\n" " --load-sql ARGS... Load SQL scripts fro files into SOURCE-DB\n" " --load-db ARGS... Load template databases from files into SOURCE_DB\n" " -m TEXT Add a description to the database\n" " --native-vfs Use the native VFS for initially empty database files\n" " --rebuild Rebuild and vacuum the database file\n" " --result-trace Show the results of each SQL command\n" " --sqlid N Use only SQL where sqlid=N\n" " --timeout N Abort if any single test needs more than N seconds\n" " -v|--verbose Increased output. Repeat for more output.\n" ); } int main(int argc, char **argv){ sqlite3_int64 iBegin; /* Start time of this program */ int quietFlag = 0; /* True if --quiet or -q */ int verboseFlag = 0; /* True if --verbose or -v */ |
︙ | ︙ |
Changes to test/in.test.
︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 | } } {1 {only a single result allowed for a SELECT that is part of an expression}} do_test in-13.X { db nullvalue "" } {} finish_test | > > > > > > > > > > > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | } } {1 {only a single result allowed for a SELECT that is part of an expression}} do_test in-13.X { db nullvalue "" } {} # At one point the following was causing valgrind to report a "jump # depends on unitialized location" problem. # do_execsql_test in-14.0 { CREATE TABLE c1(a); INSERT INTO c1 VALUES(1), (2), (4), (3); } do_execsql_test in-14.1 { SELECT * FROM c1 WHERE a IN (SELECT a FROM c1) ORDER BY 1 } {1 2 3 4} finish_test |
Changes to test/index6.test.
︙ | ︙ | |||
371 372 373 374 375 376 377 378 379 | do_execsql_test index6-10.3 { SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {9 5} do_execsql_test index6-10.3eqp { EXPLAIN QUERY PLAN SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {~/USING INDEX t10x/} finish_test | > > > > > > > > > > > | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | do_execsql_test index6-10.3 { SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {9 5} do_execsql_test index6-10.3eqp { EXPLAIN QUERY PLAN SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC; } {~/USING INDEX t10x/} # A partial index will be used for a full table scan, where possible do_execsql_test index6-11.1 { CREATE TABLE t11(a,b,c); CREATE INDEX t11x ON t11(a) WHERE b<>99; EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99; } {/USING INDEX t11x/} do_execsql_test index6-11.2 { EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99 AND c<>98; } {/USING INDEX t11x/} finish_test |
Added test/index8.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # 2016-07-27 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for ORDER BY and LIMIT on an index scan. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Performance regression reported at # http://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg98615.html # # Caused by the ORDER BY LIMIT optionation for check-in # https://sqlite.org/src/info/bf46179d44843769 # # Fixed on approximately 2016-07-27 by changes that compute a better score # for index scans by taking into account WHERE clause constraints that can # be handled by the index and do not require a table lookup. # do_execsql_test 1.0 { CREATE TABLE t1(a,b,c,d); WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b,c,d) SELECT x/10, x%10, x%19, x FROM c; CREATE INDEX t1abc ON t1(a,b,c); SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; } {0 4 4 4 2 3 4 23} # Prior to the fix, the following EQP would show a table scan and a sort # rather than an index scan. # do_execsql_test 1.0eqp { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; } {/SCAN TABLE t1 USING INDEX t1abc/} # If we change the index so that it no longer covers the WHERE clause, # then we should (correctly) revert to using a table scan. # do_execsql_test 1.1 { DROP INDEX t1abc; CREATE INDEX t1abd ON t1(a,b,d); SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; } {0 4 4 4 2 3 4 23} do_execsql_test 1.1eqp { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=4 ORDER BY a, b LIMIT 2; } {~/USING INDEX/} finish_test |
Changes to test/intpkey.test.
︙ | ︙ | |||
610 611 612 613 614 615 616 | do_execsql_test intpkey-16.0 { CREATE TABLE t16a(id "INTEGER" PRIMARY KEY AUTOINCREMENT, b [TEXT], c `INT`); } {} do_execsql_test intpkey-16.1 { PRAGMA table_info=t16a; } {0 id INTEGER 0 {} 1 1 b TEXT 0 {} 0 2 c INT 0 {} 0} | > > > > > | > > > > > > > > > > > > > > > > > > > > > | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | do_execsql_test intpkey-16.0 { CREATE TABLE t16a(id "INTEGER" PRIMARY KEY AUTOINCREMENT, b [TEXT], c `INT`); } {} do_execsql_test intpkey-16.1 { PRAGMA table_info=t16a; } {0 id INTEGER 0 {} 1 1 b TEXT 0 {} 0 2 c INT 0 {} 0} # 2016-05-06 ticket https://www.sqlite.org/src/tktview/16c9801ceba4923939085 # When the schema contains an index on the IPK and no other index # and a WHERE clause on a delete uses an OR where both sides referencing # the IPK, then it is possible that the OP_Delete will fail because there # deferred seek of the OP_Seek is not resolved prior to reaching the OP_Delete. # do_execsql_test intpkey-17.0 { CREATE TABLE t17(x INTEGER PRIMARY KEY, y TEXT); INSERT INTO t17(x,y) VALUES(123,'elephant'),(248,'giraffe'); CREATE INDEX t17x ON t17(x); DELETE FROM t17 WHERE x=99 OR x<130; SELECT * FROM t17; } {248 giraffe} do_execsql_test intpkey-17.1 { DROP INDEX t17x; DELETE FROM t17; INSERT INTO t17(x,y) VALUES(123,'elephant'),(248,'giraffe'); CREATE UNIQUE INDEX t17x ON t17(abs(x)); DELETE FROM t17 WHERE abs(x) IS NULL OR abs(x)<130; SELECT * FROM t17; } {248 giraffe} do_execsql_test intpkey-17.2 { DELETE FROM t17; INSERT INTO t17(x,y) VALUES(123,'elephant'),(248,'giraffe'); UPDATE t17 SET y='ostrich' WHERE abs(x)=248; SELECT * FROM t17 ORDER BY +x; } {123 elephant 248 ostrich} finish_test |
Changes to test/json101.test.
︙ | ︙ | |||
351 352 353 354 355 356 357 358 359 360 | INSERT INTO t8(a) VALUES('abc' || char(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35) || 'xyz'); UPDATE t8 SET b=json_array(a); SELECT b FROM t8; } {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}} do_execsql_test json-8.2 { SELECT a=json_extract(b,'$[0]') FROM t8; } {1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | INSERT INTO t8(a) VALUES('abc' || char(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35) || 'xyz'); UPDATE t8 SET b=json_array(a); SELECT b FROM t8; } {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}} do_execsql_test json-8.2 { SELECT a=json_extract(b,'$[0]') FROM t8; } {1} # The json_quote() function transforms an SQL value into a JSON value. # String values are quoted and interior quotes are escaped. NULL values # are rendered as the unquoted string "null". # do_execsql_test json-9.1 { SELECT json_quote('abc"xyz'); } {{"abc\"xyz"}} do_execsql_test json-9.2 { SELECT json_quote(3.14159); } {3.14159} do_execsql_test json-9.3 { SELECT json_quote(12345); } {12345} do_execsql_test json-9.4 { SELECT json_quote(null); } {"null"} do_catchsql_test json-9.5 { SELECT json_quote(x'30313233'); } {1 {JSON cannot hold BLOB values}} do_catchsql_test json-9.6 { SELECT json_quote(123,456) } {1 {wrong number of arguments to function json_quote()}} do_catchsql_test json-9.7 { SELECT json_quote() } {1 {wrong number of arguments to function json_quote()}} finish_test |
Added test/limit2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | # 2016-05-20 # # 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. The # focus of this file is testing the LIMIT in combination with ORDER BY # and in particular, the optimizations in the inner loop that cause an # early exit of the inner loop when the LIMIT is reached and the inner # loop is emitting rows in ORDER BY order. set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test limit2-100 { CREATE TABLE t1(a,b); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t1(a,b) SELECT 1, (x*17)%1000 + 1000 FROM c; INSERT INTO t1(a,b) VALUES(2,2),(3,1006),(4,4),(5,9999); CREATE INDEX t1ab ON t1(a,b); } set sqlite_search_count 0 do_execsql_test limit2-100.1 { SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY b LIMIT 5; } {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |} set fast_count $sqlite_search_count set sqlite_search_count 0 do_execsql_test limit2-100.2 { SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY +b LIMIT 5; } {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |} do_test limit2-100.3 { set slow_count $sqlite_search_count expr {$fast_count < 0.02*$slow_count} } {1} do_execsql_test limit2-110 { CREATE TABLE t2(x,y); INSERT INTO t2(x,y) VALUES('a',1),('a',2),('a',3),('a',4); INSERT INTO t2(x,y) VALUES('b',1),('c',2),('d',3),('e',4); CREATE INDEX t2xy ON t2(x,y); } set sqlite_search_count 0 do_execsql_test limit2-110.1 { SELECT a, b, '|' FROM t2, t1 WHERE t2.x='a' AND t1.a=t2.y ORDER BY t1.b LIMIT 5; } {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |} set fast_count $sqlite_search_count set sqlite_search_count 0 do_execsql_test limit2-110.2 { SELECT a, b, '|' FROM t2, t1 WHERE t2.x='a' AND t1.a=t2.y ORDER BY +t1.b LIMIT 5; } {2 2 | 4 4 | 1 1000 | 1 1001 | 1 1002 |} set slow_count $sqlite_search_count do_test limit2-110.3 { expr {$fast_count < 0.02*$slow_count} } {1} do_execsql_test limit2-120 { DROP INDEX t1ab; CREATE INDEX t1ab ON t1(a,b DESC); } set sqlite_search_count 0 do_execsql_test limit2-120.1 { SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY b DESC LIMIT 5; } {5 9999 | 1 1999 | 1 1998 | 1 1997 | 1 1996 |} set fast_count $sqlite_search_count set sqlite_search_count 0 do_execsql_test limit2-120.2 { SELECT a, b, '|' FROM t1 WHERE a IN (2,4,5,3,1) ORDER BY +b DESC LIMIT 5; } {5 9999 | 1 1999 | 1 1998 | 1 1997 | 1 1996 |} do_test limit2-120.3 { set slow_count $sqlite_search_count expr {$fast_count < 0.02*$slow_count} } {1} # Bug report against the new ORDER BY LIMIT optimization just prior to # release. (Unreleased so there is no ticket). # # Make sure the optimization is not applied if the inner loop can only # provide a single row of output. # do_execsql_test limit2-200 { CREATE TABLE t200(a, b); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t200(a,b) SELECT x, x FROM c; CREATE TABLE t201(x INTEGER PRIMARY KEY, y); INSERT INTO t201(x,y) VALUES(2,12345); SELECT *, '|' FROM t200, t201 WHERE x=b ORDER BY y LIMIT 3; } {2 2 2 12345 |} do_execsql_test limit2-210 { SELECT *, '|' FROM t200 LEFT JOIN t201 ON x=b ORDER BY y LIMIT 3; } {1 1 {} {} | 3 3 {} {} | 4 4 {} {} |} finish_test |
Changes to test/loadext.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 | # test file. # if {![file exists $testextension]} { set srcdir [file dir $testdir]/src set testextsrc $srcdir/test_loadext.c set cmdline [concat exec gcc $gcc_shared] | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | # test file. # if {![file exists $testextension]} { set srcdir [file dir $testdir]/src set testextsrc $srcdir/test_loadext.c set cmdline [concat exec gcc $gcc_shared] lappend cmdline -Wall -I$srcdir -I. -I.. -g $testextsrc -o $testextension if {[catch $cmdline msg]} { puts "Skipping loadext tests: Test extension not built..." puts $msg finish_test return } |
︙ | ︙ |
Changes to test/minmax.test.
︙ | ︙ | |||
623 624 625 626 627 628 629 630 631 632 | } {5} do_test_13_noopt 13.7 { SELECT min(b), count(b) FROM t1 WHERE a='a'; } { SELECT min(c), count(c) FROM t1 WHERE a='a'; } {1 5} finish_test | > > > > > > > > > > > > > > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | } {5} do_test_13_noopt 13.7 { SELECT min(b), count(b) FROM t1 WHERE a='a'; } { SELECT min(c), count(c) FROM t1 WHERE a='a'; } {1 5} # 2016-07-26. https://www.sqlite.org/src/info/a0bac8b3c3d1bb75 # Incorrect result on a min() query after a CREATE INDEX. # do_execsql_test 14.1 { CREATE TABLE t14(a INTEGER, b INTEGER); INSERT INTO t14(a,b) VALUES(100,2),(200,2),(300,2),(400,1),(500,2); SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} do_execsql_test 14.2 { CREATE INDEX t14ba ON t14(b,a); SELECT min(a) FROM t14 WHERE b='2' AND a>'50'; } {100} finish_test |
Changes to test/misc5.test.
︙ | ︙ | |||
566 567 568 569 570 571 572 573 574 575 576 577 578 579 | LIMIT (SELECT lmt FROM logs_base) ; } } {1 {no such table: logs_base}} } # Overflow the lemon parser stack by providing an overly complex # expression. Make sure that the overflow is detected and reported. # do_test misc5-7.1 { execsql {CREATE TABLE t1(x)} set sql "INSERT INTO t1 VALUES(" set tail "" for {set i 0} {$i<200} {incr i} { append sql "(1+" | > > | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | LIMIT (SELECT lmt FROM logs_base) ; } } {1 {no such table: logs_base}} } # Overflow the lemon parser stack by providing an overly complex # expression. Make sure that the overflow is detected and reported. # # This test fails when building with -DYYSTACKDEPTH=0 # do_test misc5-7.1 { execsql {CREATE TABLE t1(x)} set sql "INSERT INTO t1 VALUES(" set tail "" for {set i 0} {$i<200} {incr i} { append sql "(1+" |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
742 743 744 745 746 747 748 749 750 751 752 753 754 755 | # Exclude stmt.test, which expects sub-journals to use temporary files. stmt.test symlink.test zerodamage.test # WAL mode is different. wal* tkt-2d1a5c67d.test backcompat.test e_wal* rowallock.test }] ifcapable mem3 { test_suite "memsys3" -description { Run tests using the allocator in mem3.c. } -files [test_set $::allquicktests -exclude { autovacuum.test delete3.test manydb.test | > > > > > | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 | # Exclude stmt.test, which expects sub-journals to use temporary files. stmt.test symlink.test zerodamage.test # WAL mode is different. wal* tkt-2d1a5c67d.test backcompat.test e_wal* rowallock.test # This test does not work as the "PRAGMA journal_mode = memory" # statement switches the database out of wal mode at inopportune # times. snapshot_fault.test }] ifcapable mem3 { test_suite "memsys3" -description { Run tests using the allocator in mem3.c. } -files [test_set $::allquicktests -exclude { autovacuum.test delete3.test manydb.test |
︙ | ︙ |
Changes to test/releasetest.tcl.
︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | return $out } array set ::Configs [strip_comments { "Default" { -O2 --disable-amalgamation --disable-shared } "Sanitize" { CC=clang -fsanitize=undefined -DSQLITE_ENABLE_STAT4 } "Have-Not" { # The "Have-Not" configuration sets all possible -UHAVE_feature options # in order to verify that the code works even on platforms that lack # these support services. -DHAVE_FDATASYNC=0 -DHAVE_GMTIME_R=0 | > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | return $out } array set ::Configs [strip_comments { "Default" { -O2 --disable-amalgamation --disable-shared --enable-session } "Sanitize" { CC=clang -fsanitize=undefined -DSQLITE_ENABLE_STAT4 --enable-session } "Stdcall" { -DUSE_STDCALL=1 -O2 } "Have-Not" { # The "Have-Not" configuration sets all possible -UHAVE_feature options # in order to verify that the code works even on platforms that lack # these support services. -DHAVE_FDATASYNC=0 -DHAVE_GMTIME_R=0 |
︙ | ︙ | |||
102 103 104 105 106 107 108 | -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_STMT_SCANSTATUS | | < > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_ATOMIC_WRITE=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_STMT_SCANSTATUS --enable-json1 --enable-fts5 --enable-session } "Debug-One" { --disable-shared -O2 -DSQLITE_DEBUG=1 -DSQLITE_MEMDEBUG=1 -DSQLITE_MUTEX_NOOP=1 -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_MEMSYS5=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_MAX_ATTACHED=125 } "Fast-One" { -O6 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_RBU -DSQLITE_MAX_ATTACHED=125 -DLONGDOUBLE_TYPE=double --enable-session } "Device-One" { -O2 -DSQLITE_DEBUG=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_DEFAULT_CACHE_SIZE=64 -DSQLITE_DEFAULT_PAGE_SIZE=1024 |
︙ | ︙ | |||
164 165 166 167 168 169 170 | -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_MAX_COMPOUND_SELECT=50 -DSQLITE_MAX_PAGE_SIZE=32768 -DSQLITE_OMIT_TRACE=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_THREADSAFE=2 | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_MAX_COMPOUND_SELECT=50 -DSQLITE_MAX_PAGE_SIZE=32768 -DSQLITE_OMIT_TRACE=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_THREADSAFE=2 --enable-json1 --enable-fts5 --enable-session } "Locking-Style" { -O2 -DSQLITE_ENABLE_LOCKING_STYLE=1 } "Apple" { -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658 |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | } Darwin-x86_64 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } "Windows NT-intel" { "Have-Not" test "Default" "mptest fulltestonly" } "Windows NT-amd64" { "Have-Not" test "Default" "mptest fulltestonly" } # The Failure-Detection platform runs various tests that deliberately # fail. This is used as a test of this script to verify that this script # correctly identifies failures. | > > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | } Darwin-x86_64 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } "Windows NT-intel" { "Stdcall" test "Have-Not" test "Default" "mptest fulltestonly" } "Windows NT-amd64" { "Stdcall" test "Have-Not" test "Default" "mptest fulltestonly" } # The Failure-Detection platform runs various tests that deliberately # fail. This is used as a test of this script to verify that this script # correctly identifies failures. |
︙ | ︙ | |||
719 720 721 722 723 724 725 726 727 728 729 730 731 732 | # proc makeCommand { targets makeOpts cflags opts } { set result [list trace_cmd exec] if {$::MSVC} { set nmakeDir [file nativename $::SRCDIR] set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]] lappend result nmake /f $nmakeFile TOP=$nmakeDir } else { lappend result make } foreach makeOpt $makeOpts { lappend result $makeOpt } lappend result clean | > > > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | # proc makeCommand { targets makeOpts cflags opts } { set result [list trace_cmd exec] if {$::MSVC} { set nmakeDir [file nativename $::SRCDIR] set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]] lappend result nmake /f $nmakeFile TOP=$nmakeDir if {[regexp {USE_STDCALL=1} $cflags]} { lappend result USE_STDCALL=1 } } else { lappend result make } foreach makeOpt $makeOpts { lappend result $makeOpt } lappend result clean |
︙ | ︙ |
Changes to test/selectA.test.
︙ | ︙ | |||
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 | } { SELECT * FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY d, t8.a COLLATE NOCASE } do_catchsql_test 5.4 { SELECT * FROM t8 UNION SELECT * FROM t9 ORDER BY a+b COLLATE NOCASE } {1 {1st ORDER BY term does not match any column in the result set}} finish_test | > > > > > > > > > | 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 | } { SELECT * FROM t8 EXCEPT SELECT c, d FROM t9 ORDER BY d, t8.a COLLATE NOCASE } do_catchsql_test 5.4 { SELECT * FROM t8 UNION SELECT * FROM t9 ORDER BY a+b COLLATE NOCASE } {1 {1st ORDER BY term does not match any column in the result set}} do_execsql_test 6.1 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER); CREATE TABLE t2(b TEXT); INSERT INTO t2(b) VALUES('12345'); SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a; } {12345} finish_test |
Changes to test/shell1.test.
︙ | ︙ | |||
866 867 868 869 870 871 872 873 874 875 876 877 878 879 | # command channels opened for it as textual ones), the carriage # return character (and on Windows, the end-of-file character) # cannot be used here. # if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { continue } set hex [format %02X $i] set char [subst \\x$hex]; set oldChar $char set escapes [list] if {$tcl_platform(platform)=="windows"} { # # NOTE: On Windows, we need to escape all the whitespace characters, # the alarm (\a) character, and those with special meaning to | > > | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | # command channels opened for it as textual ones), the carriage # return character (and on Windows, the end-of-file character) # cannot be used here. # if {$i==0x0D || ($tcl_platform(platform)=="windows" && $i==0x1A)} { continue } if {$i>=0xE0 && $tcl_platform(os)=="OpenBSD"} continue if {$i>=0xE0 && $i<=0xEF && $tcl_platform(os)=="Linux"} continue set hex [format %02X $i] set char [subst \\x$hex]; set oldChar $char set escapes [list] if {$tcl_platform(platform)=="windows"} { # # NOTE: On Windows, we need to escape all the whitespace characters, # the alarm (\a) character, and those with special meaning to |
︙ | ︙ | |||
910 911 912 913 914 915 916 917 918 919 920 921 922 923 | } else { set got <empty> } error "failed with byte $hex mismatch, got $got" } } } {} # The string used here is the word "test" in Chinese. # In UTF-8, it is encoded as: \xE6\xB5\x8B\xE8\xAF\x95 set test \u6D4B\u8BD5 do_test shell1-6.0 { set fileName $test; append fileName .db | > > > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | } else { set got <empty> } error "failed with byte $hex mismatch, got $got" } } } {} # These test cases do not work on MinGW if 0 { # The string used here is the word "test" in Chinese. # In UTF-8, it is encoded as: \xE6\xB5\x8B\xE8\xAF\x95 set test \u6D4B\u8BD5 do_test shell1-6.0 { set fileName $test; append fileName .db |
︙ | ︙ | |||
947 948 949 950 951 952 953 | error "failed with error: $res" } if {$res ne "CREATE TABLE ${test}(x);"} { error "failed with mismatch: $res" } forcedelete test3.db } {} | | > | 952 953 954 955 956 957 958 959 960 961 | error "failed with error: $res" } if {$res ne "CREATE TABLE ${test}(x);"} { error "failed with mismatch: $res" } forcedelete test3.db } {} } finish_test |
Changes to test/skipscan1.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 | # index unconstrainted. # do_execsql_test skipscan1-1.2 { SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; } {abc 345 7 8 | def 345 9 10 |} do_execsql_test skipscan1-1.2eqp { EXPLAIN QUERY PLAN | | | | | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | # index unconstrainted. # do_execsql_test skipscan1-1.2 { SELECT a,b,c,d,'|' FROM t1 WHERE b=345 ORDER BY a; } {abc 345 7 8 | def 345 9 10 |} do_execsql_test skipscan1-1.2eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t1 WHERE d<>99 AND b=345 ORDER BY a; } {/* USING INDEX t1abc (ANY(a) AND b=?)*/} do_execsql_test skipscan1-1.2sort { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t1 WHERE d<>99 AND b=345 ORDER BY a; } {~/*ORDER BY*/} do_execsql_test skipscan1-1.3 { SELECT a,b,c,d,'|' FROM t1 WHERE d<>99 AND b=345 ORDER BY a DESC; } {def 345 9 10 | abc 345 7 8 |} do_execsql_test skipscan1-1.3eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t1 WHERE d<>99 AND b=345 ORDER BY a DESC; } {/* USING INDEX t1abc (ANY(a) AND b=?)*/} do_execsql_test skipscan1-1.3sort { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t1 WHERE d<>99 AND b=345 ORDER BY a DESC; } {~/*ORDER BY*/} do_execsql_test skipscan1-1.4 { SELECT a,b,c,d,'|' FROM t1 WHERE c=6 ORDER BY a, b, c; } {abc 234 6 7 | bcd 100 6 11 |} do_execsql_test skipscan1-1.4eqp { EXPLAIN QUERY PLAN |
︙ | ︙ | |||
146 147 148 149 150 151 152 | ** columns are not selective. */ ANALYZE; UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL; ANALYZE sqlite_master; } {} do_execsql_test skipscan1-2.2 { | | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | ** columns are not selective. */ ANALYZE; UPDATE sqlite_stat1 SET stat='10000 5000 2000 10' WHERE idx NOT NULL; ANALYZE sqlite_master; } {} do_execsql_test skipscan1-2.2 { SELECT a,b,c,d,'|' FROM t2 WHERE d<>99 AND b=345 ORDER BY a; } {abc 345 7 8 | def 345 9 10 |} do_execsql_test skipscan1-2.2eqp { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t2 WHERE d<>99 AND b=345 ORDER BY a; } {/* USING INDEX sqlite_autoindex_t2_1 (ANY(a) AND b=?)*/} do_execsql_test skipscan1-2.2sort { EXPLAIN QUERY PLAN SELECT a,b,c,d,'|' FROM t2 WHERE d<>99 AND b=345 ORDER BY a; } {~/*ORDER BY*/} do_execsql_test skipscan1-3.1 { CREATE TABLE t3(a TEXT, b INT, c INT, d INT, PRIMARY KEY(a,b,c)) WITHOUT ROWID; INSERT INTO t3 SELECT * FROM t1; |
︙ | ︙ |
Changes to test/snapshot.test.
︙ | ︙ | |||
348 349 350 351 352 353 354 | sqlite3 db2 test.db db2 eval "PRAGMA application_id" db2 eval "BEGIN" sqlite3_snapshot_open db2 main $::snapshot db2 eval { SELECT * FROM x1 } } {z zz zzz} | < < < < | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | sqlite3 db2 test.db db2 eval "PRAGMA application_id" db2 eval "BEGIN" sqlite3_snapshot_open db2 main $::snapshot db2 eval { SELECT * FROM x1 } } {z zz zzz} do_test 6.5 { db2 close sqlite3 db2 test.db db2 eval "BEGIN" list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg } {1 SQLITE_ERROR} |
︙ | ︙ |
Changes to test/sort5.test.
︙ | ︙ | |||
74 75 76 77 78 79 80 | sqlite3 db test.db -vfs tvfs execsql { CREATE TABLE t1(x) } # Each iteration of the following loop attempts to sort 10001 records # each a bit over 100 bytes in size. In total a little more than 1MiB # of data. # | < < < > > > > > > < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | sqlite3 db test.db -vfs tvfs execsql { CREATE TABLE t1(x) } # Each iteration of the following loop attempts to sort 10001 records # each a bit over 100 bytes in size. In total a little more than 1MiB # of data. # foreach {tn pgsz cachesz bTemp} { 1 4096 1000 0 2 1024 1000 1 3 4096 -1000 1 4 1024 -1000 1 5 4096 -9000 0 6 1024 -9000 0 } { do_execsql_test 2.$tn.0 " PRAGMA page_size = $pgsz; VACUUM; PRAGMA cache_size = $cachesz; " if {[db one {PRAGMA page_size}]!=$pgsz} { # SEE is not able to change page sizes and that messes up the # results that follow. continue } do_test 2.$tn.1 { set ::iTemp 0 catch { array unset F } execsql { WITH x(i, j) AS ( SELECT 1, randomblob(100) UNION ALL SELECT i+1, randomblob(100) FROM x WHERE i<10000 ) SELECT * FROM x ORDER BY j; } expr {[array names F]!=""} } $bTemp } finish_test |
Changes to test/speedtest1.c.
︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | break; } } } fclose(in); } #endif int main(int argc, char **argv){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ | > > > > | 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 | break; } } } fclose(in); } #endif #if SQLITE_VERSION_NUMBER<3006018 # define sqlite3_sourceid(X) "(before 3.6.18)" #endif int main(int argc, char **argv){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ |
︙ | ︙ |
Changes to test/stat.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | set ::asc 1 proc a_string {n} { string range [string repeat [incr ::asc]. $n] 1 $n } db func a_string a_string register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; SELECT * FROM stat; } {} if {[wal_is_capable]} { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat; | > > > > > > > > > > > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | set ::asc 1 proc a_string {n} { string range [string repeat [incr ::asc]. $n] 1 $n } db func a_string a_string register_dbstat_vtab db do_execsql_test stat-0.0 { PRAGMA table_info(dbstat); } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} # Attempts to drop an eponymous virtual table are a no-op. do_execsql_test stat-0.1 { DROP TABLE dbstat; PRAGMA table_info=dbstat; } {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/} db close forcedelete test.db sqlite3 db test.db db func a_string a_string register_dbstat_vtab db do_execsql_test stat-0.2 { PRAGMA auto_vacuum = OFF; CREATE VIRTUAL TABLE temp.stat USING dbstat; SELECT * FROM stat; } {} if {[wal_is_capable]} { do_execsql_test stat-0.1 { PRAGMA journal_mode = WAL; PRAGMA journal_mode = delete; SELECT name, path, pageno, pagetype, ncell, payload, unused, mx_payload FROM stat; |
︙ | ︙ |
Changes to test/tabfunc01.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set testprefix tabfunc01 ifcapable !vtab { finish_test return } load_static_extension db series do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} do_execsql_test tabfunc01-1.2 { SELECT *, '|' FROM generate_series LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} | > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | set testprefix tabfunc01 ifcapable !vtab { finish_test return } load_static_extension db series load_static_extension db carray do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} do_execsql_test tabfunc01-1.2 { SELECT *, '|' FROM generate_series LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} |
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 | # each step of output. At one point, the IN operator could not be used # by virtual tables unless omit was set. # do_execsql_test tabfunc01-500 { SELECT * FROM generate_series WHERE start IN (1,7) AND stop=20 AND step=10 ORDER BY +1; } {1 7 11 17} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | # each step of output. At one point, the IN operator could not be used # by virtual tables unless omit was set. # do_execsql_test tabfunc01-500 { SELECT * FROM generate_series WHERE start IN (1,7) AND stop=20 AND step=10 ORDER BY +1; } {1 7 11 17} # Table-valued functions on the RHS of an IN operator # do_execsql_test tabfunc01-600 { CREATE TABLE t600(a INTEGER PRIMARY KEY, b TEXT); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t600(a,b) SELECT x, printf('(%03d)',x) FROM c; SELECT b FROM t600 WHERE a IN generate_series(2,52,10); } {(002) (012) (022) (032) (042) (052)} do_test tabfunc01-700 { set PTR [intarray_addr 5 7 13 17 23] db eval { SELECT b FROM t600, carray($PTR,5) WHERE a=value; } } {(005) (007) (013) (017) (023)} do_test tabfunc01-701 { db eval { SELECT b FROM t600 WHERE a IN carray($PTR,5,'int32'); } } {(005) (007) (013) (017) (023)} do_test tabfunc01-702 { db eval { SELECT b FROM t600 WHERE a IN carray($PTR,4,'int32'); } } {(005) (007) (013) (017)} do_catchsql_test tabfunc01-710 { SELECT b FROM t600 WHERE a IN carray($PTR,5,'int33'); } {1 {unknown datatype: 'int33'}} do_test tabfunc01-720 { set PTR [int64array_addr 5 7 13 17 23] db eval { SELECT b FROM t600, carray($PTR,5,'int64') WHERE a=value; } } {(005) (007) (013) (017) (023)} do_test tabfunc01-730 { set PTR [doublearray_addr 5.0 7.0 13.0 17.0 23.0] db eval { SELECT b FROM t600, carray($PTR,5,'double') WHERE a=value; } } {(005) (007) (013) (017) (023)} do_test tabfunc01-740 { set PTR [textarray_addr 5 7 13 17 23] db eval { SELECT b FROM t600, carray($PTR,5,'char*') WHERE a=value; } } {(005) (007) (013) (017) (023)} intarray_addr int64array_addr doublearray_addr textarray_addr finish_test |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | set v [catch {sqlite3 bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | set v [catch {sqlite3 bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg } {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}} do_test tcl-1.2.1 { set v [catch {db cache bogus} msg] lappend v $msg } {1 {bad option "bogus": must be flush or size}} do_test tcl-1.2.2 { set v [catch {db cache} msg] lappend v $msg |
︙ | ︙ | |||
630 631 632 633 634 635 636 637 | do_execsql_test tcl-14.1 { CREATE TABLE t6(x); INSERT INTO t6 VALUES(1); } do_test tcl-14.2 { db one {SELECT x FROM t6 WHERE xCall()!='value'} } {} | > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | do_execsql_test tcl-14.1 { CREATE TABLE t6(x); INSERT INTO t6 VALUES(1); } do_test tcl-14.2 { db one {SELECT x FROM t6 WHERE xCall()!='value'} } {} # Verify that the "exists" and "onecolumn" methods work when # a "profile" is registered. # catch {db close} sqlite3 db :memory: proc noop-profile {args} { return } do_test tcl-15.0 { db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);} db onecolumn {SELECT a FROM t1 WHERE a>2} } {3} do_test tcl-15.1 { db exists {SELECT a FROM t1 WHERE a>2} } {1} do_test tcl-15.2 { db exists {SELECT a FROM t1 WHERE a>3} } {0} db profile noop-profile do_test tcl-15.3 { db onecolumn {SELECT a FROM t1 WHERE a>2} } {3} do_test tcl-15.4 { db exists {SELECT a FROM t1 WHERE a>2} } {1} do_test tcl-15.5 { db exists {SELECT a FROM t1 WHERE a>3} } {0} finish_test |
Added test/tempdb2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | # 2016 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. # #*********************************************************************** set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tempdb2 db close sqlite3 db "" proc int2str {i} { string range [string repeat "$i." 450] 0 899 } db func int2str int2str #------------------------------------------------------------------------- # # 1.1: Write a big transaction to the db. One so large that it forces # the file to be created and the cache flushed to disk on COMMIT. # # 1.2: Write a small transaction - one small enough that it remains in # memory on COMMIT. All the pages of table [t1] are now dirty. # # 1.3: Delete the contents of [t1]. This moves all of its leaves to the # free-list and causes the btree layer to call PagerDontWrite() on # each of them. # # Then do a big update on table [t2]. So big that the former leaves # of [t1] are forced out of the cache. Then roll back the transaction. # If the PagerDontWrite() calls are honoured and the data is not written # to disk, the update made in test 1.2 will be lost at this point. Or, if # they are ignored (as they should be for temp databases), the update # will be safely written out to disk before the cache entries are # discarded. # do_execsql_test 1.1 { PRAGMA page_size=1024; PRAGMA cache_size=50; BEGIN; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1 VALUES(1, int2str(1)); INSERT INTO t1 VALUES(2, int2str(1)); INSERT INTO t1 VALUES(3, int2str(1)); CREATE TABLE t2(a INTEGER PRIMARY KEY, b); WITH c(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100 ) INSERT INTO t2 SELECT x, int2str(x) FROM c; COMMIT; PRAGMA lock_status; } {main unlocked temp closed} do_execsql_test 1.2 { UPDATE t1 SET b=int2str(2); SELECT b=int2str(2) FROM t1 } {1 1 1} do_execsql_test 1.3 { BEGIN; DELETE FROM t1; UPDATE t2 SET b=int2str(a+1); ROLLBACK; } do_execsql_test 1.4 { SELECT b=int2str(2) FROM t1 } {1 1 1} finish_test |
Changes to test/temptable2.test.
︙ | ︙ | |||
226 227 228 229 230 231 232 | # reset_db do_execsql_test 8.1 { PRAGMA auto_vacuum = OFF; CREATE TABLE t2(a, b); CREATE INDEX i2 ON t2(a, b); WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<20 ) | | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | # reset_db do_execsql_test 8.1 { PRAGMA auto_vacuum = OFF; CREATE TABLE t2(a, b); CREATE INDEX i2 ON t2(a, b); WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<20 ) INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM x ORDER BY 1, 2; PRAGMA page_count; } {13} do_test 8.2 { sqlite3 tmp "" execsql { PRAGMA auto_vacuum = OFF; PRAGMA page_size = 8192; CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<100 ) INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x ORDER BY 1, 2; PRAGMA page_count; } tmp } {10} do_test 8.3 { sqlite3_backup B tmp main db main B step 5 |
︙ | ︙ | |||
339 340 341 342 343 344 345 | BEGIN; WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<500 ) INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x; COMMIT; INSERT INTO t2 VALUES(3, 4); } | > | | | | > < | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | BEGIN; WITH x(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<500 ) INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x; COMMIT; INSERT INTO t2 VALUES(3, 4); } ifcapable mmap { if {[permutation]!="journaltest"} { # The journaltest permutation does not support mmap, so this part of # the test is omitted. do_execsql_test 10.2 { PRAGMA mmap_size = 512000 } 512000 } } do_execsql_test 10.3 { SELECT * FROM t2 } {1 2 3 4} do_execsql_test 10.4 { PRAGMA integrity_check } ok finish_test |
Added test/temptable3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # 2016-05-10 # # 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. # #*********************************************************************** set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix temptable3 db close sqlite3 db {} do_execsql_test 1.1 { PRAGMA cache_size = 1; PRAGMA page_size = 1024; PRAGMA auto_vacuum = 2; CREATE TABLE t1(x); INSERT INTO t1 VALUES( randomblob(800) ); INSERT INTO t1 VALUES( randomblob(800) ); CREATE TABLE t2(x); PRAGMA integrity_check; } {ok} db close sqlite3 db {} do_execsql_test 1.2 { PRAGMA cache_size = 1; PRAGMA auto_vacuum = 2; CREATE TABLE t1(x); CREATE TABLE t2(x UNIQUE); INSERT INTO t2 VALUES(1), (2), (3); DROP TABLE t1; PRAGMA integrity_check; } {ok} finish_test |
Changes to test/tester.tcl.
︙ | ︙ | |||
369 370 371 372 373 374 375 376 377 378 379 380 381 382 | # This command should be called after loading tester.tcl from within # all test scripts that are incompatible with encryption codecs. # proc do_not_use_codec {} { set ::do_not_use_codec 1 reset_db } # Return true if the "reserved_bytes" integer on database files is non-zero. # proc nonzero_reserved_bytes {} { return [sqlite3 -has-codec] } | > | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | # This command should be called after loading tester.tcl from within # all test scripts that are incompatible with encryption codecs. # proc do_not_use_codec {} { set ::do_not_use_codec 1 reset_db } unset -nocomplain do_not_use_codec # Return true if the "reserved_bytes" integer on database files is non-zero. # proc nonzero_reserved_bytes {} { return [sqlite3 -has-codec] } |
︙ | ︙ | |||
517 518 519 520 521 522 523 | } {^-q$} { set cmdlinearg(output) test-out.txt set cmdlinearg(verbose) 2 } default { | > > > | > | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 | } {^-q$} { set cmdlinearg(output) test-out.txt set cmdlinearg(verbose) 2 } default { if {[file tail $a]==$a} { lappend leftover $a } else { lappend leftover [file normalize $a] } } } } set testdir [file normalize $testdir] set cmdlinearg(TESTFIXTURE_HOME) [pwd] set cmdlinearg(INFO_SCRIPT) [file normalize [info script]] set argv0 [file normalize $argv0] |
︙ | ︙ | |||
712 713 714 715 716 717 718 719 720 721 722 723 724 725 | } rename puts puts_original proc puts {args} { uplevel puts_override $args } # Invoke the do_test procedure to run a single test # proc do_test {name cmd expected} { global argv cmdlinearg fix_testname name sqlite3_memdebug_settitle $name | > > > > > > > > > > > | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | } rename puts puts_original proc puts {args} { uplevel puts_override $args } # Invoke the do_test procedure to run a single test # # The $expected parameter is the expected result. The result is the return # value from the last TCL command in $cmd. # # Normally, $expected must match exactly. But if $expected is of the form # "/regexp/" then regular expression matching is used. If $expected is # "~/regexp/" then the regular expression must NOT match. If $expected is # of the form "#/value-list/" then each term in value-list must be numeric # and must approximately match the corresponding numeric term in $result. # Values must match within 10%. Or if the $expected term is A..B then the # $result term must be in between A and B. # proc do_test {name cmd expected} { global argv cmdlinearg fix_testname name sqlite3_memdebug_settitle $name |
︙ | ︙ | |||
745 746 747 748 749 750 751 | if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {[catch {uplevel #0 "$cmd;\n"} result]} { output2_if_no_verbose -nonewline $name... output2 "\nError: $result" fail_test $name } else { | | > > > > > > > > > > > > > > > | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {[catch {uplevel #0 "$cmd;\n"} result]} { output2_if_no_verbose -nonewline $name... output2 "\nError: $result" fail_test $name } else { if {[regexp {^[~#]?/.*/$} $expected]} { # "expected" is of the form "/PATTERN/" then the result if correct if # regular expression PATTERN matches the result. "~/PATTERN/" means # the regular expression must not match. if {[string index $expected 0]=="~"} { set re [string range $expected 2 end-1] if {[string index $re 0]=="*"} { # If the regular expression begins with * then treat it as a glob instead set ok [string match $re $result] } else { set re [string map {# {[-0-9.]+}} $re] set ok [regexp $re $result] } set ok [expr {!$ok}] } elseif {[string index $expected 0]=="#"} { # Numeric range value comparison. Each term of the $result is matched # against one term of $expect. Both $result and $expected terms must be # numeric. The values must match within 10%. Or if $expected is of the # form A..B then the $result term must be between A and B. set e2 [string range $expected 2 end-1] foreach i $result j $e2 { if {[regexp {^(-?\d+)\.\.(-?\d)$} $j all A B]} { set ok [expr {$i+0>=$A && $i+0<=$B}] } else { set ok [expr {$i+0>=0.9*$j && $i+0<=1.1*$j}] } if {!$ok} break } if {$ok && [llength $result]!=[llength $e2]} {set ok 0} } else { set re [string range $expected 1 end-1] if {[string index $re 0]=="*"} { # If the regular expression begins with * then treat it as a glob instead set ok [string match $re $result] } else { set re [string map {# {[-0-9.]+}} $re] |
︙ | ︙ |
Added test/time-wordcount.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #!/bin/sh # # This script runs the wordcount program in different ways and generates # an output useful for performance comparisons. # # Select the source text to be analyzed. # if test "x$1" = "x"; then echo "Usage: $0 FILENAME [ARGS...]"; exit 1; fi # Do test runs # rm -f wcdb1.db ./wordcount --tag A: --timer --summary wcdb1.db $* --insert rm -f wcdb2.db ./wordcount --tag B: --timer --summary wcdb2.db $* --insert --without-rowid rm -f wcdb1.db ./wordcount --tag C: --timer --summary wcdb1.db $* --replace rm -f wcdb2.db ./wordcount --tag D: --timer --summary wcdb2.db $* --replace --without-rowid rm -f wcdb1.db ./wordcount --tag E: --timer --summary wcdb1.db $* --select rm -f wcdb2.db ./wordcount --tag F: --timer --summary wcdb2.db $* --select --without-rowid ./wordcount --tag G: --timer --summary wcdb1.db $* --query ./wordcount --tag H: --timer --summary wcdb1.db $* --query --without-rowid ./wordcount --tag I: --timer --summary wcdb1.db $* --delete ./wordcount --tag J: --timer --summary wcdb2.db $* --delete --without-rowid # Clean up temporary files created. # rm -f wcdb1.db wcdb2.db |
Added test/trace3.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | # 2016 July 14 # # 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. The focus of # this test file is the "sqlite3_trace_v2()" and "sqlite3_expanded_sql()" # APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !trace { finish_test ; return } set ::testprefix trace3 proc trace_v2_error { args } { lappend ::stmtlist(error) [string trim $args] error "trace error"; # this will be ignored. } proc trace_v2_record { args } { lappend ::stmtlist(record) [string trim $args] } proc trace_v2_nop { args } {}; # do nothing. do_test trace3-1.0 { execsql { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,NULL); INSERT INTO t1 VALUES(2,-1); INSERT INTO t1 VALUES(3,0); INSERT INTO t1 VALUES(4,1); INSERT INTO t1 VALUES(5,-2147483648); INSERT INTO t1 VALUES(6,2147483647); INSERT INTO t1 VALUES(7,-9223372036854775808); INSERT INTO t1 VALUES(8,9223372036854775807); INSERT INTO t1 VALUES(9,-1.0); INSERT INTO t1 VALUES(10,0.0); INSERT INTO t1 VALUES(11,1.0); INSERT INTO t1 VALUES(12,''); INSERT INTO t1 VALUES(13,'1'); INSERT INTO t1 VALUES(14,'one'); INSERT INTO t1 VALUES(15,x'abcd0123'); INSERT INTO t1 VALUES(16,x'4567cdef'); } } {} do_test trace3-1.1 { set rc [catch {db trace_v2 1 2 3} msg] lappend rc $msg } {1 {wrong # args: should be "db trace_v2 ?CALLBACK? ?MASK?"}} do_test trace3-1.2 { set rc [catch {db trace_v2 1 bad} msg] lappend rc $msg } {1 {bad trace type "bad": must be statement, profile, row, or close}} do_test trace3-2.1 { db trace_v2 trace_v2_nop db trace_v2 } {trace_v2_nop} do_test trace3-3.1 { unset -nocomplain ::stmtlist db trace_v2 trace_v2_nop execsql { SELECT a, b FROM t1 ORDER BY a; } array get ::stmtlist } {} do_test trace3-3.2 { set ::stmtlist(error) {} db trace_v2 trace_v2_error execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(error) } {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/} do_test trace3-3.3 { set ::stmtlist(record) {} db trace_v2 trace_v2_record execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/} do_test trace3-3.4 { set ::stmtlist(record) {} db trace_v2 trace_v2_record statement execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/} do_test trace3-3.5 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 1 execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/} do_test trace3-4.1 { set ::stmtlist(record) {} db trace_v2 trace_v2_record profile execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } {/^\{-?\d+ -?\d+\}$/} do_test trace3-4.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 2 execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } {/^\{-?\d+ -?\d+\}$/} do_test trace3-5.1 { set ::stmtlist(record) {} db trace_v2 trace_v2_record row execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } "/^[string trim [string repeat {\d+ } 16]]\$/" do_test trace3-5.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 4 execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } "/^[string trim [string repeat {\d+ } 16]]\$/" do_test trace3-6.1 { set ::stmtlist(record) {} db trace_v2 trace_v2_record {profile row} execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } "/^[string trim [string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/" do_test trace3-6.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record {statement profile row} execsql { SELECT a, b FROM t1 ORDER BY a; } set ::stmtlist(record) } "/^\\\{-?\\d+ \\\{SELECT a, b FROM t1 ORDER BY a;\\\}\\\} [string trim \ [string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/" do_test trace3-7.1 { set DB [sqlite3_connection_pointer db] set STMT [sqlite3_prepare_v2 $DB \ "SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 TAIL] } {/^[0-9A-Fa-f]+$/} do_test trace3-8.1 { list [sqlite3_bind_null $STMT 1] [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = NULL ORDER BY a;}} do_test trace3-8.2 { list [sqlite3_bind_int $STMT 1 123] [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}} do_test trace3-8.3 { list [sqlite3_bind_int64 $STMT 1 123] [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}} do_test trace3-8.4 { list [sqlite3_bind_text $STMT 1 "some string" 11] \ [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 'some string' ORDER BY a;}} do_test trace3-8.5 { list [sqlite3_bind_text $STMT 1 "some 'bad' string" 17] \ [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 'some ''bad'' string' ORDER BY a;}} do_test trace3-8.6 { list [sqlite3_bind_double $STMT 1 123] [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 123.0 ORDER BY a;}} do_test trace3-8.7 { list [sqlite3_bind_text16 $STMT 1 \ [encoding convertto unicode hi\000yall\000] 16] \ [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = 'hi' ORDER BY a;}} do_test trace3-8.8 { list [sqlite3_bind_blob $STMT 1 "\x12\x34\x56" 3] \ [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = x'123456' ORDER BY a;}} do_test trace3-8.9 { list [sqlite3_bind_blob $STMT 1 "\xAB\xCD\xEF" 3] \ [sqlite3_expanded_sql $STMT] } {{} {SELECT a, b FROM t1 WHERE b = x'abcdef' ORDER BY a;}} do_test trace3-9.1 { sqlite3_finalize $STMT } {SQLITE_OK} do_test trace3-10.1 { db trace_v2 "" db trace_v2 } {} do_test trace3-10.2 { unset -nocomplain ::stmtlist db trace_v2 "" {statement profile row} execsql { SELECT a, b FROM t1 ORDER BY a; } array get ::stmtlist } {} do_test trace3-11.1 { set ::stmtlist(record) {} db trace_v2 trace_v2_record close db close set ::stmtlist(record) } {/^-?\d+$/} reset_db do_test trace3-11.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 8 db close set ::stmtlist(record) } {/^-?\d+$/} finish_test |
Added test/vacuummem.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # 2005 February 15 # # 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. The # focus of this file is testing that the VACUUM statement correctly # frees any memory used for a temporary cache. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix vacuummem if {[permutation]=="memsubsys1"} { finish_test return } proc memory_used {} { set stat [sqlite3_status SQLITE_STATUS_MEMORY_USED 1] lindex $stat 1 } do_execsql_test 1.0 { PRAGMA cache_size = -2000; CREATE TABLE t1(a, b, c); WITH r(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM r WHERE i<100000 ) INSERT INTO t1 SELECT randomblob(100),randomblob(100),randomblob(100) FROM r; CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); CREATE INDEX t1c ON t1(c); } set ans "#/[memory_used]/" do_test 1.1 { memory_used } $ans do_execsql_test 1.2 VACUUM do_test 1.3 { memory_used } $ans do_execsql_test 1.4 { SELECT count(*) FROM t1 WHERE +a IS NOT NULL } {100000} do_test 1.5 { memory_used } $ans finish_test |
Added test/walcrash4.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # 2010 May 25 # # 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/wal_common.tcl ifcapable !wal {finish_test ; return } set testprefix walcrash4 do_not_use_codec #------------------------------------------------------------------------- # At one point, if "PRAGMA synchronous=full" is set and the platform # does not support POWERSAFE_OVERWRITE, and the last frame written to # the wal file in a transaction is aligned with a sector boundary, the # xSync() call was omitted. # # The following test verifies that this has been fixed. # do_execsql_test 1.0 { PRAGMA autovacuum = 0; PRAGMA page_size = 1024; PRAGMA journal_mode = wal; PRAGMA main.synchronous = full; } {wal} faultsim_save_and_close # The error message is different on unix and windows # if {$::tcl_platform(platform)=="windows"} { set msg "child killed: unknown signal" } else { set msg "child process exited abnormally" } for {set nExtra 0} {$nExtra < 10} {incr nExtra} { for {set i 0} {$i < 10} {incr i} { do_test 1.nExtra=$nExtra.i=$i.1 { faultsim_restore_and_reopen set fd [open crash.tcl w] puts $fd [subst -nocommands { sqlite3_crash_enable 1 sqlite3_test_control_pending_byte $::sqlite_pending_byte sqlite3 db test.db -vfs crash db eval { PRAGMA main.synchronous=FULL; BEGIN; CREATE TABLE t1(x UNIQUE); } for {set e 2} {[set e] < ($nExtra+2)} {incr e} { db eval "CREATE TABLE t[set e] (x)" } db eval { INSERT INTO t1 VALUES( randomblob(170000) ); COMMIT; } sqlite3_crash_now }] close $fd set r [catch { exec [info nameofexec] crash.tcl >@stdout } msg] list $r $msg } "1 {$msg}" do_execsql_test 1.nExtra=$nExtra.i=$i.2 { SELECT count(*) FROM t1; PRAGMA integrity_check; } {1 ok} } } finish_test |
Changes to test/walprotocol.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 | } [list {0 1 lock exclusive} {1 7 lock exclusive} \ {1 7 unlock exclusive} {0 1 unlock exclusive} \ ] proc lock_callback {method filename handle lock} { if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK } | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | } [list {0 1 lock exclusive} {1 7 lock exclusive} \ {1 7 unlock exclusive} {0 1 unlock exclusive} \ ] proc lock_callback {method filename handle lock} { if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK } puts "# Warning: This next test case causes SQLite to call xSleep(1) 100 times." puts "# Normally this equates to a delay of roughly 10 seconds, but if SQLite" puts "# is built on unix without HAVE_USLEEP defined, it may be much longer." do_test 1.3 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } |
︙ | ︙ |
Changes to test/where3.test.
︙ | ︙ | |||
41 42 43 44 45 46 47 | INSERT INTO t3 VALUES(999,'nine'); CREATE INDEX t3i1 ON t3(x); SELECT * FROM t1, t2 LEFT JOIN t3 ON q=x WHERE p=2 AND a=q; } } {222 two 2 222 {} {}} | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | INSERT INTO t3 VALUES(999,'nine'); CREATE INDEX t3i1 ON t3(x); SELECT * FROM t1, t2 LEFT JOIN t3 ON q=x WHERE p=2 AND a=q; } } {222 two 2 222 {} {}} ifcapable explain&&!cursorhints { do_test where3-1.1.1 { explain_no_trace {SELECT * FROM t1, t2 LEFT JOIN t3 ON q=x WHERE p=2 AND a=q} } [explain_no_trace {SELECT * FROM t1, t2 LEFT JOIN t3 ON x=q WHERE p=2 AND a=q}] } |
︙ | ︙ | |||
82 83 84 85 86 87 88 | SELECT parent1.parent1key, child1.value, child2.value FROM parent1 LEFT OUTER JOIN child1 ON child1.child1key = parent1.child1key INNER JOIN child2 ON child2.child2key = parent1.child2key; } } {1 {Value for C1.1} {Value for C2.1} 2 {} {Value for C2.2} 3 {Value for C1.3} {Value for C2.3}} | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | SELECT parent1.parent1key, child1.value, child2.value FROM parent1 LEFT OUTER JOIN child1 ON child1.child1key = parent1.child1key INNER JOIN child2 ON child2.child2key = parent1.child2key; } } {1 {Value for C1.1} {Value for C2.1} 2 {} {Value for C2.2} 3 {Value for C1.3} {Value for C2.3}} ifcapable explain&&!cursorhints { do_test where3-1.2.1 { explain_no_trace { SELECT parent1.parent1key, child1.value, child2.value FROM parent1 LEFT OUTER JOIN child1 ON child1.child1key = parent1.child1key INNER JOIN child2 ON child2.child2key = parent1.child2key; } |
︙ | ︙ |
Added test/win32nolock.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | # 2016 July 8 # # 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. # if {$tcl_platform(platform)!="windows"} return set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix win32nolock do_test win32nolock-1.0 { sqlite3 db test.db execsql { CREATE TABLE t1(a, b); BEGIN; INSERT INTO t1 VALUES(1, 2); } } {} do_test win32nolock-1.1 { execsql COMMIT catchsql { SELECT * FROM t1 } } {0 {1 2}} db close do_test win32nolock-1.2 { sqlite3 db test.db -vfs win32-none sqlite3 db2 test.db -vfs win32-none execsql { PRAGMA mmap_size = 0 } db2 execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } } {} do_test win32nolock-1.3 { execsql { SELECT * FROM t1 } } {1 2 3 4} do_test win32nolock-1.4 { execsql { SELECT * FROM t1; } db2 } {1 2} do_test win32nolock-1.5 { execsql { BEGIN; SELECT * FROM t1; } db2 } {1 2} do_test win32nolock-1.6 { execsql COMMIT execsql {SELECT * FROM t1} db2 } {1 2} ifcapable memorymanage { do_test win32nolock-1.7 { sqlite3_release_memory 1000000 execsql {SELECT * FROM t1} db2 } {1 2 3 4} } do_test win32nolock-1.8 { db close db2 close } {} do_test win32nolock-1.9.1 { sqlite3 db test.db sqlite3 db2 test.db list [catchsql { BEGIN EXCLUSIVE; } db] \ [catchsql { BEGIN EXCLUSIVE; } db2] } {{0 {}} {1 {database is locked}}} do_test win32nolock-1.9.2 { db close db2 close } {} do_test win32nolock-1.10.1 { sqlite3 db test.db -vfs win32-none sqlite3 db2 test.db list [catchsql { BEGIN EXCLUSIVE; } db] \ [catchsql { BEGIN EXCLUSIVE; } db2] } {{0 {}} {0 {}}} do_test win32nolock-1.10.2 { db close db2 close } {} do_test win32nolock-1.11.1 { sqlite3 db test.db sqlite3 db2 test.db -vfs win32-none list [catchsql { BEGIN EXCLUSIVE; } db] \ [catchsql { BEGIN EXCLUSIVE; } db2] } {{0 {}} {0 {}}} do_test win32nolock-1.11.2 { db close db2 close } {} do_test win32nolock-1.12.1 { sqlite3 db test.db -vfs win32-none sqlite3 db2 test.db -vfs win32-none list [catchsql { BEGIN EXCLUSIVE; } db] \ [catchsql { BEGIN EXCLUSIVE; } db2] } {{0 {}} {0 {}}} do_test win32nolock-1.12.2 { db close db2 close } {} finish_test |
Changes to test/wordcount.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ** --stats Show sqlite3_status() results at the end. ** --pagesize NNN Use a page size of NNN ** --cachesize NNN Use a cache size of NNN ** --commit NNN Commit after every NNN operations ** --nosync Use PRAGMA synchronous=OFF ** --journal MMMM Use PRAGMA journal_mode=MMMM ** --timer Time the operation of this program ** ** Modes: ** ** Insert mode means: ** (1) INSERT OR IGNORE INTO wordcount VALUES($new,1) ** (2) UPDATE wordcount SET cnt=cnt+1 WHERE word=$new -- if (1) is a noop ** | > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** --stats Show sqlite3_status() results at the end. ** --pagesize NNN Use a page size of NNN ** --cachesize NNN Use a cache size of NNN ** --commit NNN Commit after every NNN operations ** --nosync Use PRAGMA synchronous=OFF ** --journal MMMM Use PRAGMA journal_mode=MMMM ** --timer Time the operation of this program ** --tag NAME Tag all output using NAME. Use only stdout. ** ** Modes: ** ** Insert mode means: ** (1) INSERT OR IGNORE INTO wordcount VALUES($new,1) ** (2) UPDATE wordcount SET cnt=cnt+1 WHERE word=$new -- if (1) is a noop ** |
︙ | ︙ | |||
78 79 80 81 82 83 84 85 86 87 88 89 90 91 | #include <string.h> #include <ctype.h> #include <stdlib.h> #include <stdarg.h> #include "sqlite3.h" #define ISALPHA(X) isalpha((unsigned char)(X)) /* Return the current wall-clock time */ static sqlite3_int64 realTime(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); | > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include <string.h> #include <ctype.h> #include <stdlib.h> #include <stdarg.h> #include "sqlite3.h" #define ISALPHA(X) isalpha((unsigned char)(X)) /* Output tag */ char *zTag = "--"; /* Return the current wall-clock time */ static sqlite3_int64 realTime(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); |
︙ | ︙ | |||
111 112 113 114 115 116 117 | printf("%s;\n", zSql); } /* An sqlite3_exec() callback that prints results on standard output, ** each column separated by a single space. */ static int printResult(void *NotUsed, int nArg, char **azArg, char **azNm){ int i; | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | printf("%s;\n", zSql); } /* An sqlite3_exec() callback that prints results on standard output, ** each column separated by a single space. */ static int printResult(void *NotUsed, int nArg, char **azArg, char **azNm){ int i; printf("%s", zTag); for(i=0; i<nArg; i++){ printf(" %s", azArg[i] ? azArg[i] : "(null)"); } printf("\n"); return 0; } |
︙ | ︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 | sqlite3_stmt *pInsert = 0; /* The INSERT statement */ sqlite3_stmt *pUpdate = 0; /* The UPDATE statement */ sqlite3_stmt *pSelect = 0; /* The SELECT statement */ sqlite3_stmt *pDelete = 0; /* The DELETE statement */ FILE *in; /* The open input file */ int rc; /* Return code from an SQLite interface */ int iCur, iHiwtr; /* Statistics values, current and "highwater" */ sqlite3_int64 sumCnt = 0; /* Sum in QUERY mode */ sqlite3_int64 startTime; char zInput[2000]; /* A single line of input */ /* Process command-line arguments */ for(i=1; i<argc; i++){ const char *z = argv[i]; | > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | sqlite3_stmt *pInsert = 0; /* The INSERT statement */ sqlite3_stmt *pUpdate = 0; /* The UPDATE statement */ sqlite3_stmt *pSelect = 0; /* The SELECT statement */ sqlite3_stmt *pDelete = 0; /* The DELETE statement */ FILE *in; /* The open input file */ int rc; /* Return code from an SQLite interface */ int iCur, iHiwtr; /* Statistics values, current and "highwater" */ FILE *pTimer = stderr; /* Output channel for the timer */ sqlite3_int64 sumCnt = 0; /* Sum in QUERY mode */ sqlite3_int64 startTime; char zInput[2000]; /* A single line of input */ /* Process command-line arguments */ for(i=1; i<argc; i++){ const char *z = argv[i]; |
︙ | ︙ | |||
262 263 264 265 266 267 268 269 270 271 272 273 274 275 | i++; pageSize = atoi(argv[i]); }else if( strcmp(z,"commit")==0 && i<argc-1 ){ i++; commitInterval = atoi(argv[i]); }else if( strcmp(z,"journal")==0 && i<argc-1 ){ zJMode = argv[++i]; }else{ fatal_error("unknown option: %s\n", argv[i]); } }else if( zDbName==0 ){ zDbName = argv[i]; }else if( zFileToRead==0 ){ zFileToRead = argv[i]; | > > > | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | i++; pageSize = atoi(argv[i]); }else if( strcmp(z,"commit")==0 && i<argc-1 ){ i++; commitInterval = atoi(argv[i]); }else if( strcmp(z,"journal")==0 && i<argc-1 ){ zJMode = argv[++i]; }else if( strcmp(z,"tag")==0 && i<argc-1 ){ zTag = argv[++i]; pTimer = stdout; }else{ fatal_error("unknown option: %s\n", argv[i]); } }else if( zDbName==0 ){ zDbName = argv[i]; }else if( zFileToRead==0 ){ zFileToRead = argv[i]; |
︙ | ︙ | |||
458 459 460 461 462 463 464 | if( zFileToRead ) fclose(in); sqlite3_finalize(pInsert); sqlite3_finalize(pUpdate); sqlite3_finalize(pSelect); sqlite3_finalize(pDelete); if( iMode==MODE_QUERY ){ | | | | | | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | if( zFileToRead ) fclose(in); sqlite3_finalize(pInsert); sqlite3_finalize(pUpdate); sqlite3_finalize(pSelect); sqlite3_finalize(pDelete); if( iMode==MODE_QUERY ){ printf("%s sum of cnt: %lld\n", zTag, sumCnt); rc = sqlite3_prepare_v2(db,"SELECT sum(cnt*cnt) FROM wordcount", -1, &pSelect, 0); if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){ printf("%s double-check: %lld\n", zTag, sqlite3_column_int64(pSelect, 0)); } sqlite3_finalize(pSelect); } if( showTimer ){ sqlite3_int64 elapseTime = realTime() - startTime; fprintf(pTimer, "%3d.%03d wordcount", (int)(elapseTime/1000), (int)(elapseTime%1000)); for(i=1; i<argc; i++) if( i!=showTimer ) fprintf(pTimer, " %s", argv[i]); fprintf(pTimer, "\n"); } if( showSummary ){ sqlite3_create_function(db, "checksum", -1, SQLITE_UTF8, 0, 0, checksumStep, checksumFinalize); sqlite3_exec(db, "SELECT 'count(*): ', count(*) FROM wordcount;\n" |
︙ | ︙ | |||
497 498 499 500 501 502 503 | printResult, 0, 0); } /* Database connection statistics printed after both prepared statements ** have been finalized */ if( showStats ){ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, 0); | | | | | | | | | | | | | | | | | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | printResult, 0, 0); } /* Database connection statistics printed after both prepared statements ** have been finalized */ if( showStats ){ sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, 0); printf("%s Lookaside Slots Used: %d (max %d)\n", zTag, iCur,iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, 0); printf("%s Successful lookasides: %d\n", zTag, iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHiwtr,0); printf("%s Lookaside size faults: %d\n", zTag, iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHiwtr,0); printf("%s Lookaside OOM faults: %d\n", zTag, iHiwtr); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, 0); printf("%s Pager Heap Usage: %d bytes\n", zTag, iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); printf("%s Page cache hits: %d\n", zTag, iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); printf("%s Page cache misses: %d\n", zTag, iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); printf("%s Page cache writes: %d\n", zTag, iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, 0); printf("%s Schema Heap Usage: %d bytes\n", zTag, iCur); sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, 0); printf("%s Statement Heap Usage: %d bytes\n", zTag, iCur); } sqlite3_close(db); /* Global memory usage statistics printed after the database connection ** has closed. Memory usage should be zero at this point. */ if( showStats ){ sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, 0); printf("%s Memory Used (bytes): %d (max %d)\n", zTag,iCur,iHiwtr); sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, 0); printf("%s Outstanding Allocations: %d (max %d)\n",zTag,iCur,iHiwtr); sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, 0); printf("%s Pcache Overflow Bytes: %d (max %d)\n",zTag,iCur,iHiwtr); sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, 0); printf("%s Scratch Overflow Bytes: %d (max %d)\n",zTag,iCur,iHiwtr); sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, 0); printf("%s Largest Allocation: %d bytes\n",zTag,iHiwtr); sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, 0); printf("%s Largest Pcache Allocation: %d bytes\n",zTag,iHiwtr); sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, 0); printf("%s Largest Scratch Allocation: %d bytes\n",zTag,iHiwtr); } return 0; } |
Added tool/dbhash.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | /* ** 2016-06-07 ** ** 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 is a utility program that computes an SHA1 hash on the content ** of an SQLite database. ** ** The hash is computed over just the content of the database. Free ** space inside of the database file, and alternative on-disk representations ** of the same content (ex: UTF8 vs UTF16) do not affect the hash. So, ** for example, the database file page size, encoding, and auto_vacuum setting ** can all be changed without changing the hash. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <ctype.h> #include <string.h> #include <assert.h> #include "sqlite3.h" /* Context for the SHA1 hash */ typedef struct SHA1Context SHA1Context; struct SHA1Context { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; }; /* ** All global variables are gathered into the "g" singleton. */ struct GlobalVars { const char *zArgv0; /* Name of program */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ SHA1Context cx; /* SHA1 hash context */ } g; /* ** Debugging flags */ #define DEBUG_FULLTRACE 0x00000001 /* Trace hash to stderr */ /****************************************************************************** ** The Hash Engine ** ** Modify these routines (and appropriate state fields in global variable 'g') ** in order to compute a different (better?) hash of the database. */ /* * blk0() and blk() perform the initial expand. * I got the idea of expanding during the round function from SSLeay * * blk0le() for little-endian and blk0be() for big-endian. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r)) #define rol(x,k) SHA_ROT(x,k,32-(k)) #define ror(x,k) SHA_ROT(x,32-(k),k) #endif #define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \ |(rol(block[i],8)&0x00FF00FF)) #define blk0be(i) block[i] #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \ ^block[(i+2)&15]^block[i&15],1)) /* * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 * * Rl0() for little-endian and Rb0() for big-endian. Endianness is * determined at run-time. */ #define Rl0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2); #define Rb0(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R1(v,w,x,y,z,i) \ z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2); #define R2(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2); #define R3(v,w,x,y,z,i) \ z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ #define a qq[0] #define b qq[1] #define c qq[2] #define d qq[3] #define e qq[4] void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){ unsigned int qq[5]; /* a, b, c, d, e; */ static int one = 1; unsigned int block[16]; memcpy(block, buffer, 64); memcpy(qq,state,5*sizeof(unsigned int)); /* Copy g.cx.state[] to working vars */ /* a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; */ /* 4 rounds of 20 operations each. Loop unrolled. */ if( 1 == *(unsigned char*)&one ){ Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3); Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7); Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11); Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15); }else{ Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3); Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7); Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11); Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15); } R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } /* Initialize the SHA1 hash */ static void hash_init(void){ /* SHA1 initialization constants */ g.cx.state[0] = 0x67452301; g.cx.state[1] = 0xEFCDAB89; g.cx.state[2] = 0x98BADCFE; g.cx.state[3] = 0x10325476; g.cx.state[4] = 0xC3D2E1F0; g.cx.count[0] = g.cx.count[1] = 0; } /* Add new content to the SHA1 hash */ static void hash_step(const unsigned char *data, unsigned int len){ unsigned int i, j; j = g.cx.count[0]; if( (g.cx.count[0] += len << 3) < j ){ g.cx.count[1] += (len>>29)+1; } j = (j >> 3) & 63; if( (j + len) > 63 ){ (void)memcpy(&g.cx.buffer[j], data, (i = 64-j)); SHA1Transform(g.cx.state, g.cx.buffer); for(; i + 63 < len; i += 64){ SHA1Transform(g.cx.state, &data[i]); } j = 0; }else{ i = 0; } (void)memcpy(&g.cx.buffer[j], &data[i], len - i); } /* Add padding and compute and output the message digest. */ static void hash_finish(const char *zName){ unsigned int i; unsigned char finalcount[8]; unsigned char digest[20]; static const char zEncode[] = "0123456789abcdef"; char zOut[41]; for (i = 0; i < 8; i++){ finalcount[i] = (unsigned char)((g.cx.count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } hash_step((const unsigned char *)"\200", 1); while ((g.cx.count[0] & 504) != 448){ hash_step((const unsigned char *)"\0", 1); } hash_step(finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++){ digest[i] = (unsigned char)((g.cx.state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } for(i=0; i<20; i++){ zOut[i*2] = zEncode[(digest[i]>>4)&0xf]; zOut[i*2+1] = zEncode[digest[i] & 0xf]; } zOut[i*2]= 0; printf("%s %s\n", zOut, zName); } /* End of the hashing logic *******************************************************************************/ /* ** Print an error resulting from faulting command-line arguments and ** abort the program. */ static void cmdlineError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); exit(1); } /* ** Print an error message for an error that occurs at runtime, then ** abort the program. */ static void runtimeError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ** Prepare a new SQL statement. Print an error and abort if anything ** goes wrong. */ static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ char *zSql; int rc; sqlite3_stmt *pStmt; zSql = sqlite3_vmprintf(zFormat, ap); if( zSql==0 ) runtimeError("out of memory"); rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); if( rc ){ runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), zSql); } sqlite3_free(zSql); return pStmt; } static sqlite3_stmt *db_prepare(const char *zFormat, ...){ va_list ap; sqlite3_stmt *pStmt; va_start(ap, zFormat); pStmt = db_vprepare(zFormat, ap); va_end(ap); return pStmt; } /* ** Compute the hash for all rows of the query formed from the printf-style ** zFormat and its argument. */ static void hash_one_query(const char *zFormat, ...){ va_list ap; sqlite3_stmt *pStmt; /* The query defined by zFormat and "..." */ int nCol; /* Number of columns in the result set */ int i; /* Loop counter */ /* Prepare the query defined by zFormat and "..." */ va_start(ap, zFormat); pStmt = db_vprepare(zFormat, ap); va_end(ap); nCol = sqlite3_column_count(pStmt); /* Compute a hash over the result of the query */ while( SQLITE_ROW==sqlite3_step(pStmt) ){ for(i=0; i<nCol; i++){ switch( sqlite3_column_type(pStmt,i) ){ case SQLITE_NULL: { hash_step((const unsigned char*)"0",1); if( g.fDebug & DEBUG_FULLTRACE ) fprintf(stderr, "NULL\n"); break; } case SQLITE_INTEGER: { sqlite3_uint64 u; int j; unsigned char x[8]; sqlite3_int64 v = sqlite3_column_int64(pStmt,i); memcpy(&u, &v, 8); for(j=7; j>=0; j--){ x[j] = u & 0xff; u >>= 8; } hash_step((const unsigned char*)"1",1); hash_step(x,8); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "INT %s\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_FLOAT: { sqlite3_uint64 u; int j; unsigned char x[8]; double r = sqlite3_column_double(pStmt,i); memcpy(&u, &r, 8); for(j=7; j>=0; j--){ x[j] = u & 0xff; u >>= 8; } hash_step((const unsigned char*)"2",1); hash_step(x,8); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "FLOAT %s\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_TEXT: { int n = sqlite3_column_bytes(pStmt, i); const unsigned char *z = sqlite3_column_text(pStmt, i); hash_step((const unsigned char*)"3", 1); hash_step(z, n); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "TEXT '%s'\n", sqlite3_column_text(pStmt,i)); } break; } case SQLITE_BLOB: { int n = sqlite3_column_bytes(pStmt, i); const unsigned char *z = sqlite3_column_blob(pStmt, i); hash_step((const unsigned char*)"4", 1); hash_step(z, n); if( g.fDebug & DEBUG_FULLTRACE ){ fprintf(stderr, "BLOB (%d bytes)\n", n); } break; } } } } sqlite3_finalize(pStmt); } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] FILE ...\n", g.zArgv0); printf( "Compute a SHA1 hash on the content of database FILE. System tables such as\n" "sqlite_stat1, sqlite_stat4, and sqlite_sequence are omitted from the hash.\n" "Options:\n" " --debug N Set debugging flags to N (experts only)\n" " --like PATTERN Only hash tables whose name is LIKE the pattern\n" " --schema-only Only hash the schema - omit table content\n" " --without-schema Only hash table content - omit the schema\n" ); } int main(int argc, char **argv){ const char *zDb = 0; /* Name of the database currently being hashed */ int i; /* Loop counter */ int rc; /* Subroutine return code */ char *zErrMsg; /* Error message when opening database */ sqlite3_stmt *pStmt; /* An SQLite query */ const char *zLike = 0; /* LIKE pattern of tables to hash */ int omitSchema = 0; /* True to compute hash on content only */ int omitContent = 0; /* True to compute hash on schema only */ int nFile = 0; /* Number of input filenames seen */ g.zArgv0 = argv[0]; sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); for(i=1; i<argc; i++){ const char *z = argv[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"debug")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); g.fDebug = strtol(argv[++i], 0, 0); }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"like")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); if( zLike!=0 ) cmdlineError("only one --like allowed"); zLike = argv[++i]; }else if( strcmp(z,"schema-only")==0 ){ omitContent = 1; }else if( strcmp(z,"without-schema")==0 ){ omitSchema = 1; }else { cmdlineError("unknown option: %s", argv[i]); } }else{ nFile++; if( nFile<i ) argv[nFile] = argv[i]; } } if( nFile==0 ){ cmdlineError("no input files specified - nothing to do"); } if( omitSchema && omitContent ){ cmdlineError("only one of --without-schema and --omit-schema allowed"); } if( zLike==0 ) zLike = "%"; for(i=1; i<=nFile; i++){ static const int openFlags = SQLITE_OPEN_READWRITE | /* Read/write so hot journals can recover */ SQLITE_OPEN_URI ; zDb = argv[i]; rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0); if( rc ){ fprintf(stderr, "cannot open database file '%s'\n", zDb); continue; } rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg); if( rc || zErrMsg ){ sqlite3_close(g.db); g.db = 0; fprintf(stderr, "'%s' is not a valid SQLite database\n", zDb); continue; } /* Start the hash */ hash_init(); /* Hash table content */ if( !omitContent ){ pStmt = db_prepare( "SELECT name FROM sqlite_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " AND name NOT LIKE 'sqlite_%%'\n" " AND name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ /* We want rows of the table to be hashed in PRIMARY KEY order. ** Technically, an ORDER BY clause is required to guarantee that ** order. However, though not guaranteed by the documentation, every ** historical version of SQLite has always output rows in PRIMARY KEY ** order when there is no WHERE or GROUP BY clause, so the ORDER BY ** can be safely omitted. */ hash_one_query("SELECT * FROM \"%w\"", sqlite3_column_text(pStmt,0)); } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( "SELECT type, name, tbl_name, sql FROM sqlite_master\n" " WHERE tbl_name LIKE '%q'\n" " ORDER BY name COLLATE nocase;\n", zLike ); } /* Finish and output the hash and close the database connection. */ hash_finish(zDb); sqlite3_close(g.db); } return 0; } |
Changes to tool/lemon.c.
︙ | ︙ | |||
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean canReduce; /* True if this rule is ever reduced */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal | > > > | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ int noCode; /* True if this rule has no associated C code */ int codeEmitted; /* True if the code has been emitted already */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean canReduce; /* True if this rule is ever reduced */ Boolean doesReduce; /* Reduce actions occur after optimization */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal |
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | struct action { struct symbol *sp; /* The look-ahead symbol */ enum e_action type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; /* Each state of the generated parser's finite state machine ** is encoded as an instance of the following structure. */ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequential number for this state */ | > | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | struct action { struct symbol *sp; /* The look-ahead symbol */ enum e_action type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; struct symbol *spOpt; /* SHIFTREDUCE optimization to this symbol */ struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; /* Each state of the generated parser's finite state machine ** is encoded as an instance of the following structure. */ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequential number for this state */ struct action *ap; /* List of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ int iDfltReduce; /* Default action is to REDUCE by this rule */ struct rule *pDfltReduce;/* The default REDUCE rule. */ int autoReduce; /* True if this is an auto-reduce state */ }; #define NO_OFFSET (-2147483647) |
︙ | ︙ | |||
526 527 528 529 530 531 532 533 534 535 536 537 538 539 | ){ struct action *newaction; newaction = Action_new(); newaction->next = *app; *app = newaction; newaction->type = type; newaction->sp = sp; if( type==SHIFT ){ newaction->x.stp = (struct state *)arg; }else{ newaction->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ | > | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | ){ struct action *newaction; newaction = Action_new(); newaction->next = *app; *app = newaction; newaction->type = type; newaction->sp = sp; newaction->spOpt = 0; if( type==SHIFT ){ newaction->x.stp = (struct state *)arg; }else{ newaction->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ |
︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 | user_templatename = (char *) malloc( lemonStrlen(z)+1 ); if( user_templatename==0 ){ memory_error(); } lemon_strcpy(user_templatename, z); } | | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 | user_templatename = (char *) malloc( lemonStrlen(z)+1 ); if( user_templatename==0 ){ memory_error(); } lemon_strcpy(user_templatename, z); } /* Merge together to lists of rules ordered by rule.iRule */ static struct rule *Rule_merge(struct rule *pA, struct rule *pB){ struct rule *pFirst = 0; struct rule **ppPrev = &pFirst; while( pA && pB ){ if( pA->iRule<pB->iRule ){ *ppPrev = pA; ppPrev = &pA->next; |
︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); lem.nsymbol = i - 1; for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); lem.nterminal = i; | | > > > | 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i; while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; } assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 ); lem.nsymbol = i - 1; for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); lem.nterminal = i; /* Assign sequential rule numbers. Start with 0. Put rules that have no ** reduce action C-code associated with them last, so that the switch() ** statement that selects reduction actions will have a smaller jump table. */ for(i=0, rp=lem.rule; rp; rp=rp->next){ rp->iRule = rp->code ? i++ : -1; } for(rp=lem.rule; rp; rp=rp->next){ if( rp->iRule<0 ) rp->iRule = i++; } lem.startRule = lem.rule; |
︙ | ︙ | |||
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 | ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Token \"%s\" should be either \"%%\" or a nonterminal name.", x); | > | 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 | ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; psp->prevrule->noCode = 0; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Token \"%s\" should be either \"%%\" or a nonterminal name.", x); |
︙ | ︙ | |||
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; } rp->lhs = psp->lhs; rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; rp->lhs->rule = rp; rp->next = 0; if( psp->firstrule==0 ){ psp->firstrule = psp->lastrule = rp; | > | 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 | rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; } rp->lhs = psp->lhs; rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; rp->noCode = 1; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; rp->lhs->rule = rp; rp->next = 0; if( psp->firstrule==0 ){ psp->firstrule = psp->lastrule = rp; |
︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 | result = 0; } break; case NOT_USED: result = 0; break; } return result; } /* Generate the "*.out" log file */ void ReportOutput(struct lemon *lemp) { int i; | > > > | 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 | result = 0; } break; case NOT_USED: result = 0; break; } if( result && ap->spOpt ){ fprintf(fp," /* because %s==%s */", ap->sp->name, ap->spOpt->name); } return result; } /* Generate the "*.out" log file */ void ReportOutput(struct lemon *lemp) { int i; |
︙ | ︙ | |||
3523 3524 3525 3526 3527 3528 3529 | } } z[used] = 0; return z; } /* | | | < | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 | } } z[used] = 0; return z; } /* ** Write and transform the rp->code string so that symbols are expanded. ** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate. ** ** Return 1 if the expanded code requires that "yylhsminor" local variable ** to be defined. */ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ char *cp, *xp; int i; |
︙ | ︙ | |||
3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 | for(i=0; i<rp->nrhs; i++) used[i] = 0; lhsused = 0; if( rp->code==0 ){ static char newlinestr[2] = { '\n', '\0' }; rp->code = newlinestr; rp->line = rp->ruleline; } | > > > < < < | | > > > > | 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 | for(i=0; i<rp->nrhs; i++) used[i] = 0; lhsused = 0; if( rp->code==0 ){ static char newlinestr[2] = { '\n', '\0' }; rp->code = newlinestr; rp->line = rp->ruleline; rp->noCode = 1; }else{ rp->noCode = 0; } if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ /* The left-most RHS symbol has no value. LHS direct is ok. But ** we have to call the distructor on the RHS symbol first. */ lhsdirect = 1; if( has_destructor(rp->rhs[0],lemp) ){ append_str(0,0,0,0); append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[0]->index,1-rp->nrhs); rp->codePrefix = Strsafe(append_str(0,0,0,0)); rp->noCode = 0; } }else if( rp->lhsalias==0 ){ /* There is no LHS value symbol. */ lhsdirect = 1; }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ /* The LHS symbol and the left-most RHS symbol are the same, so ** direct writing is allowed */ lhsdirect = 1; lhsused = 1; used[0] = 1; if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){ |
︙ | ︙ | |||
3711 3712 3713 3714 3715 3716 3717 | append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum); append_str(zLhs, 0, 0, 0); append_str(";\n", 0, 0, 0); } /* Suffix code generation complete */ cp = append_str(0,0,0,0); | > | > > | 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 | append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum); append_str(zLhs, 0, 0, 0); append_str(";\n", 0, 0, 0); } /* Suffix code generation complete */ cp = append_str(0,0,0,0); if( cp && cp[0] ){ rp->codeSuffix = Strsafe(cp); rp->noCode = 0; } return rc; } /* ** Generate code which executes when the rule "rp" is reduced. Write ** the code to "out". Make sure lineno stays up-to-date. |
︙ | ︙ | |||
4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 | printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", ax[i].nAction, pActtab->nAction, nn); } #endif } free(ax); /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; | > > > > > > > > > > > > > | 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 | printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n", i, stp->statenum, ax[i].isTkn ? "Token" : "Var ", ax[i].nAction, pActtab->nAction, nn); } #endif } free(ax); /* Mark rules that are actually used for reduce actions after all ** optimizations have been applied */ for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE; for(i=0; i<lemp->nxstate; i++){ struct action *ap; for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){ ap->x.rp->doesReduce = i; } } } /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++; fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; |
︙ | ︙ | |||
4195 4196 4197 4198 4199 4200 4201 | }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ | < > | | | | > | | 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 | }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++; fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; fprintf(out, "static const %s yy_shift_ofst[] = {\n", minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz)); lineno++; lemp->tablesize += n*sz; for(i=j=0; i<n; i++){ int ofst; stp = lemp->sorted[i]; ofst = stp->iTknOfst; if( ofst==NO_OFFSET ) ofst = lemp->nactiontab; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", ofst); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; |
︙ | ︙ | |||
4392 4393 4394 4395 4396 4397 4398 | } if( i ){ fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++; } /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; /* Other rules with the same action */ | | > > | > | | | | > | > > > > | 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 | } if( i ){ fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++; } /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; /* Other rules with the same action */ if( rp->codeEmitted ) continue; if( rp->noCode ){ /* No C code actions, so this will be part of the "default:" rule */ continue; } fprintf(out," case %d: /* ", rp->iRule); writeRuleText(out, rp); fprintf(out, " */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix && rp2->codeSuffix==rp->codeSuffix ){ fprintf(out," case %d: /* ", rp2->iRule); writeRuleText(out, rp2); fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++; rp2->codeEmitted = 1; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; rp->codeEmitted = 1; } /* Finally, output the default: rule. We choose as the default: all ** empty actions. */ fprintf(out," default:\n"); lineno++; for(rp=lemp->rule; rp; rp=rp->next){ if( rp->codeEmitted ) continue; assert( rp->noCode ); fprintf(out," /* (%d) ", rp->iRule); writeRuleText(out, rp); if( rp->doesReduce ){ fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; }else{ fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n", rp->iRule); lineno++; } } fprintf(out," break;\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes if a parse fails */ tplt_print(out,lemp,lemp->failure,&lineno); tplt_xfer(lemp->name,in,out,&lineno); |
︙ | ︙ | |||
4489 4490 4491 4492 4493 4494 4495 | ** In this version, we take the most frequent REDUCE action and make ** it the default. Except, there is no default if the wildcard token ** is a possible look-ahead. */ void CompressTables(struct lemon *lemp) { struct state *stp; | | | 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 | ** In this version, we take the most frequent REDUCE action and make ** it the default. Except, there is no default if the wildcard token ** is a possible look-ahead. */ void CompressTables(struct lemon *lemp) { struct state *stp; struct action *ap, *ap2, *nextap; struct rule *rp, *rp2, *rbest; int nbest, n; int i; int usesWildcard; for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; |
︙ | ︙ | |||
4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 | pNextState = ap->x.stp; if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ ap->type = SHIFTREDUCE; ap->x.rp = pNextState->pDfltReduce; } } } } /* ** Compare two states for sorting purposes. The smaller state is the ** one with the most non-terminal actions. If they have the same number ** of non-terminal actions, then the smaller is the one with the most | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 | pNextState = ap->x.stp; if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ ap->type = SHIFTREDUCE; ap->x.rp = pNextState->pDfltReduce; } } } /* If a SHIFTREDUCE action specifies a rule that has a single RHS term ** (meaning that the SHIFTREDUCE will land back in the state where it ** started) and if there is no C-code associated with the reduce action, ** then we can go ahead and convert the action to be the same as the ** action for the RHS of the rule. */ for(i=0; i<lemp->nstate; i++){ stp = lemp->sorted[i]; for(ap=stp->ap; ap; ap=nextap){ nextap = ap->next; if( ap->type!=SHIFTREDUCE ) continue; rp = ap->x.rp; if( rp->noCode==0 ) continue; if( rp->nrhs!=1 ) continue; #if 1 /* Only apply this optimization to non-terminals. It would be OK to ** apply it to terminal symbols too, but that makes the parser tables ** larger. */ if( ap->sp->index<lemp->nterminal ) continue; #endif /* If we reach this point, it means the optimization can be applied */ nextap = ap; for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){} assert( ap2!=0 ); ap->spOpt = ap2->sp; ap->type = ap2->type; ap->x = ap2->x; } } } /* ** Compare two states for sorting purposes. The smaller state is the ** one with the most non-terminal actions. If they have the same number ** of non-terminal actions, then the smaller is the one with the most |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
112 113 114 115 116 117 118 | ** token onto the stack and goto state N. ** ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE | | | | > > | | | < > > > | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | ** token onto the stack and goto state N. ** ** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then ** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE ** ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. ** ** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. ** Given state S and lookahead X, the action is computed as either: ** ** (A) N = yy_action[ yy_shift_ofst[S] + X ] ** (B) N = yy_default[S] ** ** The (A) formula is preferred. The B formula is used instead if: ** (1) The yy_shift_ofst[S]+X value is out of range, or ** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or ** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. ** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that ** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. ** Hence only tests (1) and (2) need to be evaluated.) ** ** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of ** YY_SHIFT_USE_DFLT. ** ** The following are the tables generated in this section: ** |
︙ | ︙ | |||
199 200 201 202 203 204 205 | ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { | | | > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH int yyhwm; /* High-water mark of the stack */ #endif #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ #endif ParseARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG |
︙ | ︙ | |||
267 268 269 270 271 272 273 | %% }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* | | > | > > > > > > | > | | | > > | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | %% }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. Return the number ** of errors. Return 0 on success. */ static int yyGrowStack(yyParser *p){ int newSize; int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; if( p->yystack==&p->yystk0 ){ pNew = malloc(newSize*sizeof(pNew[0])); if( pNew ) pNew[0] = p->yystk0; }else{ pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); } if( pNew ){ p->yystack = pNew; p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", yyTracePrompt, p->yystksz, newSize); } #endif p->yystksz = newSize; } return pNew==0; } #endif /* Datatype of the argument to the memory allocated passed as the ** second argument to ParseAlloc() below. This can be changed by ** putting an appropriate #define in the %include section of the input ** grammar. |
︙ | ︙ | |||
313 314 315 316 317 318 319 | ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ | < | > | > > > > > > > > > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ #ifdef YYTRACKMAXSTACKDEPTH pParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 pParser->yytos = NULL; pParser->yystack = NULL; pParser->yystksz = 0; if( yyGrowStack(pParser) ){ pParser->yystack = &pParser->yystk0; pParser->yystksz = 1; } #endif #ifndef YYNOERRORRECOVERY pParser->yyerrcnt = -1; #endif pParser->yytos = pParser->yystack; pParser->yystack[0].stateno = 0; pParser->yystack[0].major = 0; } return pParser; } /* The following function deletes the "minor type" or semantic value ** associated with a symbol. The symbol can be either a terminal ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is |
︙ | ︙ | |||
365 366 367 368 369 370 371 | ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; | | | > | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; assert( pParser->yytos!=0 ); assert( pParser->yytos > pParser->yystack ); yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif |
︙ | ︙ | |||
393 394 395 396 397 398 399 | void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif | | | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | < | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif (*freeProc)((void*)pParser); } /* ** Return the peak depth of the stack for a parser. */ #ifdef YYTRACKMAXSTACKDEPTH int ParseStackPeak(void *p){ yyParser *pParser = (yyParser*)p; return pParser->yyhwm; } #endif /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. */ static unsigned int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yytos->stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) && (iFallback = yyFallback[iLookAhead])!=0 ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); } #endif assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ iLookAhead = iFallback; continue; } #endif #ifdef YYWILDCARD { int j = i - iLookAhead + YYWILDCARD; if( #if YY_SHIFT_MIN+YYWILDCARD<0 j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT j<YY_ACTTAB_COUNT && #endif yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); } #endif /* NDEBUG */ return yy_action[j]; } } #endif /* YYWILDCARD */ return yy_default[stateno]; }else{ return yy_action[i]; } }while(1); } |
︙ | ︙ | |||
512 513 514 515 516 517 518 | } /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ ParseARG_FETCH; | | | | | | | | > | | | < > > > | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | } /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser){ ParseARG_FETCH; yypParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ %% /******** End %stack_overflow code ********************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } /* ** Print tracing information for a SHIFT action */ #ifndef NDEBUG static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ if( yyNewState<YYNSTATE ){ fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n", yyTracePrompt,yyTokenName[yypParser->yytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%sShift '%s'\n", yyTracePrompt,yyTokenName[yypParser->yytos->major]); } } } #else # define yyTraceShift(X,Y) #endif /* ** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ ParseTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ yyStackOverflow(yypParser); return; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } } #endif if( yyNewState > YY_MAX_SHIFT ){ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yytos = yypParser->yytos; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor.yy0 = yyMinor; yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that |
︙ | ︙ | |||
609 610 611 612 613 614 615 | unsigned int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; | | | | > | | | < > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | unsigned int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; yymsp = yypParser->yytos; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ /* Check that the stack is large enough to grow by a single entry ** if the RHS of the rule is empty. This ensures that there is room ** enough on the stack to push the LHS value */ if( yyRuleInfo[yyruleno].nrhs==0 ){ #ifdef YYTRACKMAXSTACKDEPTH if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ yypParser->yyhwm++; assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif #if YYSTACKDEPTH>0 if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ yyStackOverflow(yypParser); return; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } yymsp = yypParser->yytos; } #endif } switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: |
︙ | ︙ | |||
661 662 663 664 665 666 667 | /********** End reduce actions ************************************************/ }; assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ | | | > > | | | 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | /********** End reduce actions ************************************************/ }; assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ if( yyact>YY_MAX_SHIFT ){ yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; } yymsp -= yysize-1; yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); }else{ assert( yyact == YY_ACCEPT_ACTION ); yypParser->yytos -= yysize; yy_accept(yypParser); } } /* ** The following code executes when the parse fails */ #ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ %% /************ End %parse_failure code *****************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } |
︙ | ︙ | |||
725 726 727 728 729 730 731 | ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif | > | > > | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif assert( yypParser->yytos==yypParser->yystack ); /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ %% /*********** End %parse_accept code *******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } |
︙ | ︙ | |||
769 770 771 772 773 774 775 | int yyendofinput; /* True if we are at the end of input */ #endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ | < | < < < < < < < < < < < < < < < < < < < < | 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 | int yyendofinput; /* True if we are at the end of input */ #endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ yypParser = (yyParser*)yyp; assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); } #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif yymajor = YYNOCODE; }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); |
︙ | ︙ | |||
847 848 849 850 851 852 853 | ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } | | < | | | | | > > > | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yytos >= &yypParser->yystack && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yytos->stateno, YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } yypParser->yyerrcnt = 3; yyerrorhit = 1; |
︙ | ︙ | |||
906 907 908 909 910 911 912 913 914 915 916 | if( yypParser->yyerrcnt<=0 ){ yy_syntax_error(yypParser,yymajor, yyminor); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } yymajor = YYNOCODE; #endif } | > > > | | > | | < > > | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | if( yypParser->yyerrcnt<=0 ){ yy_syntax_error(yypParser,yymajor, yyminor); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } yymajor = YYNOCODE; #endif } }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ yyStackEntry *i; char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); cDiv = ' '; } fprintf(yyTraceFILE,"]\n"); } #endif return; } |
Added tool/libvers.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* ** Compile this program against an SQLite library of unknown version ** and then run this program, and it will print out the SQLite version ** information. */ #include <stdio.h> extern const char *sqlite3_libversion(void); extern const char *sqlite3_sourceid(void); int main(int argc, char **argv){ printf("SQLite version %s\n", sqlite3_libversion()); printf("SQLite source %s\n", sqlite3_sourceid()); return 0; } |
Changes to tool/mksqlite3c-noext.tcl.
︙ | ︙ | |||
216 217 218 219 220 221 222 | append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { append line " " } if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL } else { | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | append line " " [string trim $rettype] if {[string index $rettype end] ne "*"} { append line " " } if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL } else { append line SQLITE_APICALL } append line " " $funcname $rest puts $out $line } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { |
︙ | ︙ |
Added tool/opcodesum.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #!/usr/bin/tclsh # # Run this script, redirecting input from cachegrind output, to compute the # number of CPU cycles used by each VDBE opcode. # # The cachegrind output should be configured so that it reports a single # column of Ir at the left margin. Ex: # # cg_annotation --show=Ir --auto=yes cachegrind.out.* | tclsh opcodesum.tcl # set currentop x set ncycle(x) 0 while {![eof stdin]} { set line [string map {\173 x \175 x \042 x} [gets stdin]] if {[regexp { \. case OP_.*:} $line]} { regexp {OP_(.+):} $line all currentop set ncycle($currentop) 0 } elseif {[lindex $line 1]=="default:" && [regexp {really OP_Noop and OP_Explain} $line]} { break } elseif {[lindex $line 0]!="."} { regsub -all {[^0-9]} [lindex $line 0] {} n if {$n!=""} {incr ncycle($currentop) $n} } } unset ncycle(x) set results {} foreach op [lsort [array names ncycle]] { if {$ncycle($op)==0} continue lappend results [list $ncycle($op) $op] } foreach entry [lsort -index 0 -int -decr $results] { puts [format {%-16s %10d} [lindex $entry 1] [lindex $entry 0]] } |
Changes to tool/replace.tcl.
1 2 3 4 5 6 7 8 9 | #!/usr/bin/tcl # # Replace string with another string -OR- include # only lines successfully modified with a regular # expression. # set mode [string tolower [lindex $argv 0]] set from [lindex $argv 1] set to [lindex $argv 2] | > > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/tcl # # Replace string with another string -OR- include # only lines successfully modified with a regular # expression. # fconfigure stdout -translation binary -encoding binary fconfigure stderr -translation binary -encoding binary set mode [string tolower [lindex $argv 0]] set from [lindex $argv 1] set to [lindex $argv 2] if {$mode ni [list exact regsub include]} {exit 1} if {[string length $from]==0} {exit 2} while {![eof stdin]} { set line [gets stdin] if {[eof stdin]} break switch -exact $mode { exact {set line [string map [list $from $to] $line]} regsub {regsub -all -- $from $line $to line} include {if {[regsub -all -- $from $line $to line]==0} continue} } puts stdout $line } |
Changes to tool/spaceanal.tcl.
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 | # queries the in-memory db to produce the space-analysis report. # sqlite3 mem :memory: set tabledef {CREATE TABLE space_used( name clob, -- Name of a table or index in the database file tblname clob, -- Name of associated table is_index boolean, -- TRUE if it is an index, false for a table nentry int, -- Number of entries in the BTree leaf_entries int, -- Number of leaf entries depth int, -- Depth of the b-tree payload int, -- Total amount of data stored in this table or index ovfl_payload int, -- Total amount of data stored on overflow pages ovfl_cnt int, -- Number of entries that use overflow mx_payload int, -- Maximum payload size | > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | # queries the in-memory db to produce the space-analysis report. # sqlite3 mem :memory: set tabledef {CREATE TABLE space_used( name clob, -- Name of a table or index in the database file tblname clob, -- Name of associated table is_index boolean, -- TRUE if it is an index, false for a table is_without_rowid boolean, -- TRUE if WITHOUT ROWID table nentry int, -- Number of entries in the BTree leaf_entries int, -- Number of leaf entries depth int, -- Depth of the b-tree payload int, -- Total amount of data stored in this table or index ovfl_payload int, -- Total amount of data stored on overflow pages ovfl_cnt int, -- Number of entries that use overflow mx_payload int, -- Maximum payload size |
︙ | ︙ | |||
180 181 182 183 184 185 186 | set isCompressed 0 set compressOverhead 0 set depth 0 set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { set is_index [expr {$name!=$tblname}] | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | set isCompressed 0 set compressOverhead 0 set depth 0 set sql { SELECT name, tbl_name FROM sqlite_master WHERE rootpage>0 } foreach {name tblname} [concat sqlite_master sqlite_master [db eval $sql]] { set is_index [expr {$name!=$tblname}] set is_without_rowid [is_without_rowid $name] db eval { SELECT sum(ncell) AS nentry, sum((pagetype=='leaf')*ncell) AS leaf_entries, sum(payload) AS payload, sum((pagetype=='overflow') * payload) AS ovfl_payload, sum(path LIKE '%+000000') AS ovfl_cnt, |
︙ | ︙ | |||
231 232 233 234 235 236 237 238 239 240 241 242 243 244 | set prev $pageno } mem eval { INSERT INTO space_used VALUES( $name, $tblname, $is_index, $nentry, $leaf_entries, $depth, $payload, $ovfl_payload, $ovfl_cnt, $mx_payload, | > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | set prev $pageno } mem eval { INSERT INTO space_used VALUES( $name, $tblname, $is_index, $is_without_rowid, $nentry, $leaf_entries, $depth, $payload, $ovfl_payload, $ovfl_cnt, $mx_payload, |
︙ | ︙ | |||
326 327 328 329 330 331 332 | # Query the in-memory database for the sum of various statistics # for the subset of tables/indices identified by the WHERE clause in # $where. Note that even if the WHERE clause matches no rows, the # following query returns exactly one row (because it is an aggregate). # # The results of the query are stored directly by SQLite into local | | | > | > > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | # Query the in-memory database for the sum of various statistics # for the subset of tables/indices identified by the WHERE clause in # $where. Note that even if the WHERE clause matches no rows, the # following query returns exactly one row (because it is an aggregate). # # The results of the query are stored directly by SQLite into local # variables (i.e. $nentry, $payload etc.). # mem eval " SELECT int(sum( CASE WHEN (is_without_rowid OR is_index) THEN nentry ELSE leaf_entries END )) AS nentry, int(sum(payload)) AS payload, int(sum(ovfl_payload)) AS ovfl_payload, max(mx_payload) AS mx_payload, int(sum(ovfl_cnt)) as ovfl_cnt, int(sum(leaf_pages)) AS leaf_pages, int(sum(int_pages)) AS int_pages, int(sum(ovfl_pages)) AS ovfl_pages, |
︙ | ︙ | |||
371 372 373 374 375 376 377 | # ovfl_cnt_percent: Percentage of btree entries that use overflow pages. # set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] set total_pages_percent [percent $total_pages $file_pgcnt] set storage [expr {$total_pages*$pageSize}] set payload_percent [percent $payload $storage {of storage consumed}] set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}] | | | | | | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | # ovfl_cnt_percent: Percentage of btree entries that use overflow pages. # set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}] set total_pages_percent [percent $total_pages $file_pgcnt] set storage [expr {$total_pages*$pageSize}] set payload_percent [percent $payload $storage {of storage consumed}] set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}] set avg_payload [divide $payload $nentry] set avg_unused [divide $total_unused $nentry] if {$int_pages>0} { # TODO: Is this formula correct? set nTab [mem eval " SELECT count(*) FROM ( SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0 ) "] set avg_fanout [mem eval " SELECT (sum(leaf_pages+int_pages)-$nTab)/sum(int_pages) FROM space_used WHERE $where "] set avg_fanout [format %.2f $avg_fanout] } set ovfl_cnt_percent [percent $ovfl_cnt $nentry {of all entries}] # Print out the sub-report statistics. # statline {Percentage of total database} $total_pages_percent statline {Number of entries} $nentry statline {Bytes of storage consumed} $storage if {$compressed_size!=$storage} { set compressed_size [expr {$compressed_size+$compressOverhead*$total_pages}] set pct [expr {$compressed_size*100.0/$storage}] set pct [format {%5.1f%%} $pct] statline {Bytes used after compression} $compressed_size $pct } |
︙ | ︙ |
Added tool/speed-check.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #!/bin/bash # # This is a template for a script used for day-to-day size and # performance monitoring of SQLite. Typical usage: # # sh run-speed-test.sh trunk # Baseline measurement of trunk # sh run-speed-test.sh x1 # Measure some experimental change # fossil test-diff --tk cout-trunk.txt cout-x1.txt # View chanages # # There are multiple output files, all with a base name given by # the first argument: # # summary-$BASE.txt # Copy of standard output # cout-$BASE.txt # cachegrind output # explain-$BASE.txt # EXPLAIN listings (only with --explain) # if test "$1" = "" then echo "Usage: $0 OUTPUTFILE [OPTIONS]" exit fi NAME=$1 shift CC_OPTS="-DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_MEMSYS5" SPEEDTEST_OPTS="--shrink-memory --reprepare --heap 10000000 64" SIZE=5 doExplain=0 doCachegrind=1 while test "$1" != ""; do case $1 in --reprepare) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --autovacuum) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --utf16be) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --stats) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --without-rowid) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --nomemstat) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --temp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --temp 6" ;; --wal) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --journal wal" ;; --size) shift; SIZE=$1 ;; --explain) doExplain=1 ;; --vdbeprofile) rm -f vdbe_profile.out CC_OPTS="$CC_OPTS -DVDBE_PROFILE" doCachegrind=0 ;; --heap) CC_OPTS="$CC_OPTS -DSQLITE_ENABLE_MEMSYS5" shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --heap $1 64" ;; *) CC_OPTS="$CC_OPTS $1" ;; esac shift done SPEEDTEST_OPTS="$SPEEDTEST_OPTS --size $SIZE" echo "NAME = $NAME" | tee summary-$NAME.txt echo "SPEEDTEST_OPTS = $SPEEDTEST_OPTS" | tee -a summary-$NAME.txt echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt rm -f cachegrind.out.* speedtest1 speedtest1.db sqlite3.o gcc -g -Os -Wall -I. $CC_OPTS -c sqlite3.c size sqlite3.o | tee -a summary-$NAME.txt if test $doExplain -eq 1; then gcc -g -Os -Wall -I. $CC_OPTS \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ ./shell.c ./sqlite3.c -o sqlite3 -ldl -lpthread fi SRC=./speedtest1.c gcc -g -Os -Wall -I. $CC_OPTS $SRC ./sqlite3.o -o speedtest1 -ldl -lpthread ls -l speedtest1 | tee -a summary-$NAME.txt if test $doCachegrind -eq 1; then valgrind --tool=cachegrind ./speedtest1 speedtest1.db \ $SPEEDTEST_OPTS 2>&1 | tee -a summary-$NAME.txt else ./speedtest1 speedtest1.db $SPEEDTEST_OPTS 2>&1 | tee -a summary-$NAME.txt fi size sqlite3.o | tee -a summary-$NAME.txt wc sqlite3.c if test $doCachegrind -eq 1; then cg_anno.tcl cachegrind.out.* >cout-$NAME.txt fi if test $doExplain -eq 1; then ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt fi |
Changes to tool/sqldiff.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /* ** All global variables are gathered into the "g" singleton. */ struct GlobalVars { const char *zArgv0; /* Name of program */ int bSchemaOnly; /* Only show schema differences */ int bSchemaPK; /* Use the schema-defined PK, not the true PK */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ } g; /* ** Allowed values for g.fDebug */ | > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* ** All global variables are gathered into the "g" singleton. */ struct GlobalVars { const char *zArgv0; /* Name of program */ int bSchemaOnly; /* Only show schema differences */ int bSchemaPK; /* Use the schema-defined PK, not the true PK */ int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ } g; /* ** Allowed values for g.fDebug */ |
︙ | ︙ | |||
679 680 681 682 683 684 685 | fprintf(out, "DROP INDEX %s;\n", z); sqlite3_free(z); } sqlite3_finalize(pStmt); /* Run the query and output differences */ if( !g.bSchemaOnly ){ | | | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | fprintf(out, "DROP INDEX %s;\n", z); sqlite3_free(z); } sqlite3_finalize(pStmt); /* Run the query and output differences */ if( !g.bSchemaOnly ){ pStmt = db_prepare("%s", sql.z); while( SQLITE_ROW==sqlite3_step(pStmt) ){ int iType = sqlite3_column_int(pStmt, nPk); if( iType==1 || iType==2 ){ if( iType==1 ){ /* Change the content of a row */ fprintf(out, "UPDATE %s", zId); zSep = " SET"; for(i=nPk+1; i<nQ; i+=2){ |
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | if( i>0 ) fprintf(out, ", "); printQuoted(out, sqlite3_column_value(pStmt, i)); } }else{ char *zOtaControl; int nOtaControl = sqlite3_column_bytes(pStmt, nCol); | | | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | if( i>0 ) fprintf(out, ", "); printQuoted(out, sqlite3_column_value(pStmt, i)); } }else{ char *zOtaControl; int nOtaControl = sqlite3_column_bytes(pStmt, nCol); zOtaControl = (char*)sqlite3_malloc(nOtaControl+1); memcpy(zOtaControl, sqlite3_column_text(pStmt, nCol), nOtaControl+1); for(i=0; i<nCol; i++){ int bDone = 0; if( i>=nPK && sqlite3_column_type(pStmt, i)==SQLITE_BLOB && sqlite3_column_type(pStmt, nCol+1+i)==SQLITE_BLOB |
︙ | ︙ | |||
1456 1457 1458 1459 1460 1461 1462 | if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ printf("SQL for %s:\n%s\n", zId, sql.z); goto end_summarize_one_table; } /* Run the query and output difference summary */ | | | 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | if( (g.fDebug & DEBUG_DIFF_SQL)!=0 ){ printf("SQL for %s:\n%s\n", zId, sql.z); goto end_summarize_one_table; } /* Run the query and output difference summary */ pStmt = db_prepare("%s", sql.z); nUpdate = 0; nInsert = 0; nDelete = 0; nUnchanged = 0; while( SQLITE_ROW==sqlite3_step(pStmt) ){ switch( sqlite3_column_int(pStmt,0) ){ case 1: |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 | end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); printf( "Output SQL text that would transform DB1 into DB2.\n" "Options:\n" " --changeset FILE Write a CHANGESET into FILE\n" " -L|--lib LIBRARY Load an SQLite extension library\n" " --primarykey Use schema-defined PRIMARY KEYs\n" " --rbu Output SQL to create/populate RBU table(s)\n" " --schema Show only differences in the schema\n" " --summary Show only a summary of the differences\n" " --table TAB Show only differences in table TAB\n" " --transaction Show SQL output inside a transaction\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 | end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); } /* ** Extract the next SQL keyword or quoted string from buffer zIn and copy it ** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes. ** Return a pointer to the character within zIn immediately following ** the token or quoted string just extracted. */ const char *gobble_token(const char *zIn, char *zBuf, int nBuf){ const char *p = zIn; char *pOut = zBuf; char *pEnd = &pOut[nBuf-1]; char q = 0; /* quote character, if any */ if( p==0 ) return 0; while( *p==' ' ) p++; switch( *p ){ case '"': q = '"'; break; case '\'': q = '\''; break; case '`': q = '`'; break; case '[': q = ']'; break; } if( q ){ p++; while( *p && pOut<pEnd ){ if( *p==q ){ p++; if( *p!=q ) break; } if( pOut<pEnd ) *pOut++ = *p; p++; } }else{ while( *p && *p!=' ' && *p!='(' ){ if( pOut<pEnd ) *pOut++ = *p; p++; } } *pOut = '\0'; return p; } /* ** This function is the implementation of SQL scalar function "module_name": ** ** module_name(SQL) ** ** The only argument should be an SQL statement of the type that may appear ** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE" ** statement, then the value returned is the name of the module that it ** uses. Otherwise, if the statement is not a CVT, NULL is returned. */ static void module_name_func( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ const char *zSql; char zToken[32]; assert( nVal==1 ); zSql = (const char*)sqlite3_value_text(apVal[0]); zSql = gobble_token(zSql, zToken, sizeof(zToken)); if( zSql==0 || sqlite3_stricmp(zToken, "create") ) return; zSql = gobble_token(zSql, zToken, sizeof(zToken)); if( zSql==0 || sqlite3_stricmp(zToken, "virtual") ) return; zSql = gobble_token(zSql, zToken, sizeof(zToken)); if( zSql==0 || sqlite3_stricmp(zToken, "table") ) return; zSql = gobble_token(zSql, zToken, sizeof(zToken)); if( zSql==0 ) return; zSql = gobble_token(zSql, zToken, sizeof(zToken)); if( zSql==0 || sqlite3_stricmp(zToken, "using") ) return; zSql = gobble_token(zSql, zToken, sizeof(zToken)); sqlite3_result_text(pCtx, zToken, -1, SQLITE_TRANSIENT); } /* ** Return the text of an SQL statement that itself returns the list of ** tables to process within the database. */ const char *all_tables_sql(){ if( g.bHandleVtab ){ int rc; rc = sqlite3_exec(g.db, "CREATE TEMP TABLE tblmap(module COLLATE nocase, postfix);" "INSERT INTO temp.tblmap VALUES" "('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir')," "('fts4', '_content'), ('fts4', '_segments'), ('fts4', '_segdir')," "('fts4', '_docsize'), ('fts4', '_stat')," "('fts5', '_data'), ('fts5', '_idx'), ('fts5', '_content')," "('fts5', '_docsize'), ('fts5', '_config')," "('rtree', '_node'), ('rtree', '_rowid'), ('rtree', '_parent');" , 0, 0, 0 ); assert( rc==SQLITE_OK ); rc = sqlite3_create_function( g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 ); assert( rc==SQLITE_OK ); return "SELECT name FROM main.sqlite_master\n" " WHERE type='table' AND (\n" " module_name(sql) IS NULL OR \n" " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" " ) AND name NOT IN (\n" " SELECT a.name || b.postfix \n" "FROM main.sqlite_master AS a, temp.tblmap AS b \n" "WHERE module_name(a.sql) = b.module\n" " )\n" "UNION \n" "SELECT name FROM aux.sqlite_master\n" " WHERE type='table' AND (\n" " module_name(sql) IS NULL OR \n" " module_name(sql) IN (SELECT module FROM temp.tblmap)\n" " ) AND name NOT IN (\n" " SELECT a.name || b.postfix \n" "FROM aux.sqlite_master AS a, temp.tblmap AS b \n" "WHERE module_name(a.sql) = b.module\n" " )\n" " ORDER BY name"; }else{ return "SELECT name FROM main.sqlite_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " UNION\n" "SELECT name FROM aux.sqlite_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " ORDER BY name"; } } /* ** Print sketchy documentation for this utility program */ static void showHelp(void){ printf("Usage: %s [options] DB1 DB2\n", g.zArgv0); printf( "Output SQL text that would transform DB1 into DB2.\n" "Options:\n" " --changeset FILE Write a CHANGESET into FILE\n" " -L|--lib LIBRARY Load an SQLite extension library\n" " --primarykey Use schema-defined PRIMARY KEYs\n" " --rbu Output SQL to create/populate RBU table(s)\n" " --schema Show only differences in the schema\n" " --summary Show only a summary of the differences\n" " --table TAB Show only differences in table TAB\n" " --transaction Show SQL output inside a transaction\n" " --vtab Handle fts3, fts4, fts5 and rtree tables\n" ); } int main(int argc, char **argv){ const char *zDb1 = 0; const char *zDb2 = 0; int i; |
︙ | ︙ | |||
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 | if( strcmp(z,"table")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); zTab = argv[++i]; }else if( strcmp(z,"transaction")==0 ){ useTransaction = 1; }else { cmdlineError("unknown option: %s", argv[i]); } }else if( zDb1==0 ){ zDb1 = argv[i]; }else if( zDb2==0 ){ zDb2 = argv[i]; | > > > | 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 | if( strcmp(z,"table")==0 ){ if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]); zTab = argv[++i]; }else if( strcmp(z,"transaction")==0 ){ useTransaction = 1; }else if( strcmp(z,"vtab")==0 ){ g.bHandleVtab = 1; }else { cmdlineError("unknown option: %s", argv[i]); } }else if( zDb1==0 ){ zDb1 = argv[i]; }else if( zDb2==0 ){ zDb2 = argv[i]; |
︙ | ︙ | |||
1871 1872 1873 1874 1875 1876 1877 | "WITHOUT ROWID;\n" ); } if( zTab ){ xDiff(zTab, out); }else{ /* Handle tables one by one */ | | < < < < < < < | 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | "WITHOUT ROWID;\n" ); } if( zTab ){ xDiff(zTab, out); }else{ /* Handle tables one by one */ pStmt = db_prepare("%s", all_tables_sql() ); while( SQLITE_ROW==sqlite3_step(pStmt) ){ xDiff((const char*)sqlite3_column_text(pStmt,0), out); } sqlite3_finalize(pStmt); } if( useTransaction ) printf("COMMIT;\n"); /* TBD: Handle trigger differences */ /* TBD: Handle view differences */ sqlite3_close(g.db); return 0; } |
Changes to tool/srcck1.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | (int)got, (int)n, zFilename); exit(1); } z[n] = 0; return z; } | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | (int)got, (int)n, zFilename); exit(1); } z[n] = 0; return z; } /* Check the C code in the argument to see if it might have ** side effects. The only accurate way to know this is to do a full ** parse of the C code, which this routine does not do. This routine ** uses a simple heuristic of looking for: ** ** * '=' not immediately after '>', '<', '!', or '='. ** * '++' ** * '--' |
︙ | ︙ | |||
107 108 109 110 111 112 113 | /* Search for instances of assert(...), ALWAYS(...), NEVER(...), and/or ** testcase(...) where the argument contains side effects. ** ** Print error messages whenever a side effect is found. Return the number ** of problems seen. */ | | | | | | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | /* Search for instances of assert(...), ALWAYS(...), NEVER(...), and/or ** testcase(...) where the argument contains side effects. ** ** Print error messages whenever a side effect is found. Return the number ** of problems seen. */ static unsigned int findAllSideEffects(const char *z){ unsigned int lineno = 1; /* Line number */ unsigned int i; unsigned int nErr = 0; char c, prevC = 0; for(i=0; (c = z[i])!=0; prevC=c, i++){ if( c=='\n' ){ lineno++; continue; } if( isalpha(c) && !isalpha(prevC) ){ if( strncmp(&z[i],"assert(",7)==0 || strncmp(&z[i],"ALWAYS(",7)==0 || strncmp(&z[i],"NEVER(",6)==0 || strncmp(&z[i],"testcase(",9)==0 ){ unsigned int n; const char *z2 = &z[i+5]; while( z2[0]!='(' ){ z2++; } z2++; n = findCloseParen(z2); if( hasSideEffect(z2, n) ){ nErr++; fprintf(stderr, "side-effect line %u: %.*s\n", lineno, (int)(&z2[n+1] - &z[i]), &z[i]); } } } } return nErr; } int main(int argc, char **argv){ char *z; unsigned int nErr = 0; if( argc!=2 ){ fprintf(stderr, "Usage: %s FILENAME\n", argv[0]); return 1; } z = readFile(argv[1]); nErr = findAllSideEffects(z); |
︙ | ︙ |