Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge latest begin-concurrent changes into this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | begin-concurrent-pnu |
Files: | files | file ages | folders |
SHA3-256: |
6f3dd9809fdef7d6195f1f93428a662d |
User & Date: | dan 2018-09-28 21:11:12.916 |
Context
2018-11-26
| ||
07:34 | Merge latest begin-concurrent changes into this branch. (check-in: 76608f750a user: dan tags: begin-concurrent-pnu) | |
2018-09-28
| ||
21:11 | Merge latest begin-concurrent changes into this branch. (check-in: 6f3dd9809f user: dan tags: begin-concurrent-pnu) | |
20:58 | Merge latest trunk into this branch. (check-in: 86750c927c user: dan tags: begin-concurrent) | |
2018-07-12
| ||
19:39 | Merge latest begin-concurrent changes with this branch. (check-in: d33527d223 user: dan tags: begin-concurrent-pnu) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
346 347 348 349 350 351 352 | $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/rtree.h \ | | > | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | $(TOP)/ext/fts3/fts3_unicode2.c \ $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c \ $(TOP)/ext/rtree/geopoly.c SRC += \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3session.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.h \ $(TOP)/ext/rbu/sqlite3rbu.c SRC += \ |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 | $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/test_expert.c \ $(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 \ $(TOP)/ext/misc/mmapwarm.c \ | > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/test_expert.c \ $(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/explain.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 \ $(TOP)/ext/misc/mmapwarm.c \ |
︙ | ︙ | |||
548 549 550 551 552 553 554 | $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ | | > | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/geopoly.c EXTHDR += \ $(TOP)/ext/icu/sqliteicu.h EXTHDR += \ $(TOP)/ext/rtree/sqlite3rtree.h # executables needed for testing # |
︙ | ︙ | |||
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 | changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS) 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.c | > > > | 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS) rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS) atrc$(TEXX): $(TOP)/test/atrc.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/atrc.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.c |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 !ENDIF 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. # | > > > > > > | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1 !ENDIF 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. # |
︙ | ︙ | |||
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 | # This is the source code that the shell executable should be compiled # with. # !IFNDEF SHELL_CORE_SRC !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_SRC = !ELSE SHELL_CORE_SRC = $(SQLITE3C) !ENDIF !ENDIF # This is the core library that the shell executable should depend on. # !IFNDEF SHELL_CORE_DEP !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_DEP = $(SQLITE3DLL) !ELSE SHELL_CORE_DEP = !ENDIF !ENDIF # <<mark>> # If zlib support is enabled, add the dependencies for it. # !IF $(USE_ZLIB)!=0 && $(BUILD_ZLIB)!=0 SHELL_CORE_DEP = zlib $(SHELL_CORE_DEP) TESTFIXTURE_DEP = zlib $(TESTFIXTURE_DEP) !ENDIF # <</mark>> # This is the core library that the shell executable should link with. # !IFNDEF SHELL_CORE_LIB !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_LIB = $(SQLITE3LIB) !ELSE SHELL_CORE_LIB = !ENDIF !ENDIF # These are additional linker options used for the shell executable. # | > > > > > > > > > > > > | 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 | # This is the source code that the shell executable should be compiled # with. # !IFNDEF SHELL_CORE_SRC !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_SRC = # <<mark>> !ELSEIF $(USE_AMALGAMATION)==0 SHELL_CORE_SRC = # <</mark>> !ELSE SHELL_CORE_SRC = $(SQLITE3C) !ENDIF !ENDIF # This is the core library that the shell executable should depend on. # !IFNDEF SHELL_CORE_DEP !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_DEP = $(SQLITE3DLL) # <<mark>> !ELSEIF $(USE_AMALGAMATION)==0 SHELL_CORE_DEP = libsqlite3.lib # <</mark>> !ELSE SHELL_CORE_DEP = !ENDIF !ENDIF # <<mark>> # If zlib support is enabled, add the dependencies for it. # !IF $(USE_ZLIB)!=0 && $(BUILD_ZLIB)!=0 SHELL_CORE_DEP = zlib $(SHELL_CORE_DEP) TESTFIXTURE_DEP = zlib $(TESTFIXTURE_DEP) !ENDIF # <</mark>> # This is the core library that the shell executable should link with. # !IFNDEF SHELL_CORE_LIB !IF $(DYNAMIC_SHELL)!=0 || $(FOR_WIN10)!=0 SHELL_CORE_LIB = $(SQLITE3LIB) # <<mark>> !ELSEIF $(USE_AMALGAMATION)==0 SHELL_CORE_LIB = libsqlite3.lib # <</mark>> !ELSE SHELL_CORE_LIB = !ENDIF !ENDIF # These are additional linker options used for the shell executable. # |
︙ | ︙ | |||
1180 1181 1182 1183 1184 1185 1186 | date.lo dbpage.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ | | | | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 | date.lo dbpage.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo json1.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memdb.lo memjournal.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo upsert.lo util.lo vacuum.lo \ vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \ window.lo utf.lo vtab.lo # <</mark>> |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 | SRC09 = \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rbu\sqlite3rbu.h \ $(TOP)\ext\session\sqlite3session.h # Generated source code files # SRC10 = \ opcodes.c \ | > | 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 | SRC09 = \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\geopoly.c \ $(TOP)\ext\rbu\sqlite3rbu.h \ $(TOP)\ext\session\sqlite3session.h # Generated source code files # SRC10 = \ opcodes.c \ |
︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 | $(TOP)\ext\expert\sqlite3expert.c \ $(TOP)\ext\expert\test_expert.c \ $(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 \ $(TOP)\ext\misc\mmapwarm.c \ | > | 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 | $(TOP)\ext\expert\sqlite3expert.c \ $(TOP)\ext\expert\test_expert.c \ $(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\explain.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 \ $(TOP)\ext\misc\mmapwarm.c \ |
︙ | ︙ | |||
1571 1572 1573 1574 1575 1576 1577 | $(TOP)\ext\fts2\fts2_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h EXTHDR = $(EXTHDR) \ | | > | 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 | $(TOP)\ext\fts2\fts2_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\geopoly.c EXTHDR = $(EXTHDR) \ $(TOP)\ext\icu\sqliteicu.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\rtree\sqlite3rtree.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\session\sqlite3session.h |
︙ | ︙ | |||
1605 1606 1607 1608 1609 1610 1611 | $(TOP)\test\fuzzdata6.db # <</mark>> # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 | < | | | | 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 | $(TOP)\test\fuzzdata6.db # <</mark>> # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF # <<mark>> # Extra compiler options for various test tools. # MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 |
︙ | ︙ | |||
1693 1694 1695 1696 1697 1698 1699 | scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) srcck1.exe: $(TOP)\tool\srcck1.c $(BCC) $(NO_WARN) -Fe$@ $(TOP)\tool\srcck1.c | | | | 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(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 $(SQLITE3C) srcck1.exe $(SQLITE3C) fuzzershell.exe: $(TOP)\tool\fuzzershell.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) |
︙ | ︙ | |||
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 | fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c sqlite3session.lo: $(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\session\sqlite3session.c # FTS5 things | > > > > > > | 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 | fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c json1.lo: $(TOP)\ext\misc\json1.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\json1.c stmt.lo: $(TOP)\ext\misc\stmt.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\stmt.c rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c sqlite3session.lo: $(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\session\sqlite3session.c # FTS5 things |
︙ | ︙ | |||
2262 2263 2264 2265 2266 2267 2268 | # hidden when the library is built via the amalgamation). # TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024 | | | | | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 | # hidden when the library is built via the amalgamation). # TESTFIXTURE_FLAGS = -DTCLSH_INIT_PROC=sqlite3TestInit -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN) TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS) TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2) TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C) !IF $(USE_AMALGAMATION)==0 TESTFIXTURE_SRC = $(TESTSRC) $(TOP)\src\tclsqlite.c $(TESTFIXTURE_SRC0) !ELSE |
︙ | ︙ | |||
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) LogEst.exe: $(TOP)\tool\logest.c $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\LogEst.c /link $(LDFLAGS) $(LTLINKOPTS) wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\test\wordcount.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) | > > > > | 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 | $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\ext\fts3\tool\fts3view.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) rollback-test.exe: $(TOP)\tool\rollback-test.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\tool\rollback-test.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) atrc.exe: $(TOP)\test\atrc.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\test\atrc.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) LogEst.exe: $(TOP)\tool\logest.c $(SQLITE3H) $(LTLINK) $(NO_WARN) $(TOP)\tool\LogEst.c /link $(LDFLAGS) $(LTLINKOPTS) wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\test\wordcount.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) |
︙ | ︙ | |||
2451 2452 2453 2454 2455 2456 2457 | # <</mark>> clean: del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL # <<mark>> | < | | 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 | # <</mark>> clean: del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL # <<mark>> del /Q opcodes.c opcodes.h 2>NUL del /Q lemon.* lempar.c parse.* 2>NUL del /Q mksourceid.* mkkeywordhash.* keywordhash.h 2>NUL del /Q notasharedlib.* 2>NUL -rmdir /Q/S .deps 2>NUL -rmdir /Q/S .libs 2>NUL -rmdir /Q/S tsrc 2>NUL del /Q .target_source 2>NUL del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL del /Q lsm.dll lsmtest.exe 2>NUL del /Q testloadext.dll 2>NUL del /Q testfixture.exe test.db 2>NUL del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL del /Q changeset.exe 2>NUL 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 sqlite3.h 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 sqltclsh.* 2>NUL del /Q dbfuzz.exe sessionfuzz.exe 2>NUL del /Q kvtest.exe ossshell.exe scrub.exe 2>NUL del /Q showshm.exe sqlite3_checker.* sqlite3_expert.exe 2>NUL del /Q fts5.* fts5parse.* 2>NUL del /Q lsm.h lsm1.c 2>NUL # <</mark>> |
Changes to README.md.
1 2 | <h1 align="center">SQLite Source Repository</h1> | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 | <h1 align="center">SQLite Source Repository</h1> This repository contains the complete source code for the [SQLite database engine](https://sqlite.org/). Some test scripts are also included. However, many other test scripts and most of the documentation are managed separately. SQLite [does not use Git](https://sqlite.org/whynotgit.html). If you are reading this on GitHub, then you are looking at an unofficial mirror. See <https://sqlite.org/src> for the official repository. |
︙ | ︙ |
Changes to VERSION.
|
| | | 1 | 3.26.0 |
Changes to autoconf/Makefile.msc.
︙ | ︙ | |||
273 274 275 276 277 278 279 280 281 282 283 284 285 286 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 !ENDIF 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. # | > > > > > > | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | # These are the "standard" SQLite compilation options used when compiling for # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_GEOPOLY=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_INTROSPECTION_PRAGMAS=1 !ENDIF 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. # |
︙ | ︙ | |||
924 925 926 927 928 929 930 | !ENDIF # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 | < | | | | 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | !ENDIF # Additional compiler options for the shell. These are only effective # when the shell is not being dynamically linked. # !IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 !ENDIF # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # core: dll shell |
︙ | ︙ |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
168 169 170 171 172 173 174 | #----------------------------------------------------------------------- # --enable-session # AC_ARG_ENABLE(session, [AS_HELP_STRING( [--enable-session], [enable the session extension [default=no]])], [], []) if test x"$enable_session" = "xyes"; then | | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | #----------------------------------------------------------------------- # --enable-session # AC_ARG_ENABLE(session, [AS_HELP_STRING( [--enable-session], [enable the session extension [default=no]])], [], []) if test x"$enable_session" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-debug # AC_ARG_ENABLE(debug, [AS_HELP_STRING( |
︙ | ︙ |
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.26.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.26.0' PACKAGE_STRING='sqlite 3.26.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
907 908 909 910 911 912 913 914 915 916 917 918 919 920 | enable_memsys5 enable_memsys3 enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_update_limit enable_rtree enable_session enable_gcov ' ac_precious_vars='build_alias host_alias target_alias | > | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | enable_memsys5 enable_memsys3 enable_fts3 enable_fts4 enable_fts5 enable_json1 enable_update_limit enable_geopoly enable_rtree enable_session enable_gcov ' ac_precious_vars='build_alias host_alias target_alias |
︙ | ︙ | |||
1461 1462 1463 1464 1465 1466 1467 | # # 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 | | | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 | # # 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.26.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. |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | --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 | | | 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 | --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.26.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] |
︙ | ︙ | |||
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 | --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-update-limit Enable the UPDATE/DELETE LIMIT clause --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) | > | 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 | --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-update-limit Enable the UPDATE/DELETE LIMIT clause --enable-geopoly Enable the GEOPOLY 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) |
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 | 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.26.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 |
︙ | ︙ | |||
2070 2071 2072 2073 2074 2075 2076 | 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. | | | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 | 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.26.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3928 3929 3930 3931 3932 3933 3934 | { $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 | | | | | 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 | { $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:3937: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3943: 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 |
︙ | ︙ | |||
5140 5141 5142 5143 5144 5145 5146 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5149 "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 |
︙ | ︙ | |||
6665 6666 6667 6668 6669 6670 6671 | # 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:'` | | | | 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 | # 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:6674: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6678: \$? = $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 |
︙ | ︙ | |||
7004 7005 7006 7007 7008 7009 7010 | # 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:'` | | | | 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 | # 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:7013: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7017: \$? = $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 |
︙ | ︙ | |||
7109 7110 7111 7112 7113 7114 7115 | # (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:'` | | | | 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 | # (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:7118: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7122: \$? = $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 |
︙ | ︙ | |||
7164 7165 7166 7167 7168 7169 7170 | # (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:'` | | | | 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 | # (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:7173: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7177: \$? = $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 |
︙ | ︙ | |||
9544 9545 9546 9547 9548 9549 9550 | 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 | | | 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 | 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 9553 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9640 9641 9642 9643 9644 9645 9646 | 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 | | | 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 | 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 9649 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 | if test "${enable_update_limit+set}" = set; then : enableval=$enable_update_limit; fi if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. if test "${enable_rtree+set}" = set; then : enableval=$enable_rtree; fi | > > > > > > > > > > > > > > | 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 | if test "${enable_update_limit+set}" = set; then : enableval=$enable_update_limit; fi if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi ######### # See whether we should enable GEOPOLY # Check whether --enable-geopoly was given. if test "${enable_geopoly+set}" = set; then : enableval=$enable_geopoly; enable_geopoly=yes else enable_geopoly=no fi if test "${enable_geopoly}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes fi ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. if test "${enable_rtree+set}" = set; then : enableval=$enable_rtree; fi |
︙ | ︙ | |||
12212 12213 12214 12215 12216 12217 12218 | 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=" | | | 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 | 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.26.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 $@ |
︙ | ︙ | |||
12278 12279 12280 12281 12282 12283 12284 | 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="\\ | | | 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 | 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.26.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.
︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 653 654 655 656 657 | # See whether we should enable the LIMIT clause on UPDATE and DELETE # statements. AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit], [Enable the UPDATE/DELETE LIMIT clause])) if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension])) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" | > > > > > > > > > > | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | # See whether we should enable the LIMIT clause on UPDATE and DELETE # statements. AC_ARG_ENABLE(update-limit, AC_HELP_STRING([--enable-update-limit], [Enable the UPDATE/DELETE LIMIT clause])) if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi ######### # See whether we should enable GEOPOLY AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly], [Enable the GEOPOLY extension]), [enable_geopoly=yes],[enable_geopoly=no]) if test "${enable_geopoly}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes fi ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension])) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" |
︙ | ︙ |
Added doc/F2FS.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SQLite's OS layer contains the following definitions used in F2FS related calls: #define F2FS_IOCTL_MAGIC 0xf5 #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) #define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) #define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) #define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32) #define F2FS_FEATURE_ATOMIC_WRITE 0x0004 After opening a database file on Linux (including Android), SQLite determines whether or not a file supports F2FS atomic commits as follows: u32 flags = 0; rc = ioctl(fd, F2FS_IOC_GET_FEATURES, &flags); if( rc==0 && (flags & F2FS_FEATURE_ATOMIC_WRITE) ){ /* File supports F2FS atomic commits */ }else{ /* File does NOT support F2FS atomic commits */ } where "fd" is the file-descriptor open on the database file. Usually, when writing to a database file that supports atomic commits, SQLite accumulates the entire transaction in heap memory, deferring all writes to the db file until the transaction is committed. When it is time to commit a transaction on a file that supports atomic commits, SQLite does: /* Take an F_WRLCK lock on the database file. This prevents any other ** SQLite clients from reading or writing the file until the lock ** is released. */ rc = fcntl(fd, F_SETLK, ...); if( rc!=0 ) goto failed; rc = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE); if( rc!=0 ) goto fallback_to_legacy_journal_commit; foreach (dirty page){ rc = write(fd, ...dirty page...); if( rc!=0 ){ ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE); goto fallback_to_legacy_journal_commit; } } rc = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE); if( rc!=0 ){ ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE); goto fallback_to_legacy_journal_commit; } /* If we get there, the transaction has been successfully ** committed to persistent storage. The following call ** relinquishes the F_WRLCK lock. */ fcntl(fd, F_SETLK, ...); Assumptions: 1. After either of the F2FS_IOC_ABORT_VOLATILE_WRITE calls return, the database file is in the state that it was in before F2FS_IOC_START_ATOMIC_WRITE was invoked. Even if the ioctl() fails - we're ignoring the return code. This is true regardless of the type of error that occurred in ioctl() or write(). 2. If the system fails before the F2FS_IOC_COMMIT_ATOMIC_WRITE is completed, then following a reboot the database file is in the state that it was in before F2FS_IOC_START_ATOMIC_WRITE was invoked. Or, if the write was commited right before the system failed, in a state indicating that all write() calls were successfully committed to persistent storage before the failure occurred. 3. If the process crashes before the F2FS_IOC_COMMIT_ATOMIC_WRITE is completed then the file is automatically restored to the state that it was in before F2FS_IOC_START_ATOMIC_WRITE was called. This occurs before the posix advisory lock is automatically dropped - there is no chance that another client will be able to read the file in a half-committed state before the rollback operation occurs. |
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
3804 3805 3806 3807 3808 3809 3810 | ** ** Flush the contents of the pending-terms table to disk. */ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; UNUSED_PARAMETER(iSavepoint); assert( ((Fts3Table *)pVtab)->inTransaction ); | | | 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 | ** ** Flush the contents of the pending-terms table to disk. */ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ int rc = SQLITE_OK; UNUSED_PARAMETER(iSavepoint); assert( ((Fts3Table *)pVtab)->inTransaction ); assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint ); TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint ); if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){ rc = fts3SyncMethod(pVtab); } return rc; } |
︙ | ︙ |
Changes to ext/fts3/unicode/mkunicode.tcl.
︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 | tl_print_if_entry $entry } puts "" puts " return ret;" puts "\}" } proc print_fold_test {zFunc mappings} { global tl_lookup_table foreach m $mappings { set c [lindex $m 1] if {$c == ""} { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | tl_print_if_entry $entry } puts "" puts " return ret;" puts "\}" } proc code {txt} { set txt [string trimright $txt] set txt [string trimleft $txt "\n"] set n [expr {[string length $txt] - [string length [string trim $txt]]}] set ret "" foreach L [split $txt "\n"] { append ret "[string range $L $n end]\n" } return [uplevel "subst -nocommands {$ret}"] } proc intarray {lInt} { set ret "" set n [llength $lInt] for {set i 0} {$i < $n} {incr i 10} { append ret "\n " foreach int [lrange $lInt $i [expr $i+9]] { append ret [format "%-7s" "$int, "] } } append ret "\n " set ret } proc categories_switch {Cvar first lSecond} { upvar $Cvar C set ret "" append ret "case '$first':\n" append ret " switch( zCat\[1\] ){\n" foreach s $lSecond { append ret " case '$s': aArray\[$C($first$s)\] = 1; break;\n" } append ret " case '*': \n" foreach s $lSecond { append ret " aArray\[$C($first$s)\] = 1;\n" } append ret " break;\n" append ret " default: return 1;" append ret " }\n" append ret " break;\n" } # Argument is a list. Each element of which is itself a list of two elements: # # * the codepoint # * the category # # List elements are sorted in order of codepoint. # proc print_categories {lMap} { set categories { Cc Cf Cn Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs LC Co } for {set i 0} {$i < [llength $categories]} {incr i} { set C([lindex $categories $i]) [expr 1+$i] } set caseC [categories_switch C C {c f n s o}] set caseL [categories_switch C L {l m o t u C}] set caseM [categories_switch C M {c e n}] set caseN [categories_switch C N {d l o}] set caseP [categories_switch C P {c d e f i o s}] set caseS [categories_switch C S {c k m o}] set caseZ [categories_switch C Z {l p s}] set nCat [expr [llength [array names C]] + 1] puts [code { int sqlite3Fts5UnicodeNCat(void) { return $nCat; } int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ aArray[0] = 1; switch( zCat[0] ){ $caseC $caseL $caseM $caseN $caseP $caseS $caseZ } return 0; } }] set nRepeat 0 set first [lindex $lMap 0 0] set class [lindex $lMap 0 1] set prev -1 set CASE(0) "Lu" set CASE(1) "Ll" foreach m $lMap { foreach {codepoint cl} $m {} set codepoint [expr "0x$codepoint"] if {$codepoint>=(1<<20)} continue set bNew 0 if {$codepoint!=($prev+1)} { set bNew 1 } elseif { $cl==$class || ($class=="LC" && $cl==$CASE([expr $nRepeat & 0x01])) } { incr nRepeat } elseif {$class=="Lu" && $nRepeat==1 && $cl=="Ll"} { set class LC incr nRepeat } else { set bNew 1 } if {$bNew} { lappend lEntries [list $first $class $nRepeat] set nRepeat 1 set first $codepoint set class $cl } set prev $codepoint } if {$nRepeat>0} { lappend lEntries [list $first $class $nRepeat] } set aBlock [list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] set aMap [list] foreach e $lEntries { foreach {cp class nRepeat} $e {} set block [expr ($cp>>16)] if {$block>0 && [lindex $aBlock $block]==0} { for {set i 1} {$i<=$block} {incr i} { if {[lindex $aBlock $i]==0} { lset aBlock $i [llength $aMap] } } } lappend aMap [expr {$cp & 0xFFFF}] lappend aData [expr {($nRepeat << 5) + $C($class)}] } for {set i 1} {$i<[llength $aBlock]} {incr i} { if {[lindex $aBlock $i]==0} { lset aBlock $i [llength $aMap] } } set aBlockArray [intarray $aBlock] set aMapArray [intarray $aMap] set aDataArray [intarray $aData] puts [code { static u16 aFts5UnicodeBlock[] = {$aBlockArray}; static u16 aFts5UnicodeMap[] = {$aMapArray}; static u16 aFts5UnicodeData[] = {$aDataArray}; int sqlite3Fts5UnicodeCategory(int iCode) { int iRes = -1; int iHi; int iLo; int ret; u16 iKey; if( iCode>=(1<<20) ){ return 0; } iLo = aFts5UnicodeBlock[(iCode>>16)]; iHi = aFts5UnicodeBlock[1+(iCode>>16)]; iKey = (iCode & 0xFFFF); while( iHi>iLo ){ int iTest = (iHi + iLo) / 2; assert( iTest>=iLo && iTest<iHi ); if( iKey>=aFts5UnicodeMap[iTest] ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest; } } if( iRes<0 ) return 0; if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0; ret = aFts5UnicodeData[iRes] & 0x1F; if( ret!=$C(LC) ) return ret; return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? $C(Ll) : $C(Lu); } void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = bToken; } iTbl++; } } }] } proc print_test_categories {lMap} { set lCP [list] foreach e $lMap { foreach {cp cat} $e {} if {[expr 0x$cp] < (1<<20)} { lappend lCP "{0x$cp, \"$cat\"}, " } } set aCP "\n" for {set i 0} {$i < [llength $lCP]} {incr i 4} { append aCP " [join [lrange $lCP $i $i+3]]\n" } puts [code { static int categories_test (int *piCode){ struct Codepoint { int iCode; const char *zCat; } aCP[] = {$aCP}; int i; int iCP = 0; for(i=0; i<1000000; i++){ u8 aArray[40]; int cat = 0; int c = 0; memset(aArray, 0, sizeof(aArray)); if( aCP[iCP].iCode==i ){ sqlite3Fts5UnicodeCatParse(aCP[iCP].zCat, aArray); iCP++; }else{ aArray[0] = 1; } c = sqlite3Fts5UnicodeCategory(i); if( aArray[c]==0 ){ *piCode = i; return 1; } } return 0; } }] } proc print_fold_test {zFunc mappings} { global tl_lookup_table foreach m $mappings { set c [lindex $m 1] if {$c == ""} { |
︙ | ︙ | |||
601 602 603 604 605 606 607 | } proc print_test_main {} { puts "" puts "#include <stdio.h>" puts "" puts "int main(int argc, char **argv)\{" | | > > > > > > | | 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 | } proc print_test_main {} { puts "" puts "#include <stdio.h>" puts "" puts "int main(int argc, char **argv)\{" puts " int r1, r2, r3;" puts " int code;" puts " r3 = 0;" puts " r1 = isalnum_test(&code);" puts " if( r1 ) printf(\"isalnum(): Problem with code %d\\n\",code);" puts " else printf(\"isalnum(): test passed\\n\");" puts " r2 = fold_test(&code);" puts " if( r2 ) printf(\"fold(): Problem with code %d\\n\",code);" puts " else printf(\"fold(): test passed\\n\");" if {$::generate_fts5_code} { puts " r3 = categories_test(&code);" puts " if( r3 ) printf(\"categories(): Problem with code %d\\n\",code);" puts " else printf(\"categories(): test passed\\n\");" } puts " return (r1 || r2 || r3);" puts "\}" } # Proces the command line arguments. Exit early if they are not to # our liking. # proc usage {} { |
︙ | ︙ | |||
646 647 648 649 650 651 652 653 654 655 656 | default { usage } } } print_fileheader # Print the isalnum() function to stdout. # set lRange [an_load_separator_ranges] | > > > > > > > | > | 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 | default { usage } } } print_fileheader if {$::generate_test_code} { puts "typedef unsigned short int u16;" puts "typedef unsigned char u8;" puts "#include <string.h>" } # Print the isalnum() function to stdout. # set lRange [an_load_separator_ranges] if {$generate_fts5_code==0} { print_isalnum ${function_prefix}UnicodeIsalnum $lRange } # Leave a gap between the two generated C functions. # puts "" puts "" # Load the fold data. This is used by the [rd_XXX] commands |
︙ | ︙ | |||
672 673 674 675 676 677 678 679 680 681 682 683 | print_isdiacritic ${function_prefix}UnicodeIsdiacritic $mappings puts "" puts "" # Print the fold() function to stdout. # print_fold ${function_prefix}UnicodeFold # Print the test routines and main() function to stdout, if -test # was specified. # if {$::generate_test_code} { | > > > > > > > | > > | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | print_isdiacritic ${function_prefix}UnicodeIsdiacritic $mappings puts "" puts "" # Print the fold() function to stdout. # print_fold ${function_prefix}UnicodeFold if {$generate_fts5_code} { puts "" puts "" print_categories [cc_load_unicodedata_text ${unicodedata.txt}] } # Print the test routines and main() function to stdout, if -test # was specified. # if {$::generate_test_code} { if {$generate_fts5_code==0} { print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange } print_fold_test ${function_prefix}UnicodeFold $mappings print_test_categories [cc_load_unicodedata_text ${unicodedata.txt}] print_test_main } if {$generate_fts5_code} { # no-op } else { puts "#endif /* defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) */" puts "#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */" } |
Changes to ext/fts3/unicode/parseunicode.tcl.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 | foreach elem $c { lappend c2 [expr "0x[string trim $elem]"] } set b [string trim $b] set d [string trim $d] if {$b=="C" || $b=="S"} { set tl_lookup_table($a2) $c2 } } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | foreach elem $c { lappend c2 [expr "0x[string trim $elem]"] } set b [string trim $b] set d [string trim $d] if {$b=="C" || $b=="S"} { set tl_lookup_table($a2) $c2 } } } proc cc_load_unicodedata_text {zName} { set fd [open $zName] set lField { code character_name general_category canonical_combining_classes bidirectional_category character_decomposition_mapping decimal_digit_value digit_value numeric_value mirrored unicode_1_name iso10646_comment_field uppercase_mapping lowercase_mapping titlecase_mapping } set lRet [list] while { ![eof $fd] } { set line [gets $fd] if {$line == ""} continue set fields [split $line ";"] if {[llength $fields] != [llength $lField]} { error "parse error: $line" } foreach $lField $fields {} lappend lRet [list $code $general_category] } close $fd set lRet } |
Changes to ext/fts5/fts5.h.
︙ | ︙ | |||
440 441 442 443 444 445 446 | ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms ** when tokenizing query text (it should not - to do would be ** inefficient), it doesn't matter if the user queries for | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | ** document such as "I won first place" is tokenized, entries are ** added to the FTS index for "i", "won", "first", "1st" and ** "place". ** ** This way, even if the tokenizer does not provide synonyms ** when tokenizing query text (it should not - to do would be ** inefficient), it doesn't matter if the user queries for ** 'first + place' or '1st + place', as there are entries in the ** FTS index corresponding to both forms of the first token. ** </ol> ** ** Whether it is parsing document or query text, any call to xToken that ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit ** is considered to supply a synonym for the previous token. For example, ** when parsing the document "I won first place", a tokenizer that supports |
︙ | ︙ | |||
468 469 470 471 472 473 474 | ** There is no limit to the number of synonyms that may be provided for a ** single token. ** ** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the | | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | ** There is no limit to the number of synonyms that may be provided for a ** single token. ** ** In many cases, method (1) above is the best approach. It does not add ** extra data to the FTS index or require FTS5 to query for multiple terms, ** so it is efficient in terms of disk space and query speed. However, it ** does not support prefix queries very well. If, as suggested above, the ** token "first" is substituted for "1st" by the tokenizer, then the query: ** ** <codeblock> ** ... MATCH '1s*'</codeblock> ** ** will not match documents that contain the token "1st" (as the tokenizer ** will probably not map "1s" to any prefix of "first"). ** |
︙ | ︙ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
780 781 782 783 784 785 786 | ** End of interface to code in fts5_vocab.c. **************************************************************************/ /************************************************************************** ** Interface to automatically generated code in fts5_unicode2.c. */ | | > > | | > | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | ** End of interface to code in fts5_vocab.c. **************************************************************************/ /************************************************************************** ** Interface to automatically generated code in fts5_unicode2.c. */ int sqlite3Fts5UnicodeIsdiacritic(int c); int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic); int sqlite3Fts5UnicodeCatParse(const char*, u8*); int sqlite3Fts5UnicodeCategory(int iCode); void sqlite3Fts5UnicodeAscii(u8*, u8*); /* ** End of interface to code in fts5_unicode2.c. **************************************************************************/ #endif |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 | */ static void fts5ExprIsAlnum( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ int iCode; if( nArg!=1 ){ sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_isalnum", -1 ); return; } iCode = sqlite3_value_int(apVal[0]); | > > > > > | | 2537 2538 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 | */ static void fts5ExprIsAlnum( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ int iCode; u8 aArr[32]; if( nArg!=1 ){ sqlite3_result_error(pCtx, "wrong number of arguments to function fts5_isalnum", -1 ); return; } memset(aArr, 0, sizeof(aArr)); sqlite3Fts5UnicodeCatParse("L*", aArr); sqlite3Fts5UnicodeCatParse("N*", aArr); sqlite3Fts5UnicodeCatParse("Co", aArr); iCode = sqlite3_value_int(apVal[0]); sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]); } static void fts5ExprFold( sqlite3_context *pCtx, /* Function call context */ int nArg, /* Number of args */ sqlite3_value **apVal /* Function arguments */ ){ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
5257 5258 5259 5260 5261 5262 5263 | int nChar ){ int n = 0; int i; for(i=0; i<nChar; i++){ if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ | | > > > | 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 | int nChar ){ int n = 0; int i; for(i=0; i<nChar; i++){ if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */ if( (unsigned char)p[n++]>=0xc0 ){ while( (p[n] & 0xc0)==0x80 ){ n++; if( n>=nByte ) break; } } } return n; } /* ** pIn is a UTF-8 encoded string, nIn bytes in size. Return the number of |
︙ | ︙ |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
276 277 278 279 280 281 282 | assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); p->ts.eState = 0; break; case FTS5_SAVEPOINT: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); p->ts.eState = 0; break; case FTS5_SAVEPOINT: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); assert( iSavepoint>=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; case FTS5_RELEASE: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); assert( iSavepoint<=p->ts.iSavepoint ); |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 | ** return results to the user for this query. The current cursor ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ 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 = ""; | > > > > > > > | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 | ** return results to the user for this query. The current cursor ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ 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 ); if( pTab->pSortCsr->bDesc ){ pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid; pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid; }else{ pCsr->iLastRowid = pTab->pSortCsr->iLastRowid; pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid; } 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 = ""; |
︙ | ︙ |
Changes to ext/fts5/fts5_tokenize.c.
︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 246 | struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ char *aFold; /* Buffer to fold text into */ int nFold; /* Size of aFold[] in bytes */ int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ int nException; int *aiException; }; static int fts5UnicodeAddExceptions( Unicode61Tokenizer *p, /* Tokenizer object */ const char *z, /* Characters to treat as exceptions */ int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ ){ | > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | struct Unicode61Tokenizer { unsigned char aTokenChar[128]; /* ASCII range token characters */ char *aFold; /* Buffer to fold text into */ int nFold; /* Size of aFold[] in bytes */ int bRemoveDiacritic; /* True if remove_diacritics=1 is set */ int nException; int *aiException; unsigned char aCategory[32]; /* True for token char categories */ }; static int fts5UnicodeAddExceptions( Unicode61Tokenizer *p, /* Tokenizer object */ const char *z, /* Characters to treat as exceptions */ int bTokenChars /* 1 for 'tokenchars', 0 for 'separators' */ ){ |
︙ | ︙ | |||
257 258 259 260 261 262 263 | while( zCsr<zTerm ){ int iCode; int bToken; READ_UTF8(zCsr, zTerm, iCode); if( iCode<128 ){ p->aTokenChar[iCode] = (unsigned char)bTokenChars; }else{ | | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | while( zCsr<zTerm ){ int iCode; int bToken; READ_UTF8(zCsr, zTerm, iCode); if( iCode<128 ){ p->aTokenChar[iCode] = (unsigned char)bTokenChars; }else{ bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]; assert( (bToken==0 || bToken==1) ); assert( (bTokenChars==0 || bTokenChars==1) ); if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){ int i; for(i=0; i<nNew; i++){ if( aNew[i]>iCode ) break; } |
︙ | ︙ | |||
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 | Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok; sqlite3_free(p->aiException); sqlite3_free(p->aFold); sqlite3_free(p); } return; } /* ** Create a "unicode61" tokenizer. */ static int fts5UnicodeCreate( void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; /* Return code */ Unicode61Tokenizer *p = 0; /* New tokenizer object */ UNUSED_PARAM(pUnused); if( nArg%2 ){ rc = SQLITE_ERROR; }else{ p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); if( p ){ int i; memset(p, 0, sizeof(Unicode61Tokenizer)); | > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | | > | 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 | Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok; sqlite3_free(p->aiException); sqlite3_free(p->aFold); sqlite3_free(p); } return; } static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){ const char *z = zCat; while( *z ){ while( *z==' ' || *z=='\t' ) z++; if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){ return SQLITE_ERROR; } while( *z!=' ' && *z!='\t' && *z!='\0' ) z++; } sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar); return SQLITE_OK; } /* ** Create a "unicode61" tokenizer. */ static int fts5UnicodeCreate( void *pUnused, const char **azArg, int nArg, Fts5Tokenizer **ppOut ){ int rc = SQLITE_OK; /* Return code */ Unicode61Tokenizer *p = 0; /* New tokenizer object */ UNUSED_PARAM(pUnused); if( nArg%2 ){ rc = SQLITE_ERROR; }else{ p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); if( p ){ const char *zCat = "L* N* Co"; int i; memset(p, 0, sizeof(Unicode61Tokenizer)); p->bRemoveDiacritic = 1; p->nFold = 64; p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } /* Search for a "categories" argument */ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ if( 0==sqlite3_stricmp(azArg[i], "categories") ){ zCat = azArg[i+1]; } } if( rc==SQLITE_OK ){ rc = unicodeSetCategories(p, zCat); } for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ const char *zArg = azArg[i+1]; if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){ rc = SQLITE_ERROR; } p->bRemoveDiacritic = (zArg[0]=='1'); }else if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ rc = fts5UnicodeAddExceptions(p, zArg, 1); }else if( 0==sqlite3_stricmp(azArg[i], "separators") ){ rc = fts5UnicodeAddExceptions(p, zArg, 0); }else if( 0==sqlite3_stricmp(azArg[i], "categories") ){ /* no-op */ }else{ rc = SQLITE_ERROR; } } }else{ rc = SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ fts5UnicodeDelete((Fts5Tokenizer*)p); p = 0; } *ppOut = (Fts5Tokenizer*)p; } return rc; } /* ** Return true if, for the purposes of tokenizing with the tokenizer ** passed as the first argument, codepoint iCode is considered a token ** character (not a separator). */ static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){ return ( p->aCategory[sqlite3Fts5UnicodeCategory(iCode)] ^ fts5UnicodeIsException(p, iCode) ); } static int fts5UnicodeTokenize( Fts5Tokenizer *pTokenizer, void *pCtx, int iUnused, const char *pText, int nText, |
︙ | ︙ |
Changes to ext/fts5/fts5_unicode2.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | /* ** DO NOT EDIT THIS MACHINE GENERATED FILE. */ #include <assert.h> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /* ** DO NOT EDIT THIS MACHINE GENERATED FILE. */ #include <assert.h> /* ** If the argument is a codepoint corresponding to a lowercase letter ** in the ASCII range with a diacritic added, return the codepoint ** of the ASCII letter only. For example, if passed 235 - "LATIN ** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER |
︙ | ︙ | |||
354 355 356 357 358 359 360 | else if( c>=66560 && c<66600 ){ ret = c + 40; } return ret; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | else if( c>=66560 && c<66600 ){ ret = c + 40; } return ret; } #if 0 int sqlite3Fts5UnicodeNCat(void) { return 32; } #endif int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ aArray[0] = 1; switch( zCat[0] ){ case 'C': switch( zCat[1] ){ case 'c': aArray[1] = 1; break; case 'f': aArray[2] = 1; break; case 'n': aArray[3] = 1; break; case 's': aArray[4] = 1; break; case 'o': aArray[31] = 1; break; case '*': aArray[1] = 1; aArray[2] = 1; aArray[3] = 1; aArray[4] = 1; aArray[31] = 1; break; default: return 1; } break; case 'L': switch( zCat[1] ){ case 'l': aArray[5] = 1; break; case 'm': aArray[6] = 1; break; case 'o': aArray[7] = 1; break; case 't': aArray[8] = 1; break; case 'u': aArray[9] = 1; break; case 'C': aArray[30] = 1; break; case '*': aArray[5] = 1; aArray[6] = 1; aArray[7] = 1; aArray[8] = 1; aArray[9] = 1; aArray[30] = 1; break; default: return 1; } break; case 'M': switch( zCat[1] ){ case 'c': aArray[10] = 1; break; case 'e': aArray[11] = 1; break; case 'n': aArray[12] = 1; break; case '*': aArray[10] = 1; aArray[11] = 1; aArray[12] = 1; break; default: return 1; } break; case 'N': switch( zCat[1] ){ case 'd': aArray[13] = 1; break; case 'l': aArray[14] = 1; break; case 'o': aArray[15] = 1; break; case '*': aArray[13] = 1; aArray[14] = 1; aArray[15] = 1; break; default: return 1; } break; case 'P': switch( zCat[1] ){ case 'c': aArray[16] = 1; break; case 'd': aArray[17] = 1; break; case 'e': aArray[18] = 1; break; case 'f': aArray[19] = 1; break; case 'i': aArray[20] = 1; break; case 'o': aArray[21] = 1; break; case 's': aArray[22] = 1; break; case '*': aArray[16] = 1; aArray[17] = 1; aArray[18] = 1; aArray[19] = 1; aArray[20] = 1; aArray[21] = 1; aArray[22] = 1; break; default: return 1; } break; case 'S': switch( zCat[1] ){ case 'c': aArray[23] = 1; break; case 'k': aArray[24] = 1; break; case 'm': aArray[25] = 1; break; case 'o': aArray[26] = 1; break; case '*': aArray[23] = 1; aArray[24] = 1; aArray[25] = 1; aArray[26] = 1; break; default: return 1; } break; case 'Z': switch( zCat[1] ){ case 'l': aArray[27] = 1; break; case 'p': aArray[28] = 1; break; case 's': aArray[29] = 1; break; case '*': aArray[27] = 1; aArray[28] = 1; aArray[29] = 1; break; default: return 1; } break; } return 0; } static u16 aFts5UnicodeBlock[] = { 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1760, 1763, 1765, }; static u16 aFts5UnicodeMap[] = { 0, 32, 33, 36, 37, 40, 41, 42, 43, 44, 45, 46, 48, 58, 60, 63, 65, 91, 92, 93, 94, 95, 96, 97, 123, 124, 125, 126, 127, 160, 161, 162, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 180, 181, 182, 184, 185, 186, 187, 188, 191, 192, 215, 216, 223, 247, 248, 256, 312, 313, 329, 330, 377, 383, 385, 387, 388, 391, 394, 396, 398, 402, 403, 405, 406, 409, 412, 414, 415, 417, 418, 423, 427, 428, 431, 434, 436, 437, 440, 442, 443, 444, 446, 448, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 477, 478, 496, 497, 498, 499, 500, 503, 505, 506, 564, 570, 572, 573, 575, 577, 580, 583, 584, 592, 660, 661, 688, 706, 710, 722, 736, 741, 748, 749, 750, 751, 768, 880, 884, 885, 886, 890, 891, 894, 900, 902, 903, 904, 908, 910, 912, 913, 931, 940, 975, 977, 978, 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072, 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369, 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473, 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545, 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611, 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758, 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791, 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984, 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075, 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210, 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369, 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416, 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482, 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519, 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561, 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622, 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677, 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749, 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790, 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869, 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902, 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947, 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006, 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059, 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134, 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199, 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263, 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302, 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402, 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458, 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544, 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655, 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737, 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773, 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860, 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967, 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046, 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153, 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190, 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229, 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295, 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704, 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888, 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743, 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906, 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068, 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107, 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160, 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435, 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480, 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679, 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754, 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824, 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978, 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043, 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098, 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168, 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288, 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406, 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616, 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976, 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033, 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118, 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141, 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184, 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219, 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249, 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275, 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317, 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413, 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459, 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484, 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500, 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523, 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597, 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623, 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972, 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180, 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665, 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091, 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217, 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627, 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750, 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365, 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393, 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520, 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696, 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780, 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800, 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812, 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904, 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296, 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317, 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347, 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449, 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736, 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938, 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981, 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528, 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624, 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800, 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912, 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043, 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136, 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264, 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395, 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472, 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588, 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643, 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713, 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762, 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003, 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203, 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112, 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320, 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020, 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075, 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086, 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097, 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118, 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279, 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294, 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343, 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378, 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490, 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529, 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263, 311, 320, 373, 377, 394, 400, 464, 509, 640, 672, 768, 800, 816, 833, 834, 842, 896, 927, 928, 968, 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103, 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432, 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623, 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912, 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178, 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285, 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416, 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760, 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216, 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248, 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637, 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298, 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441, 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541, 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662, 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922, 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062, 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178, 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961, 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003, 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028, 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099, 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744, 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368, 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971, 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488, 1, 32, 256, 0, 65533, }; static u16 aFts5UnicodeData[] = { 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53, 49, 85, 333, 85, 121, 85, 841, 54, 53, 50, 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61, 53, 151, 58, 53, 56, 58, 39, 52, 57, 34, 58, 56, 58, 57, 79, 56, 37, 85, 56, 47, 39, 51, 111, 53, 745, 57, 233, 773, 57, 261, 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126, 126, 73, 69, 137, 37, 73, 37, 105, 101, 73, 37, 73, 37, 190, 158, 37, 126, 126, 73, 37, 126, 94, 37, 39, 94, 69, 135, 41, 40, 37, 41, 40, 37, 41, 40, 37, 542, 37, 606, 37, 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37, 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582, 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596, 158, 38, 56, 94, 38, 101, 53, 88, 41, 53, 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105, 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541, 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38, 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76, 53, 76, 53, 44, 871, 103, 85, 162, 121, 85, 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684, 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58, 204, 70, 76, 58, 140, 71, 333, 103, 90, 39, 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333, 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300, 38, 108, 38, 172, 501, 807, 108, 53, 39, 359, 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268, 138, 44, 74, 39, 236, 327, 76, 85, 333, 53, 38, 199, 231, 44, 74, 263, 71, 711, 231, 39, 135, 44, 39, 106, 140, 74, 74, 44, 39, 42, 71, 103, 76, 333, 71, 87, 207, 58, 55, 76, 42, 199, 71, 711, 231, 71, 71, 71, 44, 106, 76, 76, 108, 44, 135, 39, 333, 76, 103, 44, 76, 42, 295, 103, 711, 231, 71, 167, 44, 39, 106, 172, 76, 42, 74, 44, 39, 71, 76, 333, 53, 55, 44, 74, 263, 71, 711, 231, 71, 167, 44, 39, 42, 44, 42, 140, 74, 74, 44, 44, 42, 71, 103, 76, 333, 58, 39, 207, 44, 39, 199, 103, 135, 71, 39, 71, 71, 103, 391, 74, 44, 74, 106, 106, 44, 39, 42, 333, 111, 218, 55, 58, 106, 263, 103, 743, 327, 167, 39, 108, 138, 108, 140, 76, 71, 71, 76, 333, 239, 58, 74, 263, 103, 743, 327, 167, 44, 39, 42, 44, 170, 44, 74, 74, 76, 74, 39, 71, 76, 333, 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106, 44, 39, 42, 71, 76, 333, 207, 58, 199, 74, 583, 775, 295, 39, 231, 44, 106, 108, 44, 266, 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268, 53, 333, 85, 71, 39, 71, 39, 39, 135, 231, 103, 39, 39, 71, 135, 44, 71, 204, 76, 39, 167, 38, 204, 333, 135, 39, 122, 501, 58, 53, 122, 76, 218, 333, 335, 58, 44, 58, 44, 58, 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42, 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90, 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76, 74, 76, 39, 333, 213, 199, 74, 76, 135, 108, 39, 106, 71, 234, 103, 140, 423, 44, 74, 76, 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41, 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319, 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151, 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551, 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108, 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76, 42, 236, 266, 44, 74, 364, 117, 38, 117, 55, 39, 44, 333, 335, 213, 49, 149, 108, 61, 333, 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138, 76, 106, 74, 44, 202, 108, 58, 85, 333, 967, 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76, 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44, 74, 268, 202, 332, 44, 333, 333, 245, 38, 213, 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44, 74, 231, 333, 245, 346, 300, 314, 76, 42, 967, 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415, 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159, 266, 268, 74, 76, 181, 333, 103, 333, 967, 198, 85, 277, 108, 53, 428, 42, 236, 135, 44, 135, 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260, 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265, 261, 265, 197, 201, 261, 41, 41, 41, 94, 229, 265, 453, 261, 264, 261, 264, 261, 264, 165, 69, 137, 40, 56, 37, 120, 101, 69, 137, 40, 120, 133, 69, 137, 120, 261, 169, 120, 101, 69, 137, 40, 88, 381, 162, 209, 85, 52, 51, 54, 84, 51, 54, 52, 277, 59, 60, 162, 61, 309, 52, 51, 149, 80, 117, 57, 54, 50, 373, 57, 53, 48, 341, 61, 162, 194, 47, 38, 207, 121, 54, 50, 38, 335, 121, 54, 50, 422, 855, 428, 139, 44, 107, 396, 90, 41, 154, 41, 90, 37, 105, 69, 105, 37, 58, 41, 90, 57, 169, 218, 41, 58, 41, 58, 41, 58, 137, 58, 37, 137, 37, 135, 37, 90, 69, 73, 185, 94, 101, 58, 57, 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186, 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018, 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666, 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217, 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57, 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281, 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69, 254, 105, 37, 94, 37, 94, 165, 70, 105, 37, 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221, 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231, 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52, 51, 117, 52, 51, 53, 52, 51, 309, 49, 85, 49, 53, 52, 51, 85, 52, 51, 54, 50, 54, 50, 54, 50, 54, 50, 181, 38, 341, 81, 858, 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 90, 54, 50, 54, 50, 54, 50, 54, 50, 49, 54, 82, 58, 302, 140, 74, 49, 166, 90, 110, 38, 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887, 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178, 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274, 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38, 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333, 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798, 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69, 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382, 70, 37, 231, 44, 103, 44, 135, 44, 743, 74, 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74, 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333, 903, 268, 85, 743, 364, 74, 53, 935, 108, 42, 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333, 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263, 44, 42, 333, 149, 519, 38, 199, 122, 39, 42, 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44, 39, 71, 38, 85, 359, 42, 76, 74, 85, 39, 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74, 44, 74, 44, 74, 53, 42, 44, 333, 39, 39, 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399, 229, 165, 39, 44, 327, 57, 423, 167, 39, 71, 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55, 58, 524, 245, 54, 50, 53, 236, 53, 81, 80, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 54, 50, 85, 54, 50, 149, 112, 117, 149, 49, 54, 50, 54, 50, 54, 50, 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34, 117, 55, 117, 54, 50, 53, 57, 53, 49, 85, 333, 85, 121, 85, 841, 54, 53, 50, 56, 48, 56, 837, 54, 57, 50, 57, 54, 50, 53, 54, 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199, 103, 87, 57, 56, 58, 87, 58, 153, 90, 98, 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455, 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575, 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263, 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71, 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799, 71, 39, 108, 76, 140, 135, 103, 871, 108, 44, 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615, 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655, 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34, 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149, 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383, 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182, 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898, 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236, 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837, 841, 229, 581, 841, 837, 41, 73, 41, 73, 137, 265, 133, 37, 229, 357, 841, 837, 73, 137, 265, 233, 837, 73, 137, 169, 41, 233, 837, 841, 837, 841, 837, 841, 837, 841, 837, 841, 837, 841, 901, 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71, 39, 39, 327, 135, 39, 39, 39, 39, 39, 39, 103, 71, 39, 39, 39, 39, 39, 39, 71, 39, 135, 231, 135, 135, 39, 327, 551, 103, 167, 551, 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946, 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210, 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266, 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351, 34, 3074, 7692, 63, 63, }; int sqlite3Fts5UnicodeCategory(int iCode) { int iRes = -1; int iHi; int iLo; int ret; u16 iKey; if( iCode>=(1<<20) ){ return 0; } iLo = aFts5UnicodeBlock[(iCode>>16)]; iHi = aFts5UnicodeBlock[1+(iCode>>16)]; iKey = (iCode & 0xFFFF); while( iHi>iLo ){ int iTest = (iHi + iLo) / 2; assert( iTest>=iLo && iTest<iHi ); if( iKey>=aFts5UnicodeMap[iTest] ){ iRes = iTest; iLo = iTest+1; }else{ iHi = iTest; } } if( iRes<0 ) return 0; if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0; ret = aFts5UnicodeData[iRes] & 0x1F; if( ret!=30 ) return ret; return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9; } void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int i = 0; int iTbl = 0; while( i<128 ){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } } |
Added ext/fts5/test/fts5cat.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 Jan 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. # #************************************************************************* # source [file join [file dirname [info script]] fts5_common.tcl] ifcapable !fts5 { finish_test ; return } set ::testprefix fts5cat do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize="unicode61 categories 'L*'"); INSERT INTO t1 VALUES ('Unlike1option2values3and4column5names'); } do_execsql_test 1.1 { SELECT rowid FROM t1('option'); } {1} do_execsql_test 1.2 { CREATE VIRTUAL TABLE t2 USING fts5(x); CREATE VIRTUAL TABLE t2t USING fts5vocab(t2, row); CREATE VIRTUAL TABLE t3 USING fts5( x, tokenize="unicode61 categories 'L* N* Co Mn'" ); CREATE VIRTUAL TABLE t3t USING fts5vocab(t3, row); CREATE VIRTUAL TABLE t4 USING fts5( x, tokenize="unicode61 categories 'L* N* Co M*'" ); CREATE VIRTUAL TABLE t4t USING fts5vocab(t4, row); INSERT INTO t2 VALUES ('สนามกีฬา'); INSERT INTO t3 VALUES ('สนามกีฬา'); INSERT INTO t4 VALUES ('สนามกีฬา'); } do_execsql_test 1.3 { SELECT * FROM t2t } {สนามก 1 1 ฬา 1 1} do_execsql_test 1.4 { SELECT * FROM t3t } {สนามกีฬา 1 1} do_execsql_test 1.5 { SELECT * FROM t4t } {สนามกีฬา 1 1} finish_test |
Changes to ext/fts5/test/fts5rank.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 | ); 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}} | > > > > > > | > | > > > > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | ); 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}} #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE VIRTUAL TABLE ttt USING fts5(a); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO ttt SELECT 'word ' || i FROM s; } do_execsql_test 5.1 { SELECT rowid FROM ttt('word') WHERE rowid BETWEEN 30 AND 40 ORDER BY rank; } {30 31 32 33 34 35 36 37 38 39 40} finish_test |
Added ext/fts5/test/fts5unicode4.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 | # 2018 July 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. # #*********************************************************************** # # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5unicode4 # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } do_execsql_test 1.0 { CREATE VIRTUAL TABLE sss USING fts5(a, prefix=3); } do_execsql_test 1.1 { INSERT INTO sss VALUES('まりや'); } finish_test |
Changes to ext/misc/completion.c.
︙ | ︙ | |||
361 362 363 364 365 366 367 | completionCursorReset(pCur); if( idxNum & 1 ){ pCur->nPrefix = sqlite3_value_bytes(argv[iArg]); if( pCur->nPrefix>0 ){ pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); if( pCur->zPrefix==0 ) return SQLITE_NOMEM; } | | < | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | completionCursorReset(pCur); if( idxNum & 1 ){ pCur->nPrefix = sqlite3_value_bytes(argv[iArg]); if( pCur->nPrefix>0 ){ pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); if( pCur->zPrefix==0 ) return SQLITE_NOMEM; } iArg = 1; } if( idxNum & 2 ){ pCur->nLine = sqlite3_value_bytes(argv[iArg]); if( pCur->nLine>0 ){ pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); if( pCur->zLine==0 ) return SQLITE_NOMEM; } } if( pCur->zLine!=0 && pCur->zPrefix==0 ){ int i = pCur->nLine; while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){ i--; } pCur->nPrefix = pCur->nLine - i; |
︙ | ︙ |
Added ext/misc/explain.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 | /* ** 2018-09-16 ** ** 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 an eponymous virtual table that returns the ** EXPLAIN output from an SQL statement. ** ** Usage example: ** ** .load ./explain ** SELECT p2 FROM explain('SELECT * FROM sqlite_master') ** WHERE opcode='OpenRead'; */ #if !defined(SQLITEINT_H) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* explain_vtab is a subclass of sqlite3_vtab which will ** serve as the underlying representation of a explain virtual table */ typedef struct explain_vtab explain_vtab; struct explain_vtab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this explain vtab */ }; /* explain_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 from an EXPLAIN operation. */ typedef struct explain_cursor explain_cursor; struct explain_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this cursor */ char *zSql; /* Value for the EXPLN_COLUMN_SQL column */ sqlite3_stmt *pExplain; /* Statement being explained */ int rc; /* Result of last sqlite3_step() on pExplain */ }; /* ** The explainConnect() method is invoked to create a new ** explain_vtab that describes the explain virtual table. ** ** Think of this routine as the constructor for explain_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the explain_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against explain will look like. */ static int explainConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ explain_vtab *pNew; int rc; /* Column numbers */ #define EXPLN_COLUMN_ADDR 0 /* Instruction address */ #define EXPLN_COLUMN_OPCODE 1 /* Opcode */ #define EXPLN_COLUMN_P1 2 /* Operand 1 */ #define EXPLN_COLUMN_P2 3 /* Operand 2 */ #define EXPLN_COLUMN_P3 4 /* Operand 3 */ #define EXPLN_COLUMN_P4 5 /* Operand 4 */ #define EXPLN_COLUMN_P5 6 /* Operand 5 */ #define EXPLN_COLUMN_COMMENT 7 /* Comment */ #define EXPLN_COLUMN_SQL 8 /* SQL that is being explained */ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(addr,opcode,p1,p2,p3,p4,p5,comment,sql HIDDEN)"); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; } return rc; } /* ** This method is the destructor for explain_cursor objects. */ static int explainDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new explain_cursor object. */ static int explainOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ explain_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->db = ((explain_vtab*)p)->db; *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a explain_cursor. */ static int explainClose(sqlite3_vtab_cursor *cur){ explain_cursor *pCur = (explain_cursor*)cur; sqlite3_finalize(pCur->pExplain); sqlite3_free(pCur->zSql); sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a explain_cursor to its next row of output. */ static int explainNext(sqlite3_vtab_cursor *cur){ explain_cursor *pCur = (explain_cursor*)cur; pCur->rc = sqlite3_step(pCur->pExplain); if( pCur->rc!=SQLITE_DONE && pCur->rc!=SQLITE_ROW ) return pCur->rc; return SQLITE_OK; } /* ** Return values of columns for the row at which the explain_cursor ** is currently pointing. */ static int explainColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ explain_cursor *pCur = (explain_cursor*)cur; if( i==EXPLN_COLUMN_SQL ){ sqlite3_result_text(ctx, pCur->zSql, -1, SQLITE_TRANSIENT); }else{ sqlite3_result_value(ctx, sqlite3_column_value(pCur->pExplain, i)); } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int explainRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ explain_cursor *pCur = (explain_cursor*)cur; *pRowid = sqlite3_column_int64(pCur->pExplain, 0); return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int explainEof(sqlite3_vtab_cursor *cur){ explain_cursor *pCur = (explain_cursor*)cur; return pCur->rc!=SQLITE_ROW; } /* ** This method is called to "rewind" the explain_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to explainColumn() or explainRowid() or ** explainEof(). ** ** The argv[0] is the SQL statement that is to be explained. */ static int explainFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ explain_cursor *pCur = (explain_cursor *)pVtabCursor; char *zSql = 0; int rc; sqlite3_finalize(pCur->pExplain); pCur->pExplain = 0; if( sqlite3_value_type(argv[0])!=SQLITE_TEXT ){ pCur->rc = SQLITE_DONE; return SQLITE_OK; } sqlite3_free(pCur->zSql); pCur->zSql = sqlite3_mprintf("%s", sqlite3_value_text(argv[0])); if( pCur->zSql ){ zSql = sqlite3_mprintf("EXPLAIN %s", pCur->zSql); } if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pExplain, 0); sqlite3_free(zSql); } if( rc ){ sqlite3_finalize(pCur->pExplain); pCur->pExplain = 0; sqlite3_free(pCur->zSql); pCur->zSql = 0; }else{ pCur->rc = sqlite3_step(pCur->pExplain); rc = (pCur->rc==SQLITE_DONE || pCur->rc==SQLITE_ROW) ? SQLITE_OK : pCur->rc; } return rc; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the explain virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int explainBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; pIdxInfo->estimatedCost = (double)1000000; pIdxInfo->estimatedRows = 500; for(i=0; i<pIdxInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; if( p->usable && p->iColumn==EXPLN_COLUMN_SQL && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ pIdxInfo->estimatedCost = 10.0; pIdxInfo->idxNum = 1; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; break; } } return SQLITE_OK; } /* ** This following structure defines all the methods for the ** explain virtual table. */ static sqlite3_module explainModule = { 0, /* iVersion */ 0, /* xCreate */ explainConnect, /* xConnect */ explainBestIndex, /* xBestIndex */ explainDisconnect, /* xDisconnect */ 0, /* xDestroy */ explainOpen, /* xOpen - open a cursor */ explainClose, /* xClose - close a cursor */ explainFilter, /* xFilter - configure scan constraints */ explainNext, /* xNext - advance a cursor */ explainEof, /* xEof - check for end of scan */ explainColumn, /* xColumn - read data */ explainRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ int sqlite3ExplainVtabInit(sqlite3 *db){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_create_module(db, "explain", &explainModule, 0); #endif return rc; } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_explain_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3ExplainVtabInit(db); #endif return rc; } |
Changes to ext/misc/fileio.c.
︙ | ︙ | |||
200 201 202 203 204 205 206 | ){ HANDLE hFindFile; WIN32_FIND_DATAW fd; LPWSTR zUnicodeName; extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); if( zUnicodeName ){ | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | ){ HANDLE hFindFile; WIN32_FIND_DATAW fd; LPWSTR zUnicodeName; extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); if( zUnicodeName ){ memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); hFindFile = FindFirstFileW(zUnicodeName, &fd); if( hFindFile!=NULL ){ pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); FindClose(hFindFile); } |
︙ | ︙ |
Changes to ext/misc/json1.c.
︙ | ︙ | |||
168 169 170 171 172 173 174 175 176 177 178 179 180 181 | JsonNode *aNode; /* Array of nodes containing the parse */ const char *zJson; /* Original JSON string */ u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ int nJson; /* Length of the zJson string in bytes */ }; /* ** Maximum nesting depth of JSON for this implementation. ** ** This limit is needed to avoid a stack overflow in the recursive ** descent parser. A depth of 2000 is far deeper than any sane JSON | > | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | JsonNode *aNode; /* Array of nodes containing the parse */ const char *zJson; /* Original JSON string */ u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ int nJson; /* Length of the zJson string in bytes */ u32 iHold; /* Replace cache line with the lowest iHold value */ }; /* ** Maximum nesting depth of JSON for this implementation. ** ** This limit is needed to avoid a stack overflow in the recursive ** descent parser. A depth of 2000 is far deeper than any sane JSON |
︙ | ︙ | |||
972 973 974 975 976 977 978 | jsonParseFillInParentage(pParse, 0, 0); return SQLITE_OK; } /* ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ | | > | > > > > > > > | > > > > > > | > | > > > > > > > > > > > > | | > | > | | 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 1009 1010 1011 1012 1013 1014 1015 1016 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 1053 | jsonParseFillInParentage(pParse, 0, 0); return SQLITE_OK; } /* ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ #define JSON_CACHE_ID (-429938) /* First cache entry */ #define JSON_CACHE_SZ 4 /* Max number of cache entries */ /* ** Obtain a complete parse of the JSON found in the first argument ** of the argv array. Use the sqlite3_get_auxdata() cache for this ** parse if it is available. If the cache is not available or if it ** is no longer valid, parse the JSON again and return the new parse, ** and also register the new parse so that it will be available for ** future sqlite3_get_auxdata() calls. */ static JsonParse *jsonParseCached( sqlite3_context *pCtx, sqlite3_value **argv, sqlite3_context *pErrCtx ){ const char *zJson = (const char*)sqlite3_value_text(argv[0]); int nJson = sqlite3_value_bytes(argv[0]); JsonParse *p; JsonParse *pMatch = 0; int iKey; int iMinKey = 0; u32 iMinHold = 0xffffffff; u32 iMaxHold = 0; if( zJson==0 ) return 0; for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){ p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey); if( p==0 ){ iMinKey = iKey; break; } if( pMatch==0 && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ p->nErr = 0; pMatch = p; }else if( p->iHold<iMinHold ){ iMinHold = p->iHold; iMinKey = iKey; } if( p->iHold>iMaxHold ){ iMaxHold = p->iHold; } } if( pMatch ){ pMatch->nErr = 0; pMatch->iHold = iMaxHold+1; return pMatch; } p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); if( p==0 ){ sqlite3_result_error_nomem(pCtx); return 0; } memset(p, 0, sizeof(*p)); p->zJson = (char*)&p[1]; memcpy((char*)p->zJson, zJson, nJson+1); if( jsonParse(p, pErrCtx, p->zJson) ){ sqlite3_free(p); return 0; } p->nJson = nJson; p->iHold = iMaxHold+1; sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, (void(*)(void*))jsonParseFree); return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); } /* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. */ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){ |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 | sqlite3_value **argv ){ JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; | | | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 | sqlite3_value **argv ){ JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; assert( p->nNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); pNode = jsonLookup(p, zPath, 0, ctx); }else{ pNode = p->aNode; |
︙ | ︙ | |||
1423 1424 1425 1426 1427 1428 1429 | JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; | | | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 | JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=1; i<argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); pNode = jsonLookup(p, zPath, 0, ctx); if( p->nErr ) break; |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | ** either the JSON or PATH inputs are not well-formed. */ static void jsonTypeFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ | | | | | | < | < < < < < | | | 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 | ** either the JSON or PATH inputs are not well-formed. */ static void jsonTypeFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ const char *zPath; JsonNode *pNode; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); pNode = jsonLookup(p, zPath, 0, ctx); }else{ pNode = p->aNode; } if( pNode ){ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } } /* ** json_valid(JSON) ** ** Return 1 if JSON is a well-formed JSON string according to RFC-7159. ** Return 0 otherwise. */ static void jsonValidFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ UNUSED_PARAM(argc); p = jsonParseCached(ctx, argv, 0); sqlite3_result_int(ctx, p!=0); } /**************************************************************************** ** Aggregate SQL function implementations ****************************************************************************/ /* |
︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 | if( pStr ){ pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ | | | | 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 | if( pStr ){ pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } |
︙ | ︙ | |||
1861 1862 1863 1864 1865 1866 1867 | if( z[i]=='"' ){ inStr = !inStr; }else if( z[i]=='\\' ){ i++; } } pStr->nUsed -= i; | | | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 | if( z[i]=='"' ){ inStr = !inStr; }else if( z[i]=='\\' ){ i++; } } pStr->nUsed -= i; memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); } #else # define jsonGroupInverse 0 #endif /* |
︙ | ︙ | |||
1907 1908 1909 1910 1911 1912 1913 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ jsonAppendChar(pStr, '}'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ | | | | 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ jsonAppendChar(pStr, '}'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } |
︙ | ︙ | |||
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 | #endif for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, aAgg[i].xStep, aAgg[i].xFinal, aAgg[i].xValue, jsonGroupInverse, 0); } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); } #endif return rc; } | > > | 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 | #endif for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } #ifndef SQLITE_OMIT_WINDOWFUNC for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, aAgg[i].xStep, aAgg[i].xFinal, aAgg[i].xValue, jsonGroupInverse, 0); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); } #endif return rc; } |
︙ | ︙ |
Added ext/misc/memstat.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 | /* ** 2018-09-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 demonstrates an eponymous virtual table that returns information ** from sqlite3_status64() and sqlite3_db_status(). ** ** Usage example: ** ** .load ./memstat ** .mode quote ** .header on ** SELECT * FROM memstat; */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) #if !defined(SQLITEINT_H) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* memstat_vtab is a subclass of sqlite3_vtab which will ** serve as the underlying representation of a memstat virtual table */ typedef struct memstat_vtab memstat_vtab; struct memstat_vtab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this memstat vtab */ }; /* memstat_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 memstat_cursor memstat_cursor; struct memstat_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this cursor */ int iRowid; /* Current row in aMemstatColumn[] */ int iDb; /* Which schema we are looking at */ int nDb; /* Number of schemas */ char **azDb; /* Names of all schemas */ sqlite3_int64 aVal[2]; /* Result values */ }; /* ** The memstatConnect() method is invoked to create a new ** memstat_vtab that describes the memstat virtual table. ** ** Think of this routine as the constructor for memstat_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the memstat_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against memstat will look like. */ static int memstatConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ memstat_vtab *pNew; int rc; /* Column numbers */ #define MSV_COLUMN_NAME 0 /* Name of quantity being measured */ #define MSV_COLUMN_SCHEMA 1 /* schema name */ #define MSV_COLUMN_VALUE 2 /* Current value */ #define MSV_COLUMN_HIWTR 3 /* Highwater mark */ rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)"); if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); pNew->db = db; } return rc; } /* ** This method is the destructor for memstat_cursor objects. */ static int memstatDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new memstat_cursor object. */ static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ memstat_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->db = ((memstat_vtab*)p)->db; *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Clear all the schema names from a cursor */ static void memstatClearSchema(memstat_cursor *pCur){ int i; if( pCur->azDb==0 ) return; for(i=0; i<pCur->nDb; i++){ sqlite3_free(pCur->azDb[i]); } sqlite3_free(pCur->azDb); pCur->azDb = 0; pCur->nDb = 0; } /* ** Fill in the azDb[] array for the cursor. */ static int memstatFindSchemas(memstat_cursor *pCur){ sqlite3_stmt *pStmt = 0; int rc; if( pCur->nDb ) return SQLITE_OK; rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ sqlite3_finalize(pStmt); return rc; } while( sqlite3_step(pStmt)==SQLITE_ROW ){ char **az, *z; az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1)); if( az==0 ){ memstatClearSchema(pCur); return SQLITE_NOMEM; } pCur->azDb = az; z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); if( z==0 ){ memstatClearSchema(pCur); return SQLITE_NOMEM; } pCur->azDb[pCur->nDb] = z; pCur->nDb++; } sqlite3_finalize(pStmt); return SQLITE_OK; } /* ** Destructor for a memstat_cursor. */ static int memstatClose(sqlite3_vtab_cursor *cur){ memstat_cursor *pCur = (memstat_cursor*)cur; memstatClearSchema(pCur); sqlite3_free(cur); return SQLITE_OK; } /* ** Allowed values for aMemstatColumn[].eType */ #define MSV_GSTAT 0 /* sqlite3_status64() information */ #define MSV_DB 1 /* sqlite3_db_status() information */ #define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */ /* ** An array of quantities that can be measured and reported by ** this virtual table */ static const struct MemstatColumns { const char *zName; /* Symbolic name */ unsigned char eType; /* Type of interface */ unsigned char mNull; /* Bitmask of which columns are NULL */ /* 2: dbname, 4: current, 8: hiwtr */ int eOp; /* Opcode */ } aMemstatColumn[] = { {"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED }, {"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE }, {"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT }, {"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED }, {"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW }, {"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE }, {"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK }, {"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED }, {"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT }, {"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE}, {"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL}, {"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED }, #if SQLITE_VERSION_NUMBER >= 3140000 {"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED }, #endif {"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED }, {"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED }, {"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT }, {"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS }, {"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE }, #if SQLITE_VERSION_NUMBER >= 3230000 {"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL }, #endif {"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS }, #ifdef SQLITE_ENABLE_ZIPVFS {"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 }, {"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 }, {"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 }, {"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 }, {"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 }, {"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 }, #endif /* SQLITE_ENABLE_ZIPVFS */ }; #define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0])) /* ** Advance a memstat_cursor to its next row of output. */ static int memstatNext(sqlite3_vtab_cursor *cur){ memstat_cursor *pCur = (memstat_cursor*)cur; int i; assert( pCur->iRowid<=MSV_NROW ); while(1){ i = (int)pCur->iRowid - 1; if( (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){ pCur->iRowid++; if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */ pCur->iDb = 0; i++; } pCur->aVal[0] = 0; pCur->aVal[1] = 0; switch( aMemstatColumn[i].eType ){ case MSV_GSTAT: { if( sqlite3_libversion_number()>=3010000 ){ sqlite3_status64(aMemstatColumn[i].eOp, &pCur->aVal[0], &pCur->aVal[1],0); }else{ int xCur, xHiwtr; sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0); pCur->aVal[0] = xCur; pCur->aVal[1] = xHiwtr; } break; } case MSV_DB: { int xCur, xHiwtr; sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0); pCur->aVal[0] = xCur; pCur->aVal[1] = xHiwtr; break; } case MSV_ZIPVFS: { int rc; rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb], aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]); if( rc!=SQLITE_OK ) continue; break; } } break; } return SQLITE_OK; } /* ** Return values of columns for the row at which the memstat_cursor ** is currently pointing. */ static int memstatColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int iCol /* Which column to return */ ){ memstat_cursor *pCur = (memstat_cursor*)cur; int i; assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW ); i = (int)pCur->iRowid - 1; if( (aMemstatColumn[i].mNull & (1<<iCol))!=0 ){ return SQLITE_OK; } switch( iCol ){ case MSV_COLUMN_NAME: { sqlite3_result_text(ctx, aMemstatColumn[i].zName, -1, SQLITE_STATIC); break; } case MSV_COLUMN_SCHEMA: { sqlite3_result_text(ctx, pCur->azDb[pCur->iDb], -1, 0); break; } case MSV_COLUMN_VALUE: { sqlite3_result_int64(ctx, pCur->aVal[0]); break; } case MSV_COLUMN_HIWTR: { sqlite3_result_int64(ctx, pCur->aVal[1]); break; } } return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ memstat_cursor *pCur = (memstat_cursor*)cur; *pRowid = pCur->iRowid*1000 + pCur->iDb; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int memstatEof(sqlite3_vtab_cursor *cur){ memstat_cursor *pCur = (memstat_cursor*)cur; return pCur->iRowid>MSV_NROW; } /* ** This method is called to "rewind" the memstat_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to memstatColumn() or memstatRowid() or ** memstatEof(). */ static int memstatFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ memstat_cursor *pCur = (memstat_cursor *)pVtabCursor; int rc = memstatFindSchemas(pCur); if( rc ) return rc; pCur->iRowid = 0; pCur->iDb = 0; return memstatNext(pVtabCursor); } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the memstat virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int memstatBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ pIdxInfo->estimatedCost = (double)500; pIdxInfo->estimatedRows = 500; return SQLITE_OK; } /* ** This following structure defines all the methods for the ** memstat virtual table. */ static sqlite3_module memstatModule = { 0, /* iVersion */ 0, /* xCreate */ memstatConnect, /* xConnect */ memstatBestIndex, /* xBestIndex */ memstatDisconnect, /* xDisconnect */ 0, /* xDestroy */ memstatOpen, /* xOpen - open a cursor */ memstatClose, /* xClose - close a cursor */ memstatFilter, /* xFilter - configure scan constraints */ memstatNext, /* xNext - advance a cursor */ memstatEof, /* xEof - check for end of scan */ memstatColumn, /* xColumn - read data */ memstatRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ int sqlite3MemstatVtabInit(sqlite3 *db){ int rc = SQLITE_OK; #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0); #endif return rc; } #ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_memstat_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE rc = sqlite3MemstatVtabInit(db); #endif return rc; } #endif /* SQLITE_CORE */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */ |
Changes to ext/misc/sha1.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2017-01-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. ** ****************************************************************************** ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2017-01-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 SQLite extension implements functions that compute SHA1 hashes. ** Two SQL functions are implemented: ** ** sha1(X) ** sha1_query(Y) ** ** The sha1(X) function computes the SHA1 hash of the input X, or NULL if ** X is NULL. |
︙ | ︙ |
Changes to ext/misc/shathree.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2017-03-08 ** ** 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 | /* ** 2017-03-08 ** ** 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 SQLite extension implements functions that compute SHA3 hashes. ** Two SQL functions are implemented: ** ** sha3(X,SIZE) ** sha3_query(Y,SIZE) ** ** The sha3(X) function computes the SHA3 hash of the input X, or NULL if ** X is NULL. |
︙ | ︙ |
Changes to ext/misc/spellfix.c.
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | return nChar; } typedef struct Transliteration Transliteration; struct Transliteration { unsigned short int cFrom; unsigned char cTo0, cTo1, cTo2, cTo3; }; /* ** Table of translations from unicode characters into ASCII. */ static const Transliteration translit[] = { { 0x00A0, 0x20, 0x00, 0x00, 0x00 }, /* to */ | > > > | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | return nChar; } typedef struct Transliteration Transliteration; struct Transliteration { unsigned short int cFrom; unsigned char cTo0, cTo1, cTo2, cTo3; #ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS unsigned char cTo4; #endif }; /* ** Table of translations from unicode characters into ASCII. */ static const Transliteration translit[] = { { 0x00A0, 0x20, 0x00, 0x00, 0x00 }, /* to */ |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 | ** ** The returned string might contain more characters than the input. ** ** Space to hold the returned string comes from sqlite3_malloc() and ** should be freed by the caller. */ static unsigned char *transliterate(const unsigned char *zIn, int nIn){ unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 ); int c, sz, nOut; if( zOut==0 ) return 0; nOut = 0; while( nIn>0 ){ c = utf8Read(zIn, nIn, &sz); zIn += sz; nIn -= sz; | > > > > | 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 | ** ** The returned string might contain more characters than the input. ** ** Space to hold the returned string comes from sqlite3_malloc() and ** should be freed by the caller. */ static unsigned char *transliterate(const unsigned char *zIn, int nIn){ #ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS unsigned char *zOut = sqlite3_malloc64( nIn*5 + 1 ); #else unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 ); #endif int c, sz, nOut; if( zOut==0 ) return 0; nOut = 0; while( nIn>0 ){ c = utf8Read(zIn, nIn, &sz); zIn += sz; nIn -= sz; |
︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | zOut[nOut++] = tbl[x].cTo0; if( tbl[x].cTo1 ){ zOut[nOut++] = tbl[x].cTo1; if( tbl[x].cTo2 ){ zOut[nOut++] = tbl[x].cTo2; if( tbl[x].cTo3 ){ zOut[nOut++] = tbl[x].cTo3; } } } c = 0; break; }else if( tbl[x].cFrom>c ){ xTop = x-1; | > > > > > | 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | zOut[nOut++] = tbl[x].cTo0; if( tbl[x].cTo1 ){ zOut[nOut++] = tbl[x].cTo1; if( tbl[x].cTo2 ){ zOut[nOut++] = tbl[x].cTo2; if( tbl[x].cTo3 ){ zOut[nOut++] = tbl[x].cTo3; #ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS if( tbl[x].cTo4 ){ zOut[nOut++] = tbl[x].cTo4; } #endif /* SQLITE_SPELLFIX_5BYTE_MAPPINGS */ } } } c = 0; break; }else if( tbl[x].cFrom>c ){ xTop = x-1; |
︙ | ︙ |
Changes to ext/rbu/rbu.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 | } int main(int argc, char **argv){ int i; const char *zTarget; /* Target database to apply RBU to */ const char *zRbu; /* Database containing RBU */ char zBuf[200]; /* Buffer for printf() */ | | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | } int main(int argc, char **argv){ int i; const char *zTarget; /* Target database to apply RBU to */ const char *zRbu; /* Database containing RBU */ char zBuf[200]; /* Buffer for printf() */ char *zErrmsg = 0; /* Error message, if any */ sqlite3rbu *pRbu; /* RBU handle */ int nStep = 0; /* Maximum number of step() calls */ int nStatStep = 0; /* Report stats after this many step calls */ int bVacuum = 0; const char *zPreSql = 0; int rc = SQLITE_OK; sqlite3_int64 nProgress = 0; int nArgc = argc-2; if( argc<3 ) usage(argv[0]); for(i=1; i<nArgc; i++){ const char *zArg = argv[i]; int nArg = strlen(zArg); |
︙ | ︙ | |||
122 123 124 125 126 127 128 | pRbu = sqlite3rbu_vacuum(zTarget, zRbu); }else{ pRbu = sqlite3rbu_open(zTarget, zRbu, 0); } report_rbu_vfs(pRbu); if( zPreSql && pRbu ){ | | | | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | pRbu = sqlite3rbu_vacuum(zTarget, zRbu); }else{ pRbu = sqlite3rbu_open(zTarget, zRbu, 0); } report_rbu_vfs(pRbu); if( zPreSql && pRbu ){ sqlite3 *dbMain = sqlite3rbu_db(pRbu, 0); rc = sqlite3_exec(dbMain, zPreSql, 0, 0, 0); if( rc==SQLITE_OK ){ sqlite3 *dbRbu = sqlite3rbu_db(pRbu, 1); rc = sqlite3_exec(dbRbu, zPreSql, 0, 0, 0); } } /* If nStep is less than or equal to zero, call ** sqlite3rbu_step() until either the RBU has been completely applied ** or an error occurs. Or, if nStep is greater than zero, call ** sqlite3rbu_step() a maximum of nStep times. */ |
︙ | ︙ |
Added ext/rtree/geopoly.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 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 896 897 898 899 900 901 902 903 904 905 906 907 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 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 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 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 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 1053 1054 1055 1056 1057 1058 1059 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 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 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 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 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 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 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 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 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 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 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 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 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 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 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 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 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 | /* ** 2018-05-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. ** ****************************************************************************** ** ** This file implements an alternative R-Tree virtual table that ** uses polygons to express the boundaries of 2-dimensional objects. ** ** This file is #include-ed onto the end of "rtree.c" so that it has ** access to all of the R-Tree internals. */ #include <stdlib.h> /* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */ #ifdef GEOPOLY_ENABLE_DEBUG static int geo_debug = 0; # define GEODEBUG(X) if(geo_debug)printf X #else # define GEODEBUG(X) #endif #ifndef JSON_NULL /* The following stuff repeats things found in json1 */ /* ** Versions of isspace(), isalnum() and isdigit() to which it is safe ** to pass signed char values. */ #ifdef sqlite3Isdigit /* Use the SQLite core versions if this routine is part of the ** SQLite amalgamation */ # define safe_isdigit(x) sqlite3Isdigit(x) # define safe_isalnum(x) sqlite3Isalnum(x) # define safe_isxdigit(x) sqlite3Isxdigit(x) #else /* Use the standard library for separate compilation */ #include <ctype.h> /* amalgamator: keep */ # define safe_isdigit(x) isdigit((unsigned char)(x)) # define safe_isalnum(x) isalnum((unsigned char)(x)) # define safe_isxdigit(x) isxdigit((unsigned char)(x)) #endif /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function. */ static const char geopolyIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define safe_isspace(x) (geopolyIsSpace[(unsigned char)x]) #endif /* JSON NULL - back to original code */ /* Compiler and version */ #ifndef GCC_VERSION #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else # define GCC_VERSION 0 #endif #endif #ifndef MSVC_VERSION #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif #endif /* Datatype for coordinates */ typedef float GeoCoord; /* ** Internal representation of a polygon. ** ** The polygon consists of a sequence of vertexes. There is a line ** segment between each pair of vertexes, and one final segment from ** the last vertex back to the first. (This differs from the GeoJSON ** standard in which the final vertex is a repeat of the first.) ** ** The polygon follows the right-hand rule. The area to the right of ** each segment is "outside" and the area to the left is "inside". ** ** The on-disk representation consists of a 4-byte header followed by ** the values. The 4-byte header is: ** ** encoding (1 byte) 0=big-endian, 1=little-endian ** nvertex (3 bytes) Number of vertexes as a big-endian integer */ typedef struct GeoPoly GeoPoly; struct GeoPoly { int nVertex; /* Number of vertexes */ unsigned char hdr[4]; /* Header for on-disk representation */ GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */ }; /* ** State of a parse of a GeoJSON input. */ typedef struct GeoParse GeoParse; struct GeoParse { const unsigned char *z; /* Unparsed input */ int nVertex; /* Number of vertexes in a[] */ int nAlloc; /* Space allocated to a[] */ int nErr; /* Number of errors encountered */ GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */ }; /* Do a 4-byte byte swap */ static void geopolySwab32(unsigned char *a){ unsigned char t = a[0]; a[0] = a[3]; a[3] = t; t = a[1]; a[1] = a[2]; a[2] = t; } /* Skip whitespace. Return the next non-whitespace character. */ static char geopolySkipSpace(GeoParse *p){ while( safe_isspace(p->z[0]) ) p->z++; return p->z[0]; } /* Parse out a number. Write the value into *pVal if pVal!=0. ** return non-zero on success and zero if the next token is not a number. */ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ char c = geopolySkipSpace(p); const unsigned char *z = p->z; int j = 0; int seenDP = 0; int seenE = 0; if( c=='-' ){ j = 1; c = z[j]; } if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0; for(;; j++){ c = z[j]; if( safe_isdigit(c) ) continue; if( c=='.' ){ if( z[j-1]=='-' ) return 0; if( seenDP ) return 0; seenDP = 1; continue; } if( c=='e' || c=='E' ){ if( z[j-1]<'0' ) return 0; if( seenE ) return -1; seenDP = seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; } if( c<'0' || c>'9' ) return 0; continue; } break; } if( z[j-1]<'0' ) return 0; if( pVal ){ #ifdef SQLITE_AMALGAMATION /* The sqlite3AtoF() routine is much much faster than atof(), if it ** is available */ double r; (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); *pVal = r; #else *pVal = (GeoCoord)atof((const char*)p->z); #endif } p->z += j; return 1; } /* ** If the input is a well-formed JSON array of coordinates with at least ** four coordinates and where each coordinate is itself a two-value array, ** then convert the JSON into a GeoPoly object and return a pointer to ** that object. ** ** If any error occurs, return NULL. */ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ GeoParse s; int rc = SQLITE_OK; memset(&s, 0, sizeof(s)); s.z = z; if( geopolySkipSpace(&s)=='[' ){ s.z++; while( geopolySkipSpace(&s)=='[' ){ int ii = 0; char c; s.z++; if( s.nVertex>=s.nAlloc ){ GeoCoord *aNew; s.nAlloc = s.nAlloc*2 + 16; aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 ); if( aNew==0 ){ rc = SQLITE_NOMEM; s.nErr++; break; } s.a = aNew; } while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){ ii++; if( ii==2 ) s.nVertex++; c = geopolySkipSpace(&s); s.z++; if( c==',' ) continue; if( c==']' && ii>=2 ) break; s.nErr++; rc = SQLITE_ERROR; goto parse_json_err; } if( geopolySkipSpace(&s)==',' ){ s.z++; continue; } break; } if( geopolySkipSpace(&s)==']' && s.nVertex>=4 && s.a[0]==s.a[s.nVertex*2-2] && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ int nByte; GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord); pOut = sqlite3_malloc64( nByte ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); pOut->hdr[0] = *(unsigned char*)&x; pOut->hdr[1] = (s.nVertex>>16)&0xff; pOut->hdr[2] = (s.nVertex>>8)&0xff; pOut->hdr[3] = s.nVertex&0xff; sqlite3_free(s.a); if( pRc ) *pRc = SQLITE_OK; return pOut; }else{ s.nErr++; rc = SQLITE_ERROR; } } parse_json_err: if( pRc ) *pRc = rc; sqlite3_free(s.a); return 0; } /* ** Given a function parameter, try to interpret it as a polygon, either ** in the binary format or JSON text. Compute a GeoPoly object and ** return a pointer to that object. Or if the input is not a well-formed ** polygon, put an error message in sqlite3_context and return NULL. */ static GeoPoly *geopolyFuncParam( sqlite3_context *pCtx, /* Context for error messages */ sqlite3_value *pVal, /* The value to decode */ int *pRc /* Write error here */ ){ GeoPoly *p = 0; int nByte; if( sqlite3_value_type(pVal)==SQLITE_BLOB && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) ){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte ){ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); if( p==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; if( pCtx ) sqlite3_result_error_nomem(pCtx); }else{ int x = 1; p->nVertex = nVertex; memcpy(p->hdr, a, nByte); if( a[0] != *(unsigned char*)&x ){ int ii; for(ii=0; ii<nVertex*2; ii++){ geopolySwab32((unsigned char*)&p->a[ii]); } p->hdr[0] ^= 1; } } } if( pRc ) *pRc = SQLITE_OK; return p; }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){ const unsigned char *zJson = sqlite3_value_text(pVal); if( zJson==0 ){ if( pRc ) *pRc = SQLITE_NOMEM; return 0; } return geopolyParseJson(zJson, pRc); }else{ if( pRc ) *pRc = SQLITE_ERROR; return 0; } } /* ** Implementation of the geopoly_blob(X) function. ** ** If the input is a well-formed Geopoly BLOB or JSON string ** then return the BLOB representation of the polygon. Otherwise ** return NULL. */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** SQL function: geopoly_json(X) ** ** Interpret X as a polygon and render it as a JSON array ** of coordinates. Or, if X is not a valid polygon, return NULL. */ static void geopolyJsonFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; sqlite3_str_append(x, "[", 1); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]); } sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } } /* ** SQL function: geopoly_svg(X, ....) ** ** Interpret X as a polygon and render it as a SVG <polyline>. ** Additional arguments are added as attributes to the <polyline>. */ static void geopolySvgFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3 *db = sqlite3_context_db_handle(context); sqlite3_str *x = sqlite3_str_new(db); int i; char cSep = '\''; sqlite3_str_appendf(x, "<polyline points="); for(i=0; i<p->nVertex; i++){ sqlite3_str_appendf(x, "%c%g,%g", cSep, p->a[i*2], p->a[i*2+1]); cSep = ' '; } sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]); for(i=1; i<argc; i++){ const char *z = (const char*)sqlite3_value_text(argv[i]); if( z && z[0] ){ sqlite3_str_appendf(x, " %s", z); } } sqlite3_str_appendf(x, "></polyline>"); sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); sqlite3_free(p); } } /* ** SQL Function: geopoly_xform(poly, A, B, C, D, E, F) ** ** Transform and/or translate a polygon as follows: ** ** x1 = A*x0 + B*y0 + E ** y1 = C*x0 + D*y0 + F ** ** For a translation: ** ** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset) ** ** Rotate by R around the point (0,0): ** ** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0) */ static void geopolyXformFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); double A = sqlite3_value_double(argv[1]); double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; if( p ){ for(ii=0; ii<p->nVertex; ii++){ x0 = p->a[ii*2]; y0 = p->a[ii*2+1]; x1 = (GeoCoord)(A*x0 + B*y0 + E); y1 = (GeoCoord)(C*x0 + D*y0 + F); p->a[ii*2] = x1; p->a[ii*2+1] = y1; } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** Implementation of the geopoly_area(X) function. ** ** If the input is a well-formed Geopoly BLOB then return the area ** enclosed by the polygon. If the polygon circulates clockwise instead ** of counterclockwise (as it should) then return the negative of the ** enclosed area. Otherwise return NULL. */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ double rArea = 0.0; int ii; for(ii=0; ii<p->nVertex-1; ii++){ rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ * 0.5; } rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ * 0.5; sqlite3_result_double(context, rArea); sqlite3_free(p); } } #define GEOPOLY_PI 3.1415926535897932385 /* Fast approximation for cosine(X) for X between -0.5*pi and 2*pi */ static double geopolyCosine(double r){ assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI ); if( r>=1.5*GEOPOLY_PI ){ r -= 2.0*GEOPOLY_PI; } if( r>=0.5*GEOPOLY_PI ){ return -geopolyCosine(r-GEOPOLY_PI); }else{ double r2 = r*r; double r3 = r2*r; double r5 = r3*r2; return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5; } } /* ** Function: geopoly_regular(X,Y,R,N) ** ** Construct a simple, convex, regular polygon centered at X, Y ** with circumradius R and with N sides. */ static void geopolyRegularFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ sqlite3_result_error_nomem(context); return; } i = 1; p->hdr[0] = *(unsigned char*)&i; p->hdr[1] = 0; p->hdr[2] = (n>>8)&0xff; p->hdr[3] = n&0xff; for(i=0; i<n; i++){ double rAngle = 2.0*GEOPOLY_PI*i/n; p->a[i*2] = x - r*geopolyCosine(rAngle-0.5*GEOPOLY_PI); p->a[i*2+1] = y + r*geopolyCosine(rAngle); } sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT); sqlite3_free(p); } /* ** If pPoly is a polygon, compute its bounding box. Then: ** ** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL ** (2) otherwise, compute a GeoPoly for the bounding box and return the ** new GeoPoly ** ** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from ** the bounding box in aCoord and return a pointer to that GeoPoly. */ static GeoPoly *geopolyBBox( sqlite3_context *context, /* For recording the error */ sqlite3_value *pPoly, /* The polygon */ RtreeCoord *aCoord, /* Results here */ int *pRc /* Error code here */ ){ GeoPoly *pOut = 0; GeoPoly *p; float mnX, mxX, mnY, mxY; if( pPoly==0 && aCoord!=0 ){ p = 0; mnX = aCoord[0].f; mxX = aCoord[1].f; mnY = aCoord[2].f; mxY = aCoord[3].f; goto geopolyBboxFill; }else{ p = geopolyFuncParam(context, pPoly, pRc); } if( p ){ int ii; mnX = mxX = p->a[0]; mnY = mxY = p->a[1]; for(ii=1; ii<p->nVertex; ii++){ double r = p->a[ii*2]; if( r<mnX ) mnX = (float)r; else if( r>mxX ) mxX = (float)r; r = p->a[ii*2+1]; if( r<mnY ) mnY = (float)r; else if( r>mxY ) mxY = (float)r; } if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); if( pRc ) *pRc = SQLITE_NOMEM; return 0; } pOut->nVertex = 4; ii = 1; pOut->hdr[0] = *(unsigned char*)ⅈ pOut->hdr[1] = 0; pOut->hdr[2] = 0; pOut->hdr[3] = 4; pOut->a[0] = mnX; pOut->a[1] = mnY; pOut->a[2] = mxX; pOut->a[3] = mnY; pOut->a[4] = mxX; pOut->a[5] = mxY; pOut->a[6] = mnX; pOut->a[7] = mxY; }else{ sqlite3_free(p); aCoord[0].f = mnX; aCoord[1].f = mxX; aCoord[2].f = mnY; aCoord[3].f = mxY; } } return pOut; } /* ** Implementation of the geopoly_bbox(X) SQL function. */ static void geopolyBBoxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** State vector for the geopoly_group_bbox() aggregate function. */ typedef struct GeoBBox GeoBBox; struct GeoBBox { int isInit; RtreeCoord a[4]; }; /* ** Implementation of the geopoly_group_bbox(X) aggregate SQL function. */ static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; (void)geopolyBBox(context, argv[0], a, &rc); if( rc==SQLITE_OK ){ GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); if( pBBox==0 ) return; if( pBBox->isInit==0 ){ pBBox->isInit = 1; memcpy(pBBox->a, a, sizeof(RtreeCoord)*4); }else{ if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0]; if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1]; if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2]; if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3]; } } } static void geopolyBBoxFinal( sqlite3_context *context ){ GeoPoly *p; GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0); if( pBBox==0 ) return; p = geopolyBBox(context, 0, pBBox->a, 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** ** +2 x0,y0 is on the line segement ** ** +1 x0,y0 is beneath line segment ** ** 0 x0,y0 is not on or beneath the line segment or the line segment ** is vertical and x0,y0 is not on the line segment ** ** The left-most coordinate min(x1,x2) is not considered to be part of ** the line segment for the purposes of this analysis. */ static int pointBeneathLine( double x0, double y0, double x1, double y1, double x2, double y2 ){ double y; if( x0==x1 && y0==y1 ) return 2; if( x1<x2 ){ if( x0<=x1 || x0>x2 ) return 0; }else if( x1>x2 ){ if( x0<=x2 || x0>x1 ) return 0; }else{ /* Vertical line segment */ if( x0!=x1 ) return 0; if( y0<y1 && y0<y2 ) return 0; if( y0>y1 && y0>y2 ) return 0; return 2; } y = y1 + (y2-y1)*(x0-x1)/(x2-x1); if( y0==y ) return 2; if( y0<y ) return 1; return 0; } /* ** SQL function: geopoly_contains_point(P,X,Y) ** ** Return +2 if point X,Y is within polygon P. ** Return +1 if point X,Y is on the polygon boundary. ** Return 0 if point X,Y is outside the polygon */ static void geopolyContainsPointFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; if( p1==0 ) return; for(ii=0; ii<p1->nVertex-1; ii++){ v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], p1->a[ii*2+2],p1->a[ii*2+3]); if( v==2 ) break; cnt += v; } if( v!=2 ){ v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], p1->a[0],p1->a[1]); } if( v==2 ){ sqlite3_result_int(context, 1); }else if( ((v+cnt)&1)==0 ){ sqlite3_result_int(context, 0); }else{ sqlite3_result_int(context, 2); } sqlite3_free(p1); } /* Forward declaration */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); /* ** SQL function: geopoly_within(P1,P2) ** ** Return +2 if P1 and P2 are the same polygon ** Return +1 if P2 is contained within P1 ** Return 0 if any part of P2 is on the outside of P1 ** */ static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } } sqlite3_free(p1); sqlite3_free(p2); } /* Objects used by the overlap algorihm. */ typedef struct GeoEvent GeoEvent; typedef struct GeoSegment GeoSegment; typedef struct GeoOverlap GeoOverlap; struct GeoEvent { double x; /* X coordinate at which event occurs */ int eType; /* 0 for ADD, 1 for REMOVE */ GeoSegment *pSeg; /* The segment to be added or removed */ GeoEvent *pNext; /* Next event in the sorted list */ }; struct GeoSegment { double C, B; /* y = C*x + B */ double y; /* Current y value */ float y0; /* Initial y value */ unsigned char side; /* 1 for p1, 2 for p2 */ unsigned int idx; /* Which segment within the side */ GeoSegment *pNext; /* Next segment in a list sorted by y */ }; struct GeoOverlap { GeoEvent *aEvent; /* Array of all events */ GeoSegment *aSegment; /* Array of all segments */ int nEvent; /* Number of events */ int nSegment; /* Number of segments */ }; /* ** Add a single segment and its associated events. */ static void geopolyAddOneSegment( GeoOverlap *p, GeoCoord x0, GeoCoord y0, GeoCoord x1, GeoCoord y1, unsigned char side, unsigned int idx ){ GeoSegment *pSeg; GeoEvent *pEvent; if( x0==x1 ) return; /* Ignore vertical segments */ if( x0>x1 ){ GeoCoord t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } pSeg = p->aSegment + p->nSegment; p->nSegment++; pSeg->C = (y1-y0)/(x1-x0); pSeg->B = y1 - x1*pSeg->C; pSeg->y0 = y0; pSeg->side = side; pSeg->idx = idx; pEvent = p->aEvent + p->nEvent; p->nEvent++; pEvent->x = x0; pEvent->eType = 0; pEvent->pSeg = pSeg; pEvent = p->aEvent + p->nEvent; p->nEvent++; pEvent->x = x1; pEvent->eType = 1; pEvent->pSeg = pSeg; } /* ** Insert all segments and events for polygon pPoly. */ static void geopolyAddSegments( GeoOverlap *p, /* Add segments to this Overlap object */ GeoPoly *pPoly, /* Take all segments from this polygon */ unsigned char side /* The side of pPoly */ ){ unsigned int i; GeoCoord *x; for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ x = pPoly->a + (i*2); geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); } x = pPoly->a + (i*2); geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); } /* ** Merge two lists of sorted events by X coordinate */ static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ GeoEvent head, *pLast; head.pNext = 0; pLast = &head; while( pRight && pLeft ){ if( pRight->x <= pLeft->x ){ pLast->pNext = pRight; pLast = pRight; pRight = pRight->pNext; }else{ pLast->pNext = pLeft; pLast = pLeft; pLeft = pLeft->pNext; } } pLast->pNext = pRight ? pRight : pLeft; return head.pNext; } /* ** Sort an array of nEvent event objects into a list. */ static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){ int mx = 0; int i, j; GeoEvent *p; GeoEvent *a[50]; for(i=0; i<nEvent; i++){ p = &aEvent[i]; p->pNext = 0; for(j=0; j<mx && a[j]; j++){ p = geopolyEventMerge(a[j], p); a[j] = 0; } a[j] = p; if( j>=mx ) mx = j+1; } p = 0; for(i=0; i<mx; i++){ p = geopolyEventMerge(a[i], p); } return p; } /* ** Merge two lists of sorted segments by Y, and then by C. */ static GeoSegment *geopolySegmentMerge(GeoSegment *pLeft, GeoSegment *pRight){ GeoSegment head, *pLast; head.pNext = 0; pLast = &head; while( pRight && pLeft ){ double r = pRight->y - pLeft->y; if( r==0.0 ) r = pRight->C - pLeft->C; if( r<0.0 ){ pLast->pNext = pRight; pLast = pRight; pRight = pRight->pNext; }else{ pLast->pNext = pLeft; pLast = pLeft; pLeft = pLeft->pNext; } } pLast->pNext = pRight ? pRight : pLeft; return head.pNext; } /* ** Sort a list of GeoSegments in order of increasing Y and in the event of ** a tie, increasing C (slope). */ static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ int mx = 0; int i; GeoSegment *p; GeoSegment *a[50]; while( pList ){ p = pList; pList = pList->pNext; p->pNext = 0; for(i=0; i<mx && a[i]; i++){ p = geopolySegmentMerge(a[i], p); a[i] = 0; } a[i] = p; if( i>=mx ) mx = i+1; } p = 0; for(i=0; i<mx; i++){ p = geopolySegmentMerge(a[i], p); } return p; } /* ** Determine the overlap between two polygons */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ int nVertex = p1->nVertex + p2->nVertex + 2; GeoOverlap *p; int nByte; GeoEvent *pThisEvent; double rX; int rc = 0; int needSort = 0; GeoSegment *pActive = 0; GeoSegment *pSeg; unsigned char aOverlap[4]; nByte = sizeof(GeoEvent)*nVertex*2 + sizeof(GeoSegment)*nVertex + sizeof(GeoOverlap); p = sqlite3_malloc( nByte ); if( p==0 ) return -1; p->aEvent = (GeoEvent*)&p[1]; p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; p->nEvent = p->nSegment = 0; geopolyAddSegments(p, p1, 1); geopolyAddSegments(p, p2, 2); pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); rX = pThisEvent->x==0.0 ? -1.0 : 0.0; memset(aOverlap, 0, sizeof(aOverlap)); while( pThisEvent ){ if( pThisEvent->x!=rX ){ GeoSegment *pPrev = 0; int iMask = 0; GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); rX = pThisEvent->x; if( needSort ){ GEODEBUG(("SORT\n")); pActive = geopolySortSegmentsByYAndC(pActive); needSort = 0; } for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pPrev ){ if( pPrev->y!=pSeg->y ){ GEODEBUG(("MASK: %d\n", iMask)); aOverlap[iMask] = 1; } } iMask ^= pSeg->side; pPrev = pSeg; } pPrev = 0; for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ double y = pSeg->C*rX + pSeg->B; GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y)); pSeg->y = y; if( pPrev ){ if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){ rc = 1; GEODEBUG(("Crossing: %d.%d and %d.%d\n", pPrev->side, pPrev->idx, pSeg->side, pSeg->idx)); goto geopolyOverlapDone; }else if( pPrev->y!=pSeg->y ){ GEODEBUG(("MASK: %d\n", iMask)); aOverlap[iMask] = 1; } } iMask ^= pSeg->side; pPrev = pSeg; } } GEODEBUG(("%s %d.%d C=%g B=%g\n", pThisEvent->eType ? "RM " : "ADD", pThisEvent->pSeg->side, pThisEvent->pSeg->idx, pThisEvent->pSeg->C, pThisEvent->pSeg->B)); if( pThisEvent->eType==0 ){ /* Add a segment */ pSeg = pThisEvent->pSeg; pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ pActive = pActive->pNext; }else{ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pSeg->pNext==pThisEvent->pSeg ){ pSeg->pNext = pSeg->pNext->pNext; break; } } } } pThisEvent = pThisEvent->pNext; } if( aOverlap[3]==0 ){ rc = 0; }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){ rc = 3; }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){ rc = 2; }else if( aOverlap[1]==0 && aOverlap[2]==0 ){ rc = 4; }else{ rc = 1; } geopolyOverlapDone: sqlite3_free(p); return rc; } /* ** SQL function: geopoly_overlap(P1,P2) ** ** Determine whether or not P1 and P2 overlap. Return value: ** ** 0 The two polygons are disjoint ** 1 They overlap ** 2 P1 is completely contained within P2 ** 3 P2 is completely contained within P1 ** 4 P1 and P2 are the same polygon ** NULL Either P1 or P2 or both are not valid polygons */ static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x); } } sqlite3_free(p1); sqlite3_free(p2); } /* ** Enable or disable debugging output */ static void geopolyDebugFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); #endif } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the geopoly virtual table. ** ** argv[0] -> module name ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> column names... */ static int geopolyInit( sqlite3 *db, /* Database connection */ void *pAux, /* One of the RTREE_COORD_* constants */ int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ sqlite3_vtab **ppVtab, /* OUT: New virtual table */ char **pzErr, /* OUT: Error message, if any */ int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; int nDb; /* Length of string argv[1] */ int nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; pRtree->eCoordType = RTREE_COORD_REAL32; pRtree->nDim = 2; pRtree->nDim2 = 4; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); pRtree->nAux = 1; /* Add one for _shape */ pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */ for(ii=3; ii<argc; ii++){ pRtree->nAux++; sqlite3_str_appendf(pSql, ",%s", argv[ii]); } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } sqlite3_free(zSql); if( rc ) goto geopolyInit_fail; pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; /* Figure out the node size to use. */ rc = getNodeSize(db, pRtree, isCreate, pzErr); if( rc ) goto geopolyInit_fail; rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); if( rc ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); goto geopolyInit_fail; } *ppVtab = (sqlite3_vtab *)pRtree; return SQLITE_OK; geopolyInit_fail: if( rc==SQLITE_OK ) rc = SQLITE_ERROR; assert( *ppVtab==0 ); assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); return rc; } /* ** GEOPOLY virtual table module xCreate method. */ static int geopolyCreate( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1); } /* ** GEOPOLY virtual table module xConnect method. */ static int geopolyConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0); } /* ** GEOPOLY virtual table module xFilter method. ** ** Query plans: ** ** 1 rowid lookup ** 2 search for objects overlapping the same bounding box ** that contains polygon argv[0] ** 3 search for objects overlapping the same bounding box ** that contains polygon argv[0] ** 4 full table scan */ static int geopolyFilter( sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */ int idxNum, /* Query plan */ const char *idxStr, /* Not Used */ int argc, sqlite3_value **argv /* Parameters to the query plan */ ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int rc = SQLITE_OK; int iCell = 0; sqlite3_stmt *pStmt; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); i64 iNode = 0; rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); if( rc==SQLITE_OK && pLeaf!=0 ){ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); assert( p!=0 ); /* Always returns pCsr->sPoint */ pCsr->aNode[0] = pLeaf; p->id = iNode; p->eWithin = PARTLY_WITHIN; rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); p->iCell = (u8)iCell; RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); }else{ pCsr->atEOF = 1; } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && idxNum<=3 ){ RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); geopolyBBox(0, argv[0], bbox, &rc); if( rc ){ goto geopoly_filter_end; } pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); pCsr->nConstraint = 4; if( p==0 ){ rc = SQLITE_NOMEM; }else{ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4); memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); if( idxNum==2 ){ /* Overlap query */ p->op = 'B'; p->iCoord = 0; p->u.rValue = bbox[1].f; p++; p->op = 'D'; p->iCoord = 1; p->u.rValue = bbox[0].f; p++; p->op = 'B'; p->iCoord = 2; p->u.rValue = bbox[3].f; p++; p->op = 'D'; p->iCoord = 3; p->u.rValue = bbox[2].f; }else{ /* Within query */ p->op = 'D'; p->iCoord = 0; p->u.rValue = bbox[0].f; p++; p->op = 'B'; p->iCoord = 1; p->u.rValue = bbox[1].f; p++; p->op = 'D'; p->iCoord = 2; p->u.rValue = bbox[2].f; p++; p->op = 'B'; p->iCoord = 3; p->u.rValue = bbox[3].f; } } } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( pNew==0 ){ rc = SQLITE_NOMEM; goto geopoly_filter_end; } pNew->id = 1; pNew->iCell = 0; pNew->eWithin = PARTLY_WITHIN; assert( pCsr->bPoint==1 ); pCsr->aNode[0] = pRoot; pRoot = 0; RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); rc = rtreeStepToLeaf(pCsr); } } geopoly_filter_end: nodeRelease(pRtree, pRoot); rtreeRelease(pRtree); return rc; } /* ** Rtree virtual table module xBestIndex method. There are three ** table scan strategies to choose from (in order from most to ** least desirable): ** ** idxNum idxStr Strategy ** ------------------------------------------------ ** 1 "rowid" Direct lookup by rowid. ** 2 "rtree" R-tree overlap query using geopoly_overlap() ** 3 "rtree" R-tree within query using geopoly_within() ** 4 "fullscan" full-table scan. ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( !p->usable ) continue; if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iRowidTerm = ii; break; } if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap() ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within(). ** See geopolyFindFunction() */ iFuncTerm = ii; idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2; } } if( iRowidTerm>=0 ){ pIdxInfo->idxNum = 1; pIdxInfo->idxStr = "rowid"; pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; return SQLITE_OK; } if( iFuncTerm>=0 ){ pIdxInfo->idxNum = idxNum; pIdxInfo->idxStr = "rtree"; pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; pIdxInfo->estimatedCost = 300.0; pIdxInfo->estimatedRows = 10; return SQLITE_OK; } pIdxInfo->idxNum = 4; pIdxInfo->idxStr = "fullscan"; pIdxInfo->estimatedCost = 3000000.0; pIdxInfo->estimatedRows = 100000; return SQLITE_OK; } /* ** GEOPOLY virtual table module xColumn method. */ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ Rtree *pRtree = (Rtree *)cur->pVtab; RtreeCursor *pCsr = (RtreeCursor *)cur; RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( p==0 ) return SQLITE_OK; if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK; if( i<=pRtree->nAux ){ if( !pCsr->bAuxValid ){ if( pCsr->pReadAux==0 ){ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, &pCsr->pReadAux, 0); if( rc ) return rc; } sqlite3_bind_int64(pCsr->pReadAux, 1, nodeGetRowid(pRtree, pNode, p->iCell)); rc = sqlite3_step(pCsr->pReadAux); if( rc==SQLITE_ROW ){ pCsr->bAuxValid = 1; }else{ sqlite3_reset(pCsr->pReadAux); if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; } } sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2)); } return SQLITE_OK; } /* ** The xUpdate method for GEOPOLY module virtual tables. ** ** For DELETE: ** ** argv[0] = the rowid to be deleted ** ** For INSERT: ** ** argv[0] = SQL NULL ** argv[1] = rowid to insert, or an SQL NULL to select automatically ** argv[2] = _shape column ** argv[3] = first application-defined column.... ** ** For UPDATE: ** ** argv[0] = rowid to modify. Never NULL ** argv[1] = rowid after the change. Never NULL ** argv[2] = new value for _shape ** argv[3] = new value for first application-defined column.... */ static int geopolyUpdate( sqlite3_vtab *pVtab, int nData, sqlite3_value **aData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ i64 oldRowid; /* The old rowid */ int oldRowidValid; /* True if oldRowid is valid */ i64 newRowid; /* The new rowid */ int newRowidValid; /* True if newRowid is valid */ int coordChange = 0; /* Change in coordinates */ if( pRtree->nNodeRef ){ /* Unable to write to the btree while another cursor is reading from it, ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;; oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0; newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL; newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0; cell.iRowid = newRowid; if( nData>1 /* not a DELETE */ && (!oldRowidValid /* INSERT */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ pVtab->zErrMsg = sqlite3_mprintf("_shape does not contain a valid polygon"); } goto geopoly_update_end; } coordChange = 1; /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){ 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); } } } } /* If aData[0] is not an SQL NULL value, it is the rowid of a ** record to delete from the r-tree table. The following block does ** just that. */ if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){ rc = rtreeDeleteRowid(pRtree, oldRowid); } /* If the aData[] array contains more than one element, elements ** (aData[2]..aData[argc-1]) contain a new record to insert into ** the r-tree structure. */ if( rc==SQLITE_OK && nData>1 && coordChange ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; if( !newRowidValid ){ rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); } if( rc==SQLITE_OK ){ int rc2; pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } } /* Change the data */ if( rc==SQLITE_OK && nData>1 ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; int nChange = 0; sqlite3_bind_int64(pUp, 1, cell.iRowid); assert( pRtree->nAux>=1 ); if( sqlite3_value_nochange(aData[2]) ){ sqlite3_bind_null(pUp, 2); }else{ GeoPoly *p = 0; if( sqlite3_value_type(aData[2])==SQLITE_TEXT && (p = geopolyFuncParam(0, aData[2], &rc))!=0 && rc==SQLITE_OK ){ sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); }else{ sqlite3_bind_value(pUp, 2, aData[2]); } sqlite3_free(p); nChange = 1; } for(jj=1; jj<pRtree->nAux; jj++){ nChange++; sqlite3_bind_value(pUp, jj+2, aData[jj+2]); } if( nChange ){ sqlite3_step(pUp); rc = sqlite3_reset(pUp); } } geopoly_update_end: rtreeRelease(pRtree); return rc; } /* ** Report that geopoly_overlap() is an overloaded function suitable ** for use in xBestIndex. */ static int geopolyFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ *pxFunc = geopolyOverlapFunc; *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ *pxFunc = geopolyWithinFunc; *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION+1; } return 0; } static sqlite3_module geopolyModule = { 2, /* iVersion */ geopolyCreate, /* xCreate - create a table */ geopolyConnect, /* xConnect - connect to an existing table */ geopolyBestIndex, /* xBestIndex - Determine search strategy */ rtreeDisconnect, /* xDisconnect - Disconnect from a table */ rtreeDestroy, /* xDestroy - Drop a table */ rtreeOpen, /* xOpen - open a cursor */ rtreeClose, /* xClose - close a cursor */ geopolyFilter, /* xFilter - configure scan constraints */ rtreeNext, /* xNext - advance a cursor */ rtreeEof, /* xEof */ geopolyColumn, /* xColumn - read data */ rtreeRowid, /* xRowid - read data */ geopolyUpdate, /* xUpdate - write data */ rtreeBeginTransaction, /* xBegin - begin transaction */ rtreeEndTransaction, /* xSync - sync transaction */ rtreeEndTransaction, /* xCommit - commit transaction */ rtreeEndTransaction, /* xRollback - rollback transaction */ geopolyFindFunction, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ }; static int sqlite3_geopoly_init(sqlite3 *db){ int rc = SQLITE_OK; static const struct { void (*xFunc)(sqlite3_context*,int,sqlite3_value**); signed char nArg; unsigned char bPure; const char *zName; } aFunc[] = { { geopolyAreaFunc, 1, 1, "geopoly_area" }, { geopolyBlobFunc, 1, 1, "geopoly_blob" }, { geopolyJsonFunc, 1, 1, "geopoly_json" }, { geopolySvgFunc, -1, 1, "geopoly_svg" }, { geopolyWithinFunc, 2, 1, "geopoly_within" }, { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" }, { geopolyOverlapFunc, 2, 1, "geopoly_overlap" }, { geopolyDebugFunc, 1, 0, "geopoly_debug" }, { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, { geopolyXformFunc, 7, 1, "geopoly_xform" }, { geopolyRegularFunc, 4, 1, "geopoly_regular" }, }; static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; int i; for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ int enc = aFunc[i].bPure ? SQLITE_UTF8|SQLITE_DETERMINISTIC : SQLITE_UTF8; rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc, 0, aFunc[i].xFunc, 0, 0); } for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aAgg[i].zName, 1, SQLITE_UTF8, 0, 0, aAgg[i].xStep, aAgg[i].xFinal); } if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0); } return rc; } |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 | int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ | > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ u8 nAuxNotNull; /* Number of initial not-null aux columns */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ u32 nNodeRef; /* Number RtreeNodes with positive nRef */ |
︙ | ︙ | |||
2889 2890 2891 2892 2893 2894 2895 | } return rc; } /* ** Select a currently unused rowid for a new r-tree record. */ | | | 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 | } return rc; } /* ** Select a currently unused rowid for a new r-tree record. */ static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){ int rc; sqlite3_bind_null(pRtree->pWriteRowid, 1); sqlite3_bind_null(pRtree->pWriteRowid, 2); sqlite3_step(pRtree->pWriteRowid); rc = sqlite3_reset(pRtree->pWriteRowid); *piRowid = sqlite3_last_insert_rowid(pRtree->db); return rc; |
︙ | ︙ | |||
3176 3177 3178 3179 3180 3181 3182 | */ if( rc==SQLITE_OK && nData>1 ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; /* Figure out the rowid of the new row. */ if( bHaveRowid==0 ){ | | | 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 | */ if( rc==SQLITE_OK && nData>1 ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; /* Figure out the rowid of the new row. */ if( bHaveRowid==0 ){ rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3268 3269 3270 3271 3272 3273 3274 | ** BEGIN; ** INSERT INTO rtree... ** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED ** COMMIT; */ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ Rtree *pRtree = (Rtree *)pVtab; | | | 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 | ** BEGIN; ** INSERT INTO rtree... ** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED ** COMMIT; */ static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ Rtree *pRtree = (Rtree *)pVtab; u8 iwt = pRtree->inWrTrans; UNUSED_PARAMETER(iSavepoint); pRtree->inWrTrans = 0; nodeBlobReset(pRtree); pRtree->inWrTrans = iwt; return SQLITE_OK; } |
︙ | ︙ | |||
3449 3450 3451 3452 3453 3454 3455 | }else{ sqlite3_str *p = sqlite3_str_new(db); int ii; char *zSql; sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; ii<pRtree->nAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); | > > > | > | 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 | }else{ sqlite3_str *p = sqlite3_str_new(db); int ii; char *zSql; sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; ii<pRtree->nAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); if( ii<pRtree->nAuxNotNull ){ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); }else{ sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } } sqlite3_str_appendf(p, " WHERE rowid=?1"); zSql = sqlite3_str_finish(p); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, |
︙ | ︙ | |||
4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 | }else{ sqlite3_result_error_code(ctx, rc); } sqlite3_free(zReport); } } /* ** Register the r-tree module with database handle db. This creates the ** virtual table module "rtree" and the debugging/analysis scalar ** function "rtreenode". */ int sqlite3RtreeInit(sqlite3 *db){ | > > > > | 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 | }else{ sqlite3_result_error_code(ctx, rc); } sqlite3_free(zReport); } } /* Conditionally include the geopoly code */ #ifdef SQLITE_ENABLE_GEOPOLY # include "geopoly.c" #endif /* ** Register the r-tree module with database handle db. This creates the ** virtual table module "rtree" and the debugging/analysis scalar ** function "rtreenode". */ int sqlite3RtreeInit(sqlite3 *db){ |
︙ | ︙ | |||
4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 | #endif rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0); } if( rc==SQLITE_OK ){ void *c = (void *)RTREE_COORD_INT32; rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0); } return rc; } /* ** This routine deletes the RtreeGeomCallback object that was attached ** one of the SQL functions create by sqlite3_rtree_geometry_callback() | > > > > > | 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 | #endif rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0); } if( rc==SQLITE_OK ){ void *c = (void *)RTREE_COORD_INT32; rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0); } #ifdef SQLITE_ENABLE_GEOPOLY if( rc==SQLITE_OK ){ rc = sqlite3_geopoly_init(db); } #endif return rc; } /* ** This routine deletes the RtreeGeomCallback object that was attached ** one of the SQL functions create by sqlite3_rtree_geometry_callback() |
︙ | ︙ |
Added ext/rtree/util/randomshape.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 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 | #!/usr/bin/tclsh # # This script generates a cluster of random polygons that are useful # for testing the geopoly extension. # # Usage: # # tclsh randomshape.tcl | tee x.sql | sqlite3 >x.html # # The output files are x.sql and x.html. Run the above multiple times # until an interesting "x.html" file is found, then use the "x.sql" inputs # to construct test cases. # proc randomenclosure {cx cy p1 p2 p3 p4} { set r 0 set pi 3.145926 set pi2 [expr {$pi*2}] set x0 [expr {$cx + rand()*$p3 + $p4}] set ans "\[\[$x0,$cy\]" while {1} { set r [expr {$r+$p1+$p2*rand()}] if {$r>=$pi2} break set m [expr {rand()*$p3 + $p4}] set x [expr {$cx+$m*cos($r)}] set y [expr {$cy+$m*sin($r)}] append ans ",\[$x,$y\]" } append ans ",\[$x0,$cy\]\]" return $ans } proc randomshape1 {} { set cx [expr {100+int(rand()*800)}] set cy [expr {100+int(rand()*600)}] set p1 [expr {rand()*0.1}] set p2 [expr {rand()*0.5+0.5}] set p3 [expr {rand()*100+25}] set p4 [expr {rand()*25}] return [randomenclosure $cx $cy $p1 $p2 $p3 $p4] } proc randomshape1_sm {} { set cx [expr {100+int(rand()*800)}] set cy [expr {100+int(rand()*600)}] set p1 [expr {rand()*0.1}] set p2 [expr {rand()*0.5+0.5}] set p3 [expr {rand()*10+25}] set p4 [expr {rand()*5}] return [randomenclosure $cx $cy $p1 $p2 $p3 $p4] } proc randomshape2 {} { set cx [expr {400+int(rand()*200)}] set cy [expr {300+int(rand()*200)}] set p1 [expr {rand()*0.05}] set p2 [expr {rand()*0.5+0.5}] set p3 [expr {rand()*50+200}] set p4 [expr {rand()*50+100}] return [randomenclosure $cx $cy $p1 $p2 $p3 $p4] } proc randomcolor {} { set n [expr {int(rand()*5)}] return [lindex {red orange green blue purple} $n] } puts {.print '<html>'} puts {.print '<svg width="1000" height="800" style="border:1px solid black">'} puts {CREATE TABLE t1(poly,clr);} puts {CREATE TABLE t2(poly,clr);} for {set i 0} {$i<30} {incr i} { puts "INSERT INTO t1(rowid,poly,clr)" puts " VALUES($i,'[randomshape1]','[randomcolor]');" } for {set i 30} {$i<80} {incr i} { puts "INSERT INTO t1(rowid,poly,clr)" puts " VALUES($i,'[randomshape1_sm]','[randomcolor]');" } for {set i 100} {$i<105} {incr i} { puts "INSERT INTO t2(rowid,poly,clr)" puts " VALUES($i,'[randomshape2]','[randomcolor]');" } puts {DELETE FROM t1 WHERE geopoly_json(poly) IS NULL;} puts {SELECT geopoly_svg(poly, printf('style="fill:none;stroke:%s;stroke-width:1;"',clr)) FROM t1;} puts {SELECT geopoly_svg(poly, printf('style="fill:none;stroke:%s;stroke-width:2;"',clr)) FROM t2;} puts {.print '<svg>'} |
Added ext/rtree/visual01.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!sqlite3 # # This is a visual test case for the geopoly virtual table. # # Run this script in the sqlite3 CLI, and redirect output into an # HTML file. This display the HTML in a webbrowser. # /* Test data. ** Lots of shapes to be displayed over a 1000x800 canvas. */ CREATE TEMP TABLE basis(name TEXT, jshape TEXT); INSERT INTO basis(name,jshape) VALUES ('box-20','[[0,0],[20,0],[20,20],[0,20],[0,0]]'), ('house-70','[[0,0],[50,0],[50,50],[25,70],[0,50],[0,0]]'), ('line-40','[[0,0],[40,0],[40,5],[0,5],[0,0]]'), ('line-80','[[0,0],[80,0],[80,7],[0,7],[0,0]]'), ('arrow-50','[[0,0],[25,25],[0,50],[15,25],[0,0]]'), ('triangle-30','[[0,0],[30,0],[15,30],[0,0]]'), ('angle-30','[[0,0],[30,0],[30,30],[26,30],[26,4],[0,4],[0,0]]'), ('star-10','[[1,0],[5,2],[9,0],[7,4],[10,8],[7,7],[5,10],[3,7],[0,8],[3,4],[1,0]]'); CREATE TEMP TABLE xform(A,B,C,D,clr); INSERT INTO xform(A,B,clr) VALUES (1,0,'black'), (0.707,0.707,'blue'), (0.5,0.866,'red'), (-0.866,0.5,'green'); CREATE TEMP TABLE xyoff(id1,id2,xoff,yoff,PRIMARY KEY(id1,id2,xoff,yoff)) WITHOUT ROWID; INSERT INTO xyoff VALUES(1,1,811,659); INSERT INTO xyoff VALUES(1,1,235,550); INSERT INTO xyoff VALUES(1,1,481,620); INSERT INTO xyoff VALUES(1,1,106,494); INSERT INTO xyoff VALUES(1,1,487,106); INSERT INTO xyoff VALUES(1,1,817,595); INSERT INTO xyoff VALUES(1,1,240,504); INSERT INTO xyoff VALUES(1,1,806,457); INSERT INTO xyoff VALUES(1,1,608,107); INSERT INTO xyoff VALUES(1,1,768,662); INSERT INTO xyoff VALUES(1,2,808,528); INSERT INTO xyoff VALUES(1,2,768,528); INSERT INTO xyoff VALUES(1,2,771,171); INSERT INTO xyoff VALUES(1,2,275,671); INSERT INTO xyoff VALUES(1,2,326,336); INSERT INTO xyoff VALUES(1,2,690,688); INSERT INTO xyoff VALUES(1,2,597,239); INSERT INTO xyoff VALUES(1,2,317,528); INSERT INTO xyoff VALUES(1,2,366,223); INSERT INTO xyoff VALUES(1,2,621,154); INSERT INTO xyoff VALUES(1,3,829,469); INSERT INTO xyoff VALUES(1,3,794,322); INSERT INTO xyoff VALUES(1,3,358,387); INSERT INTO xyoff VALUES(1,3,184,444); INSERT INTO xyoff VALUES(1,3,729,500); INSERT INTO xyoff VALUES(1,3,333,523); INSERT INTO xyoff VALUES(1,3,117,595); INSERT INTO xyoff VALUES(1,3,496,201); INSERT INTO xyoff VALUES(1,3,818,601); INSERT INTO xyoff VALUES(1,3,541,343); INSERT INTO xyoff VALUES(1,4,603,248); INSERT INTO xyoff VALUES(1,4,761,649); INSERT INTO xyoff VALUES(1,4,611,181); INSERT INTO xyoff VALUES(1,4,607,233); INSERT INTO xyoff VALUES(1,4,860,206); INSERT INTO xyoff VALUES(1,4,310,231); INSERT INTO xyoff VALUES(1,4,727,539); INSERT INTO xyoff VALUES(1,4,660,661); INSERT INTO xyoff VALUES(1,4,403,133); INSERT INTO xyoff VALUES(1,4,619,331); INSERT INTO xyoff VALUES(2,1,712,578); INSERT INTO xyoff VALUES(2,1,567,313); INSERT INTO xyoff VALUES(2,1,231,423); INSERT INTO xyoff VALUES(2,1,490,175); INSERT INTO xyoff VALUES(2,1,898,353); INSERT INTO xyoff VALUES(2,1,589,483); INSERT INTO xyoff VALUES(2,1,188,462); INSERT INTO xyoff VALUES(2,1,720,106); INSERT INTO xyoff VALUES(2,1,793,380); INSERT INTO xyoff VALUES(2,1,154,396); INSERT INTO xyoff VALUES(2,2,324,218); INSERT INTO xyoff VALUES(2,2,120,327); INSERT INTO xyoff VALUES(2,2,655,133); INSERT INTO xyoff VALUES(2,2,516,603); INSERT INTO xyoff VALUES(2,2,529,572); INSERT INTO xyoff VALUES(2,2,481,212); INSERT INTO xyoff VALUES(2,2,802,107); INSERT INTO xyoff VALUES(2,2,234,509); INSERT INTO xyoff VALUES(2,2,501,269); INSERT INTO xyoff VALUES(2,2,349,553); INSERT INTO xyoff VALUES(2,3,495,685); INSERT INTO xyoff VALUES(2,3,897,372); INSERT INTO xyoff VALUES(2,3,350,681); INSERT INTO xyoff VALUES(2,3,832,257); INSERT INTO xyoff VALUES(2,3,778,149); INSERT INTO xyoff VALUES(2,3,683,426); INSERT INTO xyoff VALUES(2,3,693,217); INSERT INTO xyoff VALUES(2,3,746,317); INSERT INTO xyoff VALUES(2,3,805,369); INSERT INTO xyoff VALUES(2,3,336,585); INSERT INTO xyoff VALUES(2,4,890,255); INSERT INTO xyoff VALUES(2,4,556,565); INSERT INTO xyoff VALUES(2,4,865,555); INSERT INTO xyoff VALUES(2,4,230,293); INSERT INTO xyoff VALUES(2,4,247,251); INSERT INTO xyoff VALUES(2,4,730,563); INSERT INTO xyoff VALUES(2,4,318,282); INSERT INTO xyoff VALUES(2,4,220,431); INSERT INTO xyoff VALUES(2,4,828,336); INSERT INTO xyoff VALUES(2,4,278,525); INSERT INTO xyoff VALUES(3,1,324,656); INSERT INTO xyoff VALUES(3,1,625,362); INSERT INTO xyoff VALUES(3,1,155,570); INSERT INTO xyoff VALUES(3,1,267,433); INSERT INTO xyoff VALUES(3,1,599,121); INSERT INTO xyoff VALUES(3,1,873,498); INSERT INTO xyoff VALUES(3,1,789,520); INSERT INTO xyoff VALUES(3,1,656,378); INSERT INTO xyoff VALUES(3,1,831,601); INSERT INTO xyoff VALUES(3,1,256,471); INSERT INTO xyoff VALUES(3,2,332,258); INSERT INTO xyoff VALUES(3,2,305,463); INSERT INTO xyoff VALUES(3,2,796,341); INSERT INTO xyoff VALUES(3,2,830,229); INSERT INTO xyoff VALUES(3,2,413,271); INSERT INTO xyoff VALUES(3,2,269,140); INSERT INTO xyoff VALUES(3,2,628,441); INSERT INTO xyoff VALUES(3,2,747,643); INSERT INTO xyoff VALUES(3,2,584,435); INSERT INTO xyoff VALUES(3,2,784,314); INSERT INTO xyoff VALUES(3,3,722,233); INSERT INTO xyoff VALUES(3,3,815,421); INSERT INTO xyoff VALUES(3,3,401,267); INSERT INTO xyoff VALUES(3,3,451,650); INSERT INTO xyoff VALUES(3,3,329,485); INSERT INTO xyoff VALUES(3,3,878,370); INSERT INTO xyoff VALUES(3,3,162,616); INSERT INTO xyoff VALUES(3,3,844,183); INSERT INTO xyoff VALUES(3,3,161,216); INSERT INTO xyoff VALUES(3,3,176,676); INSERT INTO xyoff VALUES(3,4,780,128); INSERT INTO xyoff VALUES(3,4,566,121); INSERT INTO xyoff VALUES(3,4,646,120); INSERT INTO xyoff VALUES(3,4,223,557); INSERT INTO xyoff VALUES(3,4,251,117); INSERT INTO xyoff VALUES(3,4,139,209); INSERT INTO xyoff VALUES(3,4,813,597); INSERT INTO xyoff VALUES(3,4,454,538); INSERT INTO xyoff VALUES(3,4,616,198); INSERT INTO xyoff VALUES(3,4,210,159); INSERT INTO xyoff VALUES(4,1,208,415); INSERT INTO xyoff VALUES(4,1,326,665); INSERT INTO xyoff VALUES(4,1,612,133); INSERT INTO xyoff VALUES(4,1,537,513); INSERT INTO xyoff VALUES(4,1,638,438); INSERT INTO xyoff VALUES(4,1,808,269); INSERT INTO xyoff VALUES(4,1,552,121); INSERT INTO xyoff VALUES(4,1,100,189); INSERT INTO xyoff VALUES(4,1,643,664); INSERT INTO xyoff VALUES(4,1,726,378); INSERT INTO xyoff VALUES(4,2,478,409); INSERT INTO xyoff VALUES(4,2,497,507); INSERT INTO xyoff VALUES(4,2,233,148); INSERT INTO xyoff VALUES(4,2,587,237); INSERT INTO xyoff VALUES(4,2,604,166); INSERT INTO xyoff VALUES(4,2,165,455); INSERT INTO xyoff VALUES(4,2,320,258); INSERT INTO xyoff VALUES(4,2,353,496); INSERT INTO xyoff VALUES(4,2,347,495); INSERT INTO xyoff VALUES(4,2,166,622); INSERT INTO xyoff VALUES(4,3,461,332); INSERT INTO xyoff VALUES(4,3,685,278); INSERT INTO xyoff VALUES(4,3,427,594); INSERT INTO xyoff VALUES(4,3,467,346); INSERT INTO xyoff VALUES(4,3,125,548); INSERT INTO xyoff VALUES(4,3,597,680); INSERT INTO xyoff VALUES(4,3,820,445); INSERT INTO xyoff VALUES(4,3,144,330); INSERT INTO xyoff VALUES(4,3,557,434); INSERT INTO xyoff VALUES(4,3,254,315); INSERT INTO xyoff VALUES(4,4,157,339); INSERT INTO xyoff VALUES(4,4,249,220); INSERT INTO xyoff VALUES(4,4,391,323); INSERT INTO xyoff VALUES(4,4,589,429); INSERT INTO xyoff VALUES(4,4,859,592); INSERT INTO xyoff VALUES(4,4,337,680); INSERT INTO xyoff VALUES(4,4,410,288); INSERT INTO xyoff VALUES(4,4,636,596); INSERT INTO xyoff VALUES(4,4,734,433); INSERT INTO xyoff VALUES(4,4,559,549); INSERT INTO xyoff VALUES(5,1,549,607); INSERT INTO xyoff VALUES(5,1,584,498); INSERT INTO xyoff VALUES(5,1,699,116); INSERT INTO xyoff VALUES(5,1,525,524); INSERT INTO xyoff VALUES(5,1,304,667); INSERT INTO xyoff VALUES(5,1,302,232); INSERT INTO xyoff VALUES(5,1,403,149); INSERT INTO xyoff VALUES(5,1,824,403); INSERT INTO xyoff VALUES(5,1,697,203); INSERT INTO xyoff VALUES(5,1,293,689); INSERT INTO xyoff VALUES(5,2,199,275); INSERT INTO xyoff VALUES(5,2,395,393); INSERT INTO xyoff VALUES(5,2,657,642); INSERT INTO xyoff VALUES(5,2,200,655); INSERT INTO xyoff VALUES(5,2,882,234); INSERT INTO xyoff VALUES(5,2,483,565); INSERT INTO xyoff VALUES(5,2,755,640); INSERT INTO xyoff VALUES(5,2,810,305); INSERT INTO xyoff VALUES(5,2,731,655); INSERT INTO xyoff VALUES(5,2,466,690); INSERT INTO xyoff VALUES(5,3,563,584); INSERT INTO xyoff VALUES(5,3,491,117); INSERT INTO xyoff VALUES(5,3,779,292); INSERT INTO xyoff VALUES(5,3,375,637); INSERT INTO xyoff VALUES(5,3,253,553); INSERT INTO xyoff VALUES(5,3,797,514); INSERT INTO xyoff VALUES(5,3,229,480); INSERT INTO xyoff VALUES(5,3,257,194); INSERT INTO xyoff VALUES(5,3,449,555); INSERT INTO xyoff VALUES(5,3,849,630); INSERT INTO xyoff VALUES(5,4,329,286); INSERT INTO xyoff VALUES(5,4,640,197); INSERT INTO xyoff VALUES(5,4,104,150); INSERT INTO xyoff VALUES(5,4,438,272); INSERT INTO xyoff VALUES(5,4,773,226); INSERT INTO xyoff VALUES(5,4,441,650); INSERT INTO xyoff VALUES(5,4,242,340); INSERT INTO xyoff VALUES(5,4,301,435); INSERT INTO xyoff VALUES(5,4,171,397); INSERT INTO xyoff VALUES(5,4,541,619); INSERT INTO xyoff VALUES(6,1,651,301); INSERT INTO xyoff VALUES(6,1,637,137); INSERT INTO xyoff VALUES(6,1,765,643); INSERT INTO xyoff VALUES(6,1,173,296); INSERT INTO xyoff VALUES(6,1,263,192); INSERT INTO xyoff VALUES(6,1,791,302); INSERT INTO xyoff VALUES(6,1,860,601); INSERT INTO xyoff VALUES(6,1,780,445); INSERT INTO xyoff VALUES(6,1,462,214); INSERT INTO xyoff VALUES(6,1,802,207); INSERT INTO xyoff VALUES(6,2,811,685); INSERT INTO xyoff VALUES(6,2,533,531); INSERT INTO xyoff VALUES(6,2,390,614); INSERT INTO xyoff VALUES(6,2,260,580); INSERT INTO xyoff VALUES(6,2,116,377); INSERT INTO xyoff VALUES(6,2,860,458); INSERT INTO xyoff VALUES(6,2,438,590); INSERT INTO xyoff VALUES(6,2,604,562); INSERT INTO xyoff VALUES(6,2,241,242); INSERT INTO xyoff VALUES(6,2,667,298); INSERT INTO xyoff VALUES(6,3,787,698); INSERT INTO xyoff VALUES(6,3,868,521); INSERT INTO xyoff VALUES(6,3,412,587); INSERT INTO xyoff VALUES(6,3,640,131); INSERT INTO xyoff VALUES(6,3,748,410); INSERT INTO xyoff VALUES(6,3,257,244); INSERT INTO xyoff VALUES(6,3,411,195); INSERT INTO xyoff VALUES(6,3,464,356); INSERT INTO xyoff VALUES(6,3,157,339); INSERT INTO xyoff VALUES(6,3,434,505); INSERT INTO xyoff VALUES(6,4,480,671); INSERT INTO xyoff VALUES(6,4,519,228); INSERT INTO xyoff VALUES(6,4,404,513); INSERT INTO xyoff VALUES(6,4,120,538); INSERT INTO xyoff VALUES(6,4,403,663); INSERT INTO xyoff VALUES(6,4,477,677); INSERT INTO xyoff VALUES(6,4,690,154); INSERT INTO xyoff VALUES(6,4,606,498); INSERT INTO xyoff VALUES(6,4,430,665); INSERT INTO xyoff VALUES(6,4,499,273); INSERT INTO xyoff VALUES(7,1,118,526); INSERT INTO xyoff VALUES(7,1,817,522); INSERT INTO xyoff VALUES(7,1,388,638); INSERT INTO xyoff VALUES(7,1,181,265); INSERT INTO xyoff VALUES(7,1,442,332); INSERT INTO xyoff VALUES(7,1,475,282); INSERT INTO xyoff VALUES(7,1,722,633); INSERT INTO xyoff VALUES(7,1,104,394); INSERT INTO xyoff VALUES(7,1,631,262); INSERT INTO xyoff VALUES(7,1,372,392); INSERT INTO xyoff VALUES(7,2,600,413); INSERT INTO xyoff VALUES(7,2,386,223); INSERT INTO xyoff VALUES(7,2,839,174); INSERT INTO xyoff VALUES(7,2,293,410); INSERT INTO xyoff VALUES(7,2,281,391); INSERT INTO xyoff VALUES(7,2,859,387); INSERT INTO xyoff VALUES(7,2,478,347); INSERT INTO xyoff VALUES(7,2,646,690); INSERT INTO xyoff VALUES(7,2,713,234); INSERT INTO xyoff VALUES(7,2,199,588); INSERT INTO xyoff VALUES(7,3,389,256); INSERT INTO xyoff VALUES(7,3,349,542); INSERT INTO xyoff VALUES(7,3,363,345); INSERT INTO xyoff VALUES(7,3,751,302); INSERT INTO xyoff VALUES(7,3,423,386); INSERT INTO xyoff VALUES(7,3,267,444); INSERT INTO xyoff VALUES(7,3,243,182); INSERT INTO xyoff VALUES(7,3,453,658); INSERT INTO xyoff VALUES(7,3,126,345); INSERT INTO xyoff VALUES(7,3,120,472); INSERT INTO xyoff VALUES(7,4,359,654); INSERT INTO xyoff VALUES(7,4,339,516); INSERT INTO xyoff VALUES(7,4,710,452); INSERT INTO xyoff VALUES(7,4,810,560); INSERT INTO xyoff VALUES(7,4,644,692); INSERT INTO xyoff VALUES(7,4,826,327); INSERT INTO xyoff VALUES(7,4,465,462); INSERT INTO xyoff VALUES(7,4,310,456); INSERT INTO xyoff VALUES(7,4,577,613); INSERT INTO xyoff VALUES(7,4,502,555); INSERT INTO xyoff VALUES(8,1,601,620); INSERT INTO xyoff VALUES(8,1,372,683); INSERT INTO xyoff VALUES(8,1,758,399); INSERT INTO xyoff VALUES(8,1,485,552); INSERT INTO xyoff VALUES(8,1,159,563); INSERT INTO xyoff VALUES(8,1,536,303); INSERT INTO xyoff VALUES(8,1,122,263); INSERT INTO xyoff VALUES(8,1,836,435); INSERT INTO xyoff VALUES(8,1,544,146); INSERT INTO xyoff VALUES(8,1,270,277); INSERT INTO xyoff VALUES(8,2,849,281); INSERT INTO xyoff VALUES(8,2,563,242); INSERT INTO xyoff VALUES(8,2,704,463); INSERT INTO xyoff VALUES(8,2,102,165); INSERT INTO xyoff VALUES(8,2,797,524); INSERT INTO xyoff VALUES(8,2,612,426); INSERT INTO xyoff VALUES(8,2,345,372); INSERT INTO xyoff VALUES(8,2,820,376); INSERT INTO xyoff VALUES(8,2,789,156); INSERT INTO xyoff VALUES(8,2,321,466); INSERT INTO xyoff VALUES(8,3,150,332); INSERT INTO xyoff VALUES(8,3,136,152); INSERT INTO xyoff VALUES(8,3,468,528); INSERT INTO xyoff VALUES(8,3,409,192); INSERT INTO xyoff VALUES(8,3,820,216); INSERT INTO xyoff VALUES(8,3,847,249); INSERT INTO xyoff VALUES(8,3,801,267); INSERT INTO xyoff VALUES(8,3,181,670); INSERT INTO xyoff VALUES(8,3,398,563); INSERT INTO xyoff VALUES(8,3,439,576); INSERT INTO xyoff VALUES(8,4,123,309); INSERT INTO xyoff VALUES(8,4,190,496); INSERT INTO xyoff VALUES(8,4,571,531); INSERT INTO xyoff VALUES(8,4,290,255); INSERT INTO xyoff VALUES(8,4,244,412); INSERT INTO xyoff VALUES(8,4,264,596); INSERT INTO xyoff VALUES(8,4,253,420); INSERT INTO xyoff VALUES(8,4,847,536); INSERT INTO xyoff VALUES(8,4,120,288); INSERT INTO xyoff VALUES(8,4,331,639); /* Create the geopoly object from test data above */ CREATE VIRTUAL TABLE geo1 USING geopoly(type,clr); INSERT INTO geo1(_shape,type,clr) SELECT geopoly_xform(jshape,A,B,-B,A,xoff,yoff), basis.name, xform.clr FROM basis, xform, xyoff WHERE xyoff.id1=basis.rowid AND xyoff.id2=xform.rowid; /* Query polygon */ CREATE TEMP TABLE querypoly(poly JSON, clr TEXT); INSERT INTO querypoly(clr, poly) VALUES ('orange', '[[300,300],[400,350],[500,250],[480,500],[400,480],[300,550],[280,450],[320,400],[280,350],[300,300]]'); /* Generate the HTML */ .print '<html>' .print '<h1>Everything</h1>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',clr) ) FROM geo1; SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; .print '</svg>' .print '<h1>Overlap Query</h1>' .print '<pre>' .print 'SELECT *' .print ' FROM geo1, querypoly' .print ' WHERE geopoly_overlap(_shape, poly);' .print EXPLAIN QUERY PLAN SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); .print '</pre>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; .print '</svg>' .print '<h1>Overlap Query And Result Bounding Box</h1>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); SELECT geopoly_svg(geopoly_bbox(poly), 'style="fill:none;stroke:black;stroke-width:3"' ) FROM querypoly; SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; SELECT geopoly_svg(geopoly_group_bbox(_shape), 'style="fill:none;stroke:red;stroke-width:3"' ) FROM geo1, querypoly WHERE geopoly_overlap(_shape, poly); .print '</svg>' .print '<h1>Bounding-Box Overlap Query</h1>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ), geopoly_svg(geopoly_bbox(_shape), 'style="fill:none;stroke:black;stroke-width:1"' ) FROM geo1, querypoly WHERE geopoly_overlap(geopoly_bbox(_shape), geopoly_bbox(poly)); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; SELECT geopoly_svg(geopoly_bbox(poly), 'style="fill:none;stroke:black;stroke-width:3"' ) FROM querypoly; .print '</svg>' .print '<h1>Within Query</h1>' .print '<pre>' .print 'SELECT *' .print ' FROM geo1, querypoly' .print ' WHERE geopoly_within(_shape, poly);' .print EXPLAIN QUERY PLAN SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE geopoly_within(_shape, poly); .print '</pre>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE geopoly_within(_shape, poly); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; .print '</svg>' .print '<h1>Bounding-Box WITHIN Query</h1>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ), geopoly_svg(geopoly_bbox(_shape), 'style="fill:none;stroke:black;stroke-width:1"' ) FROM geo1, querypoly WHERE geopoly_within(geopoly_bbox(_shape), geopoly_bbox(poly)); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; SELECT geopoly_svg(geopoly_bbox(poly), 'style="fill:none;stroke:black;stroke-width:3"' ) FROM querypoly; .print '</svg>' .print '<h1>Not Overlap Query</h1>' .print '<pre>' .print 'SELECT *' .print ' FROM geo1, querypoly' .print ' WHERE NOT geopoly_overlap(_shape, poly);' .print EXPLAIN QUERY PLAN SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE NOT geopoly_overlap(_shape, poly); .print '</pre>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE NOT geopoly_overlap(_shape, poly); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; .print '</svg>' .print '<h1>Not Within Query</h1>' .print '<pre>' .print 'SELECT *' .print ' FROM geo1, querypoly' .print ' WHERE NOT geopoly_within(_shape, poly);' .print EXPLAIN QUERY PLAN SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE NOT geopoly_within(_shape, poly); .print '</pre>' .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1, querypoly WHERE NOT geopoly_within(_shape, poly); SELECT geopoly_svg(poly, printf('style="fill:%s;fill-opacity:0.5;"',clr) ) FROM querypoly; .print '</svg>' .print '<h1>Color-Change For Overlapping Elements</h1>' BEGIN; UPDATE geo1 SET clr=CASE WHEN rowid IN (SELECT geo1.rowid FROM geo1, querypoly WHERE geopoly_overlap(_shape,poly)) THEN 'red' ELSE 'blue' END; .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1; SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') FROM querypoly; ROLLBACK; .print '</svg>' .print '<h1>Color-Change And Move Overlapping Elements</h1>' BEGIN; UPDATE geo1 SET clr=CASE WHEN rowid IN (SELECT geo1.rowid FROM geo1, querypoly WHERE geopoly_overlap(_shape,poly)) THEN 'red' ELSE '#76ccff' END; UPDATE geo1 SET _shape=geopoly_xform(_shape,1,0,0,1,300,0) WHERE geopoly_overlap(_shape,(SELECT poly FROM querypoly)); .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1; SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') FROM querypoly; --ROLLBACK; .print '</svg>' .print '<h1>Overlap With Translated Query Polygon</h1>' UPDATE querypoly SET poly=geopoly_xform(poly,1,0,0,1,300,0); .print '<svg width="1000" height="800" style="border:1px solid black">' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) ) FROM geo1 WHERE geopoly_overlap(_shape,(SELECT poly FROM querypoly)); SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') FROM querypoly; ROLLBACK; .print '</svg>' .print '<h1>Regular Polygons</h1>' .print '<svg width="1000" height="200" style="border:1px solid black">' SELECT geopoly_svg(geopoly_regular(100,100,40,3),'style="fill:none;stroke:red;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(200,100,40,4),'style="fill:none;stroke:orange;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(300,100,40,5),'style="fill:none;stroke:green;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(400,100,40,6),'style="fill:none;stroke:blue;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(500,100,40,7),'style="fill:none;stroke:purple;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(600,100,40,8),'style="fill:none;stroke:red;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(700,100,40,10),'style="fill:none;stroke:orange;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(800,100,40,20),'style="fill:none;stroke:green;stroke-width:1"'); SELECT geopoly_svg(geopoly_regular(900,100,40,30),'style="fill:none;stroke:blue;stroke-width:1"'); .print '</svg>' .print '</html>' |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
4884 4885 4886 4887 4888 4889 4890 | sessionAppendTableHdr(&buf, eChangeset, pTab, &rc); for(i=0; i<pTab->nChange; i++){ SessionChange *p; for(p=pTab->apChange[i]; p; p=p->pNext){ sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); | < < < | | | | > > | 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 | sessionAppendTableHdr(&buf, eChangeset, pTab, &rc); for(i=0; i<pTab->nChange; i++){ SessionChange *p; for(p=pTab->apChange[i]; p; p=p->pNext){ sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ rc = xOutput(pOut, buf.aBuf, buf.nBuf); buf.nBuf = 0; } } } } if( rc==SQLITE_OK ){ if( xOutput ){ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); }else{ *ppOut = buf.aBuf; |
︙ | ︙ |
Changes to ext/userauth/userauth.c.
︙ | ︙ | |||
206 207 208 209 210 211 212 | if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM; db->auth.zAuthPW = sqlite3_malloc( nPW+1 ); if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM; memcpy(db->auth.zAuthPW,zPW,nPW); db->auth.nAuthPW = nPW; rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel); db->auth.authLevel = authLevel; | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM; db->auth.zAuthPW = sqlite3_malloc( nPW+1 ); if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM; memcpy(db->auth.zAuthPW,zPW,nPW); db->auth.nAuthPW = nPW; rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel); db->auth.authLevel = authLevel; sqlite3ExpirePreparedStatements(db, 0); if( rc ){ return rc; /* OOM error, I/O error, etc. */ } if( authLevel<UAUTH_User ){ return SQLITE_AUTH; /* Incorrect username and/or password */ } return SQLITE_OK; /* Successful login */ |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
225 226 227 228 229 230 231 | $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/sqlite3rtree.h \ $(TOP)/ext/rtree/rtree.h \ | | > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | $(TOP)/ext/fts3/fts3_write.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/sqlite3rtree.h \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c \ $(TOP)/ext/rtree/geopoly.c SRC += \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3session.h SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ |
︙ | ︙ | |||
356 357 358 359 360 361 362 363 364 365 366 367 368 369 | # 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/mmapwarm.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ | > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | # 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/explain.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/mmapwarm.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ |
︙ | ︙ | |||
472 473 474 475 476 477 478 | $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ | | > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/geopoly.c EXTHDR += \ $(TOP)/ext/icu/sqliteicu.h EXTHDR += \ $(TOP)/ext/fts5/fts5Int.h \ fts5parse.h \ $(TOP)/ext/fts5/fts5.h EXTHDR += \ |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o fts3view$(EXE) \ $(TOP)/ext/fts3/tool/fts3view.c sqlite3.o $(THREADLIB) rollback-test$(EXE): $(TOP)/tool/rollback-test.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \ $(TOP)/tool/rollback-test.c sqlite3.o $(THREADLIB) LogEst$(EXE): $(TOP)/tool/logest.c sqlite3.h $(TCC) -o LogEst$(EXE) $(TOP)/tool/logest.c wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o wordcount$(EXE) \ $(TOP)/test/wordcount.c sqlite3.c | > > > > | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o fts3view$(EXE) \ $(TOP)/ext/fts3/tool/fts3view.c sqlite3.o $(THREADLIB) rollback-test$(EXE): $(TOP)/tool/rollback-test.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o rollback-test$(EXE) \ $(TOP)/tool/rollback-test.c sqlite3.o $(THREADLIB) atrc$(EXE): $(TOP)/test/atrc.c sqlite3.o $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o atrc$(EXE) \ $(TOP)/test/atrc.c sqlite3.o $(THREADLIB) LogEst$(EXE): $(TOP)/tool/logest.c sqlite3.h $(TCC) -o LogEst$(EXE) $(TOP)/tool/logest.c wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c $(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o wordcount$(EXE) \ $(TOP)/test/wordcount.c sqlite3.c |
︙ | ︙ |
Changes to src/alter.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 | /* ** The code in this file only exists if we are not omitting the ** ALTER TABLE logic from the build. */ #ifndef SQLITE_OMIT_ALTERTABLE | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | 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 | /* ** The code in this file only exists if we are not omitting the ** ALTER TABLE logic from the build. */ #ifndef SQLITE_OMIT_ALTERTABLE /* ** Parameter zName is the name of a table that is about to be altered ** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN). ** If the table is a system table, this function leaves an error message ** in pParse->zErr (system tables may not be altered) and returns non-zero. ** ** Or, if zName is not a system table, zero is returned. */ static int isSystemTable(Parse *pParse, const char *zName){ if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){ sqlite3ErrorMsg(pParse, "table %s may not be altered", zName); return 1; } return 0; } /* ** Generate code to verify that the schemas of database zDb and, if ** bTemp is not true, database "temp", can still be parsed. This is ** called at the end of the generation of an ALTER TABLE ... RENAME ... ** statement to ensure that the operation has not rendered any schema ** objects unusable. */ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\".%s " "WHERE name NOT LIKE 'sqlite_%%'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", zDb, MASTER_NAME, zDb, bTemp ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp.%s " "WHERE name NOT LIKE 'sqlite_%%'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", MASTER_NAME, zDb ); } } /* ** Generate code to reload the schema for database iDb. And, if iDb!=1, for ** the temp database as well. */ static void renameReloadSchema(Parse *pParse, int iDb){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); } } /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ void sqlite3AlterRenameTable( Parse *pParse, /* Parser context. */ SrcList *pSrc, /* The table to rename. */ Token *pName /* The new table name. */ ){ int iDb; /* Database that contains the table */ char *zDb; /* Name of database iDb */ Table *pTab; /* Table being renamed */ char *zName = 0; /* NULL-terminated version of pName */ sqlite3 *db = pParse->db; /* Database connection */ int nTabName; /* Number of UTF-8 characters in zTabName */ const char *zTabName; /* Original name of the table */ Vdbe *v; VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */ u32 savedDbFlags; /* Saved value of db->mDbFlags */ savedDbFlags = db->mDbFlags; if( NEVER(db->mallocFailed) ) goto exit_rename_table; assert( pSrc->nSrc==1 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); |
︙ | ︙ | |||
470 471 472 473 474 475 476 | ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | 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 | ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in ** the schema to use the new table name. */ sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" "AND name NOT LIKE 'sqlite_%%'" , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName ); /* Update the tbl_name and name columns of the sqlite_master table ** as required. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " "(type='table' OR type='index' OR type='trigger');", zDb, MASTER_NAME, zName, zName, zName, nTabName, zTabName ); #ifndef SQLITE_OMIT_AUTOINCREMENT /* If the sqlite_sequence table exists in this database, then update ** it with the new table name. */ if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){ sqlite3NestedParse(pParse, "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q", zDb, zName, pTab->zName); } #endif /* If the table being renamed is not itself part of the temp database, ** edit view and trigger definitions within the temp database ** as required. */ if( iDb!=1 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), " "tbl_name = " "CASE WHEN tbl_name=%Q COLLATE nocase AND " " sqlite_rename_test(%Q, sql, type, name, 1) " "THEN %Q ELSE tbl_name END " "WHERE type IN ('view', 'trigger')" , zDb, zTabName, zName, zTabName, zDb, zName); } /* If this is a virtual table, invoke the xRename() function if ** one is defined. The xRename() callback will modify the names ** of any resources used by the v-table implementation (including other ** SQLite tables) that are identified by the name of the virtual table. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( pVTab ){ int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); sqlite3MayAbort(pParse); } #endif renameReloadSchema(pParse, iDb); renameTestSchema(pParse, zDb, iDb==1); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); db->mDbFlags = savedDbFlags; } |
︙ | ︙ | |||
596 597 598 599 600 601 602 | int iDb; /* Database number */ 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; */ | | < | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | int iDb; /* Database number */ 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; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; pNew = pParse->pNewTable; assert( pNew ); assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pNew->pSchema); zDb = db->aDb[iDb].zDbSName; zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */ |
︙ | ︙ | |||
696 697 698 699 700 701 702 | db->mDbFlags = 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. */ | > > | | | | | | | | | > | | < | 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 | db->mDbFlags = 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. */ v = sqlite3GetVdbe(pParse); if( v ){ 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 table definition */ renameReloadSchema(pParse, iDb); } /* ** This function is called by the parser after the table-name in ** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument ** pSrc is the full-name of the table being altered. ** ** This routine makes a (partial) copy of the Table structure ** for the table being altered and sets Parse.pNewTable to point ** to it. Routines called by the parser as the column definition ** is parsed (i.e. sqlite3AddColumn()) add the new Column data to ** the copy. The copy of the Table structure is deleted by tokenize.c ** after parsing is finished. ** ** Routine sqlite3AlterFinishAddColumn() will be called to complete ** coding the "ALTER TABLE ... ADD" statement. */ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ Table *pNew; Table *pTab; int iDb; int i; int nAlloc; sqlite3 *db = pParse->db; /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); |
︙ | ︙ | |||
791 792 793 794 795 796 797 | pCol->zColl = 0; pCol->pDflt = 0; } pNew->pSchema = db->aDb[iDb].pSchema; pNew->addColOffset = pTab->addColOffset; pNew->nTabRef = 1; | < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 896 897 898 899 900 901 902 903 904 905 906 907 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 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 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 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 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 1053 1054 1055 1056 1057 1058 1059 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 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 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 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 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 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 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 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 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 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 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 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 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 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | pCol->zColl = 0; pCol->pDflt = 0; } pNew->pSchema = db->aDb[iDb].pSchema; pNew->addColOffset = pTab->addColOffset; pNew->nTabRef = 1; exit_begin_add_column: sqlite3SrcListDelete(db, pSrc); return; } /* ** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN ** command. This function checks if the table is a view or virtual ** table (columns of views or virtual tables may not be renamed). If so, ** it loads an error message into pParse and returns non-zero. ** ** Or, if pTab is not a view or virtual table, zero is returned. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) static int isRealTable(Parse *pParse, Table *pTab){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ zType = "view"; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ zType = "virtual table"; } #endif if( zType ){ sqlite3ErrorMsg( pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName ); return 1; } return 0; } #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ # define isRealTable(x,y) (0) #endif /* ** Handles the following parser reduction: ** ** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew */ void sqlite3AlterRenameColumn( Parse *pParse, /* Parsing context */ SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */ Token *pOld, /* Name of column being changed */ Token *pNew /* New column name */ ){ sqlite3 *db = pParse->db; /* Database connection */ Table *pTab; /* Table being updated */ int iCol; /* Index of column being renamed */ char *zOld = 0; /* Old column name */ char *zNew = 0; /* New column name */ const char *zDb; /* Name of schema containing the table */ int iSchema; /* Index of the schema */ int bQuote; /* True to quote the new name */ /* Locate the table to be altered */ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_rename_column; /* Cannot alter a system table */ if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column; if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column; /* Which schema holds the table to be altered */ iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iSchema>=0 ); zDb = db->aDb[iSchema].zDbSName; #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){ goto exit_rename_column; } #endif /* Make sure the old name really is a column name in the table to be ** altered. Set iCol to be the index of the column being renamed */ zOld = sqlite3NameFromToken(db, pOld); if( !zOld ) goto exit_rename_column; for(iCol=0; iCol<pTab->nCol; iCol++){ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break; } if( iCol==pTab->nCol ){ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld); goto exit_rename_column; } /* Do the rename operation using a recursive UPDATE statement that ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_master table. */ zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); bQuote = sqlite3Isquote(pNew->z[0]); sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" " AND sql NOT LIKE 'create virtual%%'", zDb, MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->zName ); sqlite3NestedParse(pParse, "UPDATE temp.%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " "WHERE type IN ('trigger', 'view')", MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iSchema); renameTestSchema(pParse, zDb, iSchema==1); exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } /* ** Each RenameToken object maps an element of the parse tree into ** the token that generated that element. The parse tree element ** might be one of: ** ** * A pointer to an Expr that represents an ID ** * The name of a table column in Column.zName ** ** A list of RenameToken objects can be constructed during parsing. ** Each new object is created by sqlite3RenameTokenMap(). ** As the parse tree is transformed, the sqlite3RenameTokenRemap() ** routine is used to keep the mapping current. ** ** After the parse finishes, renameTokenFind() routine can be used ** to look up the actual token value that created some element in ** the parse tree. */ struct RenameToken { void *p; /* Parse tree element created by token t */ Token t; /* The token that created parse tree element p */ RenameToken *pNext; /* Next is a list of all RenameToken objects */ }; /* ** The context of an ALTER TABLE RENAME COLUMN operation that gets passed ** down into the Walker. */ typedef struct RenameCtx RenameCtx; struct RenameCtx { RenameToken *pList; /* List of tokens to overwrite */ int nList; /* Number of tokens in pList */ int iCol; /* Index of column being renamed */ Table *pTab; /* Table being ALTERed */ const char *zOld; /* Old column name */ }; #ifdef SQLITE_DEBUG /* ** This function is only for debugging. It performs two tasks: ** ** 1. Checks that pointer pPtr does not already appear in the ** rename-token list. ** ** 2. Dereferences each pointer in the rename-token list. ** ** The second is most effective when debugging under valgrind or ** address-sanitizer or similar. If any of these pointers no longer ** point to valid objects, an exception is raised by the memory-checking ** tool. ** ** The point of this is to prevent comparisons of invalid pointer values. ** Even though this always seems to work, it is undefined according to the ** C standard. Example of undefined comparison: ** ** sqlite3_free(x); ** if( x==y ) ... ** ** Technically, as x no longer points into a valid object or to the byte ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, void *pPtr){ if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ RenameToken *p; u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); i += *(u8*)(p->p); } } } } #else # define renameTokenCheckAll(x,y) #endif /* ** Add a new RenameToken object mapping parse tree element pPtr into ** token *pToken to the Parse object currently under construction. ** ** Return a copy of pPtr. */ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ RenameToken *pNew; assert( pPtr || pParse->db->mallocFailed ); renameTokenCheckAll(pParse, pPtr); pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken)); if( pNew ){ pNew->p = pPtr; pNew->t = *pToken; pNew->pNext = pParse->pRename; pParse->pRename = pNew; } return pPtr; } /* ** It is assumed that there is already a RenameToken object associated ** with parse tree element pFrom. This function remaps the associated token ** to parse tree element pTo. */ void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){ RenameToken *p; renameTokenCheckAll(pParse, pTo); for(p=pParse->pRename; p; p=p->pNext){ if( p->p==pFrom ){ p->p = pTo; break; } } } /* ** Walker callback used by sqlite3RenameExprUnmap(). */ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); return WRC_Continue; } /* ** Remove all nodes that are part of expression pExpr from the rename list. */ void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sqlite3WalkExpr(&sWalker, pExpr); } /* ** Remove all nodes that are part of expression-list pEList from the ** rename list. */ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ if( pEList ){ int i; Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sqlite3WalkExprList(&sWalker, pEList); for(i=0; i<pEList->nExpr; i++){ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName); } } } /* ** Free the list of RenameToken objects given in the second argument */ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ RenameToken *pNext; RenameToken *p; for(p=pToken; p; p=pNext){ pNext = p->pNext; sqlite3DbFree(db, p); } } /* ** Search the Parse object passed as the first argument for a RenameToken ** object associated with parse tree element pPtr. If found, remove it ** from the Parse object and add it to the list maintained by the ** RenameCtx object passed as the second argument. */ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){ RenameToken **pp; assert( pPtr!=0 ); for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ if( (*pp)->p==pPtr ){ RenameToken *pToken = *pp; *pp = pToken->pNext; pToken->pNext = pCtx->pList; pCtx->pList = pToken; pCtx->nList++; break; } } } /* ** This is a Walker select callback. It does nothing. It is only required ** because without a dummy callback, sqlite3WalkExpr() and similar do not ** descend into sub-select statements. */ static int renameColumnSelectCb(Walker *pWalker, Select *p){ UNUSED_PARAMETER(pWalker); UNUSED_PARAMETER(p); return WRC_Continue; } /* ** This is a Walker expression callback. ** ** For every TK_COLUMN node in the expression tree, search to see ** if the column being references is the column being renamed by an ** ALTER TABLE statement. If it is, then attach its associated ** RenameToken object to the list of RenameToken objects being ** constructed in RenameCtx object at pWalker->u.pRename. */ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_TRIGGER && pExpr->iColumn==p->iCol && pWalker->pParse->pTriggerTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); }else if( pExpr->op==TK_COLUMN && pExpr->iColumn==p->iCol && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); } return WRC_Continue; } /* ** The RenameCtx contains a list of tokens that reference a column that ** is being renamed by an ALTER TABLE statement. Return the "last" ** RenameToken in the RenameCtx and remove that RenameToken from the ** RenameContext. "Last" means the last RenameToken encountered when ** the input SQL is parsed from left to right. Repeated calls to this routine ** return all column name tokens in the order that they are encountered ** in the SQL statement. */ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ RenameToken *pBest = pCtx->pList; RenameToken *pToken; RenameToken **pp; for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){ if( pToken->t.z>pBest->t.z ) pBest = pToken; } for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext); *pp = pBest->pNext; return pBest; } /* ** An error occured while parsing or otherwise processing a database ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an ** ALTER TABLE RENAME COLUMN program. The error message emitted by the ** sub-routine is currently stored in pParse->zErrMsg. This function ** adds context to the error message and then stores it in pCtx. */ static void renameColumnParseError( sqlite3_context *pCtx, int bPost, sqlite3_value *pType, sqlite3_value *pObject, Parse *pParse ){ const char *zT = (const char*)sqlite3_value_text(pType); const char *zN = (const char*)sqlite3_value_text(pObject); char *zErr; zErr = sqlite3_mprintf("error in %s %s%s: %s", zT, zN, (bPost ? " after rename" : ""), pParse->zErrMsg ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); } /* ** For each name in the the expression-list pEList (i.e. each ** pEList->a[i].zName) that matches the string in zOld, extract the ** corresponding rename-token from Parse object pParse and add it ** to the RenameCtx pCtx. */ static void renameColumnElistNames( Parse *pParse, RenameCtx *pCtx, ExprList *pEList, const char *zOld ){ if( pEList ){ int i; for(i=0; i<pEList->nExpr; i++){ char *zName = pEList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (void*)zName); } } } } /* ** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) ** that matches the string in zOld, extract the corresponding rename-token ** from Parse object pParse and add it to the RenameCtx pCtx. */ static void renameColumnIdlistNames( Parse *pParse, RenameCtx *pCtx, IdList *pIdList, const char *zOld ){ if( pIdList ){ int i; for(i=0; i<pIdList->nId; i++){ char *zName = pIdList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (void*)zName); } } } } /* ** Parse the SQL statement zSql using Parse object (*p). The Parse object ** is initialized by this function before it is used. */ static int renameParseSql( Parse *p, /* Memory to use for Parse object */ const char *zDb, /* Name of schema SQL belongs to */ int bTable, /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */ sqlite3 *db, /* Database handle */ const char *zSql, /* SQL to parse */ int bTemp /* True if SQL is from temp schema */ ){ int rc; char *zErr = 0; db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb); /* Parse the SQL statement passed as the first argument. If no error ** occurs and the parse does not result in a new table, index or ** trigger object, the database must be corrupt. */ memset(p, 0, sizeof(Parse)); p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN); p->db = db; p->nQueryLoop = 1; rc = sqlite3RunParser(p, zSql, &zErr); assert( p->zErrMsg==0 ); assert( rc!=SQLITE_OK || zErr==0 ); assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 ); p->zErrMsg = zErr; if( db->mallocFailed ) rc = SQLITE_NOMEM; if( rc==SQLITE_OK && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0 ){ rc = SQLITE_CORRUPT_BKPT; } #ifdef SQLITE_DEBUG /* Ensure that all mappings in the Parse.pRename list really do map to ** a part of the input string. */ if( rc==SQLITE_OK ){ int nSql = sqlite3Strlen30(zSql); RenameToken *pToken; for(pToken=p->pRename; pToken; pToken=pToken->pNext){ assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] ); } } #endif db->init.iDb = 0; return rc; } /* ** This function edits SQL statement zSql, replacing each token identified ** by the linked list pRename with the text of zNew. If argument bQuote is ** true, then zNew is always quoted first. If no error occurs, the result ** is loaded into context object pCtx as the result. ** ** Or, if an error occurs (i.e. an OOM condition), an error is left in ** pCtx and an SQLite error code returned. */ static int renameEditSql( sqlite3_context *pCtx, /* Return result here */ RenameCtx *pRename, /* Rename context */ const char *zSql, /* SQL statement to edit */ const char *zNew, /* New token text */ int bQuote /* True to always quote token */ ){ int nNew = sqlite3Strlen30(zNew); int nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; char *zQuot; char *zOut; int nQuot; /* Set zQuot to point to a buffer containing a quoted copy of the ** identifier zNew. If the corresponding identifier in the original ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to ** point to zQuot so that all substitutions are made using the ** quoted version of the new column name. */ zQuot = sqlite3MPrintf(db, "\"%w\"", zNew); if( zQuot==0 ){ return SQLITE_NOMEM; }else{ nQuot = sqlite3Strlen30(zQuot); } if( bQuote ){ zNew = zQuot; nNew = nQuot; } /* At this point pRename->pList contains a list of RenameToken objects ** corresponding to all tokens in the input SQL that must be replaced ** with the new column name. All that remains is to construct and ** return the edited SQL string. */ assert( nQuot>=nNew ); zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); if( zOut ){ int nOut = nSql; memcpy(zOut, zSql, nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ RenameToken *pBest = renameColumnTokenNext(pRename); u32 nReplace; const char *zReplace; if( sqlite3IsIdChar(*pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ nReplace = nQuot; zReplace = zQuot; } iOff = pBest->t.z - zSql; if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) ); nOut += nReplace - pBest->t.n; zOut[nOut] = '\0'; } memcpy(&zOut[iOff], zReplace, nReplace); sqlite3DbFree(db, pBest); } sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT); sqlite3DbFree(db, zOut); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zQuot); return rc; } /* ** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming ** it was read from the schema of database zDb. Return SQLITE_OK if ** successful. Otherwise, return an SQLite error code and leave an error ** message in the Parse object. */ static int renameResolveTrigger(Parse *pParse, const char *zDb){ sqlite3 *db = pParse->db; Trigger *pNew = pParse->pNewTrigger; TriggerStep *pStep; NameContext sNC; int rc = SQLITE_OK; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; assert( pNew->pTabSchema ); pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName ); pParse->eTriggerOp = pNew->op; /* Resolve symbols in WHEN clause */ if( pNew->pWhen ){ rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); } for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){ if( pStep->pSelect ){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } if( rc==SQLITE_OK && pStep->zTarget ){ Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb); if( pTarget==0 ){ rc = SQLITE_ERROR; }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){ SrcList sSrc; memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; sSrc.a[0].zName = pStep->zTarget; sSrc.a[0].pTab = pTarget; sNC.pSrcList = &sSrc; if( pStep->pWhere ){ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList); } assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) ); if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; assert( rc==SQLITE_OK ); pUpsert->pUpsertSrc = &sSrc; sNC.uNC.pUpsert = pUpsert; sNC.ncFlags = NC_UUpsert; rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget); if( rc==SQLITE_OK ){ ExprList *pUpsertSet = pUpsert->pUpsertSet; rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere); } if( rc==SQLITE_OK ){ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); } sNC.ncFlags = 0; } } } } return rc; } /* ** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr ** objects that are part of the trigger passed as the second argument. */ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ TriggerStep *pStep; /* Find tokens to edit in WHEN clause */ sqlite3WalkExpr(pWalker, pTrigger->pWhen); /* Find tokens to edit in trigger steps */ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ sqlite3WalkSelect(pWalker, pStep->pSelect); sqlite3WalkExpr(pWalker, pStep->pWhere); sqlite3WalkExprList(pWalker, pStep->pExprList); if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } } } /* ** Free the contents of Parse object (*pParse). Do not free the memory ** occupied by the Parse object itself. */ static void renameParseCleanup(Parse *pParse){ sqlite3 *db = pParse->db; if( pParse->pVdbe ){ sqlite3VdbeFinalize(pParse->pVdbe); } sqlite3DeleteTable(db, pParse->pNewTable); if( pParse->pNewIndex ) sqlite3FreeIndex(db, pParse->pNewIndex); sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); sqlite3ParserReset(pParse); } /* ** SQL function: ** ** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld) ** ** 0. zSql: SQL statement to rewrite ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3. Database: Database name (e.g. "main") ** 4. Table: Table name ** 5. iCol: Index of column to rename ** 6. zNew: New column name ** 7. bQuote: Non-zero if the new column name should be quoted. ** 8. bTemp: True if zSql comes from temp schema ** ** Do a column rename operation on the CREATE statement given in zSql. ** The iCol-th column (left-most is 0) of table zTable is renamed from zCol ** into zNew. The name should be quoted if bQuote is true. ** ** This function is used internally by the ALTER TABLE RENAME COLUMN command. ** Though accessible to application code, it is not intended for use by ** applications. The existance of this function, and the way it works, ** is subject to change without notice. ** ** If any of the parameters are out-of-bounds, then simply return NULL. ** An out-of-bounds parameter can only occur when the application calls ** this function directly. The parameters will always be well-formed when ** this routine is invoked by the bytecode for a legitimate ALTER TABLE ** statement. */ static void renameColumnFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); RenameCtx sCtx; const char *zSql = (const char*)sqlite3_value_text(argv[0]); const char *zDb = (const char*)sqlite3_value_text(argv[3]); const char *zTable = (const char*)sqlite3_value_text(argv[4]); int iCol = sqlite3_value_int(argv[5]); const char *zNew = (const char*)sqlite3_value_text(argv[6]); int bQuote = sqlite3_value_int(argv[7]); int bTemp = sqlite3_value_int(argv[8]); const char *zOld; int rc; Parse sParse; Walker sWalker; Index *pIdx; int i; Table *pTab; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; #endif UNUSED_PARAMETER(NotUsed); if( zSql==0 ) return; if( zTable==0 ) return; if( zNew==0 ) return; if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } zOld = pTab->aCol[iCol].zName; memset(&sCtx, 0, sizeof(sCtx)); sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp); /* Find tokens that need to be replaced. */ memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameColumnExprCb; sWalker.xSelectCallback = renameColumnSelectCb; sWalker.u.pRename = &sCtx; sCtx.pTab = pTab; if( rc!=SQLITE_OK ) goto renameColumnFunc_done; if( sParse.pNewTable ){ Select *pSelect = sParse.pNewTable->pSelect; if( pSelect ){ sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } if( rc!=SQLITE_OK ) goto renameColumnFunc_done; }else{ /* A regular table */ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); FKey *pFKey; assert( sParse.pNewTable->pSelect==0 ); sCtx.pTab = sParse.pNewTable; if( bFKOnly==0 ){ renameTokenFind( &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName ); if( sCtx.iCol<0 ){ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey); } sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck); for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } } for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(i=0; i<pFKey->nCol; i++){ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]); } if( 0==sqlite3_stricmp(pFKey->zTo, zTable) && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld) ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol); } } } } }else if( sParse.pNewIndex ){ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr); sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); }else{ /* A trigger */ TriggerStep *pStep; rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb)); if( rc!=SQLITE_OK ) goto renameColumnFunc_done; for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget ){ Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); if( pTarget==pTab ){ if( pStep->pUpsert ){ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld); } renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld); renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld); } } } /* Find tokens to edit in UPDATE OF clause */ if( sParse.pTriggerTab==pTab ){ renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); } /* Find tokens to edit in various expressions and selects */ renameWalkTrigger(&sWalker, sParse.pNewTrigger); } assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, 0, argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif sqlite3BtreeLeaveAll(db); } /* ** Walker expression callback used by "RENAME TABLE". */ static int renameTableExprCb(Walker *pWalker, Expr *pExpr){ RenameCtx *p = pWalker->u.pRename; if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab); } return WRC_Continue; } /* ** Walker select callback used by "RENAME TABLE". */ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){ int i; RenameCtx *p = pWalker->u.pRename; SrcList *pSrc = pSelect->pSrc; for(i=0; i<pSrc->nSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } return WRC_Continue; } /* ** This C function implements an SQL user function that is used by SQL code ** generated by the ALTER TABLE ... RENAME command to modify the definition ** of any foreign key constraints that use the table being renamed as the ** parent table. It is passed three arguments: ** ** 0: The database containing the table being renamed. ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3: The complete text of the schema statement being modified, ** 4: The old name of the table being renamed, and ** 5: The new name of the table being renamed. ** 6: True if the schema statement comes from the temp db. ** ** It returns the new schema statement. For example: ** ** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0) ** -> 'CREATE TABLE t1(a REFERENCES t3)' */ static void renameTableFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); const char *zDb = (const char*)sqlite3_value_text(argv[0]); const char *zInput = (const char*)sqlite3_value_text(argv[3]); const char *zOld = (const char*)sqlite3_value_text(argv[4]); const char *zNew = (const char*)sqlite3_value_text(argv[5]); int bTemp = sqlite3_value_int(argv[6]); UNUSED_PARAMETER(NotUsed); if( zInput && zOld && zNew ){ Parse sParse; int rc; int bQuote = 1; RenameCtx sCtx; Walker sWalker; #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif sqlite3BtreeEnterAll(db); memset(&sCtx, 0, sizeof(RenameCtx)); sCtx.pTab = sqlite3FindTable(db, zOld, zDb); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameTableExprCb; sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp); if( rc==SQLITE_OK ){ int isLegacy = (db->flags & SQLITE_LegacyAlter); if( sParse.pNewTable ){ Table *pTab = sParse.pNewTable; if( pTab->pSelect ){ if( isLegacy==0 ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; sqlite3WalkSelect(&sWalker, pTab->pSelect); } }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY if( db->flags & SQLITE_ForeignKeys ){ FKey *pFKey; for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); } } } #endif /* If this is the table being altered, fix any table refs in CHECK ** expressions. Also update the name that appears right after the ** "CREATE [VIRTUAL] TABLE" bit. */ if( sqlite3_stricmp(zOld, pTab->zName)==0 ){ sCtx.pTab = pTab; if( isLegacy==0 ){ sqlite3WalkExprList(&sWalker, pTab->pCheck); } renameTokenFind(&sParse, &sCtx, pTab->zName); } } } else if( sParse.pNewIndex ){ renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName); if( isLegacy==0 ){ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere); } } #ifndef SQLITE_OMIT_TRIGGER else{ Trigger *pTrigger = sParse.pNewTrigger; TriggerStep *pStep; if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) && sCtx.pTab->pSchema==pTrigger->pTabSchema ){ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); } if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb); if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, pTrigger); for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ renameTokenFind(&sParse, &sCtx, pStep->zTarget); } } } } } #endif } if( rc==SQLITE_OK ){ rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote); } if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, 0, argv[1], argv[2], &sParse); }else{ sqlite3_result_error_code(context, rc); } } renameParseCleanup(&sParse); renameTokenFree(db, sCtx.pList); sqlite3BtreeLeaveAll(db); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } return; } /* ** An SQL user function that checks that there are no parse or symbol ** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement. ** After an ALTER TABLE .. RENAME operation is performed and the schema ** reloaded, this function is called on each SQL statement in the schema ** to ensure that it is still usable. ** ** 0: Database name ("main", "temp" etc.). ** 1: SQL statement. ** 2: Object type ("view", "table", "trigger" or "index"). ** 3: Object name. ** 4: True if object is from temp schema. ** ** Unless it finds an error, this function normally returns NULL. However, it ** returns integer value 1 if: ** ** * the SQL argument creates a trigger, and ** * the table that the trigger is attached to is in database zDb. */ static void renameTableTest( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char const *zDb = (const char*)sqlite3_value_text(argv[0]); char const *zInput = (const char*)sqlite3_value_text(argv[1]); int bTemp = sqlite3_value_int(argv[4]); int isLegacy = (db->flags & SQLITE_LegacyAlter); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp); if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; } else if( sParse.pNewTrigger ){ if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb); } if( rc==SQLITE_OK ){ int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema); int i2 = sqlite3FindDbName(db, zDb); if( i1==i2 ) sqlite3_result_int(context, 1); } } } if( rc!=SQLITE_OK ){ renameColumnParseError(context, 1, argv[2], argv[3], &sParse); } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } /* ** Register built-in functions used to help implement ALTER TABLE */ void sqlite3AlterFunctions(void){ static FuncDef aAlterTableFuncs[] = { FUNCTION(sqlite_rename_column, 9, 0, 0, renameColumnFunc), FUNCTION(sqlite_rename_table, 7, 0, 0, renameTableFunc), FUNCTION(sqlite_rename_test, 5, 0, 0, renameTableTest), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } #endif /* SQLITE_ALTER_TABLE */ |
Changes to src/analyze.c.
︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 | for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 | | | 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 | for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx); } /* Load the statistics from the sqlite_stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( rc==SQLITE_OK ){ db->lookaside.bDisable++; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bDisable--; } for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3_free(pIdx->aiRowEst); |
︙ | ︙ |
Changes to src/auth.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 | ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; sqlite3ExpirePreparedStatements(db, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. |
︙ | ︙ | |||
203 204 205 206 207 208 209 | ){ sqlite3 *db = pParse->db; int rc; /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ | | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | ){ sqlite3 *db = pParse->db; int rc; /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ if( db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } if( db->xAuth==0 ){ return SQLITE_OK; } |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 | ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } | > > > > > > | 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 | ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 ); if( (p->db->flags & SQLITE_ResetDatabase) && sqlite3PagerIsreadonly(pBt->pPager)==0 ){ pBt->btsFlags &= ~BTS_READ_ONLY; } /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } |
︙ | ︙ | |||
9800 9801 9802 9803 9804 9805 9806 | ** reference to the page, add an error message to pCheck->zErrMsg. ** Return 1 if there are 2 or more references to the page and 0 if ** if this is the first reference to the page. ** ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ | < | | 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 | ** reference to the page, add an error message to pCheck->zErrMsg. ** Return 1 if there are 2 or more references to the page and 0 if ** if this is the first reference to the page. ** ** Also check that the page number is in bounds. */ static int checkRef(IntegrityCk *pCheck, Pgno iPage){ if( iPage>pCheck->nPage || iPage==0 ){ checkAppendMsg(pCheck, "invalid page number %d", iPage); return 1; } if( getPageReferenced(pCheck, iPage) ){ checkAppendMsg(pCheck, "2nd reference to page %d", iPage); return 1; } |
︙ | ︙ | |||
9856 9857 9858 9859 9860 9861 9862 | IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ int N /* Expected number of pages in the list */ ){ int i; int expected = N; | | | < < < < < < > | 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 | IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ int N /* Expected number of pages in the list */ ){ int i; int expected = N; int nErrAtStart = pCheck->nErr; while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; unsigned char *pOvflData; if( checkRef(pCheck, iPage) ) break; N--; if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){ checkAppendMsg(pCheck, "failed to get page %d", iPage); break; } pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage); if( isFreeList ){ int n = get4byte(&pOvflData[4]); |
︙ | ︙ | |||
9910 9911 9912 9913 9914 9915 9916 | i = get4byte(pOvflData); checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); } } #endif iPage = get4byte(pOvflData); sqlite3PagerUnref(pOvflPage); | | | | < > > > | 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 | i = get4byte(pOvflData); checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage); } } #endif iPage = get4byte(pOvflData); sqlite3PagerUnref(pOvflPage); } if( N && nErrAtStart==pCheck->nErr ){ checkAppendMsg(pCheck, "%s is %d but should be %d", isFreeList ? "size" : "overflow list length", expected-N, expected); } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** An implementation of a min-heap. ** |
︙ | ︙ | |||
10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 | sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; /* Check all the tables. */ testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~SQLITE_CellSizeCk; for(i=0; (int)i<nRoot && sCheck.mxErr; i++){ i64 notUsed; if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && aRoot[i]>1 ){ | > > > > > > > > > > > > > > > > > > | 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 | sCheck.zPfx = "Main freelist: "; checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36])); sCheck.zPfx = 0; /* Check all the tables. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ int mx = 0; int mxInHdr; for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i]; mxInHdr = get4byte(&pBt->pPage1->aData[52]); if( mx!=mxInHdr ){ checkAppendMsg(&sCheck, "max rootpage (%d) disagrees with header (%d)", mx, mxInHdr ); } }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){ checkAppendMsg(&sCheck, "incremental_vacuum enabled with a max rootpage of zero" ); } #endif testcase( pBt->db->flags & SQLITE_CellSizeCk ); pBt->db->flags &= ~SQLITE_CellSizeCk; for(i=0; (int)i<nRoot && sCheck.mxErr; i++){ i64 notUsed; if( aRoot[i]==0 ) continue; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && aRoot[i]>1 ){ |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
223 224 225 226 227 228 229 | } } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 && !db->mallocFailed ){ | < | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | } } /* Get the VDBE program ready for execution */ if( v && pParse->nErr==0 && !db->mallocFailed ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; sqlite3VdbeMakeReady(v, pParse); pParse->rc = SQLITE_DONE; }else{ pParse->rc = SQLITE_ERROR; |
︙ | ︙ | |||
438 439 440 441 442 443 444 | } return p; } /* ** Reclaim the memory used by an index */ | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | } return p; } /* ** Reclaim the memory used by an index */ void sqlite3FreeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl); |
︙ | ︙ | |||
478 479 480 481 482 483 484 | ** indices. */ p = pIndex->pTable->pIndex; while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; } if( ALWAYS(p && p->pNext==pIndex) ){ p->pNext = pIndex->pNext; } } | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | ** indices. */ p = pIndex->pTable->pIndex; while( ALWAYS(p) && p->pNext!=pIndex ){ p = p->pNext; } if( ALWAYS(p && p->pNext==pIndex) ){ p->pNext = pIndex->pNext; } } sqlite3FreeIndex(db, pIndex); } db->mDbFlags |= DBFLAG_SchemaChange; } /* ** Look through the list of open database files in db->aDb[] and if ** any have been closed, remove them from the list. Reallocate the |
︙ | ︙ | |||
624 625 626 627 628 629 630 | 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 ); } | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | 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 ); } sqlite3FreeIndex(db, pIndex); } /* Delete any foreign keys attached to this table. */ sqlite3FkDelete(db, pTable); /* Delete the Table structure itself. */ |
︙ | ︙ | |||
782 783 784 785 786 787 788 | *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ | | | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } |
︙ | ︙ | |||
877 878 879 880 881 882 883 884 885 886 887 888 889 890 | /* If creating a temp table, the name may not be qualified. Unless ** the database name is "temp" anyway. */ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); return; } if( !OMIT_TEMPDB && isTemp ) iDb = 1; zName = sqlite3NameFromToken(db, pName); } pParse->sNameToken = *pName; if( zName==0 ) return; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; | > > > | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 | /* If creating a temp table, the name may not be qualified. Unless ** the database name is "temp" anyway. */ sqlite3ErrorMsg(pParse, "temporary table name must be unqualified"); return; } if( !OMIT_TEMPDB && isTemp ) iDb = 1; zName = sqlite3NameFromToken(db, pName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)zName, pName); } } pParse->sNameToken = *pName; if( zName==0 ) return; if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto begin_table_error; } if( db->init.iDb==1 ) isTemp = 1; |
︙ | ︙ | |||
912 913 914 915 916 917 918 | /* Make sure the new table name does not collide with an existing ** index or table name in the same database. Issue an error message if ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ | | | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | /* Make sure the new table name does not collide with an existing ** index or table name in the same database. Issue an error message if ** it does. The exception is if the statement being parsed was passed ** to an sqlite3_declare_vtab() call. In that case only the column names ** and types will be used, so there is no need to test for namespace ** collisions. */ if( !IN_SPECIAL_PARSE ){ char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | if( (p = pParse->pNewTable)==0 ) return; if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; memcpy(z, pName->z, pName->n); z[pName->n] = 0; sqlite3Dequote(z); for(i=0; i<p->nCol; i++){ if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); | > | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | if( (p = pParse->pNewTable)==0 ) return; if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName); return; } z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName); memcpy(z, pName->z, pName->n); z[pName->n] = 0; sqlite3Dequote(z); for(i=0; i<p->nCol; i++){ if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); } } sqlite3ExprDelete(db, pExpr); } /* ** Backwards Compatibility Hack: ** ** Historical versions of SQLite accepted strings as column names in | > > > | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); } } if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, pExpr); } sqlite3ExprDelete(db, pExpr); } /* ** Backwards Compatibility Hack: ** ** Historical versions of SQLite accepted strings as column names in |
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 | } } if( nTerm==1 && pCol && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT | > > > | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 | } } if( nTerm==1 && pCol && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT |
︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 | for(i=0; i<pTab->nCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ pTab->aCol[i].notNull = OE_Abort; } } } | < < < < | 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | for(i=0; i<pTab->nCol; i++){ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ pTab->aCol[i].notNull = OE_Abort; } } } /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY ** into BTREE_BLOBKEY. */ if( pParse->addrCrTab ){ assert( v ); sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY); } |
︙ | ︙ | |||
2170 2171 2172 2173 2174 2175 2176 | if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ | > > > > | > | 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 | if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ if( IN_RENAME_OBJECT ){ p->pSelect = pSelect; pSelect = 0; }else{ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; |
︙ | ︙ | |||
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 | sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); sqlite3ExprListDelete(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* | > > > | 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 | sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); if( IN_RENAME_OBJECT ){ sqlite3RenameExprlistUnmap(pParse, pCNames); } sqlite3ExprListDelete(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* |
︙ | ︙ | |||
2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 | ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); pSel = sqlite3SelectDup(db, pTable->pSelect, 0); if( pSel ){ n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; db->lookaside.bDisable++; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; | > > > > | 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 | ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); pSel = sqlite3SelectDup(db, pTable->pSelect, 0); if( pSel ){ #ifndef SQLITE_OMIT_ALTERTABLE u8 eParseMode = pParse->eParseMode; pParse->eParseMode = PARSE_MODE_NORMAL; #endif n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; db->lookaside.bDisable++; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; |
︙ | ︙ | |||
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | }else{ pTable->nCol = 0; nErr++; } sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); db->lookaside.bDisable--; } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); pTable->aCol = 0; | > > > | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 | }else{ pTable->nCol = 0; nErr++; } sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); db->lookaside.bDisable--; #ifndef SQLITE_OMIT_ALTERTABLE pParse->eParseMode = eParseMode; #endif } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); pTable->aCol = 0; |
︙ | ︙ | |||
2660 2661 2662 2663 2664 2665 2666 | /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); | > | | > | 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 | /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); if( !isView ){ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); sqlite3FkDropTable(pParse, pName, pTab); } sqlite3CodeDropTable(pParse, pTab, iDb, isView); } exit_drop_table: sqlite3SrcListDelete(db, pName); } |
︙ | ︙ | |||
2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 | if( pFKey==0 ){ goto fk_end; } pFKey->pFrom = p; pFKey->pNextFrom = p->pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); z += pTo->n+1; pFKey->nCol = nCol; if( pFromCol==0 ){ pFKey->aCol[0].iFrom = p->nCol-1; | > > > | 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 | if( pFKey==0 ){ goto fk_end; } pFKey->pFrom = p; pFKey->pNextFrom = p->pFKey; z = (char*)&pFKey->aCol[nCol]; pFKey->zTo = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)z, pTo); } memcpy(z, pTo->z, pTo->n); z[pTo->n] = 0; sqlite3Dequote(z); z += pTo->n+1; pFKey->nCol = nCol; if( pFromCol==0 ){ pFKey->aCol[0].iFrom = p->nCol-1; |
︙ | ︙ | |||
2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 | } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zName); goto fk_end; } } } if( pToCol ){ for(i=0; i<nCol; i++){ int n = sqlite3Strlen30(pToCol->a[i].zName); pFKey->aCol[i].zCol = z; memcpy(z, pToCol->a[i].zName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ | > > > > > > | 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 | } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zName); goto fk_end; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName); } } } if( pToCol ){ for(i=0; i<nCol; i++){ int n = sqlite3Strlen30(pToCol->a[i].zName); pFKey->aCol[i].zCol = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName); } memcpy(z, pToCol->a[i].zName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; pFKey->aAction[0] = (u8)(flags & 0xff); /* ON DELETE action */ |
︙ | ︙ | |||
3096 3097 3098 3099 3100 3101 3102 | if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } | > | | | | | | | | | | | | | | | > | < > | 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 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 | if( pName ){ zName = sqlite3NameFromToken(db, pName); if( zName==0 ) goto exit_create_index; assert( pName->z!=0 ); if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !IN_RENAME_OBJECT ){ if( !db->init.busy ){ if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; } } if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){ if( !ifNotExist ){ sqlite3ErrorMsg(pParse, "index %s already exists", zName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); } goto exit_create_index; } } }else{ 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_SPECIAL_PARSE ) zName[7]++; } /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION if( !IN_RENAME_OBJECT ){ const char *zDb = pDb->zDbSName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; if( sqlite3AuthCheck(pParse, i, zName, pTab->zName, zDb) ){ |
︙ | ︙ | |||
3218 3219 3220 3221 3222 3223 3224 | ** a table column, store that column in aiColumn[]. For general expressions, ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. ** ** TODO: Issue a warning if two or more columns of the index are identical. ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ | > > > > > | < | < < | < | 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 | ** a table column, store that column in aiColumn[]. For general expressions, ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[]. ** ** TODO: Issue a warning if two or more columns of the index are identical. ** TODO: Issue a warning if the table primary key is used as part of the ** index key. */ pListItem = pList->a; if( IN_RENAME_OBJECT ){ pIndex->aColExpr = pList; pList = 0; } for(i=0; i<pIndex->nKeyCol; i++, pListItem++){ Expr *pCExpr; /* The i-th index expression */ int requestedSortOrder; /* ASC or DESC on the i-th expression */ const char *zColl; /* Collation sequence name */ sqlite3StringToId(pListItem->pExpr); sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if( pParse->nErr ) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); if( pCExpr->op!=TK_COLUMN ){ if( pTab==pParse->pNewTable ){ sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " "UNIQUE constraints"); goto exit_create_index; } if( pIndex->aColExpr==0 ){ pIndex->aColExpr = pList; pList = 0; } j = XN_EXPR; pIndex->aiColumn[i] = XN_EXPR; pIndex->uniqNotNull = 0; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); |
︙ | ︙ | |||
3378 3379 3380 3381 3382 3383 3384 | } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 | } if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType; goto exit_create_index; } } } if( !IN_RENAME_OBJECT ){ /* 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_SPECIAL_PARSE ); 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; } db->mDbFlags |= DBFLAG_SchemaChange; if( pTblName!=0 ){ pIndex->tnum = db->init.newTnum; } } /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then ** emit code to allocate the index rootpage on disk and make an entry for ** the index in the sqlite_master table and populate the index with ** content. But, do not do this if we are simply reading the sqlite_master ** table to parse the schema, or if this index is the PRIMARY KEY index ** of a WITHOUT ROWID table. ** ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY ** or UNIQUE index in a CREATE TABLE statement. Since the table ** has just been created, it contains no data and the index initialization ** step can be skipped. */ else if( HasRowid(pTab) || pTblName!=0 ){ Vdbe *v; char *zStmt; int iMem = ++pParse->nMem; v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; sqlite3BeginWriteOperation(pParse, 1, iDb); /* Create the rootpage for the index using CreateIndex. But before ** doing so, code a Noop instruction and store its address in ** Index.tnum. This is required in case this index is actually a ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In ** that case the convertToWithoutRowidTable() routine will replace ** the Noop with a Goto to jump over the VDBE code generated below. */ pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop); sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable */ if( pStart ){ int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n; if( pName->z[n-1]==';' ) n--; /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", onError==OE_None ? "" : " UNIQUE", n, pName->z); }else{ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */ /* zStmt = sqlite3MPrintf(""); */ zStmt = 0; } /* Add an entry in sqlite_master for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName, pTab->zName, iMem, zStmt ); sqlite3DbFree(db, zStmt); /* Fill the index with data and reparse the schema. Code an OP_Expire ** 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)); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } 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 ** OE_Ignore. This is necessary for the correct constraint check ** processing (in sqlite3GenerateConstraintChecks()) as part of ** UPDATE and INSERT statements. |
︙ | ︙ | |||
3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 | pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pIndex = 0; } /* Clean up before exiting */ exit_create_index: | > > > > > | | 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 | pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pIndex = 0; } else if( IN_RENAME_OBJECT ){ assert( pParse->pNewIndex==0 ); pParse->pNewIndex = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ) sqlite3FreeIndex(db, pIndex); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* |
︙ | ︙ | |||
3665 3666 3667 3668 3669 3670 3671 | /* ** Append a new element to the given IdList. Create a new IdList if ** need be. ** ** A new IdList is returned, or NULL if malloc() fails. */ | | > > > > | 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 | /* ** Append a new element to the given IdList. Create a new IdList if ** need be. ** ** A new IdList is returned, or NULL if malloc() fails. */ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); if( pList==0 ) return 0; } pList->a = sqlite3ArrayAllocate( db, pList->a, sizeof(pList->a[0]), &pList->nId, &i ); if( i<0 ){ sqlite3IdListDelete(db, pList); return 0; } pList->a[i].zName = sqlite3NameFromToken(db, pToken); if( IN_RENAME_OBJECT && pList->a[i].zName ){ sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); } return pList; } /* ** Delete an IdList. */ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ |
︙ | ︙ | |||
3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 | } p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 ){ goto append_from_error; } assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; pItem->pOn = pOn; pItem->pUsing = pUsing; | > > > > > > | 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 | } p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 ){ goto append_from_error; } assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( (pTable==0)==(pDatabase==0) ); assert( pItem->zName==0 || pDatabase!=0 ); if( IN_RENAME_OBJECT && pItem->zName ){ Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; sqlite3RenameTokenMap(pParse, pItem->zName, pToken); } assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; pItem->pOn = pOn; pItem->pUsing = pUsing; |
︙ | ︙ |
Changes to src/ctime.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #endif /* These macros are provided to "stringify" the value of the define ** for those options in which the value is meaningful. */ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) /* ** An array of names of all compile-time options. This array should ** be sorted A-Z. ** ** This array looks large, but in a typical installation actually uses ** only a handful of compile-time options, so most times this array is usually ** rather short and uses little memory space. | > > > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #endif /* These macros are provided to "stringify" the value of the define ** for those options in which the value is meaningful. */ #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) /* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This ** option requires a separate macro because legal values contain a single ** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ #define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 #define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) /* ** An array of names of all compile-time options. This array should ** be sorted A-Z. ** ** This array looks large, but in a typical installation actually uses ** only a handful of compile-time options, so most times this array is usually ** rather short and uses little memory space. |
︙ | ︙ | |||
109 110 111 112 113 114 115 | #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), #endif #ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #ifdef SQLITE_DEFAULT_LOOKASIDE | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT), #endif #ifdef SQLITE_DEFAULT_LOCKING_MODE "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), #endif #ifdef SQLITE_DEFAULT_LOOKASIDE "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), #endif #if SQLITE_DEFAULT_MEMSTATUS "DEFAULT_MEMSTATUS", #endif #ifdef SQLITE_DEFAULT_MMAP_SIZE "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), #endif |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
459 460 461 462 463 464 465 | for(i=0; i<nPk; i++){ assert( pPk->aiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ | | | < | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | for(i=0; i<nPk; i++){ assert( pPk->aiColumn[i]>=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ iKey = ++pParse->nMem; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); } if( eOnePass!=ONEPASS_OFF ){ /* For ONEPASS, no need to store the rowid/primary-key. There is only ** one, so just keep it in its register(s) and fall through to the ** delete code. */ nKey = nPk; /* OP_Found will use an unpacked key */ |
︙ | ︙ | |||
894 895 896 897 898 899 900 | int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iSelfTab = iDataCur + 1; | < | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; }else{ *piPartIdxLabel = 0; } } |
︙ | ︙ | |||
941 942 943 944 945 946 947 | ** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label ** because it was a partial index, then this routine should be called to ** resolve that label. */ void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ if( iLabel ){ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); | < | 939 940 941 942 943 944 945 946 947 | ** If a prior call to sqlite3GenerateIndexKey() generated a jump-over label ** because it was a partial index, then this routine should be called to ** resolve that label. */ void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ if( iLabel ){ sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel); } } |
Changes to src/expr.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 | if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft->flags&EP_xIsSelect ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } |
︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 | CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; Expr *p = pExpr; while( p ){ int op = p->op; if( p->flags & EP_Generic ) break; if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); | > > > > > > > > > > > > > < < < < < < < < < < < < < | 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 | CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; Expr *p = pExpr; while( p ){ int op = p->op; if( p->flags & EP_Generic ) break; if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER) && p->y.pTab!=0 ){ /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ int j = p->iColumn; if( j>=0 ){ const char *zColl = p->y.pTab->aCol[j].zColl; pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken); break; } if( p->flags & EP_Collate ){ if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){ p = p->pLeft; }else{ Expr *pNext = p->pRight; |
︙ | ︙ | |||
577 578 579 580 581 582 583 | regRight = exprCodeSubselect(pParse, pRight); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; assert( i>=0 && i<nLeft ); | < < | 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 | regRight = exprCodeSubselect(pParse, pRight); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; assert( i>=0 && i<nLeft ); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne); sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); if( i==nLeft-1 ){ break; } if( opx==TK_EQ ){ sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v); p5 |= SQLITE_KEEPNULL; }else if( opx==TK_NE ){ |
︙ | ︙ | |||
937 938 939 940 941 942 943 | } } /* ** Construct a new expression node for a function with multiple ** arguments. */ | | > > > > > > > > > | 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 | } } /* ** Construct a new expression node for a function with multiple ** arguments. */ Expr *sqlite3ExprFunction( Parse *pParse, /* Parsing context */ ExprList *pList, /* Argument list */ Token *pToken, /* Name of the function */ int eDistinct /* SF_Distinct or SF_ALL or 0 */ ){ Expr *pNew; sqlite3 *db = pParse->db; assert( pToken ); pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1); if( pNew==0 ){ sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); assert( !ExprHasProperty(pNew, EP_xIsSelect) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } /* ** Assign a variable number to an expression that encodes a wildcard ** in the original SQL statement. ** |
︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 | /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); assert( p->x.pSelect==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( p->x.pList==0 || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ sqlite3ExprDeleteNN(db, p->pRight); }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); } | > > > > | > | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 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 | /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); assert( p->x.pSelect==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( p->x.pList==0 || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ sqlite3ExprDeleteNN(db, p->pRight); }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); } if( ExprHasProperty(p, EP_WinFunc) ){ assert( p->op==TK_FUNCTION ); sqlite3WindowDelete(db, p->y.pWin); } } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbFreeNN(db, p); } } |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | static int dupedExprStructSize(Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==flags || p->op==TK_SELECT_COLUMN #ifndef SQLITE_OMIT_WINDOWFUNC | | | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | static int dupedExprStructSize(Expr *p, int flags){ int nSize; assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */ assert( EXPR_FULLSIZE<=0xfff ); assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 ); if( 0==flags || p->op==TK_SELECT_COLUMN #ifndef SQLITE_OMIT_WINDOWFUNC || ExprHasProperty(p, EP_WinFunc) #endif ){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_FromJoin) ); assert( !ExprHasProperty(p, EP_MemToken) ); |
︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 | pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); } } /* Fill in pNew->pLeft and pNew->pRight. */ | | > > > > > > < < < < < < < | 1266 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 1294 1295 1296 1297 | pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags); }else{ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags); } } /* Fill in pNew->pLeft and pNew->pRight. */ if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){ zAlloc += dupedExprNodeSize(p, dupFlags); if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){ pNew->pLeft = p->pLeft ? exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0; pNew->pRight = p->pRight ? exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0; } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(p, EP_WinFunc) ){ pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin); assert( ExprHasProperty(pNew, EP_WinFunc) ); } #endif /* SQLITE_OMIT_WINDOWFUNC */ if( pzBuffer ){ *pzBuffer = zAlloc; } }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->iColumn==0 || p->pRight==0 ); assert( p->pRight==0 || p->pRight==p->pLeft ); }else{ pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0); |
︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; assert( pItem->zName==0 ); pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ) sqlite3Dequote(pItem->zName); } } /* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. ** | > > > | 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; assert( pItem->zName==0 ); pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ) sqlite3Dequote(pItem->zName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName); } } } /* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. ** |
︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 | case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; } /* Fall through */ case TK_IF_NULL_ROW: case TK_REGISTER: testcase( pExpr->op==TK_REGISTER ); | > > > | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 | case TK_COLUMN: case TK_AGG_FUNCTION: case TK_AGG_COLUMN: testcase( pExpr->op==TK_ID ); testcase( pExpr->op==TK_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); testcase( pExpr->op==TK_AGG_COLUMN ); if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){ return WRC_Continue; } if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){ return WRC_Continue; } /* Fall through */ case TK_IF_NULL_ROW: case TK_REGISTER: testcase( pExpr->op==TK_REGISTER ); |
︙ | ︙ | |||
1890 1891 1892 1893 1894 1895 1896 | ** a constant. */ int sqlite3ExprIsConstant(Expr *p){ return exprIsConst(p, 1, 0); } /* | | | | | > > > > > > > | 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 | ** a constant. */ int sqlite3ExprIsConstant(Expr *p){ return exprIsConst(p, 1, 0); } /* ** Walk an expression tree. Return non-zero if ** ** (1) the expression is constant, and ** (2) the expression does originate in the ON or USING clause ** of a LEFT JOIN, and ** (3) the expression does not contain any EP_FixedCol TK_COLUMN ** operands created by the constant propagation optimization. ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when ** the prepared statement starts up. See sqlite3ExprCodeAtInit(). */ int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); } /* ** Walk an expression tree. Return non-zero if the expression is constant |
︙ | ︙ | |||
1923 1924 1925 1926 1927 1928 1929 | /* Check if pExpr is identical to any GROUP BY term. If so, consider ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 | /* Check if pExpr is identical to any GROUP BY term. If so, consider ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p); if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ if( ExprHasProperty(pExpr, EP_xIsSelect) ){ |
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | case TK_INTEGER: case TK_STRING: case TK_FLOAT: case TK_BLOB: return 0; case TK_COLUMN: return ExprHasProperty(p, EP_CanBeNull) || | | | | 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 | case TK_INTEGER: case TK_STRING: case TK_FLOAT: case TK_BLOB: return 0; case TK_COLUMN: return ExprHasProperty(p, EP_CanBeNull) || p->y.pTab==0 || /* Reference to column of index on expression */ (p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0); default: return 1; } } /* ** Return TRUE if the given expression is a constant which would be |
︙ | ︙ | |||
2345 2346 2347 2348 2349 2350 2351 | if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ /* The "x IN (SELECT rowid FROM table)" case */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; | | > | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 | if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){ /* The "x IN (SELECT rowid FROM table)" case */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; ExplainQueryPlan((pParse, 0, "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName)); sqlite3VdbeJumpHere(v, iAddr); }else{ Index *pIdx; /* Iterator variable */ int affinity_ok = 1; int i; /* Check that the affinity that will be used to perform each |
︙ | ︙ | |||
2604 2605 2606 2607 2608 2609 2610 | int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ int jmpIfDynamic = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; | < | 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 | int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ int jmpIfDynamic = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it ** is encountered if any of the following is true: ** ** * The right-hand side is a correlated subquery ** * The right-hand side is an expression list containing variables ** * We are inside a trigger |
︙ | ︙ | |||
2740 2741 2742 2743 2744 2745 2746 | if( isRowid ){ sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); | < | 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 | if( isRowid ){ sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1); } } } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } |
︙ | ︙ | |||
2821 2822 2823 2824 2825 2826 2827 | if( rHasNullFlag ){ sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); } if( jmpIfDynamic>=0 ){ sqlite3VdbeJumpHere(v, jmpIfDynamic); } | < | 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 | if( rHasNullFlag ){ sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); } if( jmpIfDynamic>=0 ){ sqlite3VdbeJumpHere(v, jmpIfDynamic); } return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ #ifndef SQLITE_OMIT_SUBQUERY /* |
︙ | ︙ | |||
2940 2941 2942 2943 2944 2945 2946 | ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. */ | < | 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 | ** at r1. ** ** sqlite3FindInIndex() might have reordered the fields of the LHS vector ** so that the fields are in the same order as an existing index. The ** aiMap[] array contains a mapping from the original LHS field order to ** the field order that matches the RHS index. */ rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */ if( i==nVector ){ /* LHS fields are not reordered */ rLhs = rLhsOrig; }else{ /* Need to reorder the LHS fields according to aiMap */ |
︙ | ︙ | |||
3099 3100 3101 3102 3103 3104 3105 | } /* Jumps here in order to return true. */ sqlite3VdbeJumpHere(v, addrTruthOp); sqlite3ExprCodeIN_finished: if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); | < | 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 | } /* Jumps here in order to return true. */ sqlite3VdbeJumpHere(v, addrTruthOp); sqlite3ExprCodeIN_finished: if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs); VdbeComment((v, "end IN expr")); sqlite3ExprCodeIN_oom_error: sqlite3DbFree(pParse->db, aiMap); sqlite3DbFree(pParse->db, zAff); } #endif /* SQLITE_OMIT_SUBQUERY */ |
︙ | ︙ | |||
3167 3168 3169 3170 3171 3172 3173 | }else{ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 | }else{ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } } /* Generate code that will load into register regOut a value that is ** appropriate for the iIdxCol-th column of index pIdx. */ void sqlite3ExprCodeLoadIndexColumn( Parse *pParse, /* The parsing context */ Index *pIdx, /* The index whose column is to be loaded */ |
︙ | ︙ | |||
3368 3369 3370 3371 3372 3373 3374 | if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | 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 | if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in register iReg. ** ** There must be an open cursor to pTab in iTable when this routine ** is called. If iColumn<0 then code is generated that extracts the rowid. */ int sqlite3ExprCodeGetColumn( Parse *pParse, /* Parsing and code generating context */ Table *pTab, /* Description of the table we are reading from */ int iColumn, /* Index of the table column */ int iTable, /* The cursor pointing to the table */ int iReg, /* Store results here */ u8 p5 /* P5 value for OP_Column + FLAGS */ ){ Vdbe *v = pParse->pVdbe; assert( v!=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); if( p5 ){ sqlite3VdbeChangeP5(v, p5); } return iReg; } /* ** Generate code to move content from registers iFrom...iFrom+nReg-1 ** over to iTo..iTo+nReg-1. */ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){ assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg); } /* ** Convert a scalar expression node to a TK_REGISTER referencing ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ static void exprToRegister(Expr *p, int iReg){ |
︙ | ︙ | |||
3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 | pCol->iSorterColumn, target); return target; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { int iTab = pExpr->iTable; if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ return pExpr->iColumn - pParse->iSelfTab; }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ iTab = pParse->iSelfTab - 1; } } | > > > > > > > > > > > > > > > > > > > > > > | | 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 3410 3411 3412 3413 3414 3415 3416 | pCol->iSorterColumn, target); return target; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { int iTab = pExpr->iTable; if( ExprHasProperty(pExpr, EP_FixedCol) ){ /* This COLUMN expression is really a constant due to WHERE clause ** constraints, and that constant is coded by the pExpr->pLeft ** expresssion. However, make sure the constant has the correct ** datatype by applying the Affinity of the table column to the ** constant. */ int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff!=SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); if( iReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target); iReg = target; } sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, &zAff[(aff-'B')*2], P4_STATIC); } return iReg; } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ return pExpr->iColumn - pParse->iSelfTab; }else{ /* Coding an expression that is part of an index where column names ** in the index refer to the table to which the index belongs */ iTab = pParse->iSelfTab - 1; } } return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } |
︙ | ︙ | |||
3657 3658 3659 3660 3661 3662 3663 | inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); | < < | 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 | inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); if( inReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target); inReg = target; } sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); return inReg; } #endif /* SQLITE_OMIT_CAST */ case TK_IS: case TK_ISNOT: op = (op==TK_IS) ? TK_EQ : TK_NE; p5 = SQLITE_NULLEQ; |
︙ | ︙ | |||
3803 3804 3805 3806 3807 3808 3809 | u32 constMask = 0; /* Mask of function arguments that are constant */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* The database connection */ u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ #ifndef SQLITE_OMIT_WINDOWFUNC | | | | 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 | u32 constMask = 0; /* Mask of function arguments that are constant */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* The database connection */ u8 enc = ENC(db); /* The text encoding used by this database */ CollSeq *pColl = 0; /* A collating sequence */ #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ /* SQL functions can be expensive. So try to move constant functions ** out of the inner loop, even if that means an extra OP_Copy. */ return sqlite3ExprCodeAtInit(pParse, pExpr, -1); |
︙ | ︙ | |||
3844 3845 3846 3847 3848 3849 3850 | if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ int endCoalesce = sqlite3VdbeMakeLabel(v); assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; i<nFarg; i++){ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce); VdbeCoverage(v); | < < < | 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 | if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ int endCoalesce = sqlite3VdbeMakeLabel(v); assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; i<nFarg; i++){ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce); VdbeCoverage(v); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); } sqlite3VdbeResolveLabel(v, endCoalesce); break; } /* The UNLIKELY() function is a no-op. The result is the value ** of the first argument. |
︙ | ︙ | |||
3913 3914 3915 3916 3917 3918 3919 | assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG ); testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); pFarg->a[0].pExpr->op2 = pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } | < < | | 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 | assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG ); testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); pFarg->a[0].pExpr->op2 = pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); }else{ r1 = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is ** a virtual table column. ** ** For infix functions (LIKE, GLOB, REGEXP, and MATCH) use the ** second argument, not the first, as the argument to test to ** see if it is a column in a virtual table. This is done because ** the left operand of infix functions (the operand we want to ** control overloading) ends up as the second argument to the ** function. The expression "A glob B" is equivalent to ** "glob(B,A). We want to use the A in "A glob B" to test ** for function overloading. But we use the B term in "glob(B,A)". */ if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); }else if( nFarg>0 ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; |
︙ | ︙ | |||
4052 4053 4054 4055 4056 4057 4058 | ** ** Then p1 is interpreted as follows: ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ | | | | 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 | ** ** Then p1 is interpreted as follows: ** ** p1==0 -> old.rowid p1==3 -> new.rowid ** p1==1 -> old.a p1==4 -> new.a ** p1==2 -> old.b p1==5 -> new.b */ Table *pTab = pExpr->y.pTab; int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; assert( pExpr->iTable==0 || pExpr->iTable==1 ); assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol ); assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey ); assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName) )); #ifndef SQLITE_OMIT_FLOATING_POINT /* If the column has REAL affinity, it may currently be stored as an ** integer. Use OP_RealAffinity to make sure it is really real. ** ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to |
︙ | ︙ | |||
4089 4090 4091 4092 4093 4094 4095 | sqlite3ErrorMsg(pParse, "row value misused"); break; } case TK_IF_NULL_ROW: { int addrINR; addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); | < < | 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 | sqlite3ErrorMsg(pParse, "row value misused"); break; } case TK_IF_NULL_ROW: { int addrINR; addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); sqlite3VdbeJumpHere(v, addrINR); sqlite3VdbeChangeP3(v, addrINR, inReg); break; } /* ** Form A: |
︙ | ︙ | |||
4128 4129 4130 4131 4132 4133 4134 | int nExpr; /* 2x number of WHEN terms */ int i; /* Loop counter */ ExprList *pEList; /* List of WHEN terms */ struct ExprList_item *aListelem; /* Array of WHEN terms */ Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ | < | 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 | int nExpr; /* 2x number of WHEN terms */ int i; /* Loop counter */ ExprList *pEList; /* List of WHEN terms */ struct ExprList_item *aListelem; /* Array of WHEN terms */ Expr opCompare; /* The X==Ei expression */ Expr *pX; /* The X expression */ Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */ assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; endLabel = sqlite3VdbeMakeLabel(v); |
︙ | ︙ | |||
4152 4153 4154 4155 4156 4157 4158 | /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: ** The value in regFree1 might get SCopy-ed into the file result. ** So make sure that the regFree1 register is not reused for other ** purposes and possibly overwritten. */ regFree1 = 0; } for(i=0; i<nExpr-1; i=i+2){ | < < < < < < | 3957 3958 3959 3960 3961 3962 3963 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 | /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001: ** The value in regFree1 might get SCopy-ed into the file result. ** So make sure that the regFree1 register is not reused for other ** purposes and possibly overwritten. */ regFree1 = 0; } for(i=0; i<nExpr-1; i=i+2){ if( pX ){ assert( pTest!=0 ); opCompare.pRight = aListelem[i].pExpr; }else{ pTest = aListelem[i].pExpr; } nextCase = sqlite3VdbeMakeLabel(v); testcase( pTest->op==TK_COLUMN ); sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL); testcase( aListelem[i+1].pExpr->op==TK_COLUMN ); sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target); sqlite3VdbeGoto(v, endLabel); sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { assert( pExpr->affinity==OE_Rollback || pExpr->affinity==OE_Abort |
︙ | ︙ | |||
4326 4327 4328 4329 4330 4331 4332 | /* ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ | | | 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 | /* ** Generate code that will evaluate expression pExpr and store the ** results in register target. The results are guaranteed to appear ** in register target. If the expression is constant, then this routine ** might choose to code the expression at initialization time. */ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeAtInit(pParse, pExpr, target); }else{ sqlite3ExprCode(pParse, pExpr, target); } } /* |
︙ | ︙ | |||
4408 4409 4410 4411 4412 4413 4414 | if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } | | > > | 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 | if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeAtInit(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ VdbeOp *pOp; if( copyOp==OP_Copy && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy |
︙ | ︙ | |||
4534 4535 4536 4537 4538 4539 4540 | if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); | < < < < | 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 | if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); break; } case TK_OR: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } |
︙ | ︙ | |||
4704 4705 4706 4707 4708 4709 4710 | assert( pExpr->op!=TK_GT || op==OP_Le ); assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ case TK_AND: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); | < < < < | 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 | assert( pExpr->op!=TK_GT || op==OP_Le ); assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ case TK_AND: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } |
︙ | ︙ | |||
4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 | return 1; } return 2; } if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op==TK_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; | > > > > > > > > > > > > > > > | < < < < < < < < < < < < < < < | 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 | return 1; } return 2; } if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op==TK_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; #ifndef SQLITE_OMIT_WINDOWFUNC /* Justification for the assert(): ** window functions have p->op==TK_FUNCTION but aggregate functions ** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate ** function and a window function should have failed before reaching ** this point. And, it is not possible to have a window function and ** a scalar function with the same name and number of arguments. So ** if we reach this point, either A and B both window functions or ** neither are a window functions. */ assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) ); if( ExprHasProperty(pA,EP_WinFunc) ){ if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2; } #endif }else if( pA->op==TK_COLLATE ){ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; assert( (combinedFlags & EP_Reduced)==0 ); if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; } } return 0; } /* ** Compare two ExprList objects. Return 0 if they are identical and ** non-zero if they differ in any way. |
︙ | ︙ | |||
5052 5053 5054 5055 5056 5057 5058 | } return 0; } /* ** This is the Expr node callback for sqlite3ExprImpliesNotNullRow(). ** If the expression node requires that the table at pWalker->iCur | | > > > > < < < < < < | < | 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 | } return 0; } /* ** This is the Expr node callback for sqlite3ExprImpliesNotNullRow(). ** If the expression node requires that the table at pWalker->iCur ** have one or more non-NULL column, then set pWalker->eCode to 1 and abort. ** ** This routine controls an optimization. False positives (setting ** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives ** (never setting pWalker->eCode) is a harmless missed optimization. */ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; switch( pExpr->op ){ case TK_ISNOT: case TK_NOT: case TK_ISNULL: case TK_IS: case TK_OR: |
︙ | ︙ | |||
5105 5106 5107 5108 5109 5110 5111 | case TK_GE: testcase( pExpr->op==TK_EQ ); testcase( pExpr->op==TK_NE ); testcase( pExpr->op==TK_LT ); testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); | | | | 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 | case TK_GE: testcase( pExpr->op==TK_EQ ); testcase( pExpr->op==TK_NE ); testcase( pExpr->op==TK_LT ); testcase( pExpr->op==TK_LE ); testcase( pExpr->op==TK_GT ); testcase( pExpr->op==TK_GE ); if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab)) || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab)) ){ return WRC_Prune; } default: return WRC_Continue; } } |
︙ | ︙ | |||
5337 5338 5339 5340 5341 5342 5343 | break; } } if( (k>=pAggInfo->nColumn) && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; | | | 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 | break; } } if( (k>=pAggInfo->nColumn) && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0 ){ pCol = &pAggInfo->aCol[k]; pCol->pTab = pExpr->y.pTab; pCol->iTable = pExpr->iTable; pCol->iColumn = pExpr->iColumn; pCol->iMem = ++pParse->nMem; pCol->iSorterColumn = -1; pCol->pExpr = pExpr; if( pAggInfo->pGroupBy ){ int j, n; |
︙ | ︙ | |||
5483 5484 5485 5486 5487 5488 5489 | } return pParse->aTempReg[--pParse->nTempReg]; } /* ** Deallocate a register, making available for reuse for some other ** purpose. | < < < < < < < < < < < < < < | 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 | } return pParse->aTempReg[--pParse->nTempReg]; } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){ pParse->aTempReg[pParse->nTempReg++] = iReg; } } /* ** Allocate or deallocate a block of nReg consecutive registers. */ int sqlite3GetTempRange(Parse *pParse, int nReg){ int i, n; if( nReg==1 ) return sqlite3GetTempReg(pParse); i = pParse->iRangeReg; n = pParse->nRangeReg; if( nReg<=n ){ pParse->iRangeReg += nReg; pParse->nRangeReg -= nReg; }else{ i = pParse->nMem+1; pParse->nMem += nReg; } return i; } void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, iReg); return; } if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; } } /* |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 | sqlite3 *db, /* The database connection */ Table *pTab, /* The table whose column is desired */ int iCursor, /* The open cursor on the table */ i16 iCol /* The column that is wanted */ ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | sqlite3 *db, /* The database connection */ Table *pTab, /* The table whose column is desired */ int iCursor, /* The open cursor on the table */ i16 iCol /* The column that is wanted */ ){ Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); if( pExpr ){ pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } return pExpr; } /* |
︙ | ︙ | |||
706 707 708 709 710 711 712 | ** ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping ** the table from the database. Triggers are disabled while running this ** DELETE, but foreign key actions are not. */ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; | | > | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | ** ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping ** the table from the database. Triggers are disabled while running this ** DELETE, but foreign key actions are not. */ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ sqlite3 *db = pParse->db; if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ assert( pTab->pSelect==0 ); /* Not a view */ if( sqlite3FkReferences(pTab)==0 ){ /* Search for a deferred foreign key constraint for which this table ** is the child table. If one cannot be found, return without ** generating any VDBE code. If one can be found, then jump over ** the entire DELETE if there are no outstanding deferred constraints ** when this statement is run. */ FKey *p; |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* | | > | | | | 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* ** Meanings of bits in of pWalker->eCode for ** sqlite3ExprReferencesUpdatedColumn() */ #define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */ #define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */ /* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn(). * Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this ** expression node references any of the ** columns that are being modifed by an UPDATE statement. */ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN ){ assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 ); if( pExpr->iColumn>=0 ){ if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){ |
︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 | } /* ** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** | | | > > > > > > | > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } /* ** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The ** only columns that are modified by the UPDATE are those for which ** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true. ** ** Return true if CHECK constraint pExpr uses any of the ** changing columns (or the rowid if it is changing). In other words, ** return true if this CHECK constraint must be validated for ** the new row in the UPDATE statement. ** ** 2018-09-15: pExpr might also be an expression for an index-on-expressions. ** The operation of this routine is the same - return true if an only if ** the expression uses one or more of columns identified by the second and ** third arguments. */ int sqlite3ExprReferencesUpdatedColumn( Expr *pExpr, /* The expression to be checked */ int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */ int chngRowid /* True if UPDATE changes the rowid */ ){ Walker w; memset(&w, 0, sizeof(w)); w.eCode = 0; w.xExprCallback = checkConstraintExprNode; w.u.aiCol = aiChng; sqlite3WalkExpr(&w, pExpr); if( !chngRowid ){ testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 ); w.eCode &= ~CKCNSTRNT_ROWID; } testcase( w.eCode==0 ); testcase( w.eCode==CKCNSTRNT_COLUMN ); testcase( w.eCode==CKCNSTRNT_ROWID ); testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) ); return w.eCode!=0; } /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE ** on table pTab. ** ** The regNewData parameter is the first register in a range that contains |
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 | int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int addr1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ | < > > > < | 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 1320 | int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int addr1; /* Address of jump instruction */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ Index *pUpIdx = 0; /* Index to which to apply the upsert */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */ int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */ int ipkTop = 0; /* Top of the IPK uniqueness check */ int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ isUpdate = regOldData!=0; db = pParse->db; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for ** normal rowid tables. nPkField is the number of key fields in the ** pPk index or 1 for a rowid table. In other words, nPkField is the ** number of fields in the true primary key of the table. */ if( HasRowid(pTab) ){ pPk = 0; |
︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 | if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; i<pCheck->nExpr; i++){ int allOk; Expr *pExpr = pCheck->a[i].pExpr; | | > > > > > > | 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 | if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ ExprList *pCheck = pTab->pCheck; pParse->iSelfTab = -(regNewData+1); onError = overrideError!=OE_Default ? overrideError : OE_Abort; for(i=0; i<pCheck->nExpr; i++){ int allOk; Expr *pExpr = pCheck->a[i].pExpr; if( aiChng && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng) ){ /* The check constraints do not reference any of the columns being ** updated so there is no point it verifying the check constraint */ continue; } allOk = sqlite3VdbeMakeLabel(v); sqlite3VdbeVerifyAbortable(v, onError); sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ char *zName = pCheck->a[i].zName; |
︙ | ︙ | |||
1437 1438 1439 1440 1441 1442 1443 | pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* UNIQUE and PRIMARY KEY constraints should be handled in the following ** order: ** | | | > > > > > | < | < | > | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 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 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 | pParse->iSelfTab = 0; } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* UNIQUE and PRIMARY KEY constraints should be handled in the following ** order: ** ** (1) OE_Update ** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore ** (3) OE_Replace ** ** OE_Fail and OE_Ignore must happen before any changes are made. ** OE_Update guarantees that only a single row will change, so it ** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback ** could happen in any order, but they are grouped up front for ** convenience. ** ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43 ** The order of constraints used to have OE_Update as (2) and OE_Abort ** and so forth as (1). But apparently PostgreSQL checks the OE_Update ** constraint before any others, so it had to be moved. ** ** Constraint checking code is generated in this order: ** (A) The rowid constraint ** (B) Unique index constraints that do not have OE_Replace as their ** default conflict resolution strategy ** (C) Unique index that do use OE_Replace by default. ** ** The ordering of (2) and (3) is accomplished by making sure the linked ** list of indexes attached to a table puts all OE_Replace indexes last ** in the list. See sqlite3CreateIndex() for where that happens. */ if( pUpsert ){ if( pUpsert->pUpsertTarget==0 ){ /* An ON CONFLICT DO NOTHING clause, without a constraint-target. ** Make all unique constraint resolution be OE_Ignore */ assert( pUpsert->pUpsertSet==0 ); overrideError = OE_Ignore; pUpsert = 0; }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){ /* If the constraint-target uniqueness check must be run first. ** Jump to that uniqueness check now */ upsertJump = sqlite3VdbeAddOp0(v, OP_Goto); VdbeComment((v, "UPSERT constraint goes first")); } } /* If rowid is changing, make sure the new rowid does not previously ** exist in the table. */ if( pkChng && pPk==0 ){ |
︙ | ︙ | |||
1502 1503 1504 1505 1506 1507 1508 | } /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after ** the UNIQUE constraints have run. */ | < < < < < | | | | > < | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | } /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after ** the UNIQUE constraints have run. */ if( onError==OE_Replace /* IPK rule is REPLACE */ && onError!=overrideError /* Rules for other contraints are different */ && pTab->pIndex /* There exist other constraints */ ){ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; VdbeComment((v, "defer IPK REPLACE until last")); } if( isUpdate ){ /* pkChng!=0 does not mean that the rowid has changed, only that ** it might have changed. Skip the conflict logic below if the rowid ** is unchanged. */ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v); } /* Check to see if the new rowid already exists in the table. Skip ** the following conflict logic if it does not. */ VdbeNoopComment((v, "uniqueness check for ROWID")); sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: |
︙ | ︙ | |||
1606 1607 1608 1609 1610 1611 1612 | #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } | < | | | < < < < | | > > > > | 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 | #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); if( ipkTop ){ ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, ipkTop-1); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Compute the revised record entries for indices as we go. ** ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){ int regIdx; /* Range of registers hold conent for pIdx */ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( pUpIdx==pIdx ){ addrUniqueOk = upsertJump+1; upsertBypass = sqlite3VdbeGoto(v, 0); VdbeComment((v, "Skip upsert subroutine")); sqlite3VdbeJumpHere(v, upsertJump); }else{ addrUniqueOk = sqlite3VdbeMakeLabel(v); } if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName)); iThisCur = iIdxCur+ix; /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ |
︙ | ︙ | |||
1711 1712 1713 1714 1715 1716 1717 | if( pUpsert->pUpsertSet==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } | < < < < < < < < < < | 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 | if( pUpsert->pUpsertSet==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table ** (3) There are no secondary indexes on the table ** (4) No delete triggers need to be fired if there is a conflict ** (5) No FK constraint counters need to be updated if a conflict occurs. */ if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ (0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } /* Check to see if the new index entry will be unique */ sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk, regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ |
︙ | ︙ | |||
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 | regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); seenReplace = 1; break; } } if( pUpIdx==pIdx ){ sqlite3VdbeJumpHere(v, upsertBypass); }else{ sqlite3VdbeResolveLabel(v, addrUniqueOk); } | > < | | > | < | > | | > | 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 | regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); seenReplace = 1; break; } } if( pUpIdx==pIdx ){ sqlite3VdbeGoto(v, upsertJump+1); sqlite3VdbeJumpHere(v, upsertBypass); }else{ sqlite3VdbeResolveLabel(v, addrUniqueOk); } if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); } /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop+1); VdbeComment((v, "Do IPK REPLACE")); sqlite3VdbeJumpHere(v, ipkBottom); } *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } #ifdef SQLITE_ENABLE_NULL_TRIM /* ** Change the P5 operand on the last opcode (which should be an OP_MakeRecord) |
︙ | ︙ | |||
1950 1951 1952 1953 1954 1955 1956 | if( !HasRowid(pTab) ) return; regData = regNewData + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); | < | 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 | if( !HasRowid(pTab) ) return; regData = regNewData + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); } if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID); } |
︙ | ︙ |
Changes to src/loadext.c.
︙ | ︙ | |||
445 446 447 448 449 450 451 | sqlite3_str_vappendf, sqlite3_str_append, sqlite3_str_appendall, sqlite3_str_appendchar, sqlite3_str_reset, sqlite3_str_errcode, sqlite3_str_length, | | > > | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | sqlite3_str_vappendf, sqlite3_str_append, sqlite3_str_appendall, sqlite3_str_appendchar, sqlite3_str_reset, sqlite3_str_errcode, sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ sqlite3_create_window_function }; /* ** 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. |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
845 846 847 848 849 850 851 | u32 oldFlags = db->flags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ db->flags &= ~aFlagOp[i].mask; } if( oldFlags!=db->flags ){ | | | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | u32 oldFlags = db->flags; if( onoff>0 ){ db->flags |= aFlagOp[i].mask; }else if( onoff==0 ){ db->flags &= ~aFlagOp[i].mask; } if( oldFlags!=db->flags ){ sqlite3ExpirePreparedStatements(db, 0); } if( pRes ){ *pRes = (db->flags & aFlagOp[i].mask)!=0; } rc = SQLITE_OK; break; } |
︙ | ︙ | |||
905 906 907 908 909 910 911 912 913 914 915 916 917 918 | */ }else{ rc = nKey1 - nKey2; } } return rc; } /* ** Another built-in collating sequence: NOCASE. ** ** This collating sequence is intended to be used for "case independent ** comparison". SQLite's knowledge of upper and lower case equivalents ** extends only to the 26 characters used in the English language. | > > > > > > > > > | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | */ }else{ rc = nKey1 - nKey2; } } return rc; } /* ** Return true if CollSeq is the default built-in BINARY. */ int sqlite3IsBinary(const CollSeq *p){ assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0 || strcmp(p->zName,"BINARY")==0 ); return p==0 || (p->xCmp==binCollFunc && p->pUser==0); } /* ** Another built-in collating sequence: NOCASE. ** ** This collating sequence is intended to be used for "case independent ** comparison". SQLite's knowledge of upper and lower case equivalents ** extends only to the 26 characters used in the English language. |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | static void disconnectAllVtab(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE int i; HashElem *p; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | static void disconnectAllVtab(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE int i; HashElem *p; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ |
︙ | ︙ | |||
1287 1288 1289 1290 1291 1292 1293 | } sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); | | | | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | } sqlite3BtreeRollback(p, tripCode, !schemaChange); } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( schemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); } sqlite3BtreeLeaveAll(db); /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; db->nDeferredImmCons = 0; |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 | const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; for(i=0; i<2 && zName==0; i++, rc &= 0xff){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; | > | 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; for(i=0; i<2 && zName==0; i++, rc &= 0xff){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; |
︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ | | | 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 | if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); return SQLITE_BUSY; }else{ sqlite3ExpirePreparedStatements(db, 0); } } p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); assert(p || db->mallocFailed); if( !p ){ return SQLITE_NOMEM_BKPT; |
︙ | ︙ | |||
2518 2519 2520 2521 2522 2523 2524 | pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } | | | 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 | pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ if( db->nVdbeActive ){ sqlite3ErrorWithMsg(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; } sqlite3ExpirePreparedStatements(db, 0); /* If collation sequence pColl was created directly by a call to ** sqlite3_create_collation, and not generated by synthCollSeq(), ** then any copies made by synthCollSeq() need to be invalidated. ** Also, collation destructor - CollSeq.xDel() - function may need ** to be called. */ |
︙ | ︙ | |||
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 | } } sqlite3_mutex_enter(db->mutex); db->errMask = 0xff; db->nDb = 2; db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; | > | 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 | } } sqlite3_mutex_enter(db->mutex); db->errMask = 0xff; db->nDb = 2; db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS; db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; |
︙ | ︙ | |||
3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 | rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_VFS_POINTER ){ *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; }else{ rc = sqlite3OsFileControl(fd, op, pArg); } sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); return rc; | > > > | 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 | rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_VFS_POINTER ){ *(sqlite3_vfs**)pArg = sqlite3PagerVfs(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){ *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager); rc = SQLITE_OK; }else if( op==SQLITE_FCNTL_DATA_VERSION ){ *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); rc = SQLITE_OK; }else{ rc = sqlite3OsFileControl(fd, op, pArg); } sqlite3BtreeLeave(pBtree); } sqlite3_mutex_leave(db->mutex); return rc; |
︙ | ︙ | |||
4193 4194 4195 4196 4197 4198 4199 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb; iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; | > > > | > > > > > > > > > > > | > | > > > | 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 | #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb; iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( sqlite3BtreeIsInTrans(pBt)==0 ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; if( sqlite3BtreeIsInReadTrans(pBt) ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ bUnlock = 1; rc = sqlite3BtreeCommit(pBt); } } }else{ rc = SQLITE_OK; } if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot); } if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); sqlite3PagerSnapshotOpen(pPager, 0); } if( bUnlock ){ sqlite3PagerSnapshotUnlock(pPager); } } } } sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ |
︙ | ︙ |
Changes to src/memdb.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file implements an in-memory VFS. A database is held as a contiguous ** block of memory. ** ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ | < > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** ** This file implements an in-memory VFS. A database is held as a contiguous ** block of memory. ** ** This file also implements interface sqlite3_serialize() and ** sqlite3_deserialize(). */ #include "sqliteInt.h" #ifdef SQLITE_ENABLE_DESERIALIZE /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs MemVfs; typedef struct MemFile MemFile; |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, #else { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif #define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) }; /* End of the overrideable system calls */ | > > > > | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | { "lstat", (sqlite3_syscall_ptr)lstat, 0 }, #else { "lstat", (sqlite3_syscall_ptr)0, 0 }, #endif #define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent) #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) # ifdef __ANDROID__ { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 }, # else { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 }, # endif #else { "ioctl", (sqlite3_syscall_ptr)0, 0 }, #endif #define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) }; /* End of the overrideable system calls */ |
︙ | ︙ | |||
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | ** Function unixMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() */ static sqlite3_mutex *unixBigLock = 0; static void unixEnterMutex(void){ sqlite3_mutex_enter(unixBigLock); } static void unixLeaveMutex(void){ sqlite3_mutex_leave(unixBigLock); } #ifdef SQLITE_DEBUG static int unixMutexHeld(void) { return sqlite3_mutex_held(unixBigLock); } #endif | > > > > > > > > > > > > > | 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 | ** Function unixMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() ** ** To prevent deadlock, the global unixBigLock must must be acquired ** before the unixInodeInfo.pLockMutex mutex, if both are held. It is ** OK to get the pLockMutex without holding unixBigLock first, but if ** that happens, the unixBigLock mutex must not be acquired until after ** pLockMutex is released. ** ** OK: enter(unixBigLock), enter(pLockInfo) ** OK: enter(unixBigLock) ** OK: enter(pLockInfo) ** ERROR: enter(pLockInfo), enter(unixBigLock) */ static sqlite3_mutex *unixBigLock = 0; static void unixEnterMutex(void){ assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */ sqlite3_mutex_enter(unixBigLock); } static void unixLeaveMutex(void){ assert( sqlite3_mutex_held(unixBigLock) ); sqlite3_mutex_leave(unixBigLock); } #ifdef SQLITE_DEBUG static int unixMutexHeld(void) { return sqlite3_mutex_held(unixBigLock); } #endif |
︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | ** An instance of the following structure is allocated for each open ** inode. Or, on LinuxThreads, there is one of these structures for ** each inode opened by each thread. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ | > > > > > > > > > > > > > > > > > > | > | | > < < | > > > > > > > > > > > > > > | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 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 | ** An instance of the following structure is allocated for each open ** inode. Or, on LinuxThreads, there is one of these structures for ** each inode opened by each thread. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of unixFile pointing to it. ** ** Mutex rules: ** ** (1) Only the pLockMutex mutex must be held in order to read or write ** any of the locking fields: ** nShared, nLock, eFileLock, bProcessLock, pUnused ** ** (2) When nRef>0, then the following fields are unchanging and can ** be read (but not written) without holding any mutex: ** fileId, pLockMutex ** ** (3) With the exceptions above, all the fields may only be read ** or written while holding the global unixBigLock mutex. ** ** Deadlock prevention: The global unixBigLock mutex may not ** be acquired while holding the pLockMutex mutex. If both unixBigLock ** and pLockMutex are needed, then unixBigLock must be acquired first. */ struct unixInodeInfo { struct unixFileId fileId; /* The lookup key */ sqlite3_mutex *pLockMutex; /* Hold this mutex for... */ int nShared; /* Number of SHARED locks held */ int nLock; /* Number of outstanding file locks */ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ unsigned char bProcessLock; /* An exclusive process lock is held */ UnixUnusedFd *pUnused; /* Unused file descriptors to close */ int nRef; /* Number of pointers to this structure */ unixShmNode *pShmNode; /* Shared memory associated with this inode */ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ unixInodeInfo *pPrev; /* .... doubly linked */ #if SQLITE_ENABLE_LOCKING_STYLE unsigned long long sharedByte; /* for AFP simulated shared lock */ #endif #if OS_VXWORKS sem_t *pSem; /* Named POSIX semaphore */ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ #endif #ifdef SQLITE_SHARED_MAPPING sqlite3_int64 nSharedMapping; /* Size of mapped region in bytes */ void *pSharedMapping; /* Memory mapped region */ #endif }; /* ** A lists of all unixInodeInfo objects. */ static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ #ifdef SQLITE_DEBUG /* ** True if the inode mutex is held, or not. Used only within assert() ** to help verify correct mutex usage. */ int unixFileMutexHeld(unixFile *pFile){ assert( pFile->pInode ); return sqlite3_mutex_held(pFile->pInode->pLockMutex); } int unixFileMutexNotheld(unixFile *pFile){ assert( pFile->pInode ); return sqlite3_mutex_notheld(pFile->pInode->pLockMutex); } #endif /* ** ** This function - unixLogErrorAtLine(), is only ever called via the macro ** unixLogError(). ** ** It is invoked after an error occurs in an OS function and errno has been |
︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. */ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p; UnixUnusedFd *pNext; for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); | > < > > > > < | 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 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 1345 1346 1347 1348 1349 | /* ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. */ static void closePendingFds(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p; UnixUnusedFd *pNext; assert( unixFileMutexHeld(pFile) ); for(p=pInode->pUnused; p; p=pNext){ pNext = p->pNext; robust_close(pFile, p->fd, __LINE__); sqlite3_free(p); } pInode->pUnused = 0; } /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; assert( unixMutexHeld() ); assert( unixFileMutexNotheld(pFile) ); if( ALWAYS(pInode) ){ pInode->nRef--; if( pInode->nRef==0 ){ assert( pInode->pShmNode==0 ); #ifdef SQLITE_SHARED_MAPPING if( pInode->pSharedMapping ){ osMunmap(pInode->pSharedMapping, pInode->nSharedMapping); pInode->pSharedMapping = 0; pInode->nSharedMapping = 0; } #endif sqlite3_mutex_enter(pInode->pLockMutex); closePendingFds(pFile); sqlite3_mutex_leave(pInode->pLockMutex); if( pInode->pPrev ){ assert( pInode->pPrev->pNext==pInode ); pInode->pPrev->pNext = pInode->pNext; }else{ assert( inodeList==pInode ); inodeList = pInode->pNext; } if( pInode->pNext ){ assert( pInode->pNext->pPrev==pInode ); pInode->pNext->pPrev = pInode->pPrev; } sqlite3_mutex_free(pInode->pLockMutex); sqlite3_free(pInode); } } } /* ** Given a file descriptor, locate the unixInodeInfo object that ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** |
︙ | ︙ | |||
1353 1354 1355 1356 1357 1358 1359 | memset(&fileId, 0, sizeof(fileId)); fileId.dev = statbuf.st_dev; #if OS_VXWORKS fileId.pId = pFile->pId; #else fileId.ino = (u64)statbuf.st_ino; #endif | < > > > > > > > | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 | memset(&fileId, 0, sizeof(fileId)); fileId.dev = statbuf.st_dev; #if OS_VXWORKS fileId.pId = pFile->pId; #else fileId.ino = (u64)statbuf.st_ino; #endif pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; } if( pInode==0 ){ pInode = sqlite3_malloc64( sizeof(*pInode) ); if( pInode==0 ){ return SQLITE_NOMEM_BKPT; } memset(pInode, 0, sizeof(*pInode)); memcpy(&pInode->fileId, &fileId, sizeof(fileId)); if( sqlite3GlobalConfig.bCoreMutex ){ pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); if( pInode->pLockMutex==0 ){ sqlite3_free(pInode); return SQLITE_NOMEM_BKPT; } } pInode->nRef = 1; pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; inodeList = pInode; }else{ pInode->nRef++; |
︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 | int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); assert( pFile->eFileLock<=SHARED_LOCK ); | | | 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | int reserved = 0; unixFile *pFile = (unixFile*)id; SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); assert( pFile ); assert( pFile->eFileLock<=SHARED_LOCK ); sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. |
︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | storeLastErrno(pFile, errno); } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } } #endif | | | 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 | storeLastErrno(pFile, errno); } else if( lock.l_type!=F_UNLCK ){ reserved = 1; } } #endif sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* |
︙ | ︙ | |||
1534 1535 1536 1537 1538 1539 1540 | ** ** Zero is returned if the call completes successfully, or -1 if a call ** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). */ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; | < > | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | ** ** Zero is returned if the call completes successfully, or -1 if a call ** to fcntl() fails. In this case, errno is set appropriately (by fcntl()). */ static int unixFileLock(unixFile *pFile, struct flock *pLock){ int rc; unixInodeInfo *pInode = pFile->pInode; assert( pInode!=0 ); assert( sqlite3_mutex_held(pInode->pLockMutex) ); if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){ if( pInode->bProcessLock==0 ){ struct flock lock; assert( pInode->nLock==0 ); lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; |
︙ | ︙ | |||
1654 1655 1656 1657 1658 1659 1660 | */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ | < > | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 | */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ |
︙ | ︙ | |||
1798 1799 1800 1801 1802 1803 1804 | pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } end_lock: | | > < | 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 | pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** Add the file descriptor used by file handle pFile to the corresponding ** pUnused list. */ static void setPendingFd(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; UnixUnusedFd *p = pFile->pPreallocatedUnused; assert( unixFileMutexHeld(pFile) ); p->pNext = pInode->pUnused; pInode->pUnused = p; pFile->h = -1; pFile->pPreallocatedUnused = 0; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } | < > | 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); #ifdef SQLITE_DEBUG /* When reducing a lock such that other processes can start ** reading the database file again, make sure that the |
︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 | /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pInode->nLock--; assert( pInode->nLock>=0 ); | | < < | | > > | 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 | /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ) closePendingFds(pFile); } end_unlock: sqlite3_mutex_leave(pInode->pLockMutex); if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; } return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock ** must be either NO_LOCK or SHARED_LOCK. ** |
︙ | ︙ | |||
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 | /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; verifyDbFile(pFile); unixUnlock(id, NO_LOCK); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); | > > > > > | > | 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 | /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; unixFile *pFile = (unixFile *)id; unixInodeInfo *pInode = pFile->pInode; assert( pInode!=0 ); verifyDbFile(pFile); unixUnlock(id, NO_LOCK); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); /* unixFile.pInode is always valid here. Otherwise, a different close ** routine (e.g. nolockClose()) would be called instead. */ assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); sqlite3_mutex_enter(pInode->pLockMutex); if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pInode->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } /************** End of the posix advisory lock implementation ***************** |
︙ | ︙ | |||
2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 | ** Close a file. */ static int semXClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; semXUnlock(id, NO_LOCK); assert( pFile ); unixEnterMutex(); releaseInodeInfo(pFile); unixLeaveMutex(); closeUnixFile(id); } return SQLITE_OK; } | > | 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 | ** Close a file. */ static int semXClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; semXUnlock(id, NO_LOCK); assert( pFile ); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); releaseInodeInfo(pFile); unixLeaveMutex(); closeUnixFile(id); } return SQLITE_OK; } |
︙ | ︙ | |||
2786 2787 2788 2789 2790 2791 2792 | assert( pFile ); context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; } | < | | 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 | assert( pFile ); context = (afpLockingContext *) pFile->lockingContext; if( context->reserved ){ *pResOut = 1; return SQLITE_OK; } sqlite3_mutex_enter(pFile->pInode->pLockMutex); /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; } /* Otherwise see if some other process holds it. */ |
︙ | ︙ | |||
2811 2812 2813 2814 2815 2816 2817 | reserved = 1; } if( IS_LOCK_ERROR(lrc) ){ rc=lrc; } } | | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 | reserved = 1; } if( IS_LOCK_ERROR(lrc) ){ rc=lrc; } } sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } /* |
︙ | ︙ | |||
2874 2875 2876 2877 2878 2879 2880 | */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ | < > | 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 | */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); /* This mutex is needed because pFile->pInode is shared across threads */ pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); /* If some thread using this PID has a lock via a different unixFile* ** handle that precludes the requested lock, return BUSY. */ if( (pFile->eFileLock!=pInode->eFileLock && (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) ){ |
︙ | ︙ | |||
3011 3012 3013 3014 3015 3016 3017 | pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } afp_end_lock: | | | 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 | pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } afp_end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; } /* ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock |
︙ | ︙ | |||
3043 3044 3045 3046 3047 3048 3049 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } | < > | 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 | pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared, osGetpid(0))); assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); |
︙ | ︙ | |||
3113 3114 3115 3116 3117 3118 3119 | pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); | | < < | | > > > | > > > | | | | | | > > | 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 | pInode->eFileLock = NO_LOCK; pFile->eFileLock = NO_LOCK; } } if( rc==SQLITE_OK ){ pInode->nLock--; assert( pInode->nLock>=0 ); if( pInode->nLock==0 ) closePendingFds(pFile); } } sqlite3_mutex_leave(pInode->pLockMutex); if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; } return rc; } /* ** Close a file & cleanup AFP specific locking context */ static int afpClose(sqlite3_file *id) { int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; assert( id!=0 ); afpUnlock(id, NO_LOCK); assert( unixFileMutexNotheld(pFile) ); unixEnterMutex(); if( pFile->pInode ){ unixInodeInfo *pInode = pFile->pInode; sqlite3_mutex_enter(pInode->pLockMutex); if( pInode->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pInode->aPending. It will be automatically closed when ** the last lock is cleared. */ setPendingFd(pFile); } sqlite3_mutex_leave(pInode->pLockMutex); } releaseInodeInfo(pFile); sqlite3_free(pFile->lockingContext); rc = closeUnixFile(id); unixLeaveMutex(); return rc; } |
︙ | ︙ | |||
4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 | if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); assert( pDbFd->pShm==0 ); /* Check to see if a unixShmNode object already exists. Reuse an existing ** one if present. Create a new one if necessary. */ unixEnterMutex(); pInode = pDbFd->pInode; pShmNode = pInode->pShmNode; if( pShmNode==0 ){ struct stat sStat; /* fstat() info for database file */ #ifndef SQLITE_SHM_DIRECTORY const char *zBasePath = pDbFd->zPath; | > | 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 | if( p==0 ) return SQLITE_NOMEM_BKPT; memset(p, 0, sizeof(*p)); assert( pDbFd->pShm==0 ); /* Check to see if a unixShmNode object already exists. Reuse an existing ** one if present. Create a new one if necessary. */ assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); pInode = pDbFd->pInode; pShmNode = pInode->pShmNode; if( pShmNode==0 ){ struct stat sStat; /* fstat() info for database file */ #ifndef SQLITE_SHM_DIRECTORY const char *zBasePath = pDbFd->zPath; |
︙ | ︙ | |||
4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 | ** any load or store begun after the barrier. */ static void unixShmBarrier( sqlite3_file *fd /* Database file holding the shared memory */ ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); } /* ** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. | > > > | 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 | ** any load or store begun after the barrier. */ static void unixShmBarrier( sqlite3_file *fd /* Database file holding the shared memory */ ){ UNUSED_PARAMETER(fd); sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ assert( fd->pMethods->xLock==nolockLock || unixFileMutexNotheld((unixFile*)fd) ); unixEnterMutex(); /* Also mutex, for redundancy */ unixLeaveMutex(); } /* ** Close a connection to shared-memory. Delete the underlying ** storage if deleteFlag is true. |
︙ | ︙ | |||
4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 | /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; sqlite3_mutex_leave(pShmNode->mutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ unixEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ if( deleteFlag && pShmNode->h>=0 ){ osUnlink(pShmNode->zFilename); } | > | 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 | /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; sqlite3_mutex_leave(pShmNode->mutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ assert( unixFileMutexNotheld(pDbFd) ); unixEnterMutex(); assert( pShmNode->nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ if( deleteFlag && pShmNode->h>=0 ){ osUnlink(pShmNode->zFilename); } |
︙ | ︙ | |||
5222 5223 5224 5225 5226 5227 5228 | unixUnlock, /* xUnlock method */ unixCheckReservedLock, /* xCheckReservedLock method */ unixShmMap /* xShmMap method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ | | | 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 | unixUnlock, /* xUnlock method */ unixCheckReservedLock, /* xCheckReservedLock method */ unixShmMap /* xShmMap method */ ) IOMETHODS( nolockIoFinder, /* Finder function name */ nolockIoMethods, /* sqlite3_io_methods object name */ 3, /* shared memory and mmap are enabled */ nolockClose, /* xClose method */ nolockLock, /* xLock method */ nolockUnlock, /* xUnlock method */ nolockCheckReservedLock, /* xCheckReservedLock method */ 0 /* xShmMap method */ ) IOMETHODS( |
︙ | ︙ | |||
5721 5722 5723 5724 5725 5726 5727 | ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is ** ignored and -1 is returned. The caller will try to open a new file ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ | | > > < > | 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 | ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is ** ignored and -1 is returned. The caller will try to open a new file ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a reusable file descriptor are not dire. */ if( inodeList!=0 && 0==osStat(zPath, &sStat) ){ unixInodeInfo *pInode; pInode = inodeList; while( pInode && (pInode->fileId.dev!=sStat.st_dev || pInode->fileId.ino!=(u64)sStat.st_ino) ){ pInode = pInode->pNext; } if( pInode ){ UnixUnusedFd **pp; assert( sqlite3_mutex_notheld(pInode->pLockMutex) ); sqlite3_mutex_enter(pInode->pLockMutex); for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } sqlite3_mutex_leave(pInode->pLockMutex); } } unixLeaveMutex(); #endif /* if !OS_VXWORKS */ return pUnused; } |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
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 | /* ** Truncate an open file to a specified size */ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate1", pFile->zPath); }else if( 0==osSetEndOfFile(pFile->h) && ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate2", pFile->zPath); } #if SQLITE_MAX_MMAP_SIZE>0 | > > > > > > > > > > > > | | < < | > | > | 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 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 | /* ** Truncate an open file to a specified size */ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ winFile *pFile = (winFile*)id; /* File handle object */ int rc = SQLITE_OK; /* Return code for this function */ DWORD lastErrno; #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_int64 oldMmapSize; #endif assert( pFile ); SimulateIOError(return SQLITE_IOERR_TRUNCATE); OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, size=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, nByte, pFile->locktype)); /* If the user has configured a chunk-size for this file, truncate the ** file so that it consists of an integer number of chunks (i.e. the ** actual file size after the operation may be larger than the requested ** size). */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } #if SQLITE_MAX_MMAP_SIZE>0 if( pFile->pMapRegion ){ oldMmapSize = pFile->mmapSize; }else{ oldMmapSize = 0; } winUnmapfile(pFile); #endif /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( winSeekFile(pFile, nByte) ){ rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate1", pFile->zPath); }else if( 0==osSetEndOfFile(pFile->h) && ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){ pFile->lastErrno = lastErrno; rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, "winTruncate2", pFile->zPath); } #if SQLITE_MAX_MMAP_SIZE>0 if( rc==SQLITE_OK && oldMmapSize>0 ){ if( oldMmapSize>nByte ){ winMapfile(pFile, -1); }else{ winMapfile(pFile, oldMmapSize); } } #endif OSTRACE(("TRUNCATE pid=%lu, pFile=%p, file=%p, rc=%s\n", osGetCurrentProcessId(), pFile, pFile->h, sqlite3ErrName(rc))); return rc; } |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 1005 | /* ** Return a pointer to a human readable string in a static buffer ** containing the state of the Pager object passed as an argument. This ** is intended to be used within debuggers. For example, as an alternative ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) */ | > > > > | | 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | /* ** Return a pointer to a human readable string in a static buffer ** containing the state of the Pager object passed as an argument. This ** is intended to be used within debuggers. For example, as an alternative ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) ** ** This routine has external linkage in order to suppress compiler warnings ** about an unused function. It is enclosed within SQLITE_DEBUG and so does ** not appear in normal builds. */ char *print_pager_state(Pager *p){ static char zRet[1024]; sqlite3_snprintf(1024, zRet, "Filename: %s\n" "State: %s errCode=%d\n" "Lock: %s\n" "Locking mode: locking_mode=%s\n" |
︙ | ︙ | |||
1765 1766 1767 1768 1769 1770 1771 | sqlite3PcacheClear(pPager->pPCache); } /* ** Return the pPager->iDataVersion value */ u32 sqlite3PagerDataVersion(Pager *pPager){ | < | 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | sqlite3PcacheClear(pPager->pPCache); } /* ** Return the pPager->iDataVersion value */ u32 sqlite3PagerDataVersion(Pager *pPager){ return pPager->iDataVersion; } /* ** Free all structures in the Pager.aSavepoint[] array and set both ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal ** if it is open and the pager is not in exclusive mode. |
︙ | ︙ | |||
6533 6534 6535 6536 6537 6538 6539 6540 | 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) ){ | > < > < > | | | 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 | 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{ PgHdr *pList; if( pagerUseWal(pPager) ){ PgHdr *pPageOne = 0; pList = sqlite3PcacheDirtyList(pPager->pPCache); if( pList==0 ){ /* Must have at least one page for the WAL commit flag. ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ rc = sqlite3PagerGet(pPager, 1, &pPageOne, 0); pList = pPageOne; pList->pDirty = 0; } assert( rc==SQLITE_OK ); if( ALWAYS(pList) ){ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1); } sqlite3PagerUnref(pPageOne); if( rc==SQLITE_OK ){ sqlite3PcacheCleanAll(pPager->pPCache); } }else{ /* The bBatch boolean is true if the batch-atomic-write commit method ** should be used. No rollback journal is created if batch-atomic-write ** is enabled. */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE sqlite3_file *fd = pPager->fd; int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) && !pPager->noSync && sqlite3JournalIsInMemory(pPager->jfd); #else # define bBatch 0 #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization ** was enabled at compile time, and if this transaction meets the ** runtime criteria to use the operation: |
︙ | ︙ | |||
6615 6616 6617 6618 6619 6620 6621 | }else{ rc = sqlite3JournalCreate(pPager->jfd); if( rc==SQLITE_OK ){ rc = pager_incr_changecounter(pPager, 0); } } } | | > | | 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 | }else{ rc = sqlite3JournalCreate(pPager->jfd); if( rc==SQLITE_OK ){ rc = pager_incr_changecounter(pPager, 0); } } } #else /* SQLITE_ENABLE_ATOMIC_WRITE */ #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( zMaster ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; assert( bBatch==0 ); } #endif rc = pager_incr_changecounter(pPager, 0); #endif /* !SQLITE_ENABLE_ATOMIC_WRITE */ if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the master journal name into the journal file. If a master ** journal file name has already been written to the journal file, ** or if zMaster is NULL (no master journal), then this call is a no-op. */ rc = writeMasterJournal(pPager, zMaster); |
︙ | ︙ | |||
6647 6648 6649 6650 6651 6652 6653 6654 | ** on a system under memory pressure it is just possible that this is ** not the case. In this case it is likely enough that the redundant ** xSync() call will be changed to a no-op by the OS anyhow. */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; if( bBatch ){ | > > < < < < | < | < | | | | | | | > > > > > > > > > > > > > > > > | 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 | ** on a system under memory pressure it is just possible that this is ** not the case. In this case it is likely enough that the redundant ** xSync() call will be changed to a no-op by the OS anyhow. */ rc = syncJournal(pPager, 0); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; pList = sqlite3PcacheDirtyList(pPager->pPCache); #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE if( bBatch ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0); if( rc==SQLITE_OK ){ rc = pager_write_pagelist(pPager, pList); if( rc==SQLITE_OK ){ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0); } if( rc!=SQLITE_OK ){ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0); } } if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ){ sqlite3OsClose(pPager->jfd); goto commit_phase_one_exit; } bBatch = 0; }else{ sqlite3OsClose(pPager->jfd); } } #endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ if( bBatch==0 ){ rc = pager_write_pagelist(pPager, pList); } if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; } sqlite3PcacheCleanAll(pPager->pPCache); /* If the file on disk is smaller than the database image, use |
︙ | ︙ | |||
7415 7416 7417 7418 7419 7420 7421 | ** ** * Temporary databases cannot have _WAL journalmode. ** ** The returned indicate the current (possibly updated) journal-mode. */ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ | < < < < < < < | 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 | ** ** * Temporary databases cannot have _WAL journalmode. ** ** The returned indicate the current (possibly updated) journal-mode. */ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ /* The eMode parameter is always valid */ assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_WAL |
︙ | ︙ | |||
7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 | if( pPager->pWal ){ rc = sqlite3WalSnapshotRecover(pPager->pWal); }else{ rc = SQLITE_ERROR; } return rc; } #endif /* SQLITE_ENABLE_SNAPSHOT */ int sqlite3PagerWalInfo(Pager *pPager, u32 *pnPrior, u32 *pnFrame){ return sqlite3WalInfo(pPager->pWal, pnPrior, pnFrame); } #endif /* !SQLITE_OMIT_WAL */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 | if( pPager->pWal ){ rc = sqlite3WalSnapshotRecover(pPager->pWal); }else{ rc = SQLITE_ERROR; } return rc; } /* ** The caller currently has a read transaction open on the database. ** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise, ** this function takes a SHARED lock on the CHECKPOINTER slot and then ** checks if the snapshot passed as the second argument is still ** available. If so, SQLITE_OK is returned. ** ** If the snapshot is not available, SQLITE_ERROR is returned. Or, if ** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error ** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER ** lock is released before returning. */ int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){ int rc; if( pPager->pWal ){ rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot); }else{ rc = SQLITE_ERROR; } return rc; } /* ** Release a lock obtained by an earlier successful call to ** sqlite3PagerSnapshotCheck(). */ void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); return sqlite3WalSnapshotUnlock(pPager->pWal); } #endif /* SQLITE_ENABLE_SNAPSHOT */ int sqlite3PagerWalInfo(Pager *pPager, u32 *pnPrior, u32 *pnFrame){ return sqlite3WalInfo(pPager->pWal, pnPrior, pnFrame); } #endif /* !SQLITE_OMIT_WAL */ |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 | # ifdef SQLITE_DIRECT_OVERFLOW_READ int sqlite3PagerUseWal(Pager *pPager, Pgno); # endif # ifdef SQLITE_ENABLE_SNAPSHOT int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); int sqlite3PagerSnapshotRecover(Pager *pPager); # endif #else # define sqlite3PagerUseWal(x,y) 0 #endif #ifdef SQLITE_ENABLE_ZIPVFS int sqlite3PagerWalFramesize(Pager *pPager); | > > | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | # ifdef SQLITE_DIRECT_OVERFLOW_READ int sqlite3PagerUseWal(Pager *pPager, Pgno); # endif # ifdef SQLITE_ENABLE_SNAPSHOT int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot); int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); int sqlite3PagerSnapshotRecover(Pager *pPager); int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif #else # define sqlite3PagerUseWal(x,y) 0 #endif #ifdef SQLITE_ENABLE_ZIPVFS int sqlite3PagerWalFramesize(Pager *pPager); |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
336 337 338 339 340 341 342 | } ccons ::= DEFAULT scanpt id(X). { Expr *p = tokenExpr(pParse, TK_STRING, X); if( p ){ sqlite3ExprIdToTrueFalse(p); testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); } | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | } ccons ::= DEFAULT scanpt id(X). { Expr *p = tokenExpr(pParse, TK_STRING, X); if( p ){ sqlite3ExprIdToTrueFalse(p); testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); } sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n); } // 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);} |
︙ | ︙ | |||
542 543 544 545 546 547 548 549 550 551 | A = pRhs; } %type multiselect_op {int} multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/} %endif SQLITE_OMIT_COMPOUND_SELECT oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) groupby_opt(P) having_opt(Q) %ifndef SQLITE_OMIT_WINDOWFUNC | > > > > > | < < > > | | | | 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 | A = pRhs; } %type multiselect_op {int} multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/} %endif SQLITE_OMIT_COMPOUND_SELECT oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); } %ifndef SQLITE_OMIT_WINDOWFUNC oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) groupby_opt(P) having_opt(Q) window_clause(R) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); if( A ){ A->pWinDefn = R; }else{ sqlite3WindowListDelete(pParse->db, R); } } %endif oneselect(A) ::= values(A). %type values {Select*} %destructor values {sqlite3SelectDelete(pParse->db, $$);} values(A) ::= VALUES LP nexprlist(X) RP. { A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0); } values(A) ::= values(A) COMMA LP nexprlist(Y) RP. { Select *pRight, *pLeft = A; pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; A = pRight; |
︙ | ︙ | |||
689 690 691 692 693 694 695 | %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} %type fullname {SrcList*} %destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} | | | > > | | > > | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} %type fullname {SrcList*} %destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} fullname(A) ::= nm(X). { A = sqlite3SrcListAppend(pParse->db,0,&X,0); if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X); } fullname(A) ::= nm(X) DOT nm(Y). { A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y); } %type xfullname {SrcList*} %destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);} xfullname(A) ::= nm(X). {A = sqlite3SrcListAppend(pParse->db,0,&X,0); /*A-overwrites-X*/} xfullname(A) ::= nm(X) DOT nm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); /*A-overwrites-X*/} |
︙ | ︙ | |||
914 915 916 917 918 919 920 | %destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} %type idlist {IdList*} %destructor idlist {sqlite3IdListDelete(pParse->db, $$);} idlist_opt(A) ::= . {A = 0;} idlist_opt(A) ::= LP idlist(X) RP. {A = X;} idlist(A) ::= idlist(A) COMMA nm(Y). | | | | > > > > > > > > > > > > > > > > > > > > | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 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 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | %destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} %type idlist {IdList*} %destructor idlist {sqlite3IdListDelete(pParse->db, $$);} idlist_opt(A) ::= . {A = 0;} idlist_opt(A) ::= LP idlist(X) RP. {A = X;} idlist(A) ::= idlist(A) COMMA nm(Y). {A = sqlite3IdListAppend(pParse,A,&Y);} idlist(A) ::= nm(Y). {A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/} /////////////////////////// Expression Processing ///////////////////////////// // %type expr {Expr*} %destructor expr {sqlite3ExprDelete(pParse->db, $$);} %type term {Expr*} %destructor term {sqlite3ExprDelete(pParse->db, $$);} %include { /* Construct a new Expr object from a single identifier. Use the ** new Expr to populate pOut. Set the span of pOut to be the identifier ** that created the expression. */ static Expr *tokenExpr(Parse *pParse, int op, Token t){ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); if( p ){ /* memset(p, 0, sizeof(Expr)); */ p->op = (u8)op; p->affinity = 0; p->flags = EP_Leaf; p->iAgg = -1; p->pLeft = p->pRight = 0; p->x.pList = 0; p->pAggInfo = 0; p->y.pTab = 0; p->op2 = 0; p->iTable = 0; p->iColumn = 0; p->u.zToken = (char*)&p[1]; memcpy(p->u.zToken, t.z, t.n); p->u.zToken[t.n] = 0; if( sqlite3Isquote(p->u.zToken[0]) ){ if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted; sqlite3Dequote(p->u.zToken); } #if SQLITE_MAX_EXPR_DEPTH>0 p->nHeight = 1; #endif if( IN_RENAME_OBJECT ){ return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); } } return p; } } expr(A) ::= term(A). expr(A) ::= LP expr(X) RP. {A = X;} expr(A) ::= id(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} expr(A) ::= nm(X) DOT nm(Y). { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)temp2, &Y); sqlite3RenameTokenMap(pParse, (void*)temp1, &X); } A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1); Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)temp3, &Z); sqlite3RenameTokenMap(pParse, (void*)temp2, &Y); } A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} term(A) ::= INTEGER(X). { A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1); } |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 | } %ifndef SQLITE_OMIT_CAST expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. { A = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1); sqlite3ExprAttachSubtrees(pParse->db, A, E, 0); } %endif SQLITE_OMIT_CAST | > > | < < < < < | | > | < < | > > > > | < < < < | > > | | 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 | } %ifndef SQLITE_OMIT_CAST expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. { A = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1); sqlite3ExprAttachSubtrees(pParse->db, A, E, 0); } %endif SQLITE_OMIT_CAST expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP. { A = sqlite3ExprFunction(pParse, Y, &X, D); } expr(A) ::= id(X) LP STAR RP. { A = sqlite3ExprFunction(pParse, 0, &X, 0); } %ifndef SQLITE_OMIT_WINDOWFUNC expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP over_clause(Z). { A = sqlite3ExprFunction(pParse, Y, &X, D); sqlite3WindowAttach(pParse, A, Z); } expr(A) ::= id(X) LP STAR RP over_clause(Z). { A = sqlite3ExprFunction(pParse, 0, &X, 0); sqlite3WindowAttach(pParse, A, Z); } %endif term(A) ::= CTIME_KW(OP). { A = sqlite3ExprFunction(pParse, 0, &OP, 0); } expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. { ExprList *pList = sqlite3ExprListAppend(pParse, X, Y); A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); if( A ){ A->x.pList = pList; |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | likeop(A) ::= NOT LIKE_KW|MATCH(X). {A=X; A.n|=0x80000000; /*A-overwrite-X*/} expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] { ExprList *pList; int bNot = OP.n & 0x80000000; OP.n &= 0x7fffffff; pList = sqlite3ExprListAppend(pParse,0, Y); pList = sqlite3ExprListAppend(pParse,pList, A); | | | | | 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 1122 1123 1124 1125 1126 | likeop(A) ::= NOT LIKE_KW|MATCH(X). {A=X; A.n|=0x80000000; /*A-overwrite-X*/} expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] { ExprList *pList; int bNot = OP.n & 0x80000000; OP.n &= 0x7fffffff; pList = sqlite3ExprListAppend(pParse,0, Y); pList = sqlite3ExprListAppend(pParse,pList, A); A = sqlite3ExprFunction(pParse, pList, &OP, 0); if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); if( A ) A->flags |= EP_InfixFunc; } expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { ExprList *pList; int bNot = OP.n & 0x80000000; OP.n &= 0x7fffffff; pList = sqlite3ExprListAppend(pParse,0, Y); pList = sqlite3ExprListAppend(pParse,pList, A); pList = sqlite3ExprListAppend(pParse,pList, E); A = sqlite3ExprFunction(pParse, pList, &OP, 0); if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); if( A ) A->flags |= EP_InfixFunc; } expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);} expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);} %include { /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ sqlite3 *db = pParse->db; if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ pA->op = (u8)op; sqlite3ExprDelete(db, pA->pRight); pA->pRight = 0; } } } |
︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 | ///////////////////////////// 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;} | > > > | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 | ///////////////////////////// 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); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &Y); } } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} |
︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E). | | | | | 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E). {A = sqlite3TriggerUpdateStep(pParse, &X, Y, Z, R, B.z, E);} // INSERT trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). { A = sqlite3TriggerInsertStep(pParse,&X,F,S,R,U,B,Z);/*A-overwrites-R*/ } // DELETE trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E). {A = sqlite3TriggerDeleteStep(pParse, &X, Y, B.z, E);} // SELECT trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E). {A = sqlite3TriggerSelectStep(pParse->db, X, B, E); /*A-overwrites-X*/} // The special RAISE expression that may occur in trigger programs expr(A) ::= RAISE LP IGNORE RP. { |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &Y); } add_column_fullname ::= fullname(X). { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, X); } kwcolumn_opt ::= . kwcolumn_opt ::= COLUMNKW. %endif SQLITE_OMIT_ALTERTABLE //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} create_vtab ::= createkw VIRTUAL TABLE ifnotexists(E) | > > > > > | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 | Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &Y); } add_column_fullname ::= fullname(X). { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, X); } cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). { sqlite3AlterRenameColumn(pParse, X, &Y, &Z); } kwcolumn_opt ::= . kwcolumn_opt ::= COLUMNKW. %endif SQLITE_OMIT_ALTERTABLE //////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// %ifndef SQLITE_OMIT_VIRTUALTABLE cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} create_vtab ::= createkw VIRTUAL TABLE ifnotexists(E) |
︙ | ︙ | |||
1636 1637 1638 1639 1640 1641 1642 | A = Z; if( ALWAYS(A) ){ A->pPartition = X; A->pOrderBy = Y; } } | | | | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | A = Z; if( ALWAYS(A) ){ A->pPartition = X; A->pOrderBy = Y; } } part_opt(A) ::= PARTITION BY nexprlist(X). { A = X; } part_opt(A) ::= . { A = 0; } frame_opt(A) ::= . { A = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); } frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y). { A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0); } |
︙ | ︙ | |||
1662 1663 1664 1665 1666 1667 1668 | frame_bound_e(A) ::= frame_bound(X). { A = X; } frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;} frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; } frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; } frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; } | | | < | | | < | | | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 | frame_bound_e(A) ::= frame_bound(X). { A = X; } frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;} frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; } frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; } frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; } %type window_clause {Window*} %destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);} window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } %type over_clause {Window*} %destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} over_clause(A) ::= filter_opt(W) OVER window(Z). { A = Z; assert( A!=0 ); A->pFilter = W; } over_clause(A) ::= filter_opt(W) OVER nm(Z). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); A->pFilter = W; }else{ sqlite3ExprDelete(pParse->db, W); } } filter_opt(A) ::= . { A = 0; } filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; } %endif /* SQLITE_OMIT_WINDOWFUNC */ |
Changes to src/pcache.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | ** 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. | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** 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 so 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 */ |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 | Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; int r1 = -1; if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); | < | 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 | Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; int r1 = -1; if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); /* reg[7] counts the number of entries in the table. ** reg[8+i] counts the number of entries in the i-th index */ sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ |
︙ | ︙ | |||
1589 1590 1591 1592 1593 1594 1595 | ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); if( db->mallocFailed==0 ){ int addrCkFault = sqlite3VdbeMakeLabel(v); int addrCkOk = sqlite3VdbeMakeLabel(v); char *zErr; int k; pParse->iSelfTab = iDataCur + 1; | < < | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 | ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0); if( db->mallocFailed==0 ){ int addrCkFault = sqlite3VdbeMakeLabel(v); int addrCkOk = sqlite3VdbeMakeLabel(v); char *zErr; int k; pParse->iSelfTab = iDataCur + 1; for(k=pCheck->nExpr-1; k>0; k--){ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0); } sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk, SQLITE_JUMPIFNULL); sqlite3VdbeResolveLabel(v, addrCkFault); pParse->iSelfTab = 0; zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s", pTab->zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); integrityCheckResultRow(v); sqlite3VdbeResolveLabel(v, addrCkOk); } sqlite3ExprListDelete(db, pCheck); } if( !isQuick ){ /* Omit the remaining tests for quick_check */ /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4, jmp5; |
︙ | ︙ | |||
2221 2222 2223 2224 2225 2226 2227 | sqlite3_str_appendall(&acc, "CREATE TABLE x"); for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){ sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]); cSep = ','; } if( i==0 ){ sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); | < | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 | sqlite3_str_appendall(&acc, "CREATE TABLE x"); for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){ sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]); cSep = ','; } if( i==0 ){ sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); i++; } j = 0; if( pPragma->mPragFlg & PragFlg_Result1 ){ sqlite3_str_appendall(&acc, ",arg HIDDEN"); j++; } |
︙ | ︙ |
Changes to src/pragma.h.
︙ | ︙ | |||
389 390 391 392 393 394 395 396 397 398 399 400 401 402 | {/* zName: */ "key", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_file_format", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyFileFmt }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE | > > > > > | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | {/* zName: */ "key", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "legacy_alter_table", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyAlter }, {/* zName: */ "legacy_file_format", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyFileFmt }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE |
︙ | ︙ | |||
651 652 653 654 655 656 657 | {/* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema }, #endif }; | | | 656 657 658 659 660 661 662 663 | {/* zName: */ "writable_schema", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_WriteSchema }, #endif }; /* Number of pragmas: 61 on by default, 78 total. */ |
Changes to src/prepare.c.
︙ | ︙ | |||
21 22 23 24 25 26 27 | */ static void corruptSchema( InitData *pData, /* Initialization context */ const char *zObj, /* Object being parsed at the point of error */ const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; | > > > > > > > | > > < > < | 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 | */ static void corruptSchema( InitData *pData, /* Initialization context */ const char *zObj, /* Object being parsed at the point of error */ const char *zExtra /* Error information */ ){ sqlite3 *db = pData->db; if( db->mallocFailed ){ pData->rc = SQLITE_NOMEM_BKPT; }else if( pData->pzErrMsg[0]!=0 ){ /* A error message has already been generated. Do not overwrite it */ }else if( pData->mInitFlags & INITFLAG_AlterTable ){ *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else{ char *z; if( zObj==0 ) zObj = "?"; z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj); if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra); *pData->pzErrMsg = z; pData->rc = SQLITE_CORRUPT_BKPT; } } /* ** This is the callback routine for the code that initializes the ** database. See sqlite3Init() below for additional information. ** This routine is also called from the OP_ParseSchema opcode of the VDBE. ** |
︙ | ︙ | |||
81 82 83 84 85 86 87 | db->init.iDb = iDb; db->init.newTnum = sqlite3Atoi(argv[1]); db->init.orphanTrigger = 0; TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | db->init.iDb = iDb; db->init.newTnum = sqlite3Atoi(argv[1]); db->init.orphanTrigger = 0; TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0); rc = db->errCode; assert( (rc&0xFF)==(rcp&0xFF) ); db->init.iDb = saved_iDb; /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); |
︙ | ︙ | |||
128 129 130 131 132 133 134 | ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ int rc; int i; #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; char const *azArg[4]; |
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 | azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," "rootpage int,sql text)"; azArg[3] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open | > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text," "rootpage int,sql text)"; azArg[3] = 0; initData.db = db; initData.iDb = iDb; initData.rc = SQLITE_OK; initData.pzErrMsg = pzErrMsg; initData.mInitFlags = mFlags; sqlite3InitCallback(&initData, 3, (char **)azArg, 0); if( initData.rc ){ rc = initData.rc; goto error_out; } /* Create a cursor to hold the database open |
︙ | ︙ | |||
369 370 371 372 373 374 375 | assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); ENC(db) = SCHEMA_ENC(db); assert( db->nDb>0 ); /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ | | | | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) ); assert( db->init.busy==0 ); ENC(db) = SCHEMA_ENC(db); assert( db->nDb>0 ); /* Do the main schema first */ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, 0, pzErrMsg, 0); if( rc ) return rc; } /* All other schemas after the main schema. The "temp" schema must be last */ for(i=db->nDb-1; i>0; i--){ assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) ); if( !DbHasProperty(db, i, DB_SchemaLoaded) ){ rc = sqlite3InitOne(db, i, pzErrMsg, 0); if( rc ) return rc; } } if( commit_internal ){ sqlite3CommitInternalChanges(db); } return SQLITE_OK; |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
682 683 684 685 686 687 688 | xtype = etSTRING; }else{ bufpt = va_arg(ap,char*); } if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ | | > > > > > | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 | xtype = etSTRING; }else{ bufpt = va_arg(ap,char*); } if( bufpt==0 ){ bufpt = ""; }else if( xtype==etDYNSTRING ){ if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 && pAccum->accError==0 ){ /* Special optimization for sqlite3_mprintf("%z..."): ** Extend an existing memory allocation rather than creating ** a new one. */ assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); pAccum->zText = bufpt; pAccum->nAlloc = sqlite3DbMallocSize(pAccum->db, bufpt); pAccum->nChar = 0x7fffffff & (int)strlen(bufpt); |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
155 156 157 158 159 160 161 | ** expression node refer back to that source column. The following changes ** are made to pExpr: ** ** pExpr->iDb Set the index in db->aDb[] of the database X ** (even if X is implied). ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | ** expression node refer back to that source column. The following changes ** are made to pExpr: ** ** pExpr->iDb Set the index in db->aDb[] of the database X ** (even if X is implied). ** pExpr->iTable Set to the cursor number for the table obtained ** from pSrcList. ** pExpr->y.pTab Points to the Table structure of X.Y (even if ** X and/or Y are implied.) ** pExpr->iColumn Set to the column number within the table. ** pExpr->op Set to TK_COLUMN. ** pExpr->pLeft Any expression this points to is deleted ** pExpr->pRight Any expression this points to is deleted. ** ** The zDb variable is the name of the database (the "X"). This value may be |
︙ | ︙ | |||
199 200 201 202 203 204 205 | assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; | < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding ** schema. If not found, pSchema will remain NULL and nothing will match ** resulting in an appropriate error message toward the end of this routine */ if( zDb ){ |
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | } if( zTab ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; assert( zTabName!=0 ); if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } } if( 0==(cntTab++) ){ pMatch = pItem; } for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match | > > > | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | } if( zTab ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; assert( zTabName!=0 ); if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } if( IN_RENAME_OBJECT && pItem->zAlias ){ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } if( 0==(cntTab++) ){ pMatch = pItem; } for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match |
︙ | ︙ | |||
284 285 286 287 288 289 290 | pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; | | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; pExpr->y.pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } pSchema = pExpr->y.pTab->pSchema; } } /* if( pSrcList ) */ #if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference. Or ** maybe it is an excluded.* from an upsert. |
︙ | ︙ | |||
345 346 347 348 349 350 351 | iCol = -1; } if( iCol<pTab->nCol ){ cnt++; #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==2 ){ testcase( iCol==(-1) ); | > > > > > | | | > | | 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 | iCol = -1; } if( iCol<pTab->nCol ){ cnt++; #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==2 ){ testcase( iCol==(-1) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; pExpr->y.pTab = pTab; eNewExprOp = TK_COLUMN; }else{ pExpr->iTable = pNC->uNC.pUpsert->regData + iCol; eNewExprOp = TK_REGISTER; ExprSetProperty(pExpr, EP_Alias); } }else #endif /* SQLITE_OMIT_UPSERT */ { #ifndef SQLITE_OMIT_TRIGGER if( iCol<0 ){ pExpr->affinity = SQLITE_AFF_INTEGER; }else if( pExpr->iTable==0 ){ testcase( iCol==31 ); testcase( iCol==32 ); pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol)); }else{ testcase( iCol==31 ); testcase( iCol==32 ); pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol)); } pExpr->y.pTab = pTab; pExpr->iColumn = (i16)iCol; eNewExprOp = TK_TRIGGER; #endif /* SQLITE_OMIT_TRIGGER */ } } } } |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 | sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; } resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); goto lookupname_end; } } } /* Advance to the next name context. The loop will exit when either ** we have a match (cnt>0) or when we run out of name contexts. | > > > | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; } resolveAlias(pParse, pEList, j, pExpr, "", nSubquery); cnt = 1; pMatch = 0; assert( zTab==0 && zDb==0 ); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr); } goto lookupname_end; } } } /* Advance to the next name context. The loop will exit when either ** we have a match (cnt>0) or when we run out of name contexts. |
︙ | ︙ | |||
460 461 462 463 464 465 466 | ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) ){ pExpr->op = TK_STRING; | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); if( ExprHasProperty(pExpr,EP_DblQuoted) ){ pExpr->op = TK_STRING; pExpr->y.pTab = 0; return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } } |
︙ | ︙ | |||
538 539 540 541 542 543 544 | ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc in SrcList pSrc. */ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ struct SrcList_item *pItem = &pSrc->a[iSrc]; | | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc in SrcList pSrc. */ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); if( p ){ struct SrcList_item *pItem = &pSrc->a[iSrc]; p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; testcase( iCol==BMS ); testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } |
︙ | ︙ | |||
630 631 632 633 634 635 636 | case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; struct SrcList_item *pItem; assert( pSrcList && pSrcList->nSrc==1 ); pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 | case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; struct SrcList_item *pItem; assert( pSrcList && pSrcList->nSrc==1 ); pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn = -1; pExpr->affinity = SQLITE_AFF_INTEGER; break; } #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */ |
︙ | ︙ | |||
659 660 661 662 663 664 665 666 667 668 669 | Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; zColumn = pExpr->u.zToken; }else{ notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; | > < < | | > > > | > > > | 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 | Expr *pRight; if( pExpr->op==TK_ID ){ zDb = 0; zTable = 0; zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; }else{ assert( pRight->op==TK_DOT ); zDb = pLeft->u.zToken; pLeft = pRight->pLeft; pRight = pRight->pRight; } zTable = pLeft->u.zToken; zColumn = pRight->u.zToken; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight); sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft); } } return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr); } /* Resolve function names */ |
︙ | ︙ | |||
753 754 755 756 757 758 759 760 | ** sqlite_version() that might change over time cannot be used ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx); } } #ifndef SQLITE_OMIT_WINDOWFUNC | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | 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 | ** sqlite_version() that might change over time cannot be used ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx); } } if( 0==IN_RENAME_OBJECT ){ #ifndef SQLITE_OMIT_WINDOWFUNC assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX) || (pDef->xValue==0 && pDef->xInverse==0) || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize) ); if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ErrorMsg(pParse, "%.*s() may not be used as a window function", nId, zId ); pNC->nErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin) || (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0) ){ const char *zType; if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){ zType = "window"; }else{ zType = "aggregate"; } sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); pNC->nErr++; is_agg = 0; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId); pNC->nErr++; is_agg = 0; } #endif 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++; } if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC pNC->ncFlags &= ~(pExpr->y.pWin ? NC_AllowWin : NC_AllowAgg); #else pNC->ncFlags &= ~NC_AllowAgg; #endif } } sqlite3WalkExprList(pWalker, pList); if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC if( pExpr->y.pWin ){ Select *pSel = pNC->pWinSelect; sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition); sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy); sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); if( 0==pSel->pWin || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin) ){ pExpr->y.pWin->pNextWin = pSel->pWin; pSel->pWin = pExpr->y.pWin; } pNC->ncFlags |= NC_AllowWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { NameContext *pNC2 = pNC; pExpr->op = TK_AGG_FUNCTION; |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | pItem->u.x.iOrderByCol = 0; if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ #ifndef SQLITE_OMIT_WINDOWFUNC | | | | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | pItem->u.x.iOrderByCol = 0; if( sqlite3ResolveExprNames(pNC, pE) ){ return 1; } for(j=0; j<pSelect->pEList->nExpr; j++){ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pE, EP_WinFunc) ){ /* Since this window function is being changed into a reference ** to the same window function the result set, remove the instance ** of this window function from the Select.pWin list. */ Window **pp; for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){ if( *pp==pE->y.pWin ){ *pp = (*pp)->pNextWin; } } } #endif pItem->u.x.iOrderByCol = j+1; } |
︙ | ︙ |
Changes to src/rowset.c.
︙ | ︙ | |||
120 121 122 123 124 125 126 | /* ** Allowed values for RowSet.rsFlags */ #define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* | | < < < < < | < < < | | | | | | | | | | | | | > | > > > > > > > > > > > | 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 | /* ** Allowed values for RowSet.rsFlags */ #define ROWSET_SORTED 0x01 /* True if RowSet.pEntry is sorted */ #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* ** Allocate a RowSet object. Return NULL if a memory allocation ** error occurs. */ RowSet *sqlite3RowSetInit(sqlite3 *db){ RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p)); if( p ){ int N = sqlite3DbMallocSize(db, p); p->pChunk = 0; p->db = db; p->pEntry = 0; p->pLast = 0; p->pForest = 0; p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); p->rsFlags = ROWSET_SORTED; p->iBatch = 0; } return p; } /* ** Deallocate all chunks from a RowSet. This frees all memory that ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ void sqlite3RowSetClear(void *pArg){ RowSet *p = (RowSet*)pArg; struct RowSetChunk *pChunk, *pNextChunk; for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ pNextChunk = pChunk->pNextChunk; sqlite3DbFree(p->db, pChunk); } p->pChunk = 0; p->nFresh = 0; p->pEntry = 0; p->pLast = 0; p->pForest = 0; p->rsFlags = ROWSET_SORTED; } /* ** Deallocate all chunks from a RowSet. This frees all memory that ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ void sqlite3RowSetDelete(void *pArg){ sqlite3RowSetClear(pArg); sqlite3DbFree(((RowSet*)pArg)->db, pArg); } /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized ** objected. ** ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
64 65 66 67 68 69 70 71 | ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ 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 */ | > < | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */ 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 */ int labelOBLopt; /* Jump here when sorter is full */ u8 sortFlags; /* Zero or more SORTFLAG_* bits */ #ifdef SQLITE_ENABLE_SORTER_REFERENCES u8 nDefer; /* Number of valid entries in aDefer[] */ struct DeferredCsr { Table *pTab; /* Table definition */ int iCsr; /* Cursor number for table */ int nKey; /* Number of PK columns for table pTab (>=1) */ } aDefer[4]; |
︙ | ︙ | |||
689 690 691 692 693 694 695 | ** less than LIMIT+OFFSET items or (b) the new record is smaller than ** the largest record currently in the sorter. If (b) is true and there ** are already LIMIT+OFFSET items in the sorter, delete the largest ** entry before inserting the new one. This way there are never more ** than LIMIT+OFFSET items in the sorter. ** ** If the new record does not need to be inserted into the sorter, | | | | | | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | ** less than LIMIT+OFFSET items or (b) the new record is smaller than ** the largest record currently in the sorter. If (b) is true and there ** are already LIMIT+OFFSET items in the sorter, delete the largest ** entry before inserting the new one. This way there are never more ** than LIMIT+OFFSET items in the sorter. ** ** If the new record does not need to be inserted into the sorter, ** jump to the next iteration of the loop. If the pSort->labelOBLopt ** value is not zero, then it is a label of where to jump. Otherwise, ** just bypass the row insert logic. See the header comment on the ** sqlite3WhereOrderByLimitOptLabel() function for additional info. */ int iCsr = pSort->iECursor; sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0); iSkip = sqlite3VdbeAddOp4Int(v, OP_IdxLE, iCsr, 0, regBase+nOBSat, nExpr-nOBSat); |
︙ | ︙ | |||
714 715 716 717 718 719 720 | op = OP_SorterInsert; }else{ op = OP_IdxInsert; } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); if( iSkip ){ | < | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | op = OP_SorterInsert; }else{ op = OP_IdxInsert; } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); if( iSkip ){ sqlite3VdbeChangeP2(v, iSkip, pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } } /* ** Add code to implement the OFFSET */ static void codeOffset( |
︙ | ︙ | |||
800 801 802 803 804 805 806 | int i; int nDefer = 0; ExprList *pExtra = 0; for(i=0; i<pEList->nExpr; i++){ struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; | | | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 | int i; int nDefer = 0; ExprList *pExtra = 0; for(i=0; i<pEList->nExpr; i++){ struct ExprList_item *pItem = &pEList->a[i]; if( pItem->u.x.iOrderByCol==0 ){ Expr *pExpr = pItem->pExpr; Table *pTab = pExpr->y.pTab; if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) ){ int j; for(j=0; j<nDefer; j++){ if( pSort->aDefer[j].iCsr==pExpr->iTable ) break; } |
︙ | ︙ | |||
823 824 825 826 827 828 829 | pPk = sqlite3PrimaryKeyIndex(pTab); nKey = pPk->nKeyCol; } for(k=0; k<nKey; k++){ Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0); if( pNew ){ pNew->iTable = pExpr->iTable; | | | | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | pPk = sqlite3PrimaryKeyIndex(pTab); nKey = pPk->nKeyCol; } for(k=0; k<nKey; k++){ Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0); if( pNew ){ pNew->iTable = pExpr->iTable; pNew->y.pTab = pExpr->y.pTab; pNew->iColumn = pPk ? pPk->aiColumn[k] : -1; pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew); } } pSort->aDefer[nDefer].pTab = pExpr->y.pTab; pSort->aDefer[nDefer].iCsr = pExpr->iTable; pSort->aDefer[nDefer].nKey = nKey; nDefer++; } } pItem->bSorterRef = 1; } |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); | < | 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | pushOntoSorter( pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } /* If any row exist in the result set, record that fact and abort. |
︙ | ︙ | |||
1189 1190 1191 1192 1193 1194 1195 | if( pSort ){ pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); | < | 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 | if( pSort ){ pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); } break; } #ifndef SQLITE_OMIT_CTE /* Write the results into a priority queue that is order according to ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an |
︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 | break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); | < < | 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 | break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid, pDest->zAffSdst, nColumn); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn); break; } case SRT_Mem: { /* The LIMIT clause will terminate the loop for us */ break; } #endif default: { assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn); }else{ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); } break; } } if( regRowid ){ |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 | ** This is not a problem, as the column type of "t1.col" is never ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } | | | 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 | ** This is not a problem, as the column type of "t1.col" is never ** used. When columnType() is called on the expression ** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT ** branch below. */ break; } assert( pTab && pExpr->y.pTab==pTab ); if( pS ){ /* The "table" is actually a sub-select or a view in the FROM clause ** of the SELECT statement. Return the declaration type and origin ** data for the result-set column of the sub-select. */ if( iCol>=0 && iCol<pS->pEList->nExpr ){ /* If iCol is less than zero, then the expression requests the |
︙ | ︙ | |||
1866 1867 1868 1869 1870 1871 1872 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ | | | | 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 | srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; assert( p!=0 ); assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */ assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */ if( pEList->a[i].zName ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT); }else if( srcName && p->op==TK_COLUMN ){ char *zCol; int iCol = p->iColumn; pTab = p->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zCol = "rowid"; }else{ zCol = pTab->aCol[iCol].zName; |
︙ | ︙ | |||
1965 1966 1967 1968 1969 1970 1971 | pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } assert( pColExpr->op!=TK_AGG_COLUMN ); if( pColExpr->op==TK_COLUMN ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; | | | 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 | pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } assert( pColExpr->op!=TK_AGG_COLUMN ); if( pColExpr->op==TK_COLUMN ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; Table *pTab = pColExpr->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); zName = pColExpr->u.zToken; }else{ |
︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 | /* ** "LIMIT -1" always shows all rows. There is some ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ | < | 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 | /* ** "LIMIT -1" always shows all rows. There is some ** controversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ if( pLimit ){ assert( pLimit->op==TK_LIMIT ); assert( pLimit->pLeft!=0 ); p->iLimit = iLimit = ++pParse->nMem; v = sqlite3GetVdbe(pParse); assert( v!=0 ); if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){ |
︙ | ︙ | |||
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 | int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ addrBreak = sqlite3VdbeMakeLabel(v); p->nSelectRow = 320; /* 4 billion rows */ | > > > > > > > | 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 | int eDest = SRT_Fifo; /* How to write to Queue */ SelectDest destQueue; /* SelectDest targetting the Queue table */ int i; /* Loop counter */ int rc; /* Result code */ ExprList *pOrderBy; /* The ORDER BY clause */ Expr *pLimit; /* Saved LIMIT and OFFSET */ int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */ #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWin ){ sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries"); return; } #endif /* Obtain authorization to do a recursive query */ if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return; /* Process the LIMIT and OFFSET clauses, if they exist */ addrBreak = sqlite3VdbeMakeLabel(v); p->nSelectRow = 320; /* 4 billion rows */ |
︙ | ︙ | |||
2948 2949 2950 2951 2952 2953 2954 | */ case SRT_Set: { int r1; testcase( pIn->nSdst>1 ); r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1, pDest->zAffSdst, pIn->nSdst); | < | 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 | */ case SRT_Set: { int r1; testcase( pIn->nSdst>1 ); r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1, pDest->zAffSdst, pIn->nSdst); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1, pIn->iSdst, pIn->nSdst); sqlite3ReleaseTempReg(pParse, r1); break; } /* If this is a scalar select that is part of an expression, then |
︙ | ︙ | |||
2991 2992 2993 2994 2995 2996 2997 | ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to ** return the next row of result. */ default: { assert( pDest->eDest==SRT_Output ); sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); | < | 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 | ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to ** return the next row of result. */ default: { assert( pDest->eDest==SRT_Output ); sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst); break; } } /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit ){ |
︙ | ︙ | |||
3446 3447 3448 3449 3450 3451 3452 | if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; Expr ifNullRow; assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr ); | | | 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 | if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr; Expr ifNullRow; assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr ); assert( pExpr->pRight==0 ); if( sqlite3ExprIsVector(pCopy) ){ sqlite3VectorErrorMsg(pSubst->pParse, pCopy); }else{ sqlite3 *db = pSubst->pParse->db; if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){ memset(&ifNullRow, 0, sizeof(ifNullRow)); ifNullRow.op = TK_IF_NULL_ROW; |
︙ | ︙ | |||
4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 | } #endif return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Make copies of relevant WHERE clause terms of the outer query into ** the WHERE clause of subquery. Example: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 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 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 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 | } #endif return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** A structure to keep track of all of the column values that fixed to ** a known value due to WHERE clause constraints of the form COLUMN=VALUE. */ typedef struct WhereConst WhereConst; struct WhereConst { Parse *pParse; /* Parsing context */ int nConst; /* Number for COLUMN=CONSTANT terms */ int nChng; /* Number of times a constant is propagated */ Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */ }; /* ** Add a new entry to the pConst object */ static void constInsert( WhereConst *pConst, Expr *pColumn, Expr *pValue ){ pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft; pConst->apExpr[pConst->nConst*2-2] = pColumn; pConst->apExpr[pConst->nConst*2-1] = pValue; } } /* ** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE ** is a constant expression and where the term must be true because it ** is part of the AND-connected terms of the expression. For each term ** found, add it to the pConst structure. */ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; if( pExpr==0 ) return; if( ExprHasProperty(pExpr, EP_FromJoin) ) return; if( pExpr->op==TK_AND ){ findConstInWhere(pConst, pExpr->pRight); findConstInWhere(pConst, pExpr->pLeft); return; } if( pExpr->op!=TK_EQ ) return; pRight = pExpr->pRight; pLeft = pExpr->pLeft; assert( pRight!=0 ); assert( pLeft!=0 ); if( pRight->op==TK_COLUMN && !ExprHasProperty(pRight, EP_FixedCol) && sqlite3ExprIsConstant(pLeft) && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) ){ constInsert(pConst, pRight, pLeft); }else if( pLeft->op==TK_COLUMN && !ExprHasProperty(pLeft, EP_FixedCol) && sqlite3ExprIsConstant(pRight) && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) ){ constInsert(pConst, pLeft, pRight); } } /* ** This is a Walker expression callback. pExpr is a candidate expression ** to be replaced by a value. If pExpr is equivalent to one of the ** columns named in pWalker->u.pConst, then overwrite it with its ** corresponding value. */ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ int i; WhereConst *pConst; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue; pConst = pWalker->u.pConst; for(i=0; i<pConst->nConst; i++){ Expr *pColumn = pConst->apExpr[i*2]; if( pColumn==pExpr ) continue; if( pColumn->iTable!=pExpr->iTable ) continue; if( pColumn->iColumn!=pExpr->iColumn ) continue; /* A match is found. Add the EP_FixedCol property */ pConst->nChng++; ExprClearProperty(pExpr, EP_Leaf); ExprSetProperty(pExpr, EP_FixedCol); assert( pExpr->pLeft==0 ); pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0); break; } return WRC_Prune; } /* ** The WHERE-clause constant propagation optimization. ** ** If the WHERE clause contains terms of the form COLUMN=CONSTANT or ** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level ** AND-connected terms that are not part of a ON clause from a LEFT JOIN) ** then throughout the query replace all other occurrences of COLUMN ** with CONSTANT within the WHERE clause. ** ** For example, the query: ** ** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b ** ** Is transformed into ** ** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39 ** ** Return true if any transformations where made and false if not. ** ** Implementation note: Constant propagation is tricky due to affinity ** and collating sequence interactions. Consider this example: ** ** CREATE TABLE t1(a INT,b TEXT); ** INSERT INTO t1 VALUES(123,'0123'); ** SELECT * FROM t1 WHERE a=123 AND b=a; ** SELECT * FROM t1 WHERE a=123 AND b=123; ** ** The two SELECT statements above should return different answers. b=a ** is alway true because the comparison uses numeric affinity, but b=123 ** is false because it uses text affinity and '0123' is not the same as '123'. ** To work around this, the expression tree is not actually changed from ** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol ** and the "123" value is hung off of the pLeft pointer. Code generator ** routines know to generate the constant "123" instead of looking up the ** column value. Also, to avoid collation problems, this optimization is ** only attempted if the "a=123" term uses the default BINARY collation. */ static int propagateConstants( Parse *pParse, /* The parsing context */ Select *p /* The query in which to propagate constants */ ){ WhereConst x; Walker w; int nChng = 0; x.pParse = pParse; do{ x.nConst = 0; x.nChng = 0; x.apExpr = 0; findConstInWhere(&x, p->pWhere); if( x.nConst ){ memset(&w, 0, sizeof(w)); w.pParse = pParse; w.xExprCallback = propagateConstantExprRewrite; w.xSelectCallback = sqlite3SelectWalkNoop; w.xSelectCallback2 = 0; w.walkerDepth = 0; w.u.pConst = &x; sqlite3WalkExpr(&w, p->pWhere); sqlite3DbFree(x.pParse->db, x.apExpr); nChng += x.nChng; } }while( x.nChng ); return nChng; } #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* ** Make copies of relevant WHERE clause terms of the outer query into ** the WHERE clause of subquery. Example: ** ** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; |
︙ | ︙ | |||
5171 5172 5173 5174 5175 5176 5177 | } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); | < < < < < < < < < < < < < < < | 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 | } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } } if( regHit==0 && pAggInfo->nAccumulator ){ regHit = regAcc; } if( regHit ){ addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); } for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){ sqlite3ExprCode(pParse, pC->pExpr, pC->iMem); } pAggInfo->directMode = 0; if( addrHitTest ){ sqlite3VdbeJumpHere(v, addrHitTest); } } /* ** Add a single OP_Explain instruction to the VDBE to explain a simple |
︙ | ︙ | |||
5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 | ** Into this: ** ** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) ** ** The transformation only works if all of the following are true: ** ** * The subquery is a UNION ALL of two or more terms ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) ** ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; | > | 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 | ** Into this: ** ** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2) ** ** The transformation only works if all of the following are true: ** ** * The subquery is a UNION ALL of two or more terms ** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * The outer query is a simple count(*) ** ** Return TRUE if the optimization is undertaken. */ static int countOfViewOptimization(Parse *pParse, Select *p){ Select *pSub, *pPrior; |
︙ | ︙ | |||
5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 | if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ pSub = p->pSrc->a[0].pSelect; if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ db = pParse->db; | > | 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 | if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ pSub = p->pSrc->a[0].pSelect; if( pSub==0 ) return 0; /* The FROM is a subquery */ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */ do{ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ pSub = pSub->pPrior; /* Repeat over compound */ }while( pSub ); /* If we reach this point then it is OK to perform the transformation */ db = pParse->db; |
︙ | ︙ | |||
5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 | sqlite3TreeViewSelect(0, p, 0); } #endif if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 | sqlite3TreeViewSelect(0, p, 0); } #endif if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif /* Do the WHERE-clause constant propagation optimization if this is ** a join. No need to speed time on this operation for non-join queries ** as the equivalent optimization will be handled by query planner in ** sqlite3WhereBegin(). */ if( pTabList->nSrc>1 && OptimizationEnabled(db, SQLITE_PropagateConst) && propagateConstants(pParse, p) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After constant propagation:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif }else{ SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n")); } #ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) && countOfViewOptimization(pParse, p) ){ if( db->mallocFailed ) goto select_end; pEList = p->pEList; pTabList = p->pSrc; } #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries */ for(i=0; i<pTabList->nSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; |
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 | */ if( OptimizationEnabled(db, SQLITE_PushDown) && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, (pItem->fg.jointype & JT_OUTER)!=0) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ | | > | 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 | */ if( OptimizationEnabled(db, SQLITE_PushDown) && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor, (pItem->fg.jointype & JT_OUTER)!=0) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p, ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif }else{ SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); } |
︙ | ︙ | |||
5770 5771 5772 5773 5774 5775 5776 | sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); sqlite3TreeViewSelect(0, p, 0); } | < < < < < < < < < < | 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 | sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: ** ** SELECT DISTINCT xyz FROM ... ORDER BY xyz |
︙ | ︙ | |||
5895 5896 5897 5898 5899 5900 5901 | p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); | | | 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 | p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } if( sSort.pOrderBy ){ sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo); sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(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 |
︙ | ︙ | |||
5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 | int regGosub = ++pParse->nMem; sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); sqlite3VdbeResolveLabel(v, addrGosub); VdbeNoopComment((v, "inner-loop subroutine")); selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp1(v, OP_Return, regGosub); VdbeComment((v, "end inner-loop subroutine")); sqlite3VdbeResolveLabel(v, iBreak); }else #endif /* SQLITE_OMIT_WINDOWFUNC */ | > | 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 | int regGosub = ++pParse->nMem; sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); sqlite3VdbeResolveLabel(v, addrGosub); VdbeNoopComment((v, "inner-loop subroutine")); sSort.labelOBLopt = 0; selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp1(v, OP_Return, regGosub); VdbeComment((v, "end inner-loop subroutine")); sqlite3VdbeResolveLabel(v, iBreak); }else #endif /* SQLITE_OMIT_WINDOWFUNC */ |
︙ | ︙ | |||
6131 6132 6133 6134 6135 6136 6137 | for(i=0; i<sAggInfo.nColumn; i++){ if( sAggInfo.aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); | < | | < < | 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 | for(i=0; i<sAggInfo.nColumn; i++){ if( sAggInfo.aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; for(i=0; i<sAggInfo.nColumn; i++){ struct AggInfo_col *pCol = &sAggInfo.aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; sqlite3ExprCodeGetColumnOfTable(v, pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); sqlite3WhereEnd(pWInfo); sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); sAggInfo.useSortingIdx = 1; } /* If the index or temporary table used by the GROUP BY sort ** will naturally deliver rows in the order required by the ORDER BY ** clause, cancel the ephemeral table open coded earlier. ** ** This is an optimization - the correct answer should result regardless. |
︙ | ︙ | |||
6179 6180 6181 6182 6183 6184 6185 | /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); | < | 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 | /* Evaluate the current GROUP BY terms and store in b0, b1, b2... ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth) ** Then compare the current GROUP BY terms against the GROUP BY terms ** from the previous row currently stored in a0, a1, a2... */ addrTopOfLoop = sqlite3VdbeCurrentAddr(v); if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut, sortPTab); } for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); |
︙ | ︙ |
Changes to src/shell.c.in.
︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | # if !defined(__RTP__) && !defined(_WRS_KERNEL) # include <pwd.h> # endif #endif #if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__) # include <unistd.h> # include <dirent.h> # if defined(__MINGW32__) # define DIRENT dirent # ifndef S_ISLNK # define S_ISLNK(mode) (0) # endif # endif #endif #include <sys/types.h> #include <sys/stat.h> #if HAVE_READLINE # include <readline/readline.h> # include <readline/history.h> | > > > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # if !defined(__RTP__) && !defined(_WRS_KERNEL) # include <pwd.h> # endif #endif #if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__) # include <unistd.h> # include <dirent.h> # define GETPID getpid # if defined(__MINGW32__) # define DIRENT dirent # ifndef S_ISLNK # define S_ISLNK(mode) (0) # endif # endif #else # define GETPID (int)GetCurrentProcessId #endif #include <sys/types.h> #include <sys/stat.h> #if HAVE_READLINE # include <readline/readline.h> # include <readline/history.h> |
︙ | ︙ | |||
561 562 563 564 565 566 567 | int nLine = zLine==0 ? 0 : 100; int n = 0; while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; zLine = realloc(zLine, nLine); | | | 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | int nLine = zLine==0 ? 0 : 100; int n = 0; while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; zLine = realloc(zLine, nLine); if( zLine==0 ) shell_out_of_memory(); } if( fgets(&zLine[n], nLine - n, in)==0 ){ if( n==0 ){ free(zLine); return 0; } zLine[n] = 0; |
︙ | ︙ | |||
588 589 590 591 592 593 594 | ** multi-byte characterset characters into UTF-8. */ if( stdin_is_interactive && in==stdin ){ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); if( zTrans ){ int nTrans = strlen30(zTrans)+1; if( nTrans>nLine ){ zLine = realloc(zLine, nTrans); | | < < < | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | ** multi-byte characterset characters into UTF-8. */ if( stdin_is_interactive && in==stdin ){ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); if( zTrans ){ int nTrans = strlen30(zTrans)+1; if( nTrans>nLine ){ zLine = realloc(zLine, nTrans); if( zLine==0 ) shell_out_of_memory(); } memcpy(zLine, zTrans, nTrans); sqlite3_free(zTrans); } } #endif /* defined(_WIN32) || defined(WIN32) */ return zLine; |
︙ | ︙ | |||
738 739 740 741 742 743 744 | if( zAppend[i]==quote ) len++; } } if( p->n+len>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + len + 20; p->z = realloc(p->z, p->nAlloc); | | < < < | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | if( zAppend[i]==quote ) len++; } } if( p->n+len>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + len + 20; p->z = realloc(p->z, p->nAlloc); if( p->z==0 ) shell_out_of_memory(); } if( quote ){ char *zCsr = p->z+p->n; *zCsr++ = quote; for(i=0; i<nAppend; i++){ *zCsr++ = zAppend[i]; |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 | ){ const char *zEditor; char *zTempFile = 0; sqlite3 *db; char *zCmd = 0; int bBin; int rc; FILE *f = 0; sqlite3_int64 sz; sqlite3_int64 x; unsigned char *p = 0; if( argc==2 ){ zEditor = (const char*)sqlite3_value_text(argv[1]); | > | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 | ){ const char *zEditor; char *zTempFile = 0; sqlite3 *db; char *zCmd = 0; int bBin; int rc; int hasCRNL = 0; FILE *f = 0; sqlite3_int64 sz; sqlite3_int64 x; unsigned char *p = 0; if( argc==2 ){ zEditor = (const char*)sqlite3_value_text(argv[1]); |
︙ | ︙ | |||
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 1240 1241 1242 1243 1244 1245 1246 1247 1248 | zTempFile = sqlite3_mprintf("temp%llx", r); if( zTempFile==0 ){ sqlite3_result_error_nomem(context); return; } } bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB; f = fopen(zTempFile, bBin ? "wb" : "w"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot open temp file", -1); goto edit_func_end; } sz = sqlite3_value_bytes(argv[0]); if( bBin ){ x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f); }else{ x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f); } fclose(f); f = 0; if( x!=sz ){ sqlite3_result_error(context, "edit() could not write the whole file", -1); goto edit_func_end; } zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile); if( zCmd==0 ){ sqlite3_result_error_nomem(context); goto edit_func_end; } rc = system(zCmd); sqlite3_free(zCmd); if( rc ){ sqlite3_result_error(context, "EDITOR returned non-zero", -1); goto edit_func_end; } | > > > > > | < | < < < < > > > > > > > > > > > > > > | 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 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 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 1294 1295 1296 | zTempFile = sqlite3_mprintf("temp%llx", r); if( zTempFile==0 ){ sqlite3_result_error_nomem(context); return; } } bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB; /* When writing the file to be edited, do \n to \r\n conversions on systems ** that want \r\n line endings */ f = fopen(zTempFile, bBin ? "wb" : "w"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot open temp file", -1); goto edit_func_end; } sz = sqlite3_value_bytes(argv[0]); if( bBin ){ x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f); }else{ const char *z = (const char*)sqlite3_value_text(argv[0]); /* Remember whether or not the value originally contained \r\n */ if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1; x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f); } fclose(f); f = 0; if( x!=sz ){ sqlite3_result_error(context, "edit() could not write the whole file", -1); goto edit_func_end; } zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile); if( zCmd==0 ){ sqlite3_result_error_nomem(context); goto edit_func_end; } rc = system(zCmd); sqlite3_free(zCmd); if( rc ){ sqlite3_result_error(context, "EDITOR returned non-zero", -1); goto edit_func_end; } f = fopen(zTempFile, "rb"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot reopen temp file after edit", -1); goto edit_func_end; } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); p = sqlite3_malloc64( sz+(bBin==0) ); if( p==0 ){ sqlite3_result_error_nomem(context); goto edit_func_end; } x = fread(p, 1, sz, f); fclose(f); f = 0; if( x!=sz ){ sqlite3_result_error(context, "could not read back the whole file", -1); goto edit_func_end; } if( bBin ){ sqlite3_result_blob64(context, p, sz, sqlite3_free); }else{ int i, j; if( hasCRNL ){ /* If the original contains \r\n then do no conversions back to \n */ j = sz; }else{ /* If the file did not originally contain \r\n then convert any new ** \r\n back into \n */ for(i=j=0; i<sz; i++){ if( p[i]=='\r' && p[i+1]=='\n' ) i++; p[j++] = p[i]; } sz = j; p[sz] = 0; } sqlite3_result_text64(context, (const char*)p, sz, sqlite3_free, SQLITE_UTF8); } p = 0; edit_func_end: if( f ) fclose(f); |
︙ | ︙ | |||
2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 | sqlite3_reset(pSql); return; } } } nAlloc += 100; p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); } abYield[iOp] = str_in_array(zOp, azYield); p->aiIndent[iOp] = 0; p->nIndent = iOp+1; if( str_in_array(zOp, azNext) ){ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; | > > | 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 | sqlite3_reset(pSql); return; } } } nAlloc += 100; p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); if( p->aiIndent==0 ) shell_out_of_memory(); abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); if( abYield==0 ) shell_out_of_memory(); } abYield[iOp] = str_in_array(zOp, azYield); p->aiIndent[iOp] = 0; p->nIndent = iOp+1; if( str_in_array(zOp, azNext) ){ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; |
︙ | ︙ | |||
3317 3318 3319 3320 3321 3322 3323 | sqlite3_free(zErr); free(zQ2); } return rc; } /* | | > > > > > > | | > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | > > | | | | | | | | | | | | | | | | | | > | | | | > | | > > > > > > > > > > > > > > > > < | < | < < | < < < < | < < < | > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < < < < | | | | | < < | | | | | | | | | > | > > > > > > > > > > > > > > > > > > > > | | | | < > | | | < | < > > | | | | | | | < < > > > > > > > > > > > > > > > > > > > > | | | | | 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 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 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 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 | sqlite3_free(zErr); free(zQ2); } return rc; } /* ** Text of help messages. ** ** The help text for each individual command begins with a line that starts ** with ".". Subsequent lines are supplimental information. ** ** There must be two or more spaces between the end of the command and the ** start of the description of what that command does. */ static const char *(azHelp[]) = { #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) ".archive ... Manage SQL archives", " Each command must have exactly one of the following options:", " -c, --create Create a new archive", " -u, --update Update or add files to an existing archive", " -t, --list List contents of archive", " -x, --extract Extract files from archive", " Optional arguments:", " -v, --verbose Print each filename as it is processed", " -f FILE, --file FILE Operate on archive FILE (default is current db)", " -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS", " -C DIR, --directory DIR Change to directory DIR to read/extract files", " -n, --dryrun Show the SQL that would have occurred", " Examples:", " .ar -cf archive.sar foo bar # Create archive.sar from files foo and bar", " .ar -tf archive.sar # List members of archive.sar", " .ar -xvf archive.sar # Verbosely extract files from archive.sar", " See also:", " http://sqlite.org/cli.html#sqlar_archive_support", #endif #ifndef SQLITE_OMIT_AUTHORIZATION ".auth ON|OFF Show authorizer callbacks", #endif ".backup ?DB? FILE Backup DB (default \"main\") to FILE", " --append Use the appendvfs", ".bail on|off Stop after hitting an error. Default OFF", ".binary on|off Turn binary output on or off. Default OFF", ".cd DIRECTORY Change the working directory to DIRECTORY", ".changes on|off Show number of rows changed by SQL", ".check GLOB Fail if output since .testcase does not match", ".clone NEWDB Clone data into NEWDB from the existing database", ".databases List names and files of attached databases", ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", ".dbinfo ?DB? Show status information about the database", ".dump ?TABLE? ... Render all database content as SQL", " Options:", " --preserve-rowids Include ROWID values in the output", " --newlines Allow unescaped newline characters in output", " TABLE is LIKE pattern for the tables to dump", ".echo on|off Turn command echo on or off", ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN", ".excel Display the output of next command in a spreadsheet", ".exit ?CODE? Exit this program with return-code CODE", ".expert EXPERIMENTAL. Suggest indexes for specified queries", /* Because explain mode comes on automatically now, the ".explain" mode ** is removed from the help screen. It is still supported for legacy, however */ /*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic",*/ ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", ".headers on|off Turn display of headers on or off", ".help ?-all? ?PATTERN? Show help text for PATTERN", ".import FILE TABLE Import data from FILE into TABLE", #ifndef SQLITE_OMIT_TEST_CONTROL ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", #endif ".indexes ?TABLE? Show names of indexes", " If TABLE is specified, only show indexes for", " tables matching TABLE using the LIKE operator.", #ifdef SQLITE_ENABLE_IOTRACE ".iotrace FILE Enable I/O diagnostic logging to FILE", #endif ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", ".lint OPTIONS Report potential schema issues.", " Options:", " fkey-indexes Find missing foreign key indexes", #ifndef SQLITE_OMIT_LOAD_EXTENSION ".load FILE ?ENTRY? Load an extension library", #endif ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", ".mode MODE ?TABLE? Set output mode", " MODE is one of:", " ascii Columns/rows delimited by 0x1F and 0x1E", " csv Comma-separated values", " column Left-aligned columns. (See .width)", " html HTML <table> code", " insert SQL insert statements for TABLE", " line One value per line", " list Values delimited by \"|\"", " quote Escape answers as for SQL", " tabs Tab-separated values", " tcl TCL list elements", ".nullvalue STRING Use STRING in place of NULL values", ".once (-e|-x|FILE) Output for the next SQL command only to FILE", " If FILE begins with '|' then open as a pipe", " Other options:", " -e Invoke system text editor", " -x Open in a spreadsheet", ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", " --append Use appendvfs to append database to the end of FILE", " --new Initialize FILE to an empty database", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", ".output ?FILE? Send output to FILE or stdout if FILE is omitted", " If FILE begins with '|' then open it as a pipe.", ".print STRING... Print literal STRING", ".prompt MAIN CONTINUE Replace the standard prompts", ".quit Exit this program", ".read FILE Read input from FILE", ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", ".save FILE Write in-memory database into FILE", ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", ".schema ?PATTERN? Show the CREATE statements matching PATTERN", " Options:", " --indent Try to pretty-print the schema", ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", " Options:", " --init Create a new SELFTEST table", " -v Verbose output", ".separator COL ?ROW? Change the column and row separators", #if defined(SQLITE_ENABLE_SESSION) ".session ?NAME? CMD ... Create or control sessions", " Subcommands:", " attach TABLE Attach TABLE", " changeset FILE Write a changeset into FILE", " close Close one session", " enable ?BOOLEAN? Set or query the enable bit", " filter GLOB... Reject tables matching GLOBs", " indirect ?BOOLEAN? Mark or query the indirect status", " isempty Query whether the session is empty", " list List currently open session names", " open DB NAME Open a new session on DB", " patchset FILE Write a patchset into FILE", " If ?NAME? is omitted, the first defined session is used.", #endif ".sha3sum ... Compute a SHA3 hash of database content", " Options:", " --schema Also hash the sqlite_master table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm. This is the default.", " --sha3-384 Use the sha3-384 algorithm", " --sha3-512 Use the sha3-512 algorithm", " Any other argument is a LIKE pattern for tables to hash", #ifndef SQLITE_NOHAVE_SYSTEM ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif ".show Show the current values for various settings", ".stats ?on|off? Show stats or turn stats on or off", #ifndef SQLITE_NOHAVE_SYSTEM ".system CMD ARGS... Run CMD ARGS... in a system shell", #endif ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", ".testcase NAME Begin redirecting output to 'testcase-out.txt'", ".timeout MS Try opening locked tables for MS milliseconds", ".timer on|off Turn SQL timer on or off", ".trace FILE|off Output each SQL statement as it is run", ".vfsinfo ?AUX? Information about the top-level VFS", ".vfslist List all available VFSes", ".vfsname ?AUX? Print the name of the VFS stack", ".width NUM1 NUM2 ... Set column widths for \"column\" mode", " Negative values right-justify", }; /* ** Output help text. ** ** zPattern describes the set of commands for which help text is provided. ** If zPattern is NULL, then show all commands, but only give a one-line ** description of each. ** ** Return the number of matches. */ static int showHelp(FILE *out, const char *zPattern){ int i, j; int n = 0; char *zPat; if( zPattern==0 || zPattern[0]=='0' ){ /* Show all commands, but only one line per command */ for(i=0; i<ArraySize(azHelp); i++){ if( azHelp[i][0]=='.' ){ utf8_printf(out, "%s\n", azHelp[i]); n++; } } }else{ /* Look for commands that for which zPattern is an exact prefix */ zPat = sqlite3_mprintf(".%s*", zPattern); for(i=0; i<ArraySize(azHelp); i++){ if( sqlite3_strglob(zPat, azHelp[i])==0 ){ utf8_printf(out, "%s\n", azHelp[i]); j = i+1; n++; } } sqlite3_free(zPat); if( n ){ if( n==1 ){ /* when zPattern is a prefix of exactly one command, then include the ** details of that command, which should begin at offset j */ while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){ utf8_printf(out, "%s\n", azHelp[j]); j++; } } return n; } /* Look for commands that contain zPattern anywhere. Show the complete ** text of all commands that match. */ zPat = sqlite3_mprintf("%%%s%%", zPattern); for(i=0; i<ArraySize(azHelp); i++){ if( azHelp[i][0]=='.' ) j = i; if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ utf8_printf(out, "%s\n", azHelp[j]); while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){ j++; utf8_printf(out, "%s\n", azHelp[j]); } i = j; n++; } } sqlite3_free(zPat); } return n; } /* Forward reference */ static int process_input(ShellState *p, FILE *in); /* ** Read the content of file zName into memory obtained from sqlite3_malloc64() ** and return a pointer to the buffer. The caller is responsible for freeing |
︙ | ︙ | |||
4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 | "SELECT count(*) FROM %s WHERE type='trigger'" }, { "number of views:", "SELECT count(*) FROM %s WHERE type='view'" }, { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; int i; char *zSchemaTab; char *zDb = nArg>=2 ? azArg[1] : "main"; sqlite3_stmt *pStmt = 0; unsigned char aHdr[100]; open_db(p, 0); if( p->db==0 ) return 1; sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", | > | 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 | "SELECT count(*) FROM %s WHERE type='trigger'" }, { "number of views:", "SELECT count(*) FROM %s WHERE type='view'" }, { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; int i; unsigned iDataVersion; char *zSchemaTab; char *zDb = nArg>=2 ? azArg[1] : "main"; sqlite3_stmt *pStmt = 0; unsigned char aHdr[100]; open_db(p, 0); if( p->db==0 ) return 1; sqlite3_prepare_v2(p->db,"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", |
︙ | ︙ | |||
4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 | for(i=0; i<ArraySize(aQuery); i++){ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); int val = db_int(p, zSql); sqlite3_free(zSql); utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); return 0; } /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ | > > | 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 | for(i=0; i<ArraySize(aQuery); i++){ char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab); int val = db_int(p, zSql); sqlite3_free(zSql); utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val); } sqlite3_free(zSchemaTab); sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); return 0; } /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ |
︙ | ︙ | |||
4920 4921 4922 4923 4924 4925 4926 | sqlite3 *db; /* Database containing the archive */ }; /* ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR. */ static int arUsage(FILE *f){ | < < < | < < < < < < < < < < < < < < < < < < < < < < | 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 | sqlite3 *db; /* Database containing the archive */ }; /* ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR. */ static int arUsage(FILE *f){ showHelp(f,"archive"); return SQLITE_ERROR; } /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ |
︙ | ︙ | |||
5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ return arUsage(stderr); }else{ char *z = azArg[1]; if( z[0]!='-' ){ /* Traditional style [tar] invocation */ int i; int iArg = 2; | > | 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 | { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, }; int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); return arUsage(stderr); }else{ char *z = azArg[1]; if( z[0]!='-' ){ /* Traditional style [tar] invocation */ int i; int iArg = 2; |
︙ | ︙ | |||
5823 5824 5825 5826 5827 5828 5829 | utf8_printf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ | | > > > | 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 | utf8_printf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ static const struct DbConfigChoices { const char *zName; int op; } aDbConfig[] = { { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, |
︙ | ︙ | |||
6070 6071 6072 6073 6074 6075 6076 | }else{ raw_printf(stderr, "Usage: .headers on|off\n"); rc = 1; } }else if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ | > > > | > > > > | 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 | }else{ raw_printf(stderr, "Usage: .headers on|off\n"); rc = 1; } }else if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ if( nArg>=2 ){ int n = showHelp(p->out, azArg[1]); if( n==0 ){ utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); } }else{ showHelp(p->out, 0); } }else if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ char *zTable; /* Insert data into this table */ char *zFile; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ |
︙ | ︙ | |||
7074 7075 7076 7077 7078 7079 7080 | pSession->nFilter = 0; sqlite3session_table_filter(pSession->p, session_filter, pSession); p->nSession++; pSession->zName = sqlite3_mprintf("%s", zName); }else /* If no command name matches, show a syntax error */ session_syntax_error: | | | 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 | pSession->nFilter = 0; sqlite3session_table_filter(pSession->p, session_filter, pSession); p->nSession++; pSession->zName = sqlite3_mprintf("%s", zName); }else /* If no command name matches, show a syntax error */ session_syntax_error: showHelp(p->out, "session"); }else #endif #ifdef SQLITE_DEBUG /* Undocumented commands for internal testing. Subject to change ** without notice. */ if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ |
︙ | ︙ | |||
8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 | int argcToFree = 0; #endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #if USE_SYSTEM_SQLITE+0!=1 if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } | > > > > > > > > > > > > > > > > > | 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 | int argcToFree = 0; #endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ if( isatty(0) && isatty(2) ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) DebugBreak(); #elif defined(SIGTRAP) raise(SIGTRAP); #endif } } #endif #if USE_SYSTEM_SQLITE+0!=1 if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
468 469 470 471 472 473 474 475 476 477 478 479 480 481 | ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) | > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) |
︙ | ︙ | |||
883 884 885 886 887 888 889 | ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** ** <li>[[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary | > | | 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** ** <li>[[SQLITE_FCNTL_PERSIST_WAL]] ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary ** write ahead log ([WAL file]) and shared memory ** files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 | > > > > > > > > > > > > > > > > > > > > | 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 | ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database ** connection or through transactions committed by separate database ** connections possibly in other processes. The [sqlite3_total_changes()] ** interface can be used to find if any database on the connection has changed, ** but that interface responds to changes on TEMP as well as MAIN and does ** not provide a mechanism to detect changes to MAIN only. Also, the ** [sqlite3_total_changes()] interface responds to internal changes only and ** omits changes made by other database connections. The ** [PRAGMA data_version] command provide a mechanism to detect changes to ** a single attached database that occur due to other database connections, ** but omits changes implemented by the database connection on which it is ** called. This file control is the only mechanism to detect changes that ** happen either internally or externally and that are associated with ** a particular attached database. ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 #define SQLITE_FCNTL_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 |
︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO | > | 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | #define SQLITE_FCNTL_JOURNAL_POINTER 28 #define SQLITE_FCNTL_WIN32_GET_HANDLE 29 #define SQLITE_FCNTL_PDB 30 #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33 #define SQLITE_FCNTL_LOCK_TIMEOUT 34 #define SQLITE_FCNTL_DATA_VERSION 35 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO |
︙ | ︙ | |||
2272 2273 2274 2275 2276 2277 2278 | ** ^This means that if the changes() SQL function (or similar) is used ** by the first INSERT, UPDATE or DELETE statement within a trigger, it ** returns the value as set when the calling statement began executing. ** ^If it is used by the second or subsequent such statement within a trigger ** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** | < < < > > > > > > > > | | > > | > > | > > > > > > > > > | 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 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 2356 | ** ^This means that if the changes() SQL function (or similar) is used ** by the first INSERT, UPDATE or DELETE statement within a trigger, it ** returns the value as set when the calling statement began executing. ** ^If it is used by the second or subsequent such statement within a trigger ** program, the value returned reflects the number of rows modified by the ** previous INSERT, UPDATE or DELETE statement within the same trigger. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. ** ** See also: ** <ul> ** <li> the [sqlite3_total_changes()] interface ** <li> the [count_changes pragma] ** <li> the [changes() SQL function] ** <li> the [data_version pragma] ** </ul> */ int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** METHOD: sqlite3 ** ** ^This function returns the total number of rows inserted, modified or ** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed ** since the database connection was opened, including those executed as ** part of trigger programs. ^Executing any other type of SQL statement ** does not affect the value returned by sqlite3_total_changes(). ** ** ^Changes made as part of [foreign key actions] are included in the ** count, but those made as part of REPLACE constraint resolution are ** not. ^Changes to a view that are intercepted by INSTEAD OF triggers ** are not counted. ** ** This the [sqlite3_total_changes(D)] interface only reports the number ** of rows that changed due to SQL statement run against database ** connection D. Any changes by other database connections are ignored. ** To detect changes against a database file from other database ** connections use the [PRAGMA data_version] command or the ** [SQLITE_FCNTL_DATA_VERSION] [file control]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. ** ** See also: ** <ul> ** <li> the [sqlite3_changes()] interface ** <li> the [count_changes pragma] ** <li> the [changes() SQL function] ** <li> the [data_version pragma] ** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control] ** </ul> */ int sqlite3_total_changes(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query ** METHOD: sqlite3 ** |
︙ | ︙ | |||
4687 4688 4689 4690 4691 4692 4693 | ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue ** and xInverse) passed to sqlite3_create_window_function are pointers to | | | 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 | ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue ** and xInverse) passed to sqlite3_create_window_function are pointers to ** C-language callbacks that implement the new function. xStep and xFinal ** must both be non-NULL. xValue and xInverse may either both be NULL, in ** which case a regular aggregate function is created, or must both be ** non-NULL, in which case the new function may be used as either an aggregate ** or aggregate window function. More details regarding the implementation ** of aggregate window functions are ** [user-defined window functions|available here]. ** |
︙ | ︙ | |||
6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 | #define SQLITE_INDEX_CONSTRAINT_GLOB 66 #define SQLITE_INDEX_CONSTRAINT_REGEXP 67 #define SQLITE_INDEX_CONSTRAINT_NE 68 #define SQLITE_INDEX_CONSTRAINT_ISNOT 69 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 /* ** CAPI3REF: Register A Virtual Table Implementation ** METHOD: sqlite3 ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before | > | 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 | #define SQLITE_INDEX_CONSTRAINT_GLOB 66 #define SQLITE_INDEX_CONSTRAINT_REGEXP 67 #define SQLITE_INDEX_CONSTRAINT_NE 68 #define SQLITE_INDEX_CONSTRAINT_ISNOT 69 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 #define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation ** METHOD: sqlite3 ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before |
︙ | ︙ | |||
7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 | ** routine returns a NULL pointer. */ sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated ** with a particular database identified by the second argument. ^The ** name of the database is "main" for the main database or "temp" for the ** TEMP database, or the name that appears after the AS keyword for ** databases that are added using the [ATTACH] SQL command. ** ^A NULL pointer can be used in place of "main" to refer to the ** main database file. ** ^The third and fourth parameters to this routine ** are passed directly through to the second and third parameters of ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into | > > > > | < > > > | > > | 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 | ** routine returns a NULL pointer. */ sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** METHOD: sqlite3 ** KEYWORDS: {file control} ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated ** with a particular database identified by the second argument. ^The ** name of the database is "main" for the main database or "temp" for the ** TEMP database, or the name that appears after the AS keyword for ** databases that are added using the [ATTACH] SQL command. ** ^A NULL pointer can be used in place of "main" to refer to the ** main database file. ** ^The third and fourth parameters to this routine ** are passed directly through to the second and third parameters of ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** ** A few opcodes for [sqlite3_file_control()] are handled directly ** by the SQLite core and never invoke the ** sqlite3_io_methods.xFileControl method. ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into ** the space pointed to by the 4th parameter. The ** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns ** the [sqlite3_file] object associated with the journal file instead of ** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns ** a pointer to the underlying [sqlite3_vfs] object for the file. ** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter ** from the pager. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error ** code is not remembered and will not be recalled by [sqlite3_errcode()] ** or [sqlite3_errmsg()]. The underlying xFileControl method might ** also return SQLITE_ERROR. There is no way to distinguish between ** an incorrect zDbName and an SQLITE_ERROR return from the underlying |
︙ | ︙ | |||
8910 8911 8912 8913 8914 8915 8916 | ** as ENOSPC, EAUTH, EISDIR, and so forth. */ int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} | < < < < < < | | | 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 | ** as ENOSPC, EAUTH, EISDIR, and so forth. */ int sqlite3_system_errno(sqlite3*); /* ** CAPI3REF: Database Snapshot ** KEYWORDS: {snapshot} {sqlite3_snapshot} ** ** An instance of the snapshot object records the state of a [WAL mode] ** database for some specific point in history. ** ** In [WAL mode], multiple [database connections] that are open on the ** same database file can each be reading a different historical version ** of the database file. When a [database connection] begins a read ** transaction, that connection sees an unchanging copy of the database ** as it existed for the point in time when the transaction first started. ** Subsequent changes to the database from other connections are not seen ** by the reader until a new read transaction is started. ** ** The sqlite3_snapshot object records state information about an historical ** version of the database file so that it is possible to later open a new read ** transaction that sees that historical version of the database rather than ** the most recent version. */ typedef struct sqlite3_snapshot { unsigned char hidden[48]; } sqlite3_snapshot; /* ** CAPI3REF: Record A Database Snapshot ** CONSTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined ** in this case. ** ** <ul> ** <li> The database handle must not be in [autocommit mode]. ** ** <li> Schema S of [database connection] D must be a [WAL mode] database. ** ** <li> There must not be a write transaction open on schema S of database ** connection D. ** ** <li> One or more transactions must have been written to the current wal |
︙ | ︙ | |||
8978 8979 8980 8981 8982 8983 8984 | ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the | | | | | | | < | | | < | > > > > | > | < | > | > > > > > > > > | | | | > > > | | | | > | < > | < | | > > > | 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 | ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( sqlite3 *db, const char *zSchema, sqlite3_snapshot **ppSnapshot ); /* ** CAPI3REF: Start a read transaction on an historical snapshot ** METHOD: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read ** transaction or upgrades an existing one for schema S of ** [database connection] D such that the read transaction refers to ** historical [snapshot] P, rather than the most recent change to the ** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK ** on success or an appropriate [error code] if it fails. ** ** ^In order to succeed, the database connection must not be in ** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there ** is already a read transaction open on schema S, then the database handle ** must have no active statements (SELECT statements that have been passed ** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). ** SQLITE_ERROR is returned if either of these conditions is violated, or ** if schema S does not exist, or if the snapshot object is invalid. ** ** ^A call to sqlite3_snapshot_open() will fail to open if the specified ** snapshot has been overwritten by a [checkpoint]. In this case ** SQLITE_ERROR_SNAPSHOT is returned. ** ** If there is already a read transaction open when this function is ** invoked, then the same read transaction remains open (on the same ** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT ** is returned. If another error code - for example SQLITE_PROTOCOL or an ** SQLITE_IOERR error code - is returned, then the final state of the ** read transaction is undefined. If SQLITE_OK is returned, then the ** read transaction is now open on database snapshot P. ** ** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the ** database connection D does not know that the database file for ** schema S is in [WAL mode]. A database connection might not know ** that the database file is in [WAL mode] if there has been no prior ** I/O on that database connection, or if the database entered [WAL mode] ** after the most recent I/O on the database connection.)^ ** (Hint: Run "[PRAGMA application_id]" against a newly opened ** database connection in order to make it ready to use snapshots.) ** ** The [sqlite3_snapshot_open()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( sqlite3 *db, const char *zSchema, sqlite3_snapshot *pSnapshot ); /* ** CAPI3REF: Destroy a snapshot ** DESTRUCTOR: sqlite3_snapshot ** ** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P. ** The application must eventually free every [sqlite3_snapshot] object ** using this routine to avoid a memory leak. ** ** The [sqlite3_snapshot_free()] interface is only available when the ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); /* ** CAPI3REF: Compare the ages of two snapshot handles. ** METHOD: sqlite3_snapshot ** ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages ** of two valid snapshot handles. ** ** If the two snapshot handles are not associated with the same database ** file, the result of the comparison is undefined. ** ** Additionally, the result of the comparison is only valid if both of the ** snapshot handles were obtained by calling sqlite3_snapshot_get() since the ** last time the wal file was deleted. The wal file is deleted when the ** database is changed back to rollback mode or when the number of database ** clients drops to zero. If either snapshot handle was obtained before the ** wal file was last deleted, the value returned by this function ** is undefined. ** ** Otherwise, this API returns a negative value if P1 refers to an older ** snapshot than P2, zero if the two handles refer to the same database ** snapshot, and a positive value if P1 is a newer snapshot than P2. ** ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( sqlite3_snapshot *p1, sqlite3_snapshot *p2 ); /* ** CAPI3REF: Recover snapshots from a wal file ** METHOD: sqlite3_snapshot ** ** If a [WAL file] remains on disk after all database connections close ** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control] ** or because the last process to have the database opened exited without ** calling [sqlite3_close()]) and a new connection is subsequently opened ** on that database and [WAL file], the [sqlite3_snapshot_open()] interface ** will only be able to open the last transaction added to the WAL file ** even though the WAL file contains other valid transactions. ** ** This function attempts to scan the WAL file associated with database zDb ** of database handle db and make all valid snapshots available to ** sqlite3_snapshot_open(). It is an error if there is already a read ** transaction open on the database, or if the database is not a WAL mode ** database. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. ** ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Wal related information regarding the most recent COMMIT ** EXPERIMENTAL ** |
︙ | ︙ | |||
9218 9219 9220 9221 9222 9223 9224 | ** The following are allowed values for 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization ** in the P argument is held in memory obtained from [sqlite3_malloc64()] ** and that SQLite should take ownership of this memory and automatically ** free it when it has finished using it. Without this flag, the caller | | | 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 | ** The following are allowed values for 6th argument (the F argument) to ** the [sqlite3_deserialize(D,S,P,N,M,F)] interface. ** ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization ** in the P argument is held in memory obtained from [sqlite3_malloc64()] ** and that SQLite should take ownership of this memory and automatically ** free it when it has finished using it. Without this flag, the caller ** is responsible for freeing any dynamically allocated memory. ** ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to ** grow the size of the database using calls to [sqlite3_realloc64()]. This ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. ** Without this flag, the deserialized database cannot increase in size beyond ** the number of bytes specified by the M parameter. ** |
︙ | ︙ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
306 307 308 309 310 311 312 313 314 315 316 317 318 319 | void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); void (*str_appendchar)(sqlite3_str*, int N, char C); void (*str_reset)(sqlite3_str*); int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); }; /* ** 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)( | > > > > > > | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | void (*str_append)(sqlite3_str*, const char *zIn, int N); void (*str_appendall)(sqlite3_str*, const char *zIn); void (*str_appendchar)(sqlite3_str*, int N, char C); void (*str_reset)(sqlite3_str*); int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); int (*create_window_function)(sqlite3*,const char*,int,int,void*, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); }; /* ** 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)( |
︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 | #define sqlite3_str_append sqlite3_api->str_append #define sqlite3_str_appendall sqlite3_api->str_appendall #define sqlite3_str_appendchar sqlite3_api->str_appendchar #define sqlite3_str_reset sqlite3_api->str_reset #define sqlite3_str_errcode sqlite3_api->str_errcode #define sqlite3_str_length sqlite3_api->str_length #define sqlite3_str_value sqlite3_api->str_value #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; | > > | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | #define sqlite3_str_append sqlite3_api->str_append #define sqlite3_str_appendall sqlite3_api->str_appendall #define sqlite3_str_appendchar sqlite3_api->str_appendchar #define sqlite3_str_reset sqlite3_api->str_reset #define sqlite3_str_errcode sqlite3_api->str_errcode #define sqlite3_str_length sqlite3_api->str_length #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function #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; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
363 364 365 366 367 368 369 | #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif | < < < < < < < < < < < | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif #if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG #endif /* ** Enable SQLITE_ENABLE_EXPLAIN_COMMENTS if SQLITE_DEBUG is turned on. */ #if !defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) && defined(SQLITE_DEBUG) # define SQLITE_ENABLE_EXPLAIN_COMMENTS 1 #endif |
︙ | ︙ | |||
798 799 800 801 802 803 804 | /* ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer */ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ | | > | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | /* ** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer */ #ifndef SQLITE_PTRSIZE # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 # endif #endif /* The uptr type is an unsigned integer large enough to hold a pointer |
︙ | ︙ | |||
839 840 841 842 843 844 845 | ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER # if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ | | | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 | ** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined ** at run-time. */ #ifndef SQLITE_BYTEORDER # if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ defined(__arm__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ppc__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif #endif |
︙ | ︙ | |||
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 | typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ | > | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SQLiteThread SQLiteThread; typedef struct SelectDest SelectDest; typedef struct SrcList SrcList; typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ |
︙ | ︙ | |||
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | #define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ #define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ #define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_NoopUpdate 0x01000000 /* UPDATE operations are no-ops */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ #define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ | > | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 | #define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */ #define SQLITE_QueryOnly 0x00100000 /* Disable database changes */ #define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */ #define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */ #define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/ #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ #define SQLITE_NoopUpdate 0x01000000 /* UPDATE operations are no-ops */ /* Flags used only if debugging */ #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ #define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ |
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 | /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ | | > | 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 | /* ** Bits of the sqlite3.dbOptFlags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ /* 0x0002 available for reuse */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */ #define SQLITE_Transitive 0x0080 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */ #define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_PushDown 0x1000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x4000 /* Skip-scans */ #define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) #define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0) |
︙ | ︙ | |||
2288 2289 2290 2291 2292 2293 2294 | tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** | | | > > | | 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 | tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** The memory that "z" points to is owned by other objects. Take care ** that the owner of the "z" string does not deallocate the string before ** the Token goes out of scope! Very often, the "z" points to some place ** in the middle of the Parse.zSql text. But it might also point to a ** static string. */ struct Token { const char *z; /* Text of the token. Not NULL-terminated! */ unsigned int n; /* Number of characters in this token */ }; /* |
︙ | ︙ | |||
2463 2464 2465 2466 2467 2468 2469 | ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 op2; /* TK_REGISTER: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ | > | | < | < > | > | 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 | ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 op2; /* TK_REGISTER: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* TK_FUNCTION: Window definition for the func */ } y; }; /* ** The following are the meanings of bits in the Expr.flags field. */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ #define EP_Agg 0x000002 /* Contains one or more aggregate functions */ #define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ #define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ #define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ #define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ #define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ #define EP_Alias 0x400000 /* Is an alias for a result set column */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ /* ** The EP_Propagate mask is a set of properties that automatically propagate ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) |
︙ | ︙ | |||
2965 2966 2967 2968 2969 2970 2971 | struct AutoincInfo { AutoincInfo *pNext; /* Next info block in a list of them all */ Table *pTab; /* Table this info block refers to */ int iDb; /* Index in sqlite3.aDb[] of database holding pTab */ int regCtr; /* Memory register holding the rowid counter */ }; | < < < < < < < | 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 | struct AutoincInfo { AutoincInfo *pNext; /* Next info block in a list of them all */ Table *pTab; /* Table this info block refers to */ int iDb; /* Index in sqlite3.aDb[] of database holding pTab */ int regCtr; /* Memory register holding the rowid counter */ }; /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE ** statement. All such objects are stored in the linked list headed at ** Parse.pTriggerPrg and deleted once statement compilation has been ** completed. ** |
︙ | ︙ | |||
3047 3048 3049 3050 3051 3052 3053 | u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ | < < < | 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 | u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 okConstFactor; /* OK to factor out constants */ u8 disableLookaside; /* Number of times lookaside has been disabled */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ ExprList *pConstExpr;/* Constant expressions */ Token constraintName;/* Name of the constraint currently being parsed */ yDbMask writeMask; /* Start a write transaction on these databases */ yDbMask cookieMask; /* Bitmask of schema verified databases */ int regRowid; /* Register holding rowid of CREATE TABLE entry */ |
︙ | ︙ | |||
3088 3089 3090 3091 3092 3093 3094 | u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is | | < < < < < < < < > > > < > > > > > > > > > | | > > > > > > > > > > > > | 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 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 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 | u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ u8 disableTriggers; /* True to disable triggers */ /************************************************************************** ** Fields above must be initialized to zero. The fields that follow, ** down to the beginning of the recursive section, do not need to be ** initialized as they will be set before being used. The boundary is ** determined by offsetof(Parse,aTempReg). **************************************************************************/ int aTempReg[8]; /* Holding area for temporary registers */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************ ** Above is constant between recursions. Below is reset before and after ** each recursion. The boundary between these two regions is determined ** using offsetof(Parse,sLastToken) so the sLastToken field must be the ** first field in the recursive region. ************************************************************************/ Token sLastToken; /* The last token parsed */ ynVar nVar; /* Number of '?' variables seen in the SQL so far */ u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */ u8 explain; /* True if the EXPLAIN flag is found on the query */ #if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)) u8 eParseMode; /* PARSE_MODE_XXX constant */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Index *pNewIndex; /* An index being constructed by CREATE INDEX */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ #ifndef SQLITE_OMIT_VIRTUALTABLE Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ With *pWithToFree; /* Free this WITH object at the end of the parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME_COLUMN 2 #define PARSE_MODE_RENAME_TABLE 3 /* ** Sizes and pointers of various parts of the Parse object. */ #define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ /* ** Return true if currently inside an sqlite3_declare_vtab() call. */ #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB) #endif #if defined(SQLITE_OMIT_ALTERTABLE) #define IN_RENAME_OBJECT 0 #else #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN) #endif #if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE) #define IN_SPECIAL_PARSE 0 #else #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL) #endif /* ** An instance of the following structure can be declared on a stack and used ** to save the Parse.zAuthContext value so that it can be restored later. */ struct AuthContext { |
︙ | ︙ | |||
3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 | ** OPFLAG_SEEKEQ == BTREE_SEEK_EQ ** OPFLAG_FORDELETE == BTREE_FORDELETE ** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION ** OPFLAG_AUXDELETE == BTREE_AUXDELETE */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ | > | 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 | ** OPFLAG_SEEKEQ == BTREE_SEEK_EQ ** OPFLAG_FORDELETE == BTREE_FORDELETE ** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION ** OPFLAG_AUXDELETE == BTREE_AUXDELETE */ #define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */ /* Also used in P2 (not P5) of OP_Delete */ #define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */ #define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */ #define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ |
︙ | ︙ | |||
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 | ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. */ typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ } InitData; /* ** Structure containing global configuration data for the SQLite library. ** ** This structure also contains some state information. */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ | > > > > > > | 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 | ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback. */ typedef struct { sqlite3 *db; /* The database being initialized */ char **pzErrMsg; /* Error message stored here */ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */ int rc; /* Result code stored here */ u32 mInitFlags; /* Flags controlling error messages */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */ /* ** Structure containing global configuration data for the SQLite library. ** ** This structure also contains some state information. */ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ |
︙ | ︙ | |||
3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 | struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ ExprList *pGroupBy; /* GROUP BY clause */ Select *pSelect; /* HAVING to WHERE clause ctx */ struct WindowRewrite *pRewrite; /* Window rewrite context */ } u; }; /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); | > > | 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 | struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ int *aiCol; /* array of column indexes */ struct IdxCover *pIdxCover; /* Check for index coverage */ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ ExprList *pGroupBy; /* GROUP BY clause */ Select *pSelect; /* HAVING to WHERE clause ctx */ struct WindowRewrite *pRewrite; /* Window rewrite context */ struct WhereConst *pConst; /* WHERE clause constants */ struct RenameCtx *pRename; /* RENAME COLUMN context */ } u; }; /* Forward declarations */ int sqlite3WalkExpr(Walker*, Expr*); int sqlite3WalkExprList(Walker*, ExprList*); int sqlite3WalkSelect(Walker*, Select*); |
︙ | ︙ | |||
3633 3634 3635 3636 3637 3638 3639 | # define sqlite3Isalnum(x) isalnum((unsigned char)(x)) # define sqlite3Isalpha(x) isalpha((unsigned char)(x)) # define sqlite3Isdigit(x) isdigit((unsigned char)(x)) # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') #endif | < < | 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 | # define sqlite3Isalnum(x) isalnum((unsigned char)(x)) # define sqlite3Isalpha(x) isalpha((unsigned char)(x)) # define sqlite3Isdigit(x) isdigit((unsigned char)(x)) # define sqlite3Isxdigit(x) isxdigit((unsigned char)(x)) # define sqlite3Tolower(x) tolower((unsigned char)(x)) # define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`') #endif int sqlite3IsIdChar(u8); /* ** Internal function prototypes */ int sqlite3StrICmp(const char*,const char*); int sqlite3Strlen30(const char*); char *sqlite3ColumnType(Column*,char*); |
︙ | ︙ | |||
3788 3789 3790 3791 3792 3793 3794 | #endif Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); Expr *sqlite3Expr(sqlite3*,int,const char*); void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); | | > | 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 3821 3822 | #endif Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); Expr *sqlite3Expr(sqlite3*,int,const char*); void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); void sqlite3PExprAddSelect(Parse*, Expr*, Select*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); int sqlite3InitOne(sqlite3*, int, char**, u32); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); #ifndef SQLITE_OMIT_VIRTUALTABLE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName); #endif void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); |
︙ | ︙ | |||
3849 3850 3851 3852 3853 3854 3855 | void sqlite3BitvecClear(Bitvec*, u32, void*); void sqlite3BitvecDestroy(Bitvec*); u32 sqlite3BitvecSize(Bitvec*); #ifndef SQLITE_UNTESTABLE int sqlite3BitvecBuiltinTest(int,int*); #endif | | > | > | | 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 | void sqlite3BitvecClear(Bitvec*, u32, void*); void sqlite3BitvecDestroy(Bitvec*); u32 sqlite3BitvecSize(Bitvec*); #ifndef SQLITE_UNTESTABLE int sqlite3BitvecBuiltinTest(int,int*); #endif RowSet *sqlite3RowSetInit(sqlite3*); void sqlite3RowSetDelete(void*); void sqlite3RowSetClear(void*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif #if SQLITE_MAX_ATTACHED>30 int sqlite3DbMaskAllZero(yDbMask); #endif void sqlite3DropTable(Parse*, SrcList*, int, int); void sqlite3CodeDropTable(Parse*, Table*, int, int); void sqlite3DeleteTable(sqlite3*, Table*); void sqlite3FreeIndex(sqlite3*, Index*); #ifndef SQLITE_OMIT_AUTOINCREMENT void sqlite3AutoincrementBegin(Parse *pParse); void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); |
︙ | ︙ | |||
3913 3914 3915 3916 3917 3918 3919 | void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, Upsert*); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); | | < < < < < < < | 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 | void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, Upsert*); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsOrdered(WhereInfo*); int sqlite3WhereOrderByLimitOptLabel(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 */ void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeAtInit(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); void sqlite3ExprCodeAndCache(Parse*, Expr*, int); |
︙ | ︙ | |||
3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 | int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); void sqlite3ResolvePartIdxLabel(Parse*,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM void sqlite3SetMakeRecordP5(Vdbe*,Table*); #else # define sqlite3SetMakeRecordP5(A,B) #endif | > | 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 | int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); void sqlite3ResolvePartIdxLabel(Parse*,int); int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*,int*,Upsert*); #ifdef SQLITE_ENABLE_NULL_TRIM void sqlite3SetMakeRecordP5(Vdbe*,Table*); #else # define sqlite3SetMakeRecordP5(A,B) #endif |
︙ | ︙ | |||
4047 4048 4049 4050 4051 4052 4053 | void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, int, int, int); void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); | | | | | 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 | void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, int, int, int); void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, Select*,u8,Upsert*, const char*,const char*); TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8, const char*,const char*); TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, const char*,const char*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else |
︙ | ︙ | |||
4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 | #ifdef SQLITE_ENABLE_DESERIALIZE int sqlite3MemdbInit(void); #endif const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); | > | 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 | #ifdef SQLITE_ENABLE_DESERIALIZE int sqlite3MemdbInit(void); #endif const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); int sqlite3IsBinary(const CollSeq*); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); |
︙ | ︙ | |||
4219 4220 4221 4222 4223 4224 4225 4226 4227 | #ifdef VDBE_PROFILE extern sqlite3_uint64 sqlite3NProfileCnt; #endif void sqlite3RootPageMoved(sqlite3*, int, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); | > | > > > > | 4225 4226 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 4256 4257 4258 | #ifdef VDBE_PROFILE extern sqlite3_uint64 sqlite3NProfileCnt; #endif void sqlite3RootPageMoved(sqlite3*, int, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*, int); int sqlite3CodeSubselect(Parse*, Expr *, int, int); void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); int sqlite3ResolveExprNames(NameContext*, Expr*); int sqlite3ResolveExprListNames(NameContext*, ExprList*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); void *sqlite3RenameTokenMap(Parse*, void*, Token*); void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); void sqlite3RenameExprUnmap(Parse*, Expr*); void sqlite3RenameExprlistUnmap(Parse*, ExprList*); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*, Column*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # include <assert.h> typedef unsigned char u8; #endif #include <ctype.h> /* Used to get the current process ID */ #if !defined(_WIN32) # include <unistd.h> # define GETPID getpid #elif !defined(_WIN32_WCE) # ifndef SQLITE_AMALGAMATION # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include <windows.h> # endif # define GETPID (int)GetCurrentProcessId #endif /* * Windows needs to know which symbols to export. Unix does not. * BUILD_sqlite should be undefined for Unix. */ | > > > | 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 | # include <assert.h> typedef unsigned char u8; #endif #include <ctype.h> /* Used to get the current process ID */ #if !defined(_WIN32) # include <signal.h> # include <unistd.h> # define GETPID getpid #elif !defined(_WIN32_WCE) # ifndef SQLITE_AMALGAMATION # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # include <windows.h> # endif # include <io.h> # define isatty(h) _isatty(h) # define GETPID (int)GetCurrentProcessId #endif /* * Windows needs to know which symbols to export. Unix does not. * BUILD_sqlite should be undefined for Unix. */ |
︙ | ︙ | |||
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 | */ #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; #else flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; #endif if( objc==2 ){ zArg = Tcl_GetStringFromObj(objv[1], 0); if( strcmp(zArg,"-version")==0 ){ Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-sourceid")==0 ){ | > | 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 | */ #ifdef SQLITE_TCL_DEFAULT_FULLMUTEX flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX; #else flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; #endif if( objc==1 ) return sqliteCmdUsage(interp, objv); if( objc==2 ){ zArg = Tcl_GetStringFromObj(objv[1], 0); if( strcmp(zArg,"-version")==0 ){ Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-sourceid")==0 ){ |
︙ | ︙ | |||
3729 3730 3731 3732 3733 3734 3735 | const char *zScript = 0; char zArgc[32]; #if defined(TCLSH_INIT_PROC) extern const char *TCLSH_INIT_PROC(Tcl_Interp*); #endif #if !defined(_WIN32_WCE) | | > | | | | > > > > > > > | 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 | const char *zScript = 0; char zArgc[32]; #if defined(TCLSH_INIT_PROC) extern const char *TCLSH_INIT_PROC(Tcl_Interp*); #endif #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ if( isatty(0) && isatty(2) ){ fprintf(stderr, "attach debugger to process %d and press any key to continue.\n", GETPID()); fgetc(stdin); }else{ #if defined(_WIN32) || defined(WIN32) DebugBreak(); #elif defined(SIGTRAP) raise(SIGTRAP); #endif } } #endif /* Call sqlite3_shutdown() once before doing anything else. This is to ** test that sqlite3_shutdown() can be safely called by a process before ** sqlite3_initialize() is. */ sqlite3_shutdown(); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 | zName = Tcl_GetString(objv[2]); pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3])); rc = sqlite3_snapshot_open(db, zName, pSnapshot); if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; } return TCL_OK; } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* | > > | 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 | zName = Tcl_GetString(objv[2]); pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3])); rc = sqlite3_snapshot_open(db, zName, pSnapshot); if( rc!=SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_ERROR; }else{ Tcl_ResetResult(interp); } return TCL_OK; } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_SNAPSHOT /* |
︙ | ︙ | |||
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 | if( iArg!=0 ) { Tcl_AppendResult(interp, "Unexpected non-zero errno: ", Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0); return TCL_ERROR; } return TCL_OK; } /* ** 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. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 | if( iArg!=0 ) { Tcl_AppendResult(interp, "Unexpected non-zero errno: ", Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0); return TCL_ERROR; } return TCL_OK; } /* ** tclcmd: file_control_data_version DB DBNAME ** ** This TCL command runs the sqlite3_file_control with the ** SQLITE_FCNTL_DATA_VERSION opcode, returning the result. */ static int SQLITE_TCLAPI file_control_data_version( 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 */ ){ unsigned int iVers; /* data version */ char *zDb; /* Db name ("main", "temp" etc.) */ sqlite3 *db; /* Database handle */ int rc; /* file_control() return code */ char zBuf[100]; if( objc!=3 && objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ return TCL_ERROR; } zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL; rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers); if( rc ){ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_ERROR; }else{ sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers); Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE); return TCL_OK; } } /* ** 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. |
︙ | ︙ | |||
6940 6941 6942 6943 6944 6945 6946 | static const struct { const char *zOptName; int mask; } aOpt[] = { { "all", SQLITE_AllOpts }, { "none", 0 }, { "query-flattener", SQLITE_QueryFlattener }, | < | 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 | static const struct { const char *zOptName; int mask; } aOpt[] = { { "all", SQLITE_AllOpts }, { "none", 0 }, { "query-flattener", SQLITE_QueryFlattener }, { "groupby-order", SQLITE_GroupByOrder }, { "factor-constants", SQLITE_FactorOutConst }, { "distinct-opt", SQLITE_DistinctOpt }, { "cover-idx-scan", SQLITE_CoverIdxScan }, { "order-by-idx-join", SQLITE_OrderByIdxJoin }, { "transitive", SQLITE_Transitive }, { "omit-noop-join", SQLITE_OmitNoopJoin }, |
︙ | ︙ | |||
6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 | 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_remember_init(sqlite3*,char**,const sqlite3_api_routines*); | > | 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 | 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_explain_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_remember_init(sqlite3*,char**,const sqlite3_api_routines*); |
︙ | ︙ | |||
7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 | 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 }, { "remember", sqlite3_remember_init }, | > | 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 | 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 }, { "explain", sqlite3_explain_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 }, { "remember", sqlite3_remember_init }, |
︙ | ︙ | |||
7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 | { "vfs_unregister_all", vfs_unregister_all, 0 }, { "vfs_reregister_all", vfs_reregister_all, 0 }, { "file_control_test", file_control_test, 0 }, { "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 }, #if SQLITE_OS_WIN { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_get_handle", file_control_win32_get_handle, 0 }, { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, #endif { "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, | > | 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 | { "vfs_unregister_all", vfs_unregister_all, 0 }, { "vfs_reregister_all", vfs_reregister_all, 0 }, { "file_control_test", file_control_test, 0 }, { "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, { "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, { "file_control_chunksize_test", file_control_chunksize_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "file_control_data_version", file_control_data_version, 0 }, #if SQLITE_OS_WIN { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_get_handle", file_control_win32_get_handle, 0 }, { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, #endif { "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
120 121 122 123 124 125 126 | Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "worker_threads", STRINGVALUE(SQLITE_MAX_WORKER_THREADS), TCL_GLOBAL_ONLY ); | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "worker_threads", STRINGVALUE(SQLITE_MAX_WORKER_THREADS), TCL_GLOBAL_ONLY ); #ifdef SQLITE_MEMDEBUG Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memdebug", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_8_3_NAMES Tcl_SetVar2(interp, "sqlite_options", "8_3_names", "1", TCL_GLOBAL_ONLY); |
︙ | ︙ |
Changes to src/test_vfs.c.
︙ | ︙ | |||
129 130 131 132 133 134 135 136 | #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_FULLPATHNAME_MASK 0x00008000 #define TESTVFS_READ_MASK 0x00010000 #define TESTVFS_UNLOCK_MASK 0x00020000 #define TESTVFS_LOCK_MASK 0x00040000 #define TESTVFS_CKLOCK_MASK 0x00080000 | > | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | #define TESTVFS_TRUNCATE_MASK 0x00002000 #define TESTVFS_ACCESS_MASK 0x00004000 #define TESTVFS_FULLPATHNAME_MASK 0x00008000 #define TESTVFS_READ_MASK 0x00010000 #define TESTVFS_UNLOCK_MASK 0x00020000 #define TESTVFS_LOCK_MASK 0x00040000 #define TESTVFS_CKLOCK_MASK 0x00080000 #define TESTVFS_FCNTL_MASK 0x00100000 #define TESTVFS_ALL_MASK 0x001FFFFF #define TESTVFS_MAX_PAGES 1024 /* ** A shared-memory buffer. There is one of these objects for each shared ** memory region opened by clients. If two clients open the same file, |
︙ | ︙ | |||
513 514 515 516 517 518 519 | return sqlite3OsCheckReservedLock(pFd->pReal, pResOut); } /* ** File control method. For custom operations on an tvfs-file. */ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ | | > | > > > > > > > > > > > > > > > > > > > > > > > | | 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 | return sqlite3OsCheckReservedLock(pFd->pReal, pResOut); } /* ** File control method. For custom operations on an tvfs-file. */ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( op==SQLITE_FCNTL_PRAGMA ){ char **argv = (char**)pArg; if( sqlite3_stricmp(argv[1],"error")==0 ){ int rc = SQLITE_ERROR; if( argv[2] ){ const char *z = argv[2]; int x = atoi(z); if( x ){ rc = x; while( sqlite3Isdigit(z[0]) ){ z++; } while( sqlite3Isspace(z[0]) ){ z++; } } if( z[0] ) argv[0] = sqlite3_mprintf("%s", z); } return rc; } if( sqlite3_stricmp(argv[1], "filename")==0 ){ argv[0] = sqlite3_mprintf("%s", pFd->zFilename); return SQLITE_OK; } } if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){ struct Fcntl { int iFnctl; const char *zFnctl; } aF[] = { { SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" }, { SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" }, }; int i; for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){ if( op==aF[i].iFnctl ) break; } if( i<sizeof(aF)/sizeof(aF[0]) ){ int rc = 0; tvfsExecTcl(p, "xFileControl", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(aF[i].zFnctl, -1), 0, 0 ); tvfsResultCode(p, &rc); if( rc ) return rc; } } return sqlite3OsFileControl(pFd->pReal, op, pArg); } /* ** Return the sector-size in bytes for an tvfs-file. */ static int tvfsSectorSize(sqlite3_file *pFile){ TestvfsFd *pFd = tvfsGetFd(pFile); |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 | { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, { "xAccess", TESTVFS_ACCESS_MASK }, { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, { "xUnlock", TESTVFS_UNLOCK_MASK }, { "xLock", TESTVFS_LOCK_MASK }, { "xCheckReservedLock", TESTVFS_CKLOCK_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); return TCL_ERROR; | > | 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 | { "xOpen", TESTVFS_OPEN_MASK }, { "xClose", TESTVFS_CLOSE_MASK }, { "xAccess", TESTVFS_ACCESS_MASK }, { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, { "xUnlock", TESTVFS_UNLOCK_MASK }, { "xLock", TESTVFS_LOCK_MASK }, { "xCheckReservedLock", TESTVFS_CKLOCK_MASK }, { "xFileControl", TESTVFS_FCNTL_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; int mask = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "LIST"); return TCL_ERROR; |
︙ | ︙ |
Changes to src/test_window.c.
︙ | ︙ | |||
147 148 149 150 151 152 153 | if( objc!=7 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME XSTEP XFINAL XVALUE XINVERSE"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | if( objc!=7 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME XSTEP XFINAL XVALUE XINVERSE"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); pNew = (TestWindow*)ckalloc(sizeof(TestWindow)); memset(pNew, 0, sizeof(TestWindow)); pNew->xStep = Tcl_DuplicateObj(objv[3]); pNew->xFinal = Tcl_DuplicateObj(objv[4]); pNew->xValue = Tcl_DuplicateObj(objv[5]); pNew->xInverse = Tcl_DuplicateObj(objv[6]); pNew->interp = interp; |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
180 181 182 183 184 185 186 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ }; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif | | < < | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */ }; #define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40])) #endif /* Make the IdChar function accessible from ctime.c and alter.c */ int sqlite3IsIdChar(u8 c){ return IdChar(c); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Return the id of the next token in string (*pz). Before returning, set ** (*pz) to point to the byte following the parsed token. */ static int getToken(const unsigned char **pz){ |
︙ | ︙ | |||
686 687 688 689 690 691 692 | pParse->nTableLock = 0; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_free(pParse->apVtabLock); #endif | | > > | > < | 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 | pParse->nTableLock = 0; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_free(pParse->apVtabLock); #endif if( !IN_SPECIAL_PARSE ){ /* If the pParse->declareVtab flag is set, do not delete any table ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } if( !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DbFree(db, pParse->pVList); while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; pParse->pAinc = p->pNext; sqlite3DbFreeNN(db, p); } while( pParse->pZombieTab ){ |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
370 371 372 373 374 375 376 377 378 379 380 381 382 383 | if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); }else{ sqlite3TreeViewLine(pView, "{%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); | > > > | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); }else{ sqlite3TreeViewLine(pView, "{%d:%d}%s", pExpr->iTable, pExpr->iColumn, zFlgs); } if( ExprHasProperty(pExpr, EP_FixedCol) ){ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); } break; } case TK_INTEGER: { if( pExpr->flags & EP_IntValue ){ sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); }else{ sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); |
︙ | ︙ | |||
490 491 492 493 494 495 496 | Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; pWin = 0; }else{ pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC | | | | 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 | Window *pWin; if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; pWin = 0; }else{ pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = pExpr->y.pWin; #else pWin = 0; #endif } if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", pExpr->op2, pExpr->u.zToken); }else{ sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } if( pFarg ){ sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0); } #ifndef SQLITE_OMIT_WINDOWFUNC if( pWin ){ sqlite3TreeViewWindow(pView, pWin, 0); } #endif break; } #ifndef SQLITE_OMIT_SUBQUERY |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
177 178 179 180 181 182 183 | /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); | > | | | | | | | | > | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ zName = sqlite3NameFromToken(db, pName); if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto trigger_cleanup; } assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !IN_RENAME_OBJECT ){ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){ if( !noErr ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); }else{ assert( !db->init.busy ); sqlite3CodeVerifySchema(pParse, iDb); } goto trigger_cleanup; } } /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } |
︙ | ︙ | |||
208 209 210 211 212 213 214 | if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName, 0); goto trigger_cleanup; } #ifndef SQLITE_OMIT_AUTHORIZATION | < > | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName, 0); goto trigger_cleanup; } #ifndef SQLITE_OMIT_AUTHORIZATION if( !IN_RENAME_OBJECT ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int code = SQLITE_CREATE_TRIGGER; const char *zDb = db->aDb[iTabDb].zDbSName; const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb; if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; |
︙ | ︙ | |||
242 243 244 245 246 247 248 | pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; | > > > > > | > | > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName); pTrigger->pWhen = pWhen; pWhen = 0; }else{ pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } pTrigger->pColumns = pColumns; pColumns = 0; assert( pParse->pNewTrigger==0 ); pParse->pNewTrigger = pTrigger; trigger_cleanup: sqlite3DbFree(db, zName); sqlite3SrcListDelete(db, pTableName); sqlite3IdListDelete(db, pColumns); |
︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 | sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) || sqlite3FixExpr(&sFix, pTrig->pWhen) ){ goto triggerfinish_cleanup; } /* if we are not initializing, ** build the sqlite_master entry */ if( !db->init.busy ){ Vdbe *v; char *z; | > > > > > > > > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | sqlite3TokenInit(&nameToken, pTrig->zName); sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken); if( sqlite3FixTriggerStep(&sFix, pTrig->step_list) || sqlite3FixExpr(&sFix, pTrig->pWhen) ){ goto triggerfinish_cleanup; } #ifndef SQLITE_OMIT_ALTERTABLE if( IN_RENAME_OBJECT ){ assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, ** build the sqlite_master entry */ if( !db->init.busy ){ Vdbe *v; char *z; |
︙ | ︙ | |||
333 334 335 336 337 338 339 | pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | pLink->pNext = pTab->pTrigger; pTab->pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger(db, pTrig); assert( IN_RENAME_OBJECT || !pParse->pNewTrigger ); sqlite3DeleteTriggerStep(db, pStepList); } /* ** Duplicate a range of text from an SQL statement, then convert all ** whitespace characters into ordinary space characters. */ |
︙ | ︙ | |||
380 381 382 383 384 385 386 | /* ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( | | > > > > | > | > > > > | > | > | > > > > > > | | > | > | > > > > | > | 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 | /* ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ Token *pName, /* The target name */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; memcpy(z, pName->z, pName->n); sqlite3Dequote(z); pTriggerStep->zTarget = z; pTriggerStep->op = op; pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); } } return pTriggerStep; } /* ** Build a trigger step out of an INSERT statement. Return a pointer ** to the new trigger step. ** ** The parser calls this routine when it sees an INSERT inside the ** body of a trigger. */ TriggerStep *sqlite3TriggerInsertStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ Upsert *pUpsert, /* ON CONFLICT clauses for upsert */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; assert(pSelect != 0 || db->mallocFailed); pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pSelect = pSelect; pSelect = 0; }else{ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } pTriggerStep->pIdList = pColumn; pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; }else{ testcase( pColumn ); sqlite3IdListDelete(db, pColumn); testcase( pUpsert ); sqlite3UpsertDelete(db, pUpsert); } sqlite3SelectDelete(db, pSelect); return pTriggerStep; } /* ** Construct a trigger step that implements an UPDATE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; pEList = 0; pWhere = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); return pTriggerStep; } /* ** Construct a trigger step that implements a DELETE statement and return ** a pointer to that trigger step. The parser calls this routine when it ** sees a DELETE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerDeleteStep( Parse *pParse, /* Parser */ Token *pTableName, /* The table from which rows are deleted */ Expr *pWhere, /* The WHERE clause */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pWhere = pWhere; pWhere = 0; }else{ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); } pTriggerStep->orconf = OE_Default; } sqlite3ExprDelete(db, pWhere); return pTriggerStep; } /* |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 | } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; ** \_______/ \________/ \______/ \________________/ * onError pTabList pChanges pWhere | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } /* ** Check to see if column iCol of index pIdx references any of the ** columns defined by aXRef and chngRowid. Return true if it does ** and false if not. This is an optimization. False-positives are a ** performance degradation, but false-negatives can result in a corrupt ** index and incorrect answers. ** ** aXRef[j] will be non-negative if column j of the original table is ** being updated. chngRowid will be true if the rowid of the table is ** being updated. */ static int indexColumnIsBeingUpdated( Index *pIdx, /* The index to check */ int iCol, /* Which column of the index to check */ int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ i16 iIdxCol = pIdx->aiColumn[iCol]; assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */ if( iIdxCol>=0 ){ return aXRef[iIdxCol]>=0; } assert( iIdxCol==XN_EXPR ); assert( pIdx->aColExpr!=0 ); assert( pIdx->aColExpr->a[iCol].pExpr!=0 ); return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr, aXRef,chngRowid); } /* ** Check to see if index pIdx is a partial index whose conditional ** expression might change values due to an UPDATE. Return true if ** the index is subject to change and false if the index is guaranteed ** to be unchanged. This is an optimization. False-positives are a ** performance degradation, but false-negatives can result in a corrupt ** index and incorrect answers. ** ** aXRef[j] will be non-negative if column j of the original table is ** being updated. chngRowid will be true if the rowid of the table is ** being updated. */ static int indexWhereClauseMightChange( Index *pIdx, /* The index to check */ int *aXRef, /* aXRef[j]>=0 if column j is being updated */ int chngRowid /* true if the rowid is being updated */ ){ if( pIdx->pPartIdxWhere==0 ) return 0; return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, aXRef, chngRowid); } /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; ** \_______/ \________/ \______/ \________________/ * onError pTabList pChanges pWhere |
︙ | ︙ | |||
309 310 311 312 313 314 315 | pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. | < < | > > | < | 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 | pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0; hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey); /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold ** the key for accessing each index. */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; if( chngKey || hasFK>1 || pIdx==pPk || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; }else{ reg = 0; for(i=0; i<pIdx->nKeyCol; i++){ if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){ reg = ++pParse->nMem; pParse->nMem += pIdx->nColumn; if( (onError==OE_Replace) || (onError==OE_Default && pIdx->onError==OE_Replace) ){ bReplace = 1; } |
︙ | ︙ | |||
617 618 619 620 621 622 623 | /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or ** if there are one or more BEFORE triggers that use this value via ** a new.* reference in a trigger program. */ testcase( i==31 ); testcase( i==32 ); | | < < < < < < | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or ** if there are one or more BEFORE triggers that use this value via ** a new.* reference in a trigger program. */ testcase( i==31 ); testcase( i==32 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); } } } /* Fire any BEFORE UPDATE triggers. This happens before constraints are |
︙ | ︙ | |||
876 877 878 879 880 881 882 | /* Populate the argument registers. */ for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); | | | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 | /* Populate the argument registers. */ for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */ } } if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg); if( pRowid ){ sqlite3ExprCode(pParse, pRowid, regArg+1); }else{ |
︙ | ︙ |
Changes to src/upsert.c.
︙ | ︙ | |||
200 201 202 203 204 205 206 | Table *pTab, /* The table being updated */ Index *pIdx, /* The UNIQUE constraint that failed */ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ | | > > | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | Table *pTab, /* The table being updated */ Index *pIdx, /* The UNIQUE constraint that failed */ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */ ){ Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ int iDataCur; assert( v!=0 ); assert( pUpsert!=0 ); VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); iDataCur = pUpsert->iDataCur; if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid); sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regRowid); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | */ #ifdef SQLITE_DEBUG # define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) #else # define memAboutToChange(P,M) #endif | < < < < < < < < < < < < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | */ #ifdef SQLITE_DEBUG # define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M) #else # define memAboutToChange(P,M) #endif /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test ** procedures use this information to make sure that indices are ** working correctly. This variable has no function other than to ** help verify the correct operation of the library. */ |
︙ | ︙ | |||
510 511 512 513 514 515 516 | printf(" si:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ printf(" r:%g", p->u.r); #endif | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | printf(" si:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ printf(" r:%g", p->u.r); #endif }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ char zBuf[200]; sqlite3VdbeMemPrettyPrint(p, zBuf); printf(" %s", zBuf); } if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | assert( pOut!=pIn1 ); while( 1 ){ memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); #ifdef SQLITE_DEBUG pOut->pScopyFrom = 0; | < | 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | assert( pOut!=pIn1 ); while( 1 ){ memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); #ifdef SQLITE_DEBUG pOut->pScopyFrom = 0; #endif REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut); if( (n--)==0 ) break; pOut++; pIn1++; } break; |
︙ | ︙ | |||
1968 1969 1970 1971 1972 1973 1974 | }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); | > | > > > > | 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 | }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); assert( flags3==pIn3->flags ); /* testcase( flags3!=pIn3->flags ); ** this used to be possible with pIn1==pIn3, but not since ** the column cache was removed. The following assignment ** is essentially a no-op. But, it provides defense-in-depth ** in case our analysis is incorrect, so it is left in. */ flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } /* Handle the common case of integer comparison here, as an |
︙ | ︙ | |||
2898 2899 2900 2901 2902 2903 2904 | }else{ /* Rare case of a really large header */ nVarint = sqlite3VarintLen(nHdr); nHdr += nVarint; if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++; } nByte = nHdr+nData; | < < < > > > > > > > > > > | | > | 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 2922 | }else{ /* Rare case of a really large header */ nVarint = sqlite3VarintLen(nHdr); nHdr += nVarint; if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++; } nByte = nHdr+nData; /* Make sure the output register has a buffer large enough to store ** the new record. The output register (pOp->p3) is not allowed to ** be one of the input registers (because the following call to ** sqlite3VdbeMemClearAndResize() could clobber the value before it is used). */ if( nByte+nZero<=pOut->szMalloc ){ /* The output register is already large enough to hold the record. ** No error checks or buffer enlargement is required */ pOut->z = pOut->zMalloc; }else{ /* Need to make sure that the output is not too big and then enlarge ** the output register to hold the full result */ if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } } zNewRecord = (u8 *)pOut->z; /* Write the record */ i = putVarint32(zNewRecord, nHdr); j = nHdr; assert( pData0<=pLast ); |
︙ | ︙ | |||
3099 3100 3101 3102 3103 3104 3105 | for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } if( isSchemaChange ){ | | | 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 | for(ii=0; ii<db->nDb; ii++){ rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } } if( isSchemaChange ){ sqlite3ExpirePreparedStatements(db, 0); sqlite3ResetAllSchemasOfConnection(db); db->mDbFlags |= DBFLAG_SchemaChange; } } /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all ** savepoints nested inside of the savepoint being operated on. */ |
︙ | ︙ | |||
3418 3419 3420 3421 3422 3423 3424 | }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ | | | 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 | }else if( pOp->p2==BTREE_FILE_FORMAT ){ /* Record changes in the file format */ pDb->pSchema->file_format = pOp->p3; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ sqlite3ExpirePreparedStatements(db, 0); p->expired = 0; } if( rc ) goto abort_due_to_error; break; } /* Opcode: OpenRead P1 P2 P3 P4 P5 |
︙ | ︙ | |||
3536 3537 3538 3539 3540 3541 3542 | case OP_OpenWrite: assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); | | | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 | case OP_OpenWrite: assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx || p->readOnly==0 ); if( p->expired==1 ){ rc = SQLITE_ABORT_ROLLBACK; goto abort_due_to_error; } nField = 0; pKeyInfo = 0; p2 = pOp->p2; |
︙ | ︙ | |||
3919 3920 3921 3922 3923 3924 3925 | ** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this ** opcode must be followed by an IdxGE opcode with the same arguments. ** The IdxGE opcode will be skipped if this opcode succeeds, but the ** IdxGE opcode will be used on subsequent loop iterations. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ | | | | | | 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | ** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this ** opcode must be followed by an IdxGE opcode with the same arguments. ** The IdxGE opcode will be skipped if this opcode succeeds, but the ** IdxGE opcode will be used on subsequent loop iterations. ** ** See also: Found, NotFound, SeekGt, SeekGe, SeekLt */ case OP_SeekLT: /* jump, in3, group */ case OP_SeekLE: /* jump, in3, group */ case OP_SeekGE: /* jump, in3, group */ case OP_SeekGT: { /* jump, in3, group */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ UnpackedRecord r; /* The key to seek for */ int nField; /* Number of columns or fields in the key */ i64 iKey; /* The rowid we are to seek to */ int eqOnly; /* Only interested in == results */ |
︙ | ︙ | |||
4350 4351 4352 4353 4354 4355 4356 4357 | VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); | > > > > > > | > > | | 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 | VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ /* Make sure pIn3->u.i contains a valid integer representation of ** the key value, but do not change the datatype of the register, as ** other parts of the perpared statement might be depending on the ** current datatype. */ u16 origFlags = pIn3->flags; int isNotInt; applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); isNotInt = (pIn3->flags & MEM_Int)==0; pIn3->flags = origFlags; if( isNotInt ) goto jump_to_p2; } /* Fall through into OP_NotExists */ case OP_NotExists: /* jump, in3 */ pIn3 = &aMem[pOp->p3]; assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = OP_SeekRowid; #endif assert( pC->isTable ); |
︙ | ︙ | |||
5556 5557 5558 5559 5560 5561 5562 | r.default_rc = -1; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); r.default_rc = 0; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG | > > > | > > > | 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 | r.default_rc = -1; }else{ assert( pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT ); r.default_rc = 0; } r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG { int i; for(i=0; i<r.nField; i++){ assert( memIsValid(&r.aMem[i]) ); REGISTER_TRACE(pOp->p3+i, &aMem[pOp->p3+i]); } } #endif res = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); if( (pOp->opcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); res = -res; |
︙ | ︙ | |||
5743 5744 5745 5746 5747 5748 5749 | if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER table of database P1 | | > | 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 | if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER table of database P1 ** that match the WHERE clause P4. If P4 is a NULL pointer, then the ** entire schema for P1 is reparsed. ** ** This opcode invokes the parser to create a new virtual machine, ** then runs the new virtual machine. It is thus a re-entrant opcode. */ case OP_ParseSchema: { int iDb; const char *zMaster; |
︙ | ︙ | |||
5767 5768 5769 5770 5771 5772 5773 | assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); } #endif iDb = pOp->p1; assert( iDb>=0 && iDb<db->nDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); | | > > > > > > > > > > | > | 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 | assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); } #endif iDb = pOp->p1; assert( iDb>=0 && iDb<db->nDb ); assert( DbHasProperty(db, iDb, DB_SchemaLoaded) ); #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); db->mDbFlags |= DBFLAG_SchemaChange; p->expired = 0; }else #endif { zMaster = MASTER_NAME; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; zSql = sqlite3MPrintf(db, "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zMaster, pOp->p4.z); if( zSql==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ assert( db->init.busy==0 ); |
︙ | ︙ | |||
5924 5925 5926 5927 5928 5929 5930 | ** ** An assertion fails if P2 is not an integer. */ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); | | | < > | > | | | 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 | ** ** An assertion fails if P2 is not an integer. */ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); if( (pIn1->flags & MEM_Blob)==0 ){ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } assert( sqlite3VdbeMemIsRowSet(pIn1) ); sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i); break; } /* Opcode: RowSetRead P1 P2 P3 * * ** Synopsis: r[P3]=rowset(P1) ** ** Extract the smallest value from the RowSet object in P1 ** and put that value into register P3. ** Or, if RowSet object P1 is initially empty, leave P3 ** unchanged and jump to instruction P2. */ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) ); if( (pIn1->flags & MEM_Blob)==0 || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); VdbeBranchTaken(1,2); goto jump_to_p2_and_check_for_interrupt; }else{ /* A value was pulled from the index */ |
︙ | ︙ | |||
5994 5995 5996 5997 5998 5999 6000 | pIn3 = &aMem[pOp->p3]; iSet = pOp->p4.i; assert( pIn3->flags&MEM_Int ); /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ | | | < | | | | 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 | pIn3 = &aMem[pOp->p3]; iSet = pOp->p4.i; assert( pIn3->flags&MEM_Int ); /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ if( (pIn1->flags & MEM_Blob)==0 ){ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } assert( sqlite3VdbeMemIsRowSet(pIn1) ); assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ) goto jump_to_p2; } if( iSet>=0 ){ sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER |
︙ | ︙ | |||
6071 6072 6073 6074 6075 6076 6077 | goto abort_due_to_error; } /* Register pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ | | | > | > > > > | > | 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 | goto abort_due_to_error; } /* Register pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ if( (pRt->flags&MEM_Blob)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local ** variable nMem (and later, VdbeFrame.nChildMem) to this value. */ nMem = pProgram->nMem + pProgram->nCsr; assert( nMem>0 ); if( pProgram->nCsr==0 ) nMem++; nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor*) + (pProgram->nOp + 7)/8; pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; } sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; pRt->n = nByte; pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; pFrame->nChildMem = nMem; pFrame->nChildCsr = pProgram->nCsr; pFrame->pc = (int)(pOp - aOp); pFrame->aMem = p->aMem; pFrame->nMem = p->nMem; pFrame->apCsr = p->apCsr; pFrame->nCursor = p->nCursor; pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif #ifdef SQLITE_DEBUG pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; #endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Undefined; pMem->db = db; } }else{ pFrame = (VdbeFrame*)pRt->z; assert( pRt->xDel==sqlite3VdbeFrameMemDel ); assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( (int)(pOp - aOp)==pFrame->pc ); } p->nFrame++; |
︙ | ︙ | |||
6717 6718 6719 6720 6721 6722 6723 | rc = SQLITE_OK; goto jump_to_p2; } break; } #endif | | > > > > > > > | | | 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 | rc = SQLITE_OK; goto jump_to_p2; } break; } #endif /* Opcode: Expire P1 P2 * * * ** ** Cause precompiled statements to expire. When an expired statement ** is executed using sqlite3_step() it will either automatically ** reprepare itself (if it was originally created using sqlite3_prepare_v2()) ** or it will fail with SQLITE_SCHEMA. ** ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero, ** then only the currently executing statement is expired. ** ** If P2 is 0, then SQL statements are expired immediately. If P2 is 1, ** then running SQL statements are allowed to continue to run to completion. ** The P2==1 case occurs when a CREATE INDEX or similar schema change happens ** that might help the statement run faster but which does not affect the ** correctness of operation. */ case OP_Expire: { assert( pOp->p2==0 || pOp->p2==1 ); if( !pOp->p1 ){ sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ p->expired = pOp->p2+1; } break; } #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** Synopsis: iDb=P1 root=P2 write=P3 |
︙ | ︙ | |||
6961 6962 6963 6964 6965 6966 6967 | ** Synopsis: r[P3]=vcolumn(P2) ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 | < | > | | > | 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 | ** Synopsis: r[P3]=vcolumn(P2) ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of ** an unchanging column during an UPDATE operation, then the P5 ** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() ** function to return true inside the xColumn method of the virtual ** table implementation. The P5 column might also contain other ** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are ** unused by OP_VColumn. */ case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; |
︙ | ︙ | |||
6986 6987 6988 6989 6990 6991 6992 | break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; | > | | 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 | break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 ); if( pOp->p5 & OPFLAG_NOCHNG ){ sqlite3VdbeMemSetNull(pDest); pDest->flags = MEM_Null|MEM_Zero; pDest->u.nZero = 0; }else{ MemSetTypeFlag(pDest, MEM_Null); } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); |
︙ | ︙ | |||
7063 7064 7065 7066 7067 7068 7069 | ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; | > | > > > | 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 | ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; int isLegacy; isLegacy = (db->flags & SQLITE_LegacyAlter); db->flags |= SQLITE_LegacyAlter; pVtab = pOp->p4.pVtab->pVtab; pName = &aMem[pOp->p1]; assert( pVtab->pModule->xRename ); assert( memIsValid(pName) ); assert( p->readOnly==0 ); REGISTER_TRACE(pOp->p1, pName); assert( pName->flags & MEM_Str ); testcase( pName->enc==SQLITE_UTF8 ); testcase( pName->enc==SQLITE_UTF16BE ); testcase( pName->enc==SQLITE_UTF16LE ); rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8); if( rc ) goto abort_due_to_error; rc = pVtab->pModule->xRename(pVtab, pName->z); if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter; sqlite3VtabImportErrmsg(p, pVtab); p->expired = 0; if( rc ) goto abort_due_to_error; break; } #endif |
︙ | ︙ | |||
7247 7248 7249 7250 7251 7252 7253 | ** automatically converted into an sqlite3_context object and the operation ** changed to this OP_Function opcode. In this way, the initialization of ** the sqlite3_context object occurs only once, rather than once for each ** evaluation of the function. ** ** See also: Function0, AggStep, AggFinal */ | | | | 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 | ** automatically converted into an sqlite3_context object and the operation ** changed to this OP_Function opcode. In this way, the initialization of ** the sqlite3_context object occurs only once, rather than once for each ** evaluation of the function. ** ** See also: Function0, AggStep, AggFinal */ case OP_PureFunc0: /* group */ case OP_Function0: { /* group */ int n; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); |
︙ | ︙ | |||
7272 7273 7274 7275 7276 7277 7278 | pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; assert( OP_PureFunc == OP_PureFunc0+2 ); assert( OP_Function == OP_Function0+2 ); pOp->opcode += 2; /* Fall through into OP_Function */ } | | | | 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 | pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; assert( OP_PureFunc == OP_PureFunc0+2 ); assert( OP_Function == OP_Function0+2 ); pOp->opcode += 2; /* Fall through into OP_Function */ } case OP_PureFunc: /* group */ case OP_Function: { /* group */ int i; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCCTX ); pCtx = pOp->p4.pCtx; /* If this function is inside of a trigger, the register array in aMem[] |
︙ | ︙ | |||
7458 7459 7460 7461 7462 7463 7464 | ** An Abort is safe if either there have been no writes, or if there is ** an active statement journal. */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 | ** An Abort is safe if either there have been no writes, or if there is ** an active statement journal. */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
234 235 236 237 238 239 240 | void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeReusable(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeClearObject(sqlite3*,Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,Parse*); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); | < < < | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeReusable(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeClearObject(sqlite3*,Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,Parse*); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); #endif void sqlite3VdbeResetStepResult(Vdbe*); void sqlite3VdbeRewind(Vdbe*); int sqlite3VdbeReset(Vdbe*); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
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 | i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ int nChange; /* Statement changes (Vdbe.nChange) */ int nDbChange; /* Value of db->nChange */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** Internally, the vdbe manipulates nearly all SQL values as Mem ** structures. Each Mem struct may cache multiple representations (string, ** integer etc.) of the same value. */ struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ | > > > > > > > > > > < < < < < < | 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 | i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #if SQLITE_DEBUG u32 iFrameMagic; /* magic number for sanity checking */ #endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ int nChange; /* Statement changes (Vdbe.nChange) */ int nDbChange; /* Value of db->nChange */ }; /* Magic number for sanity checking on VdbeFrame objects */ #define SQLITE_FRAME_MAGIC 0x879fb71e /* ** Return a pointer to the array of registers allocated for use ** by a VdbeFrame. */ #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** Internally, the vdbe manipulates nearly all SQL values as Mem ** structures. Each Mem struct may cache multiple representations (string, ** integer etc.) of the same value. */ struct sqlite3_value { union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 eSubtype; /* Subtype for this value */ int n; /* Number of characters in string value, excluding '\0' */ char *z; /* String or BLOB value */ /* ShallowCopy only needs to copy the information above */ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ sqlite3 *db; /* The associated database connection */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; /* ** Size of struct Mem not including the Mem.zMalloc member or anything that ** follows. */ #define MEMCELLSIZE offsetof(Mem,zMalloc) |
︙ | ︙ | |||
238 239 240 241 242 243 244 | */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_AffMask 0x001f /* Mask of affinity bits */ | | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | */ #define MEM_Null 0x0001 /* Value is NULL (or a pointer) */ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_AffMask 0x001f /* Mask of affinity bits */ /* Available 0x0020 */ /* Available 0x0040 */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0xc1ff /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management |
︙ | ︙ | |||
266 267 268 269 270 271 272 | #define MEM_Zero 0x0000 #endif /* Return TRUE if Mem X contains dynamically allocated content - anything ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ | | | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | #define MEM_Zero 0x0000 #endif /* Return TRUE if Mem X contains dynamically allocated content - anything ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** Clear any existing type flags from a Mem and replace them with f */ #define MemSetTypeFlag(p, f) \ ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) |
︙ | ︙ | |||
386 387 388 389 390 391 392 | int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ | > | < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | int rcApp; /* errcode set by sqlite3_result_error_code() */ u32 nWrite; /* Number of write operations that have occurred */ #endif u16 nResColumn; /* Number of columns in one row of the result set */ u8 errorAction; /* Recovery action to do in case of an error */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft doingRerun:1; /* True if rerunning after an auto-reprepare */ bft changeCntOn:1; /* True to update the change-counter */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ |
︙ | ︙ | |||
479 480 481 482 483 484 485 | #else void sqlite3VdbeMemSetDouble(Mem*, double); #endif void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); | > > > | > > > > | | 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 | #else void sqlite3VdbeMemSetDouble(Mem*, double); #endif void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); #ifdef SQLITE_DEBUG int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeBooleanValue(Mem*, int ifNull); void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); void sqlite3VdbeMemCast(Mem*,u8,u8); int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); void sqlite3VdbeMemRelease(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); #endif const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); int sqlite3VdbeCloseStatement(Vdbe *, int); #ifdef SQLITE_DEBUG int sqlite3VdbeFrameIsValid(VdbeFrame*); #endif void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); #endif int sqlite3VdbeTransferError(Vdbe *p); int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
968 969 970 971 972 973 974 | /* .uTemp = */ (u32)0, /* .db = */ (sqlite3*)0, /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, #endif | < < < | 968 969 970 971 972 973 974 975 976 977 978 979 980 981 | /* .uTemp = */ (u32)0, /* .db = */ (sqlite3*)0, /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, #endif }; return &nullMem; } /* ** Check to see if column iCol of the given statement is valid. If ** it is, return a pointer to the Mem for the value of that column. |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
189 190 191 192 193 194 195 | pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOp->zComment = 0; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ | < < < < < < < < | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS pOp->zComment = 0; #endif #ifdef SQLITE_DEBUG if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); test_addop_breakpoint(); } #endif #ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0; |
︙ | ︙ | |||
320 321 322 323 324 325 326 | ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ if( pParse->explain==2 ){ char *zMsg; | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ if( pParse->explain==2 ){ char *zMsg; Vdbe *v; va_list ap; int iThis; va_start(ap, zFmt); zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); va_end(ap); v = pParse->pVdbe; iThis = v->nOp; |
︙ | ︙ | |||
441 442 443 444 445 446 447 | } #endif assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } | < < < < < < < < < < < < < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | } #endif assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */ p->aLabel[j] = v->nOp; } } /* ** Mark the VDBE as one that can only be run one time. */ void sqlite3VdbeRunOnlyOnce(Vdbe *p){ p->runOnlyOnce = 1; } |
︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 | while( (N--)>0 ){ p->db = db; p->flags = flags; p->szMalloc = 0; #ifdef SQLITE_DEBUG p->pScopyFrom = 0; #endif | < < < | 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 | while( (N--)>0 ){ p->db = db; p->flags = flags; p->szMalloc = 0; #ifdef SQLITE_DEBUG p->pScopyFrom = 0; #endif p++; } } /* ** Release an array of N Mem elements */ |
︙ | ︙ | |||
1681 1682 1683 1684 1685 1686 1687 | ** sqlite3MemRelease() were called from here. With -O2, this jumps ** to 6.6 percent. The test case is inserting 1000 rows into a table ** with no indexes using a single prepared INSERT statement, bind() ** and reset(). Inserts are grouped into a transaction. */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); | | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 | ** sqlite3MemRelease() were called from here. With -O2, this jumps ** to 6.6 percent. The test case is inserting 1000 rows into a table ** with no indexes using a single prepared INSERT statement, bind() ** and reset(). Inserts are grouped into a transaction. */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); testcase( p->xDel==sqlite3VdbeFrameMemDel ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } p->flags = MEM_Undefined; }while( (++p)<pEnd ); } } #ifdef SQLITE_DEBUG /* ** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is ** and false if something is wrong. ** ** This routine is intended for use inside of assert() statements only. */ int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){ if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0; return 1; } #endif /* ** This is a destructor on a Mem object (which is really an sqlite3_value) ** that deletes the Frame object that is attached to it as a blob. ** ** This routine does not delete the Frame right away. It merely adds the ** frame to a list of frames to be deleted when the Vdbe halts. */ void sqlite3VdbeFrameMemDel(void *pArg){ VdbeFrame *pFrame = (VdbeFrame*)pArg; assert( sqlite3VdbeFrameIsValid(pFrame) ); pFrame->pParent = pFrame->v->pDelFrame; pFrame->v->pDelFrame = pFrame; } /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). */ void sqlite3VdbeFrameDelete(VdbeFrame *p){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; i<p->nChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); sqlite3DbFree(p->v->db, p); } |
︙ | ︙ | |||
3019 3020 3021 3022 3023 3024 3025 | /* If the VM did not run to completion or if it encountered an ** error, then it might not have been halted properly. So halt ** it now. */ sqlite3VdbeHalt(p); | | | 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 | /* If the VM did not run to completion or if it encountered an ** error, then it might not have been halted properly. So halt ** it now. */ sqlite3VdbeHalt(p); /* If the VDBE has been run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ vdbeInvokeSqllog(p); sqlite3VdbeTransferError(p); |
︙ | ︙ | |||
4001 4002 4003 4004 4005 4006 4007 | int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ int f1, f2; int combined_flags; f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; | | | 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 | int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ int f1, f2; int combined_flags; f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) ); /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. */ if( combined_flags&MEM_Null ){ return (f2&MEM_Null) - (f1&MEM_Null); } |
︙ | ︙ | |||
4675 4676 4677 4678 4679 4680 4681 4682 | ** as expired. ** ** An expired statement means that recompilation of the statement is ** recommend. Statements expire when things happen that make their ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. */ | > > > > > > > > | | | 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 | ** as expired. ** ** An expired statement means that recompilation of the statement is ** recommend. Statements expire when things happen that make their ** programs obsolete. Removing user-defined functions or collating ** sequences, or changing an authorization function are the types of ** things that make prepared statements obsolete. ** ** If iCode is 1, then expiration is advisory. The statement should ** be reprepared before being restarted, but if it is already running ** it is allowed to run to completion. ** ** Internally, this function just sets the Vdbe.expired flag on all ** prepared statements. The flag is set to 1 for an immediate expiration ** and set to 2 for an advisory expiration. */ void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pNext){ p->expired = iCode+1; } } /* ** Return the database associated with the Vdbe. */ sqlite3 *sqlite3VdbeDb(Vdbe *v){ |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); /* Cannot be both MEM_Int and MEM_Real at the same time */ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ | | < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); /* Cannot be both MEM_Int and MEM_Real at the same time */ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be ** set. */ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){ |
︙ | ︙ | |||
152 153 154 155 156 157 158 | ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); #ifdef SQLITE_OMIT_UTF16 |
︙ | ︙ | |||
185 186 187 188 189 190 191 | ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or ** blob if bPreserve is true. If bPreserve is false, any prior content ** in pMem->z is discarded. */ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already ** contain a valid string or blob value. */ assert( bPreserve==0 || pMem->flags&(MEM_Blob|MEM_Str) ); testcase( bPreserve && pMem->z==0 ); |
︙ | ︙ | |||
273 274 275 276 277 278 279 | ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | ** Change pMem so that its MEM_Str or MEM_Blob value is stored in ** MEM.zMalloc, where it can be safely written. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ int rc = vdbeMemAddTerminator(pMem); if( rc ) return rc; } } |
︙ | ︙ | |||
298 299 300 301 302 303 304 | ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); assert( pMem->flags&MEM_Blob ); | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); assert( pMem->flags&MEM_Blob ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ nByte = 1; } |
︙ | ︙ | |||
353 354 355 356 357 358 359 | int fg = pMem->flags; const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | int fg = pMem->flags; const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ pMem->enc = 0; return SQLITE_NOMEM_BKPT; } |
︙ | ︙ | |||
458 459 460 461 462 463 464 | assert( VdbeMemDynamic(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ | < < < < < < < | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | assert( VdbeMemDynamic(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); } p->flags = MEM_Null; } /* ** Release memory held by the Mem p, both external memory cleared ** by p->xDel and memory in p->zMalloc. |
︙ | ︙ | |||
614 615 616 617 618 619 620 | /* ** The MEM structure is already a MEM_Real. Try to also make it a ** MEM_Int if we can. */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; assert( pMem->flags & MEM_Real ); | | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | /* ** The MEM structure is already a MEM_Real. Try to also make it a ** MEM_Int if we can. */ void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; assert( pMem->flags & MEM_Real ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); ix = doubleToInt64(pMem->u.r); /* Only mark the value as an integer if ** |
︙ | ︙ | |||
641 642 643 644 645 646 647 | } /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | } /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); MemSetTypeFlag(pMem, MEM_Int); return SQLITE_OK; } |
︙ | ︙ | |||
859 860 861 862 863 864 865 866 867 868 869 | if( !sqlite3IsNaN(val) ){ pMem->u.r = val; pMem->flags = MEM_Real; } } #endif /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. */ | > > > > > > > > > > > > > > | > | | | > | < < < < | < | < | 851 852 853 854 855 856 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 | if( !sqlite3IsNaN(val) ){ pMem->u.r = val; pMem->flags = MEM_Real; } } #endif #ifdef SQLITE_DEBUG /* ** Return true if the Mem holds a RowSet object. This routine is intended ** for use inside of assert() statements. */ int sqlite3VdbeMemIsRowSet(const Mem *pMem){ return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn) && pMem->xDel==sqlite3RowSetDelete; } #endif /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. ** ** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation ** error occurs. */ int sqlite3VdbeMemSetRowSet(Mem *pMem){ sqlite3 *db = pMem->db; RowSet *p; assert( db!=0 ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); sqlite3VdbeMemRelease(pMem); p = sqlite3RowSetInit(db); if( p==0 ) return SQLITE_NOMEM; pMem->z = (char*)p; pMem->flags = MEM_Blob|MEM_Dyn; pMem->xDel = sqlite3RowSetDelete; return SQLITE_OK; } /* ** Return true if the Mem object contains a TEXT or BLOB that is ** too large - whose size exceeds SQLITE_MAX_LENGTH. */ int sqlite3VdbeMemTooBig(Mem *p){ |
︙ | ︙ | |||
930 931 932 933 934 935 936 | /* pMem is the register that is changing. But also mark pX as ** undefined so that we can quickly detect the shallow-copy error */ pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } pMem->pScopyFrom = 0; | < < < | < < < | < < < | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 | /* pMem is the register that is changing. But also mark pX as ** undefined so that we can quickly detect the shallow-copy error */ pX->flags = MEM_Undefined; pX->pScopyFrom = 0; } } pMem->pScopyFrom = 0; } #endif /* SQLITE_DEBUG */ /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are freed. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ vdbeMemClearExternAndSetNull(pTo); assert( !VdbeMemDynamic(pTo) ); sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); } void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ assert( !sqlite3VdbeMemIsRowSet(pFrom) ); assert( pTo->db==pFrom->db ); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } memcpy(pTo, pFrom, MEMCELLSIZE); if( (pFrom->flags&MEM_Static)==0 ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } } /* ** Make a full copy of pFrom into pTo. Prior contents of pTo are ** freed before the copy is made. */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; assert( !sqlite3VdbeMemIsRowSet(pFrom) ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; if( pTo->flags&(MEM_Str|MEM_Blob) ){ if( 0==(pFrom->flags&MEM_Static) ){ pTo->flags |= MEM_Ephem; rc = sqlite3VdbeMemMakeWriteable(pTo); } } |
︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 | void (*xDel)(void*) /* Destructor function */ ){ int nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ u16 flags = 0; /* New value for pMem->flags */ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | void (*xDel)(void*) /* Destructor function */ ){ int nByte = n; /* New value for pMem->n */ int iLimit; /* Maximum allowed string or blob size */ u16 flags = 0; /* New value for pMem->flags */ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ sqlite3VdbeMemSetNull(pMem); return SQLITE_OK; } |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | int rc = SQLITE_OK; /* Return code */ 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. */ | | | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 | int rc = SQLITE_OK; /* Return code */ 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( !sqlite3VdbeMemIsRowSet(pMem) ); 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; |
︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 | ** Convert it into a string with encoding enc and return a pointer ** to a zero-terminated version of that string. */ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); | | | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | ** Convert it into a string with encoding enc and return a pointer ** to a zero-terminated version of that string. */ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(pVal) ) return 0; pVal->flags |= MEM_Str; if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); } |
︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 | ** If that is the case, then the result must be aligned on an even byte ** boundary. */ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); | | | 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 | ** If that is the case, then the result must be aligned on an even byte ** boundary. */ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ return 0; } |
︙ | ︙ | |||
1787 1788 1789 1790 1791 1792 1793 | int sqlite3Stat4Column( sqlite3 *db, /* Database handle */ const void *pRec, /* Pointer to buffer containing record */ int nRec, /* Size of buffer pRec in bytes */ int iCol, /* Column to extract */ sqlite3_value **ppVal /* OUT: Extracted value */ ){ | | | | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | int sqlite3Stat4Column( sqlite3 *db, /* Database handle */ const void *pRec, /* Pointer to buffer containing record */ int nRec, /* Size of buffer pRec in bytes */ int iCol, /* Column to extract */ sqlite3_value **ppVal /* OUT: Extracted value */ ){ u32 t = 0; /* a column type code */ int nHdr; /* Size of the header in the record */ int iHdr; /* Next unread header byte */ int iField; /* Next unread data byte */ int szField = 0; /* Size of the current data field */ int i; /* Column index */ u8 *a = (u8*)pRec; /* Typecast byte array */ Mem *pMem = *ppVal; /* Write result into this Mem object */ assert( iCol>0 ); iHdr = getVarint32(a, nHdr); if( nHdr>nRec || iHdr>=nHdr ) return SQLITE_CORRUPT_BKPT; |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
2103 2104 2105 2106 2107 2108 2109 | static int vdbeMergeEngineInit( SortSubtask *pTask, /* Thread that will run pMerger */ MergeEngine *pMerger, /* MergeEngine to initialize */ int eMode /* One of the INCRINIT_XXX constants */ ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ | > | > > > > | 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | static int vdbeMergeEngineInit( SortSubtask *pTask, /* Thread that will run pMerger */ MergeEngine *pMerger, /* MergeEngine to initialize */ int eMode /* One of the INCRINIT_XXX constants */ ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ int nTree; /* Number of subtrees to merge */ /* Failure to allocate the merge would have been detected prior to ** invoking this routine */ assert( pMerger!=0 ); /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); /* Verify that the MergeEngine is assigned to a single thread */ assert( pMerger->pTask==0 ); pMerger->pTask = pTask; nTree = pMerger->nTree; for(i=0; i<nTree; i++){ if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){ /* PmaReaders should be normally initialized in order, as if they are ** reading from the same temp file this makes for more linear file IO. ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is ** in use it will block the vdbePmaReaderNext() call while it uses ** the main thread to fill its buffer. So calling PmaReaderNext() |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
258 259 260 261 262 263 264 | VTable *p = db->pDisconnect; db->pDisconnect = 0; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | VTable *p = db->pDisconnect; db->pDisconnect = 0; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); } } |
︙ | ︙ | |||
324 325 326 327 328 329 330 | void sqlite3VtabBeginParse( Parse *pParse, /* Parsing context */ Token *pName1, /* Name of new table, or database name */ Token *pName2, /* Name of new table or NULL */ Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ | < < < > > | 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 | void sqlite3VtabBeginParse( Parse *pParse, /* Parsing context */ Token *pName1, /* Name of new table, or database name */ Token *pName2, /* Name of new table or NULL */ Token *pModuleName, /* Name of the module for the virtual table */ int ifNotExists /* No error if the table already exists */ ){ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, ifNotExists); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); db = pParse->db; assert( pTable->nModuleArg==0 ); addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); addModuleArgument(db, pTable, 0); addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); pParse->sNameToken.n = (int)( &pModuleName->z[pModuleName->n] - pParse->sNameToken.z ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Creating a virtual table invokes the authorization callback twice. ** The first invocation, to obtain permission to INSERT a row into the ** sqlite_master table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ int iDb = sqlite3SchemaToIndex(db, pTable->pSchema); assert( iDb>=0 ); /* The database the table is being created in */ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName, pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName); } #endif } /* |
︙ | ︙ | |||
754 755 756 757 758 759 760 | sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; assert( IsVirtual(pTab) ); memset(&sParse, 0, sizeof(sParse)); | | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } pTab = pCtx->pTab; assert( IsVirtual(pTab) ); memset(&sParse, 0, sizeof(sParse)); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; sParse.db = db; sParse.nQueryLoop = 1; if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) && sParse.pNewTable && !db->mallocFailed && !sParse.pNewTable->pSelect && !IsVirtual(sParse.pNewTable) |
︙ | ︙ | |||
795 796 797 798 799 800 801 | } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } | | | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } sParse.eParseMode = PARSE_MODE_NORMAL; if( sParse.pVdbe ){ sqlite3VdbeFinalize(sParse.pVdbe); } sqlite3DeleteTable(db, sParse.pNewTable); sqlite3ParserReset(&sParse); |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | void *pArg = 0; FuncDef *pNew; int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | void *pArg = 0; FuncDef *pNew; int rc = 0; /* Check to see the left operand is a column in a virtual table */ if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; if( !IsVirtual(pTab) ) return pDef; pVtab = sqlite3GetVTable(db, pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction==0 ) return pDef; |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
254 255 256 257 258 259 260 261 262 263 264 265 266 267 | #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. ** ** If a client begins recovering a WAL file and finds that (a) the checksum ** values in the wal-header are correct and (b) the version field is not ** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. | > > > > > > > > > > > > | 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 | #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif /* ** WAL mode depends on atomic aligned 32-bit loads and stores in a few ** places. The following macros try to make this explicit. */ #if GCC_VESRION>=5004000 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #endif /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. ** ** If a client begins recovering a WAL file and finds that (a) the checksum ** values in the wal-header are correct and (b) the version field is not ** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN. |
︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 | rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter); assert( rc==SQLITE_OK || pIter==0 ); } if( pIter && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK ){ | < > | 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 | rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter); assert( rc==SQLITE_OK || pIter==0 ); } if( pIter && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; pInfo->nBackfillAttempted = mxSafeFrame; /* Sync the WAL to disk */ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); i64 nSize; /* Current size of database file */ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSize<nReq ){ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); } } |
︙ | ︙ | |||
2568 2569 2570 2571 2572 2573 2574 | mxFrame = pWal->hdr.mxFrame; #ifdef SQLITE_ENABLE_SNAPSHOT if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){ mxFrame = pWal->pSnapshot->mxFrame; } #endif for(i=1; i<WAL_NREADER; i++){ | | | | 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 | mxFrame = pWal->hdr.mxFrame; #ifdef SQLITE_ENABLE_SNAPSHOT if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){ mxFrame = pWal->pSnapshot->mxFrame; } #endif for(i=1; i<WAL_NREADER; i++){ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; mxI = i; } } if( (pWal->readOnly & WAL_SHM_RDONLY)==0 && (mxReadMark<mxFrame || mxI==0) ){ for(i=1; i<WAL_NREADER; i++){ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame); mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; }else if( rc!=SQLITE_BUSY ){ return rc; } } |
︙ | ︙ | |||
2633 2634 2635 2636 2637 2638 2639 | ** A) on the basis that there is a newer version (version B) of the same ** page later in the wal file. But if version B happens to like past ** frame pWal->hdr.mxFrame - then the client would incorrectly assume ** that it can read version A from the database file. However, since ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ | | | | 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 | ** A) on the basis that there is a newer version (version B) of the same ** page later in the wal file. But if version B happens to like past ** frame pWal->hdr.mxFrame - then the client would incorrectly assume ** that it can read version A from the database file. However, since ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; walShmBarrier(pWal); if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); return WAL_RETRY; }else{ assert( mxReadMark<=pWal->hdr.mxFrame ); pWal->readLock = (i16)mxI; |
︙ | ︙ | |||
2734 2735 2736 2737 2738 2739 2740 | ** it takes a snapshot of the state of the WAL and wal-index for the current ** instant in time. The current thread will continue to use this snapshot. ** Other threads might append new content to the WAL and wal-index but ** that extra content is ignored by the current thread. ** ** If the database contents have changes since the previous read ** transaction, then *pChanged is set to 1 before returning. The | | | 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 | ** it takes a snapshot of the state of the WAL and wal-index for the current ** instant in time. The current thread will continue to use this snapshot. ** Other threads might append new content to the WAL and wal-index but ** that extra content is ignored by the current thread. ** ** If the database contents have changes since the previous read ** transaction, then *pChanged is set to 1 before returning. The ** Pager layer will use this to know that its cache is stale and ** needs to be flushed. */ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ int rc; /* Return code */ int cnt = 0; /* Number of TryBeginRead attempts */ #ifdef SQLITE_ENABLE_SNAPSHOT |
︙ | ︙ | |||
2797 2798 2799 2800 2801 2802 2803 | */ rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are | | | > | 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 | */ rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr ** with *pSnapshot and set *pChanged as appropriate for opening the ** snapshot. */ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) && pSnapshot->mxFrame>=pInfo->nBackfillAttempted ){ assert( pWal->readLock>0 ); memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); *pChanged = bChanged; }else{ rc = SQLITE_ERROR_SNAPSHOT; } /* Release the shared CKPT lock obtained above. */ walUnlockShared(pWal, WAL_CKPT_LOCK); pWal->minFrame = 1; } if( rc!=SQLITE_OK ){ sqlite3WalEndReadTransaction(pWal); } } |
︙ | ︙ | |||
3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 | ** is incremented each time the wal file is restarted. */ if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1; if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1; if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1; if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; return 0; } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** If the argument is not NULL, it points to a Wal object that holds a ** read-lock. This function returns the database page-size if it is known, ** or zero if it is not (or if pWal is NULL). | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 | ** is incremented each time the wal file is restarted. */ if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1; if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1; if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1; if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1; return 0; } /* ** The caller currently has a read transaction open on the database. ** This function takes a SHARED lock on the CHECKPOINTER slot and then ** checks if the snapshot passed as the second argument is still ** available. If so, SQLITE_OK is returned. ** ** If the snapshot is not available, SQLITE_ERROR is returned. Or, if ** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error ** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER ** lock is released before returning. */ int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ int rc; rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot; if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted ){ rc = SQLITE_ERROR_SNAPSHOT; walUnlockShared(pWal, WAL_CKPT_LOCK); } } return rc; } /* ** Release a lock obtained by an earlier successful call to ** sqlite3WalSnapshotCheck(). */ void sqlite3WalSnapshotUnlock(Wal *pWal){ assert( pWal ); walUnlockShared(pWal, WAL_CKPT_LOCK); } #endif /* SQLITE_ENABLE_SNAPSHOT */ #ifdef SQLITE_ENABLE_ZIPVFS /* ** If the argument is not NULL, it points to a Wal object that holds a ** read-lock. This function returns the database page-size if it is known, ** or zero if it is not (or if pWal is NULL). |
︙ | ︙ |
Changes to src/wal.h.
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 | */ int sqlite3WalHeapMemory(Wal *pWal); #ifdef SQLITE_ENABLE_SNAPSHOT int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); int sqlite3WalSnapshotRecover(Wal *pWal); #endif #ifndef SQLITE_OMIT_CONCURRENT /* Tell the wal layer that we want to commit a concurrent transaction */ int sqlite3WalLockForCommit(Wal *pWal, PgHdr *pPg, Bitvec *pRead, Pgno*); /* Upgrade the state of the client to take into account changes written | > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | */ int sqlite3WalHeapMemory(Wal *pWal); #ifdef SQLITE_ENABLE_SNAPSHOT int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); int sqlite3WalSnapshotRecover(Wal *pWal); int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot); void sqlite3WalSnapshotUnlock(Wal *pWal); #endif #ifndef SQLITE_OMIT_CONCURRENT /* Tell the wal layer that we want to commit a concurrent transaction */ int sqlite3WalLockForCommit(Wal *pWal, PgHdr *pPg, Bitvec *pRead, Pgno*); /* Upgrade the state of the client to take into account changes written |
︙ | ︙ |
Changes to src/walker.c.
︙ | ︙ | |||
51 52 53 54 55 56 57 | continue; }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else if( pExpr->x.pList ){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } #ifndef SQLITE_OMIT_WINDOWFUNC | | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | continue; }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort; }else if( pExpr->x.pList ){ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort; } #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort; } #endif } break; |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* | | | > > > > > > > > | > > | | > > > > > | > > > > | > > > > | 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 | ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* ** In the ORDER BY LIMIT optimization, if the inner-most loop is known ** to emit rows in increasing order, and if the last row emitted by the ** inner-most loop did not fit within the sorter, then we can skip all ** subsequent rows for the current iteration of the inner loop (because they ** will not fit in the sorter either) and continue with the second inner ** loop - the loop immediately outside the inner-most. ** ** When a row does not fit in the sorter (because the sorter already ** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the ** label returned by this function. ** ** If the ORDER BY LIMIT optimization applies, the jump destination should ** be the continuation for the second-inner-most loop. If the ORDER BY ** LIMIT optimization does not apply, then the jump destination should ** be the continuation for the inner-most loop. ** ** It is always safe for this routine to return the continuation of the ** inner-most loop, in the sense that a correct answer will result. ** Returning the continuation the second inner loop is an optimization ** that might make the code run a little faster, but should not change ** the final answer. */ int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){ WhereLevel *pInner; if( !pWInfo->bOrderedInnerLoop ){ /* The ORDER BY LIMIT optimization does not apply. Jump to the ** continuation of the inner-most loop. */ return pWInfo->iContinue; } pInner = &pWInfo->a[pWInfo->nLevel-1]; assert( pInner->addrNxt!=0 ); return pInner->addrNxt; } /* ** 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){ |
︙ | ︙ | |||
798 799 800 801 802 803 804 | assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ | < | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); |
︙ | ︙ | |||
835 836 837 838 839 840 841 | pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); } sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); | < | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 | pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); } sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); /* Jump here when skipping the initialization */ sqlite3VdbeJumpHere(v, addrInit); end_auto_index_create: sqlite3ExprDelete(pParse->db, pPartial); } |
︙ | ︙ | |||
941 942 943 944 945 946 947 948 949 950 951 952 953 954 | assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; if( op==WO_AUX ){ pIdxCons[j].op = pTerm->eMatchOp; | > > > > > > > > > > > > > > | 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 989 | assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) && (pTerm->eOperator & (WO_IS|WO_ISNULL)) ){ /* An "IS" term in the WHERE clause where the virtual table is the rhs ** of a LEFT JOIN. Do not pass this term to the virtual table ** implementation, as this can lead to incorrect results from SQL such ** as: ** ** "LEFT JOIN vtab WHERE vtab.col IS NULL" */ testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); continue; } assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; if( op==WO_AUX ){ pIdxCons[j].op = pTerm->eMatchOp; |
︙ | ︙ | |||
1432 1433 1434 1435 1436 1437 1438 | int nOut = pLoop->nOut; LogEst nNew; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; | | > > | 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | int nOut = pLoop->nOut; LogEst nNew; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; if( p->nSample>0 && nEq<p->nSampleCol && OptimizationEnabled(pParse->db, SQLITE_Stat34) ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; int nBtm = pLoop->u.btree.nBtm; int nTop = pLoop->u.btree.nTop; /* Variable iLower will be set to the estimate of the number of rows in |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 | ** (4) The template has the same or lower cost than the current loop */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; int rc; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED | > > > > > > > > | 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 | ** (4) The template has the same or lower cost than the current loop */ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ WhereLoop **ppPrev, *p; WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; int rc; /* Stop the search once we hit the query planner search limit */ if( pBuilder->iPlanLimit==0 ){ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; return SQLITE_DONE; } pBuilder->iPlanLimit--; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED |
︙ | ︙ | |||
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 | }else{ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ testcase( eOp & WO_EQ ); testcase( eOp & WO_IS ); testcase( eOp & WO_ISNULL ); rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); | > | 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 | }else{ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) && OptimizationEnabled(db, SQLITE_Stat34) ){ Expr *pExpr = pTerm->pExpr; if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){ testcase( eOp & WO_EQ ); testcase( eOp & WO_IS ); testcase( eOp & WO_ISNULL ); rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut); |
︙ | ︙ | |||
3198 3199 3200 3201 3202 3203 3204 | if( iCons>=0 && iCons<pIdxInfo->nConstraint ){ CollSeq *pC = 0; int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; Expr *pX = pHidden->pWC->a[iTerm].pExpr; if( pX->pLeft ){ pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight); } | | | 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 | if( iCons>=0 && iCons<pIdxInfo->nConstraint ){ CollSeq *pC = 0; int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset; Expr *pX = pHidden->pWC->a[iTerm].pExpr; if( pX->pLeft ){ pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight); } zRet = (pC ? pC->zName : sqlite3StrBINARY); } return zRet; } /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. |
︙ | ︙ | |||
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 | int rc = SQLITE_OK; WhereLoop *pNew; u8 priorJointype = 0; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){ Bitmask mUnusable = 0; pNew->iTab = iTab; 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; | > > | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 | int rc = SQLITE_OK; WhereLoop *pNew; u8 priorJointype = 0; /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT; for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){ Bitmask mUnusable = 0; pNew->iTab = iTab; pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; 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; |
︙ | ︙ | |||
3518 3519 3520 3521 3522 3523 3524 | { rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; | | > > > > > > > > | 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 | { rc = whereLoopAddBtree(pBuilder, mPrereq); } if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ){ if( rc==SQLITE_DONE ){ /* We hit the query planner search limit set by iPlanLimit */ sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search"); rc = SQLITE_OK; }else{ break; } } } whereLoopClear(db, pNew); return rc; } /* |
︙ | ︙ | |||
4049 4050 4051 4052 4053 4054 4055 | } if( isOrdered>=0 && isOrdered<nOrderBy ){ if( aSortCost[isOrdered]==0 ){ aSortCost[isOrdered] = whereSortingCost( pWInfo, nRowEst, nOrderBy, isOrdered ); } | > > > > | | 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 | } if( isOrdered>=0 && isOrdered<nOrderBy ){ if( aSortCost[isOrdered]==0 ){ aSortCost[isOrdered] = whereSortingCost( pWInfo, nRowEst, nOrderBy, isOrdered ); } /* TUNING: Add a small extra penalty (5) to sorting as an ** extra encouragment to the query planner to select a plan ** where the rows emerge in the correct order without any sorting ** required. */ rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, rUnsorted, rCost)); }else{ rCost = rUnsorted; |
︙ | ︙ | |||
4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 | Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; | > | 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 | Bitmask notUsed; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom, WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; |
︙ | ︙ | |||
5066 5067 5068 5069 5070 5071 5072 | WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); | < | 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 | WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; /* Generate loop termination code. */ VdbeModuleComment((v, "End WHERE-core")); for(i=pWInfo->nLevel-1; i>=0; i--){ int addr; pLevel = &pWInfo->a[i]; pLoop = pLevel->pWLoop; if( pLevel->op!=OP_Noop ){ #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT int addrSeek = 0; |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned int bldFlags; /* SQLITE_BLDF_* flags */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. | > > > > > > > > > > > > > > > > > > > > > | 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 | WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned int bldFlags; /* SQLITE_BLDF_* flags */ unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ /* The WhereLoopBuilder.iPlanLimit is used to limit the number of ** index+constraint combinations the query planner will consider for a ** particular query. If this parameter is unlimited, then certain ** pathological queries can spend excess time in the sqlite3WhereBegin() ** routine. The limit is high enough that is should not impact real-world ** queries. ** ** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is ** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM ** clause is processed, so that every table in a join is guaranteed to be ** able to propose a some index+constraint combinations even if the initial ** baseline limit was exhausted by prior tables of the join. */ #ifndef SQLITE_QUERY_PLANNER_LIMIT # define SQLITE_QUERY_PLANNER_LIMIT 20000 #endif #ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR # define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000 #endif /* ** The WHERE clause processing routine has two halves. The ** first part does the start of the WHERE loop and the second ** half does the tail of the WHERE loop. An instance of ** this structure is returned by the first half and passed ** into the second half to give some continuity. |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
343 344 345 346 347 348 349 | while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ n--; } /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); | < | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ n--; } /* Code the OP_Affinity opcode if there is anything left to do. */ if( n>0 ){ sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n); } } /* ** Expression pRight, which is the RHS of a comparison operation, is ** either a vector of n elements or, if n==1, a scalar expression. ** Before the comparison operation, affinity zAff is to be applied |
︙ | ︙ | |||
881 882 883 884 885 886 887 | ** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ | < | < < | 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | ** an access of the index rather than the original table. */ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ int rc = WRC_Continue; struct CCurHint *pHint = pWalker->u.pCCurHint; if( pExpr->op==TK_COLUMN ){ if( pExpr->iTable!=pHint->iTabCur ){ int reg = ++pWalker->pParse->nMem; /* Register for column value */ sqlite3ExprCode(pWalker->pParse, pExpr, reg); pExpr->op = TK_REGISTER; pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | */ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ IdxExprTrans *pX = p->u.pIdxTrans; if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; | | | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | */ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ IdxExprTrans *pX = p->u.pIdxTrans; if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; } } /* |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; int iIn; /* Counter for IN constraints */ | < | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 | ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; int iIn; /* Counter for IN constraints */ iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; j<nConstraint; j++){ int iTarget = iReg+j+2; pTerm = pLoop->aLTerm[j]; if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ |
︙ | ︙ | |||
1325 1326 1327 1328 1329 1330 1331 | /* These registers need to be preserved in case there is an IN operator ** loop. So we could deallocate the registers here (and potentially ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems ** simpler and safer to simply not reuse the registers. ** ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); */ | < | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 | /* These registers need to be preserved in case there is an IN operator ** loop. So we could deallocate the registers here (and potentially ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems ** simpler and safer to simply not reuse the registers. ** ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); */ }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 ){ /* Case 2: We can directly reference a single row using an |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | 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); | < < < | 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 | 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); pLevel->op = OP_Noop; }else if( (pLoop->wsFlags & WHERE_IPK)!=0 && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 ){ /* Case 3: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; |
︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | } sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); VdbeComment((v, "pk")); VdbeCoverageIf(v, pX->op==TK_GT); VdbeCoverageIf(v, pX->op==TK_LE); VdbeCoverageIf(v, pX->op==TK_LT); VdbeCoverageIf(v, pX->op==TK_GE); | < | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | } sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); VdbeComment((v, "pk")); VdbeCoverageIf(v, pX->op==TK_GT); VdbeCoverageIf(v, pX->op==TK_LE); VdbeCoverageIf(v, pX->op==TK_LT); VdbeCoverageIf(v, pX->op==TK_GE); sqlite3ReleaseTempReg(pParse, rTemp); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); } if( pEnd ){ |
︙ | ︙ | |||
1456 1457 1458 1459 1460 1461 1462 | pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); | < | 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 | pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; assert( pLevel->p5==0 ); if( testOp!=OP_Noop ){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); VdbeCoverageIf(v, testOp==OP_Le); VdbeCoverageIf(v, testOp==OP_Lt); VdbeCoverageIf(v, testOp==OP_Ge); VdbeCoverageIf(v, testOp==OP_Gt); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); } |
︙ | ︙ | |||
1682 1683 1684 1685 1686 1687 1688 | /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; | < | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 | /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; codeExprOrVector(pParse, pRight, regBase+nEq, nTop); whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd); if( (pRangeEnd->wtFlags & TERM_VNULL)==0 && sqlite3ExprCanBeNull(pRight) ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); |
︙ | ︙ | |||
1707 1708 1709 1710 1711 1712 1713 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); | < | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); endEq = 0; nConstraint++; } sqlite3DbFree(db, zStartAff); sqlite3DbFree(db, zEndAff); /* Top of the loop body */ |
︙ | ︙ | |||
1741 1742 1743 1744 1745 1746 1747 | }else if( HasRowid(pIdx->pTable) ){ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) && (pWInfo->eOnePass==ONEPASS_SINGLE) )){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); | < | 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | }else if( HasRowid(pIdx->pTable) ){ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE) && (pWInfo->eOnePass==ONEPASS_SINGLE) )){ iRowidReg = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); VdbeCoverage(v); }else{ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); } }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); |
︙ | ︙ | |||
1976 1977 1978 1979 1980 1981 1982 | /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ | < | | > | | 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 | /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, regRowid, iSet); VdbeCoverage(v); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); int nPk = pPk->nKeyCol; int iPk; int r; /* Read the PK into an array of temp registers. */ r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPk<nPk; iPk++){ int iCol = pPk->aiColumn[iPk]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk); } /* Check if the temp table already contains this key. If so, ** the row has already been included in the result set and ** can be ignored (by jumping past the Gosub below). Otherwise, ** insert the key into the temp table and proceed with processing ** the row. |
︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 | /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); | < | 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 | /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
190 191 192 193 194 195 196 | static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ | | | | | | 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 | static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ const u8 *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ u8 c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ u8 wc[4]; /* Wildcard characters */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ int rc; /* Result code to return */ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; |
︙ | ︙ | |||
226 227 228 229 230 231 232 | sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ z = (u8*)pRight->u.zToken; } if( z ){ | < < < < < < < < < < < < < < < < < | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ z = (u8*)pRight->u.zToken; } if( z ){ /* Count the number of prefix characters prior to the first wildcard */ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; if( c==wc[3] && z[cnt]!=0 ) cnt++; } |
︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 | char *zNew = pPrefix->u.zToken; zNew[cnt] = 0; for(iFrom=iTo=0; iFrom<cnt; iFrom++){ if( zNew[iFrom]==wc[3] ) iFrom++; zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; } *ppPrefix = pPrefix; /* If the RHS pattern is a bound parameter, make arrangements to ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | char *zNew = pPrefix->u.zToken; zNew[cnt] = 0; for(iFrom=iTo=0; iFrom<cnt; iFrom++){ if( zNew[iFrom]==wc[3] ) iFrom++; zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; /* If the RHS begins with a digit or a minus sign, then the LHS must be ** an ordinary column (not a virtual table column) with TEXT affinity. ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false ** even though "lhs LIKE rhs" is true. But if the RHS does not start ** with a digit or '-', then "lhs LIKE rhs" will always be false if ** the LHS is numeric and so the optimization still works. ** ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033 ** The RHS pattern must not be '/%' because the termination condition ** will then become "x<'0'" and if the affinity is numeric, will then ** be converted into "x<0", which is incorrect. */ if( sqlite3Isdigit(zNew[0]) || zNew[0]=='-' || (zNew[0]+1=='0' && iTo==1) ){ if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ ){ sqlite3ExprDelete(db, pPrefix); sqlite3ValueFree(pVal); return 0; } } } *ppPrefix = pPrefix; /* If the RHS pattern is a bound parameter, make arrangements to ** reprepare the statement when that parameter is rebound */ if( op==TK_VARIABLE ){ Vdbe *v = pParse->pVdbe; |
︙ | ︙ | |||
336 337 338 339 340 341 342 343 344 345 346 347 348 349 | ** appropriate virtual table operator. The return value is 1 or 2 if there ** is a match. The usual return is 1, but if the RHS is also a column ** of virtual table in forms (5) or (7) then return 2. ** ** If the expression matches none of the patterns above, return 0. */ static int isAuxiliaryVtabOperator( Expr *pExpr, /* Test this expression */ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ Expr **ppLeft, /* Column expression to left of MATCH/op2 */ Expr **ppRight /* Expression to left of MATCH/op2 */ ){ if( pExpr->op==TK_FUNCTION ){ static const struct Op2 { | > | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | ** appropriate virtual table operator. The return value is 1 or 2 if there ** is a match. The usual return is 1, but if the RHS is also a column ** of virtual table in forms (5) or (7) then return 2. ** ** If the expression matches none of the patterns above, return 0. */ static int isAuxiliaryVtabOperator( sqlite3 *db, /* Parsing context */ Expr *pExpr, /* Test this expression */ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ Expr **ppLeft, /* Column expression to left of MATCH/op2 */ Expr **ppRight /* Expression to left of MATCH/op2 */ ){ if( pExpr->op==TK_FUNCTION ){ static const struct Op2 { |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 | Expr *pCol; /* Column reference */ int i; pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; } pCol = pList->a[1].pExpr; | > > > > > > > > | < < | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | Expr *pCol; /* Column reference */ int i; pList = pExpr->x.pList; if( pList==0 || pList->nExpr!=2 ){ return 0; } /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a ** virtual table on their second argument, which is the same as ** the left-hand side operand in their in-fix form. ** ** vtab_column MATCH expression ** MATCH(expression,vtab_column) */ pCol = pList->a[1].pExpr; if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ for(i=0; i<ArraySize(aOp); i++){ if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){ *peOp2 = aOp[i].eOp2; *ppRight = pList->a[0].pExpr; *ppLeft = pCol; return 1; } } } /* We can also match against the first column of overloaded ** functions where xFindFunction returns a value of at least ** SQLITE_INDEX_CONSTRAINT_FUNCTION. ** ** OVERLOADED(vtab_column,expression) ** ** Historically, xFindFunction expected to see lower-case function ** names. But for this use case, xFindFunction is expected to deal ** with function names in an arbitrary case. */ pCol = pList->a[0].pExpr; if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ sqlite3_vtab *pVtab; sqlite3_module *pMod; void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); void *pNotUsed; pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab; assert( pVtab!=0 ); assert( pVtab->pModule!=0 ); pMod = (sqlite3_module *)pVtab->pModule; if( pMod->xFindFunction!=0 ){ i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ *peOp2 = i; *ppRight = pList->a[1].pExpr; *ppLeft = pCol; return 1; } } } }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ int res = 0; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){ res++; } if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){ res++; SWAP(Expr*, pLeft, pRight); } *ppLeft = pLeft; *ppRight = pRight; if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE; if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT; |
︙ | ︙ | |||
816 817 818 819 820 821 822 | int idxNew; transferJoinMarkings(pNew, pExpr); assert( !ExprHasProperty(pNew, EP_xIsSelect) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | int idxNew; transferJoinMarkings(pNew, pExpr); assert( !ExprHasProperty(pNew, EP_xIsSelect) ); pNew->x.pList = pList; idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } } } } |
︙ | ︙ | |||
855 856 857 858 859 860 861 | aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); if( sqlite3IsBinary(pColl) ) return 1; return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight); } /* ** Recursively walk the expressions of a SELECT statement and generate ** a bitmask indicating which tables are used in that expression ** tree. |
︙ | ︙ | |||
1196 1197 1198 1199 1200 1201 1202 | ** LIKE on all candidate expressions by clearing the isComplete flag */ if( c=='A'-1 ) isComplete = 0; c = sqlite3UpperToLower[c]; } *pC = c + 1; } | | | 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 | ** LIKE on all candidate expressions by clearing the isComplete flag */ if( c=='A'-1 ) isComplete = 0; c = sqlite3UpperToLower[c]; } *pC = c + 1; } zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); |
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 | ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** 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 ){ Expr *pRight = 0, *pLeft = 0; | | | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 | ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL. ** 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 ){ Expr *pRight = 0, *pLeft = 0; int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); while( res-- > 0 ){ int idxNew; WhereTerm *pNewTerm; Bitmask prereqColumn, prereqExpr; prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); |
︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 | /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask; | | | 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 | /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask; if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return sqlite3WhereGetMask(pMaskSet, p->iTable); }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ assert( p->op!=TK_IF_NULL_ROW ); return 0; } mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0; if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft); |
︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 | pTab->zName, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; | | | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | pTab->zName, j); return; } pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; pColRef->y.pTab = pTab; pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } |
Changes to src/window.c.
︙ | ︙ | |||
620 621 622 623 624 625 626 | if( i==nSrc ) return WRC_Continue; } } switch( pExpr->op ){ case TK_FUNCTION: | | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | if( i==nSrc ) return WRC_Continue; } } switch( pExpr->op ){ case TK_FUNCTION: if( !ExprHasProperty(pExpr, EP_WinFunc) ){ break; }else{ Window *pWin; for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } /* Fall through. */ |
︙ | ︙ | |||
955 956 957 958 959 960 961 | } /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ | > > > > | | > | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | } /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); /* This routine is only called for the parser. If pWin was not ** allocated due to an OOM, then the parser would fail before ever ** invoking this routine */ if( ALWAYS(pWin) ){ p->y.pWin = pWin; ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; if( p->flags & EP_Distinct ){ sqlite3ErrorMsg(pParse, "DISTINCT is not supported for window functions"); } } }else{ |
︙ | ︙ | |||
2119 2120 2121 2122 2123 2124 2125 | /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to ** pOwner. */ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ Window *pNew = 0; | | | 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 | /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to ** pOwner. */ Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ Window *pNew = 0; if( ALWAYS(p) ){ pNew = sqlite3DbMallocZero(db, sizeof(Window)); if( pNew ){ pNew->zName = sqlite3DbStrDup(db, p->zName); pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0); pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); pNew->eType = p->eType; |
︙ | ︙ |
Changes to test/all.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # set testdir [file dirname $argv0] source $testdir/permutations.test run_test_suite full run_test_suite no_optimization run_test_suite memsubsys1 run_test_suite memsubsys2 run_test_suite singlethread run_test_suite multithread run_test_suite onefile run_test_suite utf16 | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # set testdir [file dirname $argv0] source $testdir/permutations.test run_test_suite full ifcapable rbu { run_test_suite rbu } run_test_suite no_optimization run_test_suite memsubsys1 run_test_suite memsubsys2 run_test_suite singlethread run_test_suite multithread run_test_suite onefile run_test_suite utf16 |
︙ | ︙ |
Changes to test/alter.test.
︙ | ︙ | |||
677 678 679 680 681 682 683 | do_test alter-8.2 { execsql { SELECT a, sum(b) FROM t2 GROUP BY a; } } {1 18 2 9} #-------------------------------------------------------------------------- | | < | | | < < | | | | > > > > | < | 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 | do_test alter-8.2 { execsql { SELECT a, sum(b) FROM t2 GROUP BY a; } } {1 18 2 9} #-------------------------------------------------------------------------- # alter-9.X - Special test: Make sure the sqlite_rename_column() and # rename_table() functions do not crash when handed bad input. # do_test alter-9.1 { execsql {SELECT SQLITE_RENAME_COLUMN(0,0,0,0,0,0,0,0,0)} } {{}} foreach {tn sql} { 1 { SELECT SQLITE_RENAME_TABLE(0,0,0,0,0,0,0) } 2 { SELECT SQLITE_RENAME_TABLE(10,20,30,40,50,60,70) } 3 { SELECT SQLITE_RENAME_TABLE('foo','foo','foo','foo','foo','foo','foo') } } { do_test alter-9.2.$tn { catch { execsql $sql } } 1 } #------------------------------------------------------------------------ # alter-10.X - Make sure ALTER TABLE works with multi-byte UTF-8 characters # in the names. # do_test alter-10.1 { execsql "CREATE TABLE xyz(x UNIQUE)" |
︙ | ︙ | |||
871 872 873 874 875 876 877 | SELECT * FROM t16a ORDER BY a; } {abc 1.25 99 xyzzy cba 5.5 98 fizzle} do_execsql_test alter-16.2 { ALTER TABLE t16a RENAME TO t16a_rn; SELECT * FROM t16a_rn ORDER BY a; } {abc 1.25 99 xyzzy cba 5.5 98 fizzle} | | < < < > > | < | < | < < < < < | < < > > | < < < < < < < < < > | | < < < < < > | | < < < < < < < < < | > | 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 896 897 | SELECT * FROM t16a ORDER BY a; } {abc 1.25 99 xyzzy cba 5.5 98 fizzle} do_execsql_test alter-16.2 { ALTER TABLE t16a RENAME TO t16a_rn; SELECT * FROM t16a_rn ORDER BY a; } {abc 1.25 99 xyzzy cba 5.5 98 fizzle} # 2018-09-16 ticket b41031ea2b5372378cb3d2d43cf9fe2a4a5c2510 # ifcapable rtree { db close sqlite3 db :memory: do_execsql_test alter-17.100 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE VIRTUAL TABLE t2 USING rtree(id,x0,x1); INSERT INTO t1 VALUES(1,'apple'),(2,'fig'),(3,'pear'); INSERT INTO t2 VALUES(1,1.0,2.0),(2,2.0,3.0),(3,1.5,3.5); CREATE TRIGGER r1 AFTER UPDATE ON t1 BEGIN DELETE FROM t2 WHERE id = OLD.a; END; ALTER TABLE t1 RENAME TO t3; UPDATE t3 SET b='peach' WHERE a=2; SELECT * FROM t2 ORDER BY 1; } {1 1.0 2.0 3 1.5 3.5} } finish_test |
Changes to test/alter4.test.
︙ | ︙ | |||
389 390 391 392 393 394 395 396 397 | 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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} reset_db do_execsql_test alter4-11.0 { CREATE TABLE t1(c INTEGER PRIMARY KEY, d); PRAGMA foreign_keys = on; ALTER TABLE t1 ADD COLUMN e; } do_execsql_test alter4-11.1 { ALTER TABLE t1 ADD COLUMN f REFERENCES t1; } do_catchsql_test alter4-11.2 { ALTER TABLE t1 ADD COLUMN g REFERENCES t1 DEFAULT 4; } {1 {Cannot add a REFERENCES column with non-NULL default value}} do_catchsql_test alter4-11.3 { ALTER TABLE t2 ADD COLUMN g; } {1 {no such table: t2}} ifcapable fts5 { do_execsql_test alter4-11.4 { CREATE VIRTUAL TABLE fff USING fts5(f); } do_catchsql_test alter4-11.2 { ALTER TABLE fff ADD COLUMN g; } {1 {virtual tables may not be altered}} } finish_test |
Added test/alterauth.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 | # 2018 September 2 # # 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 # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } set testprefix alterauth set ::auth [list] proc xAuth {type args} { if {$type == "SQLITE_ALTER_TABLE"} { lappend ::auth [concat $type [lrange $args 0 3]] } return SQLITE_OK } db auth xAuth do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); } do_test 1.1 { set ::auth [list] execsql { ALTER TABLE t1 RENAME TO t2 } set ::auth } {{SQLITE_ALTER_TABLE main t1 {} {}}} do_test 1.2 { set ::auth [list] execsql { ALTER TABLE t2 RENAME c TO ccc } set ::auth } {{SQLITE_ALTER_TABLE main t2 {} {}}} do_test 1.3 { set ::auth [list] execsql { ALTER TABLE t2 ADD COLUMN d } set ::auth } {{SQLITE_ALTER_TABLE main t2 {} {}}} proc xAuth {type args} { if {$type == "SQLITE_ALTER_TABLE"} { return SQLITE_DENY } return SQLITE_OK } do_test 2.1 { catchsql { ALTER TABLE t2 RENAME TO t3 } } {1 {not authorized}} do_test 2.2 { catchsql { ALTER TABLE t2 RENAME d TO ddd } } {1 {not authorized}} do_test 2.3 { catchsql { ALTER TABLE t2 ADD COLUMN e } } {1 {not authorized}} finish_test |
Added test/altercol.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 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 | # 2009 February 2 # # 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 that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... RENAME COLUMN ... TO". # # $Id: alter4.test,v 1.1 2009/02/02 18:03:22 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercol # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } # Drop all the tables and views in the 'main' database of database connect # [db]. Sort the objects by name before dropping them. # proc drop_all_tables_and_views {db} { set SQL { SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' ORDER BY 1 } foreach {z t} [db eval $SQL] { db eval "DROP $t $z" } } foreach {tn before after} { 1 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB)} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB)} 2 {CREATE TABLE t1(a INTEGER, x TEXT, "b" BLOB)} {CREATE TABLE t1(a INTEGER, x TEXT, "d" BLOB)} 3 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(b!=''))} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(d!=''))} 4 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK(t1.b!=''))} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK(t1.d!=''))} 5 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, CHECK( coalesce(b,c) ))} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, CHECK( coalesce(d,c) ))} 6 {CREATE TABLE t1(a INTEGER, "b"TEXT, c BLOB, CHECK( coalesce(b,c) ))} {CREATE TABLE t1(a INTEGER, "d"TEXT, c BLOB, CHECK( coalesce(d,c) ))} 7 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b, c))} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d, c))} 8 {CREATE TABLE t1(a INTEGER, b TEXT PRIMARY KEY, c BLOB)} {CREATE TABLE t1(a INTEGER, d TEXT PRIMARY KEY, c BLOB)} 9 {CREATE TABLE t1(a, b TEXT, c, PRIMARY KEY(a, b), UNIQUE("B"))} {CREATE TABLE t1(a, d TEXT, c, PRIMARY KEY(a, d), UNIQUE("d"))} 10 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(a, c)} {{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(a, c)}} 11 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b, c)} {{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d, c)}} 12 {CREATE TABLE t1(a, b, c); CREATE INDEX t1i ON t1(b+b+b+b, c) WHERE b>0} {{CREATE TABLE t1(a, d, c)} {CREATE INDEX t1i ON t1(d+d+d+d, c) WHERE d>0}} 13 {CREATE TABLE t1(a, b, c, FOREIGN KEY (b) REFERENCES t2)} {CREATE TABLE t1(a, d, c, FOREIGN KEY (d) REFERENCES t2)} 14 {CREATE TABLE t1(a INTEGER, b TEXT, c BLOB, PRIMARY KEY(b))} {CREATE TABLE t1(a INTEGER, d TEXT, c BLOB, PRIMARY KEY(d))} 15 {CREATE TABLE t1(a INTEGER, b INTEGER, c BLOB, PRIMARY KEY(b))} {CREATE TABLE t1(a INTEGER, d INTEGER, c BLOB, PRIMARY KEY(d))} 16 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB)} {CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB)} 17 {CREATE TABLE t1(a INTEGER, b INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (b) REFERENCES t2)} {CREATE TABLE t1(a INTEGER, d INTEGER PRIMARY KEY, c BLOB, FOREIGN KEY (d) REFERENCES t2)} } { reset_db do_execsql_test 1.$tn.0 $before do_execsql_test 1.$tn.1 { INSERT INTO t1 VALUES(1, 2, 3); } do_execsql_test 1.$tn.2 { ALTER TABLE t1 RENAME COLUMN b TO d; } do_execsql_test 1.$tn.3 { SELECT * FROM t1; } {1 2 3} if {[string first INDEX $before]>0} { set res $after } else { set res [list $after] } do_execsql_test 1.$tn.4 { SELECT sql FROM sqlite_master WHERE tbl_name='t1' AND sql!='' } $res } #------------------------------------------------------------------------- # do_execsql_test 2.0 { CREATE TABLE t3(a, b, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (b, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4); } sqlite3 db2 test.db do_execsql_test -db db2 2.1 { SELECT b FROM t3 } do_execsql_test 2.2 { ALTER TABLE t3 RENAME b TO biglongname; SELECT sql FROM sqlite_master WHERE name='t3'; } {{CREATE TABLE t3(a, biglongname, c, d, e, f, g, h, i, j, k, l, m, FOREIGN KEY (biglongname, c, d, e, f, g, h, i, j, k, l, m) REFERENCES t4)}} do_execsql_test -db db2 2.3 { SELECT biglongname FROM t3 } #------------------------------------------------------------------------- # do_execsql_test 3.0 { CREATE TABLE t4(x, y, z); CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.y<0 BEGIN SELECT x, y, z FROM t4; DELETE FROM t4 WHERE y=32; UPDATE t4 SET x=y+1, y=0 WHERE y=32; INSERT INTO t4(x, y, z) SELECT 4, 5, 6 WHERE 0; END; INSERT INTO t4 VALUES(3, 2, 1); } do_execsql_test 3.1 { ALTER TABLE t4 RENAME y TO abc; SELECT sql FROM sqlite_master WHERE name='t4'; } {{CREATE TABLE t4(x, abc, z)}} do_execsql_test 3.2 { SELECT * FROM t4; } {3 2 1} do_execsql_test 3.3 { INSERT INTO t4 VALUES(6, 5, 4); } {} do_execsql_test 3.4 { SELECT sql FROM sqlite_master WHERE type='trigger' } { {CREATE TRIGGER ttt AFTER INSERT ON t4 WHEN new.abc<0 BEGIN SELECT x, abc, z FROM t4; DELETE FROM t4 WHERE abc=32; UPDATE t4 SET x=abc+1, abc=0 WHERE abc=32; INSERT INTO t4(x, abc, z) SELECT 4, 5, 6 WHERE 0; END} } #------------------------------------------------------------------------- # do_execsql_test 4.0 { CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, d)); CREATE TABLE p1(c, d, PRIMARY KEY(c, d)); PRAGMA foreign_keys = 1; INSERT INTO p1 VALUES(1, 2); INSERT INTO p1 VALUES(3, 4); } do_execsql_test 4.1 { ALTER TABLE p1 RENAME d TO "silly name"; SELECT sql FROM sqlite_master WHERE name IN ('c1', 'p1'); } { {CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "silly name"))} {CREATE TABLE p1(c, "silly name", PRIMARY KEY(c, "silly name"))} } do_execsql_test 4.2 { INSERT INTO c1 VALUES(1, 2); } do_execsql_test 4.3 { CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1); } do_execsql_test 4.4 { ALTER TABLE p1 RENAME "silly name" TO reasonable; SELECT sql FROM sqlite_master WHERE name IN ('c1', 'c2', 'p1'); } { {CREATE TABLE c1(a, b, FOREIGN KEY (a, b) REFERENCES p1(c, "reasonable"))} {CREATE TABLE p1(c, "reasonable", PRIMARY KEY(c, "reasonable"))} {CREATE TABLE c2(a, b, FOREIGN KEY (a, b) REFERENCES p1)} } #------------------------------------------------------------------------- do_execsql_test 5.0 { CREATE TABLE t5(a, b, c); CREATE INDEX t5a ON t5(a); INSERT INTO t5 VALUES(1, 2, 3), (4, 5, 6); ANALYZE; } do_execsql_test 5.1 { ALTER TABLE t5 RENAME b TO big; SELECT big FROM t5; } {2 5} do_catchsql_test 6.1 { ALTER TABLE sqlite_stat1 RENAME tbl TO thetable; } {1 {table sqlite_stat1 may not be altered}} #------------------------------------------------------------------------- # do_execsql_test 6.0 { CREATE TABLE blob( rid INTEGER PRIMARY KEY, rcvid INTEGER, size INTEGER, uuid TEXT UNIQUE NOT NULL, content BLOB, CHECK( length(uuid)>=40 AND rid>0 ) ); } do_execsql_test 6.1 { ALTER TABLE "blob" RENAME COLUMN "rid" TO "a1"; } do_catchsql_test 6.2 { ALTER TABLE "blob" RENAME COLUMN "a1" TO [where]; } {0 {}} do_execsql_test 6.3 { SELECT "where" FROM blob; } {} #------------------------------------------------------------------------- # Triggers. # db close db2 close reset_db do_execsql_test 7.0 { CREATE TABLE c(x); INSERT INTO c VALUES(0); CREATE TABLE t6("col a", "col b", "col c"); CREATE TRIGGER zzz AFTER UPDATE OF "col a", "col c" ON t6 BEGIN UPDATE c SET x=x+1; END; } do_execsql_test 7.1.1 { INSERT INTO t6 VALUES(0, 0, 0); UPDATE t6 SET "col c" = 1; SELECT * FROM c; } {1} do_execsql_test 7.1.2 { ALTER TABLE t6 RENAME "col c" TO "col 3"; } do_execsql_test 7.1.3 { UPDATE t6 SET "col 3" = 0; SELECT * FROM c; } {2} #------------------------------------------------------------------------- # Views. # reset_db do_execsql_test 8.0 { CREATE TABLE a1(x INTEGER, y TEXT, z BLOB, PRIMARY KEY(x)); CREATE TABLE a2(a, b, c); CREATE VIEW v1 AS SELECT x, y, z FROM a1; } do_execsql_test 8.1 { ALTER TABLE a1 RENAME y TO yyy; SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW v1 AS SELECT x, yyy, z FROM a1}} do_execsql_test 8.2.1 { DROP VIEW v1; CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2; } {} do_execsql_test 8.2.2 { ALTER TABLE a1 RENAME x TO xxx; } do_execsql_test 8.2.3 { SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2}} do_execsql_test 8.3.1 { DROP TABLE a2; DROP VIEW v2; CREATE TABLE a2(a INTEGER PRIMARY KEY, b, c); CREATE VIEW v2 AS SELECT xxx, xxx+xxx, a, a+a FROM a1, a2; } {} do_execsql_test 8.3.2 { ALTER TABLE a1 RENAME xxx TO x; } do_execsql_test 8.3.3 { SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW v2 AS SELECT x, x+x, a, a+a FROM a1, a2}} do_execsql_test 8.4.0 { CREATE TABLE b1(a, b, c); CREATE TABLE b2(x, y, z); } do_execsql_test 8.4.1 { CREATE VIEW vvv AS SELECT c+c || coalesce(c, c) FROM b1, b2 WHERE x=c GROUP BY c HAVING c>0; ALTER TABLE b1 RENAME c TO "a;b"; SELECT sql FROM sqlite_master WHERE name='vvv'; } {{CREATE VIEW vvv AS SELECT "a;b"+"a;b" || coalesce("a;b", "a;b") FROM b1, b2 WHERE x="a;b" GROUP BY "a;b" HAVING "a;b">0}} do_execsql_test 8.4.2 { CREATE VIEW www AS SELECT b FROM b1 UNION ALL SELECT y FROM b2; ALTER TABLE b1 RENAME b TO bbb; SELECT sql FROM sqlite_master WHERE name='www'; } {{CREATE VIEW www AS SELECT bbb FROM b1 UNION ALL SELECT y FROM b2}} db collate nocase {string compare} do_execsql_test 8.4.3 { CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT x FROM b2 ORDER BY 1 COLLATE nocase; } do_execsql_test 8.4.4 { ALTER TABLE b2 RENAME x TO hello; SELECT sql FROM sqlite_master WHERE name='xxx'; } {{CREATE VIEW xxx AS SELECT a FROM b1 UNION SELECT hello FROM b2 ORDER BY 1 COLLATE nocase}} do_catchsql_test 8.4.5 { CREATE VIEW zzz AS SELECT george, ringo FROM b1; ALTER TABLE b1 RENAME a TO aaa; } {1 {error in view zzz: no such column: george}} #------------------------------------------------------------------------- # More triggers. # proc do_rename_column_test {tn old new lSchema} { for {set i 0} {$i < 2} {incr i} { drop_all_tables_and_views db set lSorted [list] foreach sql $lSchema { execsql $sql lappend lSorted [string trim $sql] } set lSorted [lsort $lSorted] do_execsql_test $tn.$i.1 { SELECT sql FROM sqlite_master WHERE sql!='' ORDER BY 1 } $lSorted if {$i==1} { db close sqlite3 db test.db } do_execsql_test $tn.$i.2 "ALTER TABLE t1 RENAME $old TO $new" do_execsql_test $tn.$i.3 { SELECT sql FROM sqlite_master ORDER BY 1 } [string map [list $old $new] $lSorted] } } foreach {tn old new lSchema} { 1 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE TRIGGER AFTER INSERT ON t1 BEGIN SELECT _x_ FROM t1; END } } 2 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE TABLE t2(c, d, e) } { CREATE TRIGGER ttt AFTER INSERT ON t2 BEGIN SELECT _x_ FROM t1; END } } 3 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) } { CREATE TABLE t2(c, d, e) } { CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN INSERT INTO t2 VALUES(new.a, new.b, new._x_); END } } 4 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) } { CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN INSERT INTO t1 VALUES(new.a, new.b, new._x_) ON CONFLICT (_x_) WHERE _x_>10 DO UPDATE SET _x_ = _x_+1; END } } 4 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_ INTEGER, PRIMARY KEY(_x_), CHECK(_x_>0)) } { CREATE TRIGGER ttt AFTER UPDATE ON t1 BEGIN INSERT INTO t1 VALUES(new.a, new.b, new._x_) ON CONFLICT (_x_) WHERE _x_>10 DO NOTHING; END } } } { do_rename_column_test 9.$tn $old $new $lSchema } #------------------------------------------------------------------------- # Test that views can be edited even if there are missing collation # sequences or user defined functions. # reset_db ifcapable vtab { foreach {tn old new lSchema} { 1 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE VIEW s1 AS SELECT a, b, _x_ FROM t1 WHERE _x_='abc' COLLATE xyz } } 2 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE scalar(_x_) } } 3 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE VIEW v1 AS SELECT a, b, _x_ FROM t1 WHERE _x_ = unicode(1, 2, 3) } } 4 _x_ _xxx_ { { CREATE TABLE t1(a, b, _x_) } { CREATE VIRTUAL TABLE e1 USING echo(t1) } } } { register_echo_module db do_rename_column_test 10.$tn $old $new $lSchema } #-------------------------------------------------------------------------- # Test that if a view or trigger refers to a virtual table for which the # module is not available, RENAME COLUMN cannot proceed. # reset_db register_echo_module db do_execsql_test 11.0 { CREATE TABLE x1(a, b, c); CREATE VIRTUAL TABLE e1 USING echo(x1); } db close sqlite3 db test.db do_execsql_test 11.1 { ALTER TABLE x1 RENAME b TO bbb; SELECT sql FROM sqlite_master; } { {CREATE TABLE x1(a, bbb, c)} {CREATE VIRTUAL TABLE e1 USING echo(x1)} } do_execsql_test 11.2 { CREATE VIEW v1 AS SELECT e1.*, x1.c FROM e1, x1; } do_catchsql_test 11.3 { ALTER TABLE x1 RENAME c TO ccc; } {1 {error in view v1: no such module: echo}} } #------------------------------------------------------------------------- # Test some error conditions: # # 1. Renaming a column of a system table, # 2. Renaming a column of a VIEW, # 3. Renaming a column of a virtual table. # 4. Renaming a column that does not exist. # 5. Renaming a column of a table that does not exist. # reset_db do_execsql_test 12.1.1 { CREATE TABLE t1(a, b); CREATE INDEX t1a ON t1(a); INSERT INTO t1 VALUES(1, 1), (2, 2), (3, 4); ANALYZE; } do_catchsql_test 12.1.2 { ALTER TABLE sqlite_stat1 RENAME idx TO theindex; } {1 {table sqlite_stat1 may not be altered}} do_execsql_test 12.1.3 { SELECT sql FROM sqlite_master WHERE tbl_name = 'sqlite_stat1' } {{CREATE TABLE sqlite_stat1(tbl,idx,stat)}} do_execsql_test 12.2.1 { CREATE VIEW v1 AS SELECT * FROM t1; CREATE VIEW v2(c, d) AS SELECT * FROM t1; } do_catchsql_test 12.2.2 { ALTER TABLE v1 RENAME a TO z; } {1 {cannot rename columns of view "v1"}} do_catchsql_test 12.2.3 { ALTER TABLE v2 RENAME c TO y; } {1 {cannot rename columns of view "v2"}} ifcapable fts5 { do_execsql_test 12.3.1 { CREATE VIRTUAL TABLE ft USING fts5(a, b, c); } do_catchsql_test 12.3.2 { ALTER TABLE ft RENAME a TO z; } {1 {cannot rename columns of virtual table "ft"}} } do_execsql_test 12.4.1 { CREATE TABLE t2(x, y, z); } do_catchsql_test 12.4.2 { ALTER TABLE t2 RENAME COLUMN a TO b; } {1 {no such column: "a"}} do_catchsql_test 12.5.1 { ALTER TABLE t3 RENAME COLUMN a TO b; } {1 {no such table: t3}} #------------------------------------------------------------------------- # Test the effect of some parse/resolve errors. # reset_db do_execsql_test 13.1.1 { CREATE TABLE x1(i INTEGER, t TEXT UNIQUE); CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN SELECT * FROM nosuchtable; END; } do_catchsql_test 13.1.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in trigger tr1: no such table: main.nosuchtable}} do_execsql_test 13.1.3 { DROP TRIGGER tr1; CREATE INDEX x1i ON x1(i); SELECT sql FROM sqlite_master WHERE name='x1i'; } {{CREATE INDEX x1i ON x1(i)}} do_execsql_test 13.1.4 { PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i'; } {} do_catchsql_test 13.1.5 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in index x1i: no such column: j}} do_execsql_test 13.1.6 { UPDATE sqlite_master SET sql = '' WHERE name='x1i'; } {} do_catchsql_test 13.1.7 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {database disk image is malformed}} do_execsql_test 13.1.8 { DELETE FROM sqlite_master WHERE name = 'x1i'; } do_execsql_test 13.2.0 { CREATE TABLE data(x UNIQUE, y, z); } foreach {tn trigger error} { 1 { CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN UPDATE data SET x=x+1 WHERE zzz=new.i; END; } {no such column: zzz} 2 { CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN INSERT INTO data(x, y) VALUES(new.i, new.t, 1) ON CONFLICT (x) DO UPDATE SET z=zz+1; END; } {no such column: zz} 3 { CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN INSERT INTO x1(i, t) VALUES(new.i+1, new.t||'1') ON CONFLICT (tttttt) DO UPDATE SET t=i+1; END; } {no such column: tttttt} 4 { CREATE TRIGGER tr1 AFTER INSERT ON x1 BEGIN INSERT INTO nosuchtable VALUES(new.i, new.t); END; } {no such table: main.nosuchtable} } { do_execsql_test 13.2.$tn.1 " DROP TRIGGER IF EXISTS tr1; $trigger " do_catchsql_test 13.2.$tn.2 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } "1 {error in trigger tr1: $error}" } #------------------------------------------------------------------------- # Passing invalid parameters directly to sqlite_rename_column(). # do_execsql_test 14.1 { CREATE TABLE ddd(sql, type, object, db, tbl, icol, znew, bquote); INSERT INTO ddd VALUES( 'CREATE TABLE x1(i INTEGER, t TEXT)', 'table', 'x1', 'main', 'x1', -1, 'zzz', 0 ), ( 'CREATE TABLE x1(i INTEGER, t TEXT)', 'table', 'x1', 'main', 'x1', 2, 'zzz', 0 ), ( 'CREATE TABLE x1(i INTEGER, t TEXT)', 'table', 'x1', 'main', 'notable', 0, 'zzz', 0 ), ( 'CREATE TABLE x1(i INTEGER, t TEXT)', 'table', 'x1', 'main', 'ddd', -1, 'zzz', 0 ); } {} do_execsql_test 14.2 { SELECT sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0) FROM ddd; } {{} {} {} {}} #------------------------------------------------------------------------- # reset_db do_execsql_test 15.0 { CREATE TABLE xxx(a, b, c); SELECT a AS d FROM xxx WHERE d=0; } do_execsql_test 15.1 { CREATE VIEW vvv AS SELECT a AS d FROM xxx WHERE d=0; ALTER TABLE xxx RENAME a TO xyz; } do_execsql_test 15.2 { SELECT sql FROM sqlite_master WHERE type='view'; } {{CREATE VIEW vvv AS SELECT xyz AS d FROM xxx WHERE d=0}} #------------------------------------------------------------------------- # do_execsql_test 16.1.0 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(d,e,f); INSERT INTO t1 VALUES(1,2,3); INSERT INTO t2 VALUES(4,5,6); CREATE VIEW v4 AS SELECT a, d FROM t1, t2; SELECT * FROM v4; } {1 4} do_catchsql_test 16.1.1 { ALTER TABLE t2 RENAME d TO a; } {1 {error in view v4 after rename: ambiguous column name: a}} do_execsql_test 16.1.2 { SELECT * FROM v4; } {1 4} do_execsql_test 16.1.3 { CREATE UNIQUE INDEX t2d ON t2(d); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.a, new.b, new.c) ON CONFLICT(d) DO UPDATE SET f = excluded.f; END; } do_execsql_test 16.1.4 { INSERT INTO t1 VALUES(4, 8, 456); SELECT * FROM t2; } {4 5 456} do_execsql_test 16.1.5 { ALTER TABLE t2 RENAME COLUMN f TO "big f"; INSERT INTO t1 VALUES(4, 0, 20456); SELECT * FROM t2; } {4 5 20456} do_execsql_test 16.1.6 { ALTER TABLE t1 RENAME COLUMN c TO "big c"; INSERT INTO t1 VALUES(4, 0, 0); SELECT * FROM t2; } {4 5 0} do_execsql_test 16.2.1 { CREATE VIEW temp.v5 AS SELECT "big c" FROM t1; SELECT * FROM v5; } {3 456 20456 0} do_execsql_test 16.2.2 { ALTER TABLE t1 RENAME COLUMN "big c" TO reallybigc; } {} do_execsql_test 16.2.3 { SELECT * FROM v5; } {3 456 20456 0} #------------------------------------------------------------------------- # do_execsql_test 17.0 { CREATE TABLE u7(x, y, z); CREATE TRIGGER u7t AFTER INSERT ON u7 BEGIN INSERT INTO u8 VALUES(new.x, new.y, new.z); END; } {} do_catchsql_test 17.1 { ALTER TABLE u7 RENAME x TO xxx; } {1 {error in trigger u7t: no such table: main.u8}} do_execsql_test 17.2 { CREATE TEMP TABLE uu7(x, y, z); CREATE TRIGGER uu7t AFTER INSERT ON uu7 BEGIN INSERT INTO u8 VALUES(new.x, new.y, new.z); END; } {} do_catchsql_test 17.3 { ALTER TABLE uu7 RENAME x TO xxx; } {1 {error in trigger uu7t: no such table: u8}} reset_db forcedelete test.db2 do_execsql_test 18.0 { ATTACH 'test.db2' AS aux; CREATE TABLE t1(a); CREATE TABLE aux.log(v); CREATE TEMP TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO log VALUES(new.a); END; INSERT INTO t1 VALUES(111); SELECT v FROM log; } {111} do_execsql_test 18.1 { ALTER TABLE t1 RENAME a TO b; } reset_db do_execsql_test 19.0 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.a) FROM t1, t2 WHERE t1.b=t2.d; } do_execsql_test 19.1 { ALTER TABLE t1 RENAME a TO f; SELECT sql FROM sqlite_master WHERE name = 'v2'; } { {CREATE VIEW v2(e) AS SELECT coalesce(t2.c,t1.f) FROM t1, t2 WHERE t1.b=t2.d} } finish_test |
Added test/alterlegacy.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 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 | # 2018 September 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. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix alterlegacy # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE t1(a, b, CHECK(t1.a != t1.b)); CREATE TABLE t2(a, b); CREATE INDEX t2expr ON t2(a) WHERE t2.b>0; } do_execsql_test 1.1 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } # Legacy behavior is to corrupt the schema in this case, as the table name in # the CHECK constraint is incorrect after "t1" is renamed. This version is # slightly different - it rejects the change and rolls back the transaction. do_catchsql_test 1.2 { ALTER TABLE t1 RENAME TO t1new; } {1 {no such column: t1.a}} do_execsql_test 1.3 { CREATE TABLE t3(c, d); ALTER TABLE t3 RENAME TO t3new; DROP TABLE t3new; } do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } do_catchsql_test 1.3 { ALTER TABLE t2 RENAME TO t2new; } {1 {no such column: t2.b}} do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } #------------------------------------------------------------------------- reset_db ifcapable vtab { register_echo_module db do_execsql_test 2.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE abc(a, b, c); INSERT INTO abc VALUES(1, 2, 3); CREATE VIRTUAL TABLE eee USING echo('abc'); SELECT * FROM eee; } {1 2 3} do_execsql_test 2.1 { ALTER TABLE eee RENAME TO fff; SELECT * FROM fff; } {1 2 3} db close sqlite3 db test.db do_catchsql_test 2.2 { ALTER TABLE fff RENAME TO ggg; } {1 {no such module: echo}} } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE txx(a, b, c); INSERT INTO txx VALUES(1, 2, 3); CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx; CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one; CREATE VIEW temp.ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx; } do_execsql_test 3.1.1 { SELECT * FROM vvv; } {1 2 3} do_execsql_test 3.1.2a { ALTER TABLE txx RENAME TO "t xx"; } do_catchsql_test 3.1.2b { SELECT * FROM vvv; } {1 {no such table: main.txx}} do_execsql_test 3.1.3 { SELECT sql FROM sqlite_master WHERE name='vvv'; } {{CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx}} do_catchsql_test 3.2.1 { SELECT * FROM uuu; } {1 {no such table: main.txx}} do_execsql_test 3.2.2 { SELECT sql FROM sqlite_master WHERE name='uuu';; } {{CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one}} do_catchsql_test 3.3.1 { SELECT * FROM ttt; } {1 {no such table: txx}} do_execsql_test 3.3.2 { SELECT sql FROM sqlite_temp_master WHERE name='ttt'; } {{CREATE VIEW ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { PRAGMA legacy_alter_table = 1; CREATE table t1(x, y); CREATE table t2(a, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT t1.x, * FROM t1, t2; INSERT INTO t2 VALUES(new.x, new.y); END; } do_execsql_test 4.1 { INSERT INTO t1 VALUES(1, 1); ALTER TABLE t1 RENAME TO t11; } do_catchsql_test 4.1a { INSERT INTO t11 VALUES(2, 2); } {1 {no such table: main.t1}} do_execsql_test 4.1b { ALTER TABLE t11 RENAME TO t1; ALTER TABLE t2 RENAME TO t22; } do_catchsql_test 4.1c { INSERT INTO t1 VALUES(3, 3); } {1 {no such table: main.t2}} proc squish {a} { string trim [regsub -all {[[:space:]][[:space:]]*} $a { }] } db func squish squish do_test 4.2 { execsql { SELECT squish(sql) FROM sqlite_master WHERE name = 'tr1' } } [list [squish { CREATE TRIGGER tr1 AFTER INSERT ON "t1" BEGIN SELECT t1.x, * FROM t1, t2; INSERT INTO t2 VALUES(new.x, new.y); END }]] #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE t9(a, b, c); CREATE TABLE t10(a, b, c); CREATE TEMP TABLE t9(a, b, c); CREATE TRIGGER temp.t9t AFTER INSERT ON temp.t9 BEGIN INSERT INTO t10 VALUES(new.a, new.b, new.c); END; INSERT INTO temp.t9 VALUES(1, 2, 3); SELECT * FROM t10; } {1 2 3} do_execsql_test 5.1 { ALTER TABLE temp.t9 RENAME TO 't1234567890' } do_execsql_test 5.2 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(3, 4); CREATE VIEW v AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2; SELECT * FROM v; } {1 2 3 4} do_execsql_test 5.3 { ALTER TABLE t2 RENAME TO one; } {} do_catchsql_test 5.4 { SELECT * FROM v } {1 {no such table: main.t2}} do_execsql_test 5.5 { ALTER TABLE one RENAME TO t2; DROP VIEW v; CREATE VIEW temp.vv AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2; SELECT * FROM vv; } {1 2 3 4} do_execsql_test 5.6 { ALTER TABLE t2 RENAME TO one; } {} do_catchsql_test 5.7 { SELECT * FROM vv } {1 {no such table: t2}} #------------------------------------------------------------------------- ifcapable vtab { register_tcl_module db proc tcl_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } } return {} } do_execsql_test 6.0 { CREATE VIRTUAL TABLE x1 USING tcl(tcl_command); } do_execsql_test 6.1 { ALTER TABLE x1 RENAME TO x2; SELECT sql FROM sqlite_master WHERE name = 'x2' } {{CREATE VIRTUAL TABLE "x2" USING tcl(tcl_command)}} do_execsql_test 7.1 { CREATE TABLE ddd(db, sql, zOld, zNew, bTemp); INSERT INTO ddd VALUES( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', 'ddd', NULL, 0 ), ( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0 ), ( 'main', NULL, 'ddd', 'eee', 0 ); } {} } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 8.1 { PRAGMA legacy_alter_table = 1; ATTACH 'test.db2' AS aux; PRAGMA foreign_keys = on; CREATE TABLE aux.p1(a INTEGER PRIMARY KEY, b); CREATE TABLE aux.c1(x INTEGER PRIMARY KEY, y REFERENCES p1(a)); INSERT INTO aux.p1 VALUES(1, 1); INSERT INTO aux.p1 VALUES(2, 2); INSERT INTO aux.c1 VALUES(NULL, 2); CREATE TABLE aux.c2(x INTEGER PRIMARY KEY, y REFERENCES c1(a)); } do_execsql_test 8.2 { ALTER TABLE aux.p1 RENAME TO ppp; } do_execsql_test 8.2 { INSERT INTO aux.c1 VALUES(NULL, 1); SELECT sql FROM aux.sqlite_master WHERE name = 'c1'; } {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}} reset_db do_execsql_test 9.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT * FROM t2; } do_execsql_test 9.1 { ALTER TABLE t1 RENAME TO t3; } {} do_execsql_test 9.1b { ALTER TABLE t3 RENAME TO t1; } {} do_execsql_test 9.2 { DROP VIEW v1; CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.a); END; } do_execsql_test 9.3 { ALTER TABLE t1 RENAME TO t3; } {} forcedelete test.db2 do_execsql_test 9.4 { ALTER TABLE t3 RENAME TO t1; DROP TRIGGER tr; ATTACH 'test.db2' AS aux; CREATE TRIGGER tr AFTER INSERT ON t1 WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END; CREATE TABLE aux.t1(x); CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END; } do_execsql_test 9.5 { ALTER TABLE main.t1 RENAME TO t3; } do_execsql_test 9.6 { SELECT sql FROM sqlite_temp_master; SELECT sql FROM sqlite_master WHERE type='trigger'; } { {CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END} {CREATE TRIGGER tr AFTER INSERT ON "t3" WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END} } #------------------------------------------------------------------------- reset_db ifcapable fts5 { do_execsql_test 10.0 { PRAGMA legacy_alter_table = 1; CREATE VIRTUAL TABLE fff USING fts5(x, y, z); } do_execsql_test 10.1 { BEGIN; INSERT INTO fff VALUES('a', 'b', 'c'); ALTER TABLE fff RENAME TO ggg; COMMIT; } do_execsql_test 10.2 { SELECT * FROM ggg; } {a b c} } #------------------------------------------------------------------------- reset_db forcedelete test.db2 db func trigger trigger set ::trigger [list] proc trigger {args} { lappend ::trigger $args } do_execsql_test 11.0 { PRAGMA legacy_alter_table = 1; ATTACH 'test.db2' AS aux; CREATE TABLE aux.t1(a, b, c); CREATE TABLE main.t1(a, b, c); CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT trigger(new.a, new.b, new.c); END; } do_execsql_test 11.1 { INSERT INTO main.t1 VALUES(1, 2, 3); INSERT INTO aux.t1 VALUES(4, 5, 6); } do_test 11.2 { set ::trigger } {{4 5 6}} do_execsql_test 11.3 { SELECT name, tbl_name FROM sqlite_temp_master; } {tr t1} do_execsql_test 11.4 { ALTER TABLE main.t1 RENAME TO t2; SELECT name, tbl_name FROM sqlite_temp_master; } {tr t1} do_execsql_test 11.5 { ALTER TABLE aux.t1 RENAME TO t2; SELECT name, tbl_name FROM sqlite_temp_master; } {tr t2} do_execsql_test 11.6 { INSERT INTO aux.t2 VALUES(7, 8, 9); } do_test 11.7 { set ::trigger } {{4 5 6} {7 8 9}} #------------------------------------------------------------------------- reset_db do_execsql_test 12.0 { PRAGMA legacy_alter_table = 1; CREATE TABLE t1(a); CREATE TABLE t2(w); CREATE TRIGGER temp.r1 AFTER INSERT ON main.t2 BEGIN INSERT INTO t1(a) VALUES(new.w); END; CREATE TEMP TABLE t2(x); } do_execsql_test 12.1 { ALTER TABLE main.t2 RENAME TO t3; } do_execsql_test 12.2 { INSERT INTO t3 VALUES('WWW'); SELECT * FROM t1; } {WWW} #------------------------------------------------------------------------- reset_db ifcapable rtree { do_execsql_test 14.0 { PRAGMA legacy_alter_table = 1; CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy); CREATE TABLE "mytable" ( "fid" INTEGER PRIMARY KEY, "geom" BLOB); CREATE TRIGGER tr1 AFTER UPDATE OF "geom" ON "mytable" WHEN OLD."fid" = NEW."fid" AND NEW."geom" IS NULL BEGIN DELETE FROM rt WHERE id = OLD."fid"; END; INSERT INTO mytable VALUES(1, X'abcd'); } do_execsql_test 14.1 { UPDATE mytable SET geom = X'1234' } do_execsql_test 14.2 { ALTER TABLE mytable RENAME TO mytable_renamed; } do_execsql_test 14.3 { CREATE TRIGGER tr2 AFTER INSERT ON mytable_renamed BEGIN DELETE FROM rt WHERE id=(SELECT min(id) FROM rt); END; } do_execsql_test 14.4 { ALTER TABLE mytable_renamed RENAME TO mytable2; } } reset_db do_execsql_test 14.5 { PRAGMA legacy_alter_table = 1; CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER xyz AFTER INSERT ON t1 BEGIN SELECT a, b FROM v1; END; } do_execsql_test 14.6 { ALTER TABLE t1 RENAME TO tt1; } finish_test |
Changes to test/altermalloc.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # $Id: altermalloc.test,v 1.10 2008/10/30 17:21:13 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # $Id: altermalloc.test,v 1.10 2008/10/30 17:21:13 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } source $testdir/malloc_common.tcl do_malloc_test altermalloc-1 -tclprep { |
︙ | ︙ |
Added test/altermalloc2.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 | # 2018 August 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. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set testprefix altermalloc2 # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(abcd, efgh); } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } catch {db close} forcedelete test.db sqlite3 db test.db do_execsql_test 2.0 { PRAGMA encoding = 'utf-16'; CREATE TABLE t1(abcd, efgh); } faultsim_save_and_close do_faultsim_test 2 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } reset_db do_execsql_test 3.0 { CREATE TABLE t1(abcd, efgh); CREATE VIEW v1 AS SELECT * FROM t1 WHERE abcd>efgh; } faultsim_save_and_close do_faultsim_test 3 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } reset_db do_execsql_test 4.0 { CREATE TABLE rr(a, b); CREATE VIEW vv AS SELECT * FROM rr; CREATE TRIGGER vv1 INSTEAD OF INSERT ON vv BEGIN SELECT 1, 2, 3; END; CREATE TRIGGER tr1 AFTER INSERT ON rr BEGIN INSERT INTO vv VALUES(new.a, new.b); END; } {} faultsim_save_and_close do_faultsim_test 4 -faults oom-* -prep { faultsim_restore_and_reopen execsql { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE rr RENAME a TO c; } } -test { faultsim_test_result {0 {}} } finish_test |
Added test/altertab.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 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 | # 2018 August 24 # # 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 altertab # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b, CHECK(t1.a != t1.b)); CREATE TABLE t2(a, b); CREATE INDEX t2expr ON t2(a) WHERE t2.b>0; } do_execsql_test 1.1 { SELECT sql FROM sqlite_master } { {CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } do_execsql_test 1.2 { ALTER TABLE t1 RENAME TO t1new; } do_execsql_test 1.3 { CREATE TABLE t3(c, d); ALTER TABLE t3 RENAME TO t3new; DROP TABLE t3new; } do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))} {CREATE TABLE t2(a, b)} {CREATE INDEX t2expr ON t2(a) WHERE t2.b>0} } do_execsql_test 1.3 { ALTER TABLE t2 RENAME TO t2new; } do_execsql_test 1.4 { SELECT sql FROM sqlite_master } { {CREATE TABLE "t1new"(a, b, CHECK("t1new".a != "t1new".b))} {CREATE TABLE "t2new"(a, b)} {CREATE INDEX t2expr ON "t2new"(a) WHERE "t2new".b>0} } #------------------------------------------------------------------------- reset_db ifcapable vtab { register_echo_module db do_execsql_test 2.0 { CREATE TABLE abc(a, b, c); INSERT INTO abc VALUES(1, 2, 3); CREATE VIRTUAL TABLE eee USING echo('abc'); SELECT * FROM eee; } {1 2 3} do_execsql_test 2.1 { ALTER TABLE eee RENAME TO fff; SELECT * FROM fff; } {1 2 3} db close sqlite3 db test.db do_catchsql_test 2.2 { ALTER TABLE fff RENAME TO ggg; } {1 {no such module: echo}} } #------------------------------------------------------------------------- reset_db do_execsql_test 3.0 { CREATE TABLE txx(a, b, c); INSERT INTO txx VALUES(1, 2, 3); CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx; CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one; CREATE VIEW temp.ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx; } do_execsql_test 3.1.1 { SELECT * FROM vvv; } {1 2 3} do_execsql_test 3.1.2 { ALTER TABLE txx RENAME TO "t xx"; SELECT * FROM vvv; } {1 2 3} do_execsql_test 3.1.3 { SELECT sql FROM sqlite_master WHERE name='vvv'; } {{CREATE VIEW vvv AS SELECT main."t xx".a, "t xx".b, c FROM "t xx"}} do_execsql_test 3.2.1 { SELECT * FROM uuu; } {1 2 3} do_execsql_test 3.2.2 { SELECT sql FROM sqlite_master WHERE name='uuu';; } {{CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM "t xx" AS one}} do_execsql_test 3.3.1 { SELECT * FROM ttt; } {1 2 2 1} do_execsql_test 3.3.2 { SELECT sql FROM sqlite_temp_master WHERE name='ttt'; } {{CREATE VIEW ttt AS SELECT main."t xx".a, "t xx".b, one.b, main.one.a FROM "t xx" AS one, "t xx"}} #------------------------------------------------------------------------- reset_db do_execsql_test 4.0 { CREATE table t1(x, y); CREATE table t2(a, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT t1.x, * FROM t1, t2; INSERT INTO t2 VALUES(new.x, new.y); END; } do_execsql_test 4.1 { INSERT INTO t1 VALUES(1, 1); ALTER TABLE t1 RENAME TO t11; INSERT INTO t11 VALUES(2, 2); ALTER TABLE t2 RENAME TO t22; INSERT INTO t11 VALUES(3, 3); } proc squish {a} { string trim [regsub -all {[[:space:]][[:space:]]*} $a { }] } db func squish squish do_test 4.2 { execsql { SELECT squish(sql) FROM sqlite_master WHERE name = 'tr1' } } [list [squish { CREATE TRIGGER tr1 AFTER INSERT ON "t11" BEGIN SELECT "t11".x, * FROM "t11", "t22"; INSERT INTO "t22" VALUES(new.x, new.y); END }]] #------------------------------------------------------------------------- reset_db do_execsql_test 5.0 { CREATE TABLE t9(a, b, c); CREATE TABLE t10(a, b, c); CREATE TEMP TABLE t9(a, b, c); CREATE TRIGGER temp.t9t AFTER INSERT ON temp.t9 BEGIN INSERT INTO t10 VALUES(new.a, new.b, new.c); END; INSERT INTO temp.t9 VALUES(1, 2, 3); SELECT * FROM t10; } {1 2 3} do_execsql_test 5.1 { ALTER TABLE temp.t9 RENAME TO 't1234567890' } do_execsql_test 5.2 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(3, 4); CREATE VIEW v AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2; SELECT * FROM v; } {1 2 3 4} do_catchsql_test 5.3 { ALTER TABLE t2 RENAME TO one; } {1 {error in view v after rename: ambiguous column name: one.a}} do_execsql_test 5.4 { SELECT * FROM v } {1 2 3 4} do_execsql_test 5.5 { DROP VIEW v; CREATE VIEW temp.vv AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2; SELECT * FROM vv; } {1 2 3 4} do_catchsql_test 5.6 { ALTER TABLE t2 RENAME TO one; } {1 {error in view vv after rename: ambiguous column name: one.a}} #------------------------------------------------------------------------- ifcapable vtab { register_tcl_module db proc tcl_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } } return {} } do_execsql_test 6.0 { CREATE VIRTUAL TABLE x1 USING tcl(tcl_command); } do_execsql_test 6.1 { ALTER TABLE x1 RENAME TO x2; SELECT sql FROM sqlite_master WHERE name = 'x2' } {{CREATE VIRTUAL TABLE "x2" USING tcl(tcl_command)}} do_execsql_test 7.1 { CREATE TABLE ddd(db, sql, zOld, zNew, bTemp); INSERT INTO ddd VALUES( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', 'ddd', NULL, 0 ), ( 'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0 ), ( 'main', NULL, 'ddd', 'eee', 0 ); } {} do_execsql_test 7.2 { SELECT sqlite_rename_table(db, 0, 0, sql, zOld, zNew, bTemp) FROM ddd; } {{} {} {}} } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 8.1 { ATTACH 'test.db2' AS aux; PRAGMA foreign_keys = on; CREATE TABLE aux.p1(a INTEGER PRIMARY KEY, b); CREATE TABLE aux.c1(x INTEGER PRIMARY KEY, y REFERENCES p1(a)); INSERT INTO aux.p1 VALUES(1, 1); INSERT INTO aux.p1 VALUES(2, 2); INSERT INTO aux.c1 VALUES(NULL, 2); CREATE TABLE aux.c2(x INTEGER PRIMARY KEY, y REFERENCES c1(a)); } do_execsql_test 8.2 { ALTER TABLE aux.p1 RENAME TO ppp; } do_execsql_test 8.2 { INSERT INTO aux.c1 VALUES(NULL, 1); SELECT sql FROM aux.sqlite_master WHERE name = 'c1'; } {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}} reset_db do_execsql_test 9.0 { CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT * FROM t2; } do_catchsql_test 9.1 { ALTER TABLE t1 RENAME TO t3; } {1 {error in view v1: no such table: main.t2}} do_execsql_test 9.2 { DROP VIEW v1; CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.a); END; } do_catchsql_test 9.3 { ALTER TABLE t1 RENAME TO t3; } {1 {error in trigger tr: no such table: main.t2}} forcedelete test.db2 do_execsql_test 9.4 { DROP TRIGGER tr; ATTACH 'test.db2' AS aux; CREATE TRIGGER tr AFTER INSERT ON t1 WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END; CREATE TABLE aux.t1(x); CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END; } do_execsql_test 9.5 { ALTER TABLE main.t1 RENAME TO t3; } do_execsql_test 9.6 { SELECT sql FROM sqlite_temp_master; SELECT sql FROM sqlite_master WHERE type='trigger'; } { {CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END} {CREATE TRIGGER tr AFTER INSERT ON "t3" WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END} } #------------------------------------------------------------------------- reset_db ifcapable fts5 { do_execsql_test 10.0 { CREATE VIRTUAL TABLE fff USING fts5(x, y, z); } do_execsql_test 10.1 { BEGIN; INSERT INTO fff VALUES('a', 'b', 'c'); ALTER TABLE fff RENAME TO ggg; COMMIT; } do_execsql_test 10.2 { SELECT * FROM ggg; } {a b c} } #------------------------------------------------------------------------- reset_db forcedelete test.db2 db func trigger trigger set ::trigger [list] proc trigger {args} { lappend ::trigger $args } do_execsql_test 11.0 { ATTACH 'test.db2' AS aux; CREATE TABLE aux.t1(a, b, c); CREATE TABLE main.t1(a, b, c); CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT trigger(new.a, new.b, new.c); END; } do_execsql_test 11.1 { INSERT INTO main.t1 VALUES(1, 2, 3); INSERT INTO aux.t1 VALUES(4, 5, 6); } do_test 11.2 { set ::trigger } {{4 5 6}} do_execsql_test 11.3 { SELECT name, tbl_name FROM sqlite_temp_master; } {tr t1} do_execsql_test 11.4 { ALTER TABLE main.t1 RENAME TO t2; SELECT name, tbl_name FROM sqlite_temp_master; } {tr t1} do_execsql_test 11.5 { ALTER TABLE aux.t1 RENAME TO t2; SELECT name, tbl_name FROM sqlite_temp_master; } {tr t2} do_execsql_test 11.6 { INSERT INTO aux.t2 VALUES(7, 8, 9); } do_test 11.7 { set ::trigger } {{4 5 6} {7 8 9}} #------------------------------------------------------------------------- reset_db do_execsql_test 12.0 { CREATE TABLE t1(a); CREATE TABLE t2(w); CREATE TRIGGER temp.r1 AFTER INSERT ON main.t2 BEGIN INSERT INTO t1(a) VALUES(new.w); END; CREATE TEMP TABLE t2(x); } do_execsql_test 12.1 { ALTER TABLE main.t2 RENAME TO t3; } do_execsql_test 12.2 { INSERT INTO t3 VALUES('WWW'); SELECT * FROM t1; } {WWW} #------------------------------------------------------------------------- reset_db do_execsql_test 13.0 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b); CREATE TABLE log(c); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO log SELECT y FROM t1, t2; END; } do_execsql_test 13.1 { INSERT INTO t1 VALUES(1, 2); } do_catchsql_test 13.2 { ALTER TABLE t2 RENAME b TO y; } {1 {error in trigger tr1 after rename: ambiguous column name: y}} #------------------------------------------------------------------------- reset_db ifcapable rtree { do_execsql_test 14.0 { CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy); CREATE TABLE "mytable" ( "fid" INTEGER PRIMARY KEY, "geom" BLOB); CREATE TRIGGER tr1 AFTER UPDATE OF "geom" ON "mytable" WHEN OLD."fid" = NEW."fid" AND NEW."geom" IS NULL BEGIN DELETE FROM rt WHERE id = OLD."fid"; END; INSERT INTO mytable VALUES(1, X'abcd'); } do_execsql_test 14.1 { UPDATE mytable SET geom = X'1234' } do_execsql_test 14.2 { ALTER TABLE mytable RENAME TO mytable_renamed; } do_execsql_test 14.3 { CREATE TRIGGER tr2 AFTER INSERT ON mytable_renamed BEGIN DELETE FROM rt WHERE id=(SELECT min(id) FROM rt); END; } do_execsql_test 14.4 { ALTER TABLE mytable_renamed RENAME TO mytable2; } } reset_db do_execsql_test 14.5 { CREATE TABLE t1(a, b, c); CREATE VIEW v1 AS SELECT * FROM t1; CREATE TRIGGER xyz AFTER INSERT ON t1 BEGIN SELECT a, b FROM v1; END; } do_execsql_test 14.6 { ALTER TABLE t1 RENAME TO tt1; } finish_test |
Added test/altertab2.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 | # 2018 September 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. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altertab # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } ifcapable fts5 { do_execsql_test 1.0 { CREATE TABLE rr(a, b); CREATE VIRTUAL TABLE ff USING fts5(a, b); CREATE TRIGGER tr1 AFTER INSERT ON rr BEGIN INSERT INTO ff VALUES(new.a, new.b); END; INSERT INTO rr VALUES('hello', 'world'); SELECT * FROM ff; } {hello world} do_execsql_test 1.1 { ALTER TABLE ff RENAME TO ffff; } do_execsql_test 1.2 { INSERT INTO rr VALUES('in', 'tcl'); SELECT * FROM ffff; } {hello world in tcl} } finish_test |
Added test/atomic2.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 | # 2018-07-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 if an IO error is encountered # as part of an atomic F2FS commit, an attempt is made to commit the # transaction using a legacy journal commit. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix atomic2 db close if {[atomic_batch_write test.db]==0} { puts "No f2fs atomic-batch-write support. Skipping tests..." finish_test return } reset_db do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE INDEX i1x ON t1(x); CREATE INDEX i2x ON t1(y); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; } set setup [list \ -injectstart at_injectstart \ -injectstop at_injectstop \ ] set ::at_fail 0 set ::at_nfail 0 proc at_injectstart {iFail} { set ::at_fail $iFail set ::at_nfail 0 } proc at_injectstop {} { set ::at_fail 0 return $::at_nfail } proc at_vfs_callback {method file z args} { if {$::at_fail>0} { incr ::at_fail -1 if {$::at_fail==0} { incr ::at_nfail return SQLITE_IOERR } elseif {$method=="xFileControl" && $z=="COMMIT_ATOMIC_WRITE"} { set ::at_fail 0 } } return SQLITE_OK } testvfs tvfs -default 1 tvfs script at_vfs_callback tvfs filter {xFileControl xWrite} faultsim_save_and_close do_one_faultsim_test 2.0 {*}$setup -prep { faultsim_restore_and_reopen } -body { execsql { WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s; } } -test { faultsim_test_result {0 {}} set res [execsql {SELECT count(*) FROM t1; PRAGMA integrity_check}] if {$res!="200 ok"} { error "expected {200 ok}, got $res" } } db close tvfs delete finish_test |
Added test/atrc.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 | /* ** This program generates a script that stresses the ALTER TABLE statement. ** Compile like this: ** ** gcc -g -c sqlite3.c ** gcc -g -o atrc atrc.c sqlite3.o -ldl -lpthread ** ** Run the program this way: ** ** ./atrc DATABASE | ./sqlite3 DATABASE ** ** This program "atrc" generates a script that can be fed into an ordinary ** command-line shell. The script performs many ALTER TABLE statements, ** runs ".schema --indent" and "PRAGMA integrity_check;", does more ** ALTER TABLE statements to restore the original schema, and then ** runs "PRAGMA integrity_check" again. Every table and column has its ** name changed. The entire script is contained within BEGIN...ROLLBACK ** so that no changes are ever actually made to the database. */ #include "sqlite3.h" #include <stdio.h> /* ** Generate the text of ALTER TABLE statements that will rename ** every column in table zTable to a generic name composed from ** zColPrefix and a sequential number. The generated text is ** appended pConvert. If pUndo is not NULL, then SQL text that ** will undo the change is appended to pUndo. ** ** The table to be converted must be in the "main" schema. */ int rename_all_columns_of_table( sqlite3 *db, /* Database connection */ const char *zTab, /* Table whose columns should all be renamed */ const char *zColPrefix, /* Prefix for new column names */ sqlite3_str *pConvert, /* Append ALTER TABLE statements here */ sqlite3_str *pUndo /* SQL to undo the change, if not NULL */ ){ sqlite3_stmt *pStmt; int rc; int cnt = 0; rc = sqlite3_prepare_v2(db, "SELECT name FROM pragma_table_info(?1);", -1, &pStmt, 0); if( rc ) return rc; sqlite3_bind_text(pStmt, 1, zTab, -1, SQLITE_STATIC); while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zCol = (const char*)sqlite3_column_text(pStmt, 0); cnt++; sqlite3_str_appendf(pConvert, "ALTER TABLE \"%w\" RENAME COLUMN \"%w\" TO \"%w%d\";\n", zTab, zCol, zColPrefix, cnt ); if( pUndo ){ sqlite3_str_appendf(pUndo, "ALTER TABLE \"%w\" RENAME COLUMN \"%w%d\" TO \"%w\";\n", zTab, zColPrefix, cnt, zCol ); } } sqlite3_finalize(pStmt); return SQLITE_OK; } /* Rename all tables and their columns in the main database */ int rename_all_tables( sqlite3 *db, /* Database connection */ sqlite3_str *pConvert, /* Append SQL to do the rename here */ sqlite3_str *pUndo /* Append SQL to undo the rename here */ ){ sqlite3_stmt *pStmt; int rc; int cnt = 0; rc = sqlite3_prepare_v2(db, "SELECT name FROM sqlite_master WHERE type='table'" " AND name NOT LIKE 'sqlite_%';", -1, &pStmt, 0); if( rc ) return rc; while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zTab = (const char*)sqlite3_column_text(pStmt, 0); char *zNewTab; char zPrefix[2]; zPrefix[0] = (cnt%26) + 'a'; zPrefix[1] = 0; zNewTab = sqlite3_mprintf("tx%d", ++cnt); if( pUndo ){ sqlite3_str_appendf(pUndo, "ALTER TABLE \"%s\" RENAME TO \"%w\";\n", zNewTab, zTab ); } rename_all_columns_of_table(db, zTab, zPrefix, pConvert, pUndo); sqlite3_str_appendf(pConvert, "ALTER TABLE \"%w\" RENAME TO \"%s\";\n", zTab, zNewTab ); sqlite3_free(zNewTab); } sqlite3_finalize(pStmt); return SQLITE_OK; } /* ** Generate a script that does this: ** ** (1) Start a transaction ** (2) Rename all tables and columns to use generic names. ** (3) Print the schema after this rename ** (4) Run pragma integrity_check ** (5) Do more ALTER TABLE statements to change the names back ** (6) Run pragma integrity_check again ** (7) Rollback the transaction */ int main(int argc, char **argv){ sqlite3 *db; int rc; sqlite3_str *pConvert; sqlite3_str *pUndo; char *zDbName; char *zSql1, *zSql2; if( argc!=2 ){ fprintf(stderr, "Usage: %s DATABASE\n", argv[0]); } zDbName = argv[1]; rc = sqlite3_open(zDbName, &db); if( rc ){ fprintf(stderr, "sqlite3_open() returns %d\n", rc); return 1; } pConvert = sqlite3_str_new(db); pUndo = sqlite3_str_new(db); rename_all_tables(db, pConvert, pUndo); zSql1 = sqlite3_str_finish(pConvert); zSql2 = sqlite3_str_finish(pUndo); sqlite3_close(db); printf("BEGIN;\n"); printf("%s", zSql1); sqlite3_free(zSql1); printf(".schema --indent\n"); printf("PRAGMA integrity_check;\n"); printf("%s", zSql2); sqlite3_free(zSql2); printf("PRAGMA integrity_check;\n"); printf("ROLLBACK;\n"); return 0; } |
Changes to test/attachmalloc.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # # $Id: attachmalloc.test,v 1.10 2008/10/22 10:45:38 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # $Id: attachmalloc.test,v 1.10 2008/10/22 10:45:38 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !attach { finish_test return } source $testdir/malloc_common.tcl do_malloc_test attachmalloc-1 -tclprep { |
︙ | ︙ |
Changes to test/auth.test.
︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | } {0 {1 2 3 4 5 6}} do_catchsql_test auth-1.314 { WITH RECURSIVE auth1314(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM auth1314 WHERE x<5) SELECT * FROM t1 LEFT JOIN auth1314; } {1 {not authorized}} } ;# ifcapable cte do_test auth-2.1 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { return SQLITE_DENY } return SQLITE_OK | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 | } {0 {1 2 3 4 5 6}} do_catchsql_test auth-1.314 { WITH RECURSIVE auth1314(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM auth1314 WHERE x<5) SELECT * FROM t1 LEFT JOIN auth1314; } {1 {not authorized}} } ;# ifcapable cte # # db eval {SELECT sql FROM temp.sqlite_master} {puts "TEMP: $sql;"} # db eval {SELECT sql FROM main.sqlite_master} {puts "MAIN: $sql;"} # # MAIN: CREATE TABLE "t2"(a,b,c); # MAIN: CREATE TABLE t4(a,b,c); # MAIN: CREATE INDEX t4i1 ON t4(a); # MAIN: CREATE INDEX t4i2 ON t4(b,a,c); # MAIN: CREATE TABLE sqlite_stat1(tbl,idx,stat); # MAIN: CREATE TABLE t1(a,b); # ifcapable altertable&&vtab { do_test 1.350 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN b TO bcdefg; } } {0 {}} do_execsql_test auth-1.351 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.352 { set authargs } {main t1 {} {}} do_test 1.353 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN bcdefg TO b; } } {0 {}} do_execsql_test auth-1.354 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.355 { set authargs } {main t1 {} {}} do_test 1.356 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN bcdefg TO b; } } {1 {not authorized}} do_execsql_test auth-1.356 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.357 { set authargs } {main t1 {} {}} } do_test auth-2.1 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { return SQLITE_DENY } return SQLITE_OK |
︙ | ︙ | |||
2525 2526 2527 2528 2529 2530 2531 | SQLITE_READ t7 {} {} {} \ ] # Test also that if SQLITE_DENY is returned from an SQLITE_READ authorizer # invocation with no column name specified, compilation fails. # set ::authargs [list] | | > | 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 | SQLITE_READ t7 {} {} {} \ ] # Test also that if SQLITE_DENY is returned from an SQLITE_READ authorizer # invocation with no column name specified, compilation fails. # set ::authargs [list] proc auth {op args} { foreach {a b c d} $args break lappend ::authargs $op $a $b $c $d if {$op == "SQLITE_READ"} { return "SQLITE_DENY" } return "SQLITE_OK" } set ::authargs [list] do_catchsql_test auth-8.3 { SELECT count(*) FROM t7 |
︙ | ︙ |
Added test/bestindex6.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 | # 2018-09-09 # # 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 bestindex6 ifcapable !vtab { finish_test return } register_tcl_module db proc vtab_command {src method args} { switch -- $method { xConnect { return [db one {SELECT sql FROM sqlite_master where name = $src}] } xBestIndex { set clist [lindex $args 0] set wlist 1 set iCons 0 set ret [list] foreach cons $clist { catch { array unset C } array set C $cons if {$C(usable)} { set col [db one { SELECT name FROM pragma_table_info($src) WHERE cid=$C(column) }] switch $C(op) { isnull { lappend wlist "$col IS NULL" lappend ret omit $iCons } eq { lappend wlist "$col = %$iCons%" lappend ret omit $iCons } } } incr iCons } #puts "xBestIndex: $ret" lappend ret idxStr [join $wlist " AND "] return $ret } xFilter { foreach {idxnum idxstr aa} $args {} set map [list] for {set iCons 0} {$iCons < [llength $aa]} {incr iCons} { lappend map %$iCons% [lindex $aa $iCons] } set ret [list sql \ "SELECT rowid, * FROM $src WHERE [string map $map $idxstr]" ] # puts "xFilter: $ret" return $ret } } return {} } do_execsql_test 1.0 { CREATE TABLE t1(id int, value text); CREATE TABLE t2(ctx int, id int, value text); INSERT INTO t1 VALUES(1,'try'); INSERT INTO t2 VALUES(1,1,'good'); INSERT INTO t2 VALUES(2,2,'evil'); CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); CREATE VIRTUAL TABLE vt2 USING tcl(vtab_command t2); } do_execsql_test 1.1 { select * from t2 left join t1 on t1.id=t2.ctx where t1.value is null; } {2 2 evil {} {}} do_execsql_test 1.2 { select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is null; } {2 2 evil {} {}} unset -nocomplain xxx do_execsql_test 1.3 { select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is $xxx; } {2 2 evil {} {}} do_execsql_test 1.4 { select * from t2 left join vt1 on vt1.id=t2.ctx where vt1.value = 3 } {} finish_test |
Changes to test/btree02.test.
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | INSERT INTO t3(cnt) SELECT i FROM c; SELECT count(*) FROM t1; } {10} do_test btree02-110 { db eval BEGIN set i 0 db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} { db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)} # puts "a,b,cnt = ($a,$b,$cnt)" incr i if {$i%2==1} { set bx [expr {$b+1000}] # puts "INSERT ($a),$bx" db eval {INSERT INTO t1(a,ax,b) VALUES(printf('(%s)',$a),random(),$bx)} } else { # puts "DELETE a=$a" db eval {DELETE FROM t1 WHERE a=$a} } db eval {COMMIT; BEGIN} } db one {COMMIT; SELECT count(*) FROM t1;} | > > | | 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 | INSERT INTO t3(cnt) SELECT i FROM c; SELECT count(*) FROM t1; } {10} do_test btree02-110 { db eval BEGIN set i 0 db eval {SELECT a, ax, b, cnt FROM t1 CROSS JOIN t3 WHERE b IS NOT NULL} { if {$a==""} {set a 0} if {$b==""} {set b 0} db eval {INSERT INTO t2(x,y) VALUES($b,$cnt)} # puts "a,b,cnt = ($a,$b,$cnt)" incr i if {$i%2==1} { set bx [expr {$b+1000}] # puts "INSERT ($a),$bx" db eval {INSERT INTO t1(a,ax,b) VALUES(printf('(%s)',$a),random(),$bx)} } else { # puts "DELETE a=$a" db eval {DELETE FROM t1 WHERE a=$a} } db eval {COMMIT; BEGIN} } db one {COMMIT; SELECT count(*) FROM t1;} } {27} finish_test |
Changes to test/capi3.test.
︙ | ︙ | |||
807 808 809 810 811 812 813 | foreach {code english} $code2english { do_test capi3-9.$test_number "sqlite3_test_errstr $code" $english incr test_number } # Test the error message when a "real" out of memory occurs. if { [permutation] != "nofaultsim" } { | < | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | foreach {code english} $code2english { do_test capi3-9.$test_number "sqlite3_test_errstr $code" $english incr test_number } # Test the error message when a "real" out of memory occurs. if { [permutation] != "nofaultsim" } { do_test capi3-10-1 { sqlite3 db test.db set DB [sqlite3_connection_pointer db] sqlite3_memdebug_fail 1 catchsql { select * from sqlite_master; } |
︙ | ︙ | |||
844 845 846 847 848 849 850 | ifcapable {utf16} { do_test capi3-10-6 { utf8 [sqlite3_errmsg16 $::DB] } {out of memory} } db close sqlite3_memdebug_fail -1 | < | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 | ifcapable {utf16} { do_test capi3-10-6 { utf8 [sqlite3_errmsg16 $::DB] } {out of memory} } db close sqlite3_memdebug_fail -1 } # The following tests - capi3-11.* - test that a COMMIT or ROLLBACK # statement issued while there are still outstanding VMs that are part of # the transaction fails. sqlite3 db test.db set DB [sqlite3_connection_pointer db] |
︙ | ︙ |
Changes to test/capi3c.test.
︙ | ︙ | |||
753 754 755 756 757 758 759 | foreach {code english} $code2english { do_test capi3c-9.$test_number "sqlite3_test_errstr $code" $english incr test_number } # Test the error message when a "real" out of memory occurs. if { [permutation] != "nofaultsim" } { | < < | 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 | foreach {code english} $code2english { do_test capi3c-9.$test_number "sqlite3_test_errstr $code" $english incr test_number } # Test the error message when a "real" out of memory occurs. if { [permutation] != "nofaultsim" } { do_test capi3c-10-1 { sqlite3 db test.db set DB [sqlite3_connection_pointer db] sqlite3_memdebug_fail 0 catchsql { select * from sqlite_master; } } {1 {out of memory}} do_test capi3c-10-2 { sqlite3_errmsg $::DB } {out of memory} ifcapable {utf16} { do_test capi3c-10-3 { utf8 [sqlite3_errmsg16 $::DB] } {out of memory} } db close sqlite3_memdebug_fail -1 } # The following tests - capi3c-11.* - test that a COMMIT or ROLLBACK # statement issued while there are still outstanding VMs that are part of # the transaction fails. sqlite3 db test.db set DB [sqlite3_connection_pointer db] |
︙ | ︙ |
Changes to test/corrupt2.test.
︙ | ︙ | |||
587 588 589 590 591 592 593 | sqlite3 db test.db execsql { PRAGMA freelist_count } } {2} do_execsql_test 14.3 { PRAGMA integrity_check; } {{*** in database main *** | | | | 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 | sqlite3 db test.db execsql { PRAGMA freelist_count } } {2} do_execsql_test 14.3 { PRAGMA integrity_check; } {{*** in database main *** Main freelist: size is 3 but should be 2}} # Use 2 of the free pages on the free-list. # do_execsql_test 14.4 { INSERT INTO t1 VALUES(randomblob(2500)); PRAGMA freelist_count; } {0} do_execsql_test 14.5 { PRAGMA integrity_check; } {{*** in database main *** Main freelist: size is 1 but should be 0}} finish_test finish_test |
Changes to test/corrupt3.test.
︙ | ︙ | |||
63 64 65 66 67 68 69 | do_test corrupt3-1.5 { hexio_get_int [hexio_read test.db 2048 4] } 0 ;# First chained overflow is 0 integrity_check corrupt3-1.6 # Make the overflow chain loop back on itself. See if the | | < > > | > > > | 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 | do_test corrupt3-1.5 { hexio_get_int [hexio_read test.db 2048 4] } 0 ;# First chained overflow is 0 integrity_check corrupt3-1.6 # Make the overflow chain loop back on itself. See if the # corruption is detected. # do_test corrupt3-1.7 { db close hexio_write test.db 2048 [hexio_render_int32 3] sqlite3 db test.db catchsql { SELECT x FROM t1 } } [list 0 $bigstring] do_test corrupt3-1.8 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** On tree page 2 cell 0: 2nd reference to page 3}}} # Change the pointer for the first page of the overflow # change to be a non-existant page. # do_test corrupt3-1.9 { db close hexio_write test.db 2044 [hexio_render_int32 4] |
︙ | ︙ | |||
107 108 109 110 111 112 113 | } } [list 1 {database disk image is malformed}] do_test corrupt3-1.12 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** | | | 111 112 113 114 115 116 117 118 119 120 121 | } } [list 1 {database disk image is malformed}] do_test corrupt3-1.12 { catchsql { PRAGMA integrity_check } } {0 {{*** in database main *** On tree page 2 cell 0: overflow list length is 0 but should be 1 Page 3 is never used}}} finish_test |
Added test/countofview.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 | # 2018-08-04 # # 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/malloc_common.tcl set testprefix countofview do_execsql_test 1.0 { CREATE TABLE t2(c); CREATE TABLE t3(f); INSERT INTO t2 VALUES(1), (2); INSERT INTO t3 VALUES(3); } do_execsql_test 1.1 { select c from t2 union all select f from t3 limit 1 offset 1 } {2} do_execsql_test 1.2 { select count(*) from ( select c from t2 union all select f from t3 limit 1 offset 1 ) } {1} do_execsql_test 1.3 { select count(*) from ( select c from t2 union all select f from t3 ) } {3} finish_test |
Changes to test/crash5.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # $Id: crash5.test,v 1.3 2008/07/12 14:52:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # $Id: crash5.test,v 1.3 2008/07/12 14:52:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if memory debugging is turned on. # ifcapable !crashtest||!memorymanage { puts "Skipping crash5 tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } db close |
︙ | ︙ |
Changes to test/cursorhint2.test.
︙ | ︙ | |||
181 182 183 184 185 186 187 188 189 | } do_extract_hints_test 2.12 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1) } { x2 {EQ(c0,r[2])} } finish_test | > > > > > > > > > > > > > > > | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | } do_extract_hints_test 2.12 { SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1) } { x2 {EQ(c0,r[2])} } reset_db do_execsql_test 3.0 { CREATE TABLE t1 (i1 TEXT); CREATE TABLE t2 (i2 TEXT UNIQUE); INSERT INTO t1 VALUES('0'); INSERT INTO t2 VALUES('0'); } do_extract_hints_test 3.1 { SELECT * FROM t1 CROSS JOIN t2 WHERE (t1.i1 = t2.i2) AND t2.i2 = 1; } { t1 {EQ(c0,r[1])} t2 EQ(c0,1) } finish_test |
Added test/dataversion1.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 | # 2018-07-18 # # 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 case for SQLITE_FCNTL_DATA_VERSION # set testdir [file dirname $argv0] source $testdir/tester.tcl # Construct a database and get its initial data version sqlite3 db test.db do_test dataversion1-100 { db eval { CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(99); SELECT * FROM t1; } } {99} set dv1 [file_control_data_version db main] # The data version does not change by ATTACH or by changes to # other schemas within the same connection. # do_test dataversion1-101 { db eval { ATTACH ':memory:' AS aux1; CREATE TABLE aux1.t2(y); CREATE TEMP TABLE t3(z); } file_control_data_version db main } $dv1 # The data version does change when SQL modifies the table do_test dataversion1-110 { db eval { UPDATE t1 SET x=x+1; } set dv2 [file_control_data_version db] expr {$::dv1==$dv2} } {0} # But the data version is constant if there are changes to other # schemas set dv1 [file_control_data_version db main] do_test dataversion1-120 { db eval { UPDATE t2 SET y=y+1; } file_control_data_version db } $dv1 # Changes to the database via another connection are not detected # until there is a read transaction. # sqlite3 db2 test.db do_test dataversion1-130 { db2 eval { SELECT * FROM t1 } } {100} do_test dataversion1-131 { file_control_data_version db } $dv1 do_test dataversion1-132 { db2 eval { UPDATE t1 SET x=x+1; } set dv2 [file_control_data_version db] expr {$::dv1==$dv2} } {1} do_test dataversion1-133 { db eval {SELECT * FROM t1} set dv2 [file_control_data_version db] expr {$::dv1==$dv2} } {0} finish_test |
Changes to test/e_createtable.test.
︙ | ︙ | |||
879 880 881 882 883 884 885 | h DEFAULT ( substr('abcd', 0, 2) || 'cd' ), i DEFAULT CURRENT_TIME, j DEFAULT CURRENT_DATE, k DEFAULT CURRENT_TIMESTAMP ); } {} | | | | 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | h DEFAULT ( substr('abcd', 0, 2) || 'cd' ), i DEFAULT CURRENT_TIME, j DEFAULT CURRENT_DATE, k DEFAULT CURRENT_TIMESTAMP ); } {} # EVIDENCE-OF: R-33440-07331 For the purposes of the DEFAULT clause, an # expression is considered constant if it contains no sub-queries, # column or table references, bound parameters, or string literals # enclosed in double-quotes instead of single-quotes. # do_createtable_tests 3.4.1 -error { default value of column [x] is not constant } { 1 {CREATE TABLE t5(x DEFAULT ( (SELECT 1) ))} {} |
︙ | ︙ |
Changes to test/eqp.test.
︙ | ︙ | |||
739 740 741 742 743 744 745 | } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE t1 } | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > | | 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 | } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE t1 } # 2018-08-16: While working on Fossil I discovered that EXPLAIN QUERY PLAN # did not describe IN operators implemented using a ROWID lookup. These # test cases ensure that problem as been fixed. # do_execsql_test 9.0 { -- Schema from Fossil 2018-08-16 CREATE TABLE forumpost( fpid INTEGER PRIMARY KEY, froot INT, fprev INT, firt INT, fmtime REAL ); CREATE INDEX forumthread ON forumpost(froot,fmtime); CREATE TABLE blob( rid INTEGER PRIMARY KEY, rcvid INTEGER, size INTEGER, uuid TEXT UNIQUE NOT NULL, content BLOB, CHECK( length(uuid)>=40 AND rid>0 ) ); CREATE TABLE event( type TEXT, mtime DATETIME, objid INTEGER PRIMARY KEY, tagid INTEGER, uid INTEGER REFERENCES user, bgcolor TEXT, euser TEXT, user TEXT, ecomment TEXT, comment TEXT, brief TEXT, omtime DATETIME ); CREATE INDEX event_i1 ON event(mtime); CREATE TABLE private(rid INTEGER PRIMARY KEY); } do_eqp_test 9.1 { WITH thread(age,duration,cnt,root,last) AS ( SELECT julianday('now') - max(fmtime) AS age, max(fmtime) - min(fmtime) AS duration, sum(fprev IS NULL) AS msg_count, froot, (SELECT fpid FROM forumpost WHERE froot=x.froot AND fpid NOT IN private ORDER BY fmtime DESC LIMIT 1) FROM forumpost AS x WHERE fpid NOT IN private --- Ensure this table mentioned in EQP output! GROUP BY froot ORDER BY 1 LIMIT 26 OFFSET 5 ) SELECT thread.age, thread.duration, thread.cnt, blob.uuid, substr(event.comment,instr(event.comment,':')+1) FROM thread, blob, event WHERE blob.rid=thread.last AND event.objid=thread.last ORDER BY 1; } { QUERY PLAN |--MATERIALIZE xxxxxx | |--SCAN TABLE forumpost AS x USING INDEX forumthread | |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | |--CORRELATED SCALAR SUBQUERY | | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?) | | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | `--USE TEMP B-TREE FOR ORDER BY |--SCAN SUBQUERY xxxxxx |--SEARCH TABLE blob USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE event USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/fkey2.test.
︙ | ︙ | |||
979 980 981 982 983 984 985 | } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { | | > > | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { db eval {SELECT sqlite_rename_table( 'main', 'table', 't1', $zCreate, $zOld, $zNew, 0 )} } do_test fkey2-14.2.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test fkey2-14.2.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} |
︙ | ︙ |
Changes to test/fts3ao.test.
︙ | ︙ | |||
89 90 91 92 93 94 95 | } {} do_test fts3ao-2.9 { catchsql { ALTER TABLE fts_t1 RENAME to t1; } } {1 {SQL logic error}} do_test fts3ao-2.10 { | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | } {} do_test fts3ao-2.9 { catchsql { ALTER TABLE fts_t1 RENAME to t1; } } {1 {SQL logic error}} do_test fts3ao-2.10 { execsql { SELECT rowid, snippet( fts_t1 ) FROM fts_t1 WHERE a MATCH 'four'; } } {1 {one three <b>four</b>}} do_test fts3ao-2.11 { execsql { SELECT tbl_name FROM sqlite_master WHERE type = 'table'} } {fts_t1 fts_t1_content fts_t1_segments fts_t1_segdir t1_segdir} do_test fts3ao-2.12 { execsql COMMIT execsql {SELECT a FROM fts_t1} |
︙ | ︙ |
Changes to test/fuzz_malloc.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # This file tests malloc failures in concert with fuzzy SQL generation. # # $Id: fuzz_malloc.test,v 1.10 2008/08/20 16:35:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # This file tests malloc failures in concert with fuzzy SQL generation. # # $Id: fuzz_malloc.test,v 1.10 2008/08/20 16:35:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/fuzz_common.tcl if {[info exists G(isquick)]} { set ::REPEATS 20 } elseif {[info exists G(issoak)]} { set ::REPEATS 100 |
︙ | ︙ |
Changes to test/fuzzcheck.c.
︙ | ︙ | |||
802 803 804 805 806 807 808 | "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" | | > | 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 | "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" " --info Show information about SOURCE-DB w/o running tests\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 fron 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" " --native-malloc Turn off MEMSYS3/5 and Lookaside\n" " --oss-fuzz Enable OSS-FUZZ testing\n" " --prng-seed N Seed value for the PRGN inside of SQLite\n" " -q|--quiet Reduced output\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" ); } |
︙ | ︙ | |||
837 838 839 840 841 842 843 844 845 846 847 848 849 850 | Blob *pDb; /* For looping over template databases */ int i; /* Loop index for the argv[] loop */ int onlySqlid = -1; /* --sqlid */ int onlyDbid = -1; /* --dbid */ int nativeFlag = 0; /* --native-vfs */ int rebuildFlag = 0; /* --rebuild */ int vdbeLimitFlag = 0; /* --limit-vdbe */ int timeoutTest = 0; /* undocumented --timeout-test flag */ int runFlags = 0; /* Flags sent to runSql() */ char *zMsg = 0; /* Add this message */ int nSrcDb = 0; /* Number of source databases */ char **azSrcDb = 0; /* Array of source database names */ int iSrcDb; /* Loop over all source databases */ int nTest = 0; /* Total number of tests performed */ | > | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | Blob *pDb; /* For looping over template databases */ int i; /* Loop index for the argv[] loop */ int onlySqlid = -1; /* --sqlid */ int onlyDbid = -1; /* --dbid */ int nativeFlag = 0; /* --native-vfs */ int rebuildFlag = 0; /* --rebuild */ int vdbeLimitFlag = 0; /* --limit-vdbe */ int infoFlag = 0; /* --info */ int timeoutTest = 0; /* undocumented --timeout-test flag */ int runFlags = 0; /* Flags sent to runSql() */ char *zMsg = 0; /* Add this message */ int nSrcDb = 0; /* Number of source databases */ char **azSrcDb = 0; /* Array of source database names */ int iSrcDb; /* Loop over all source databases */ int nTest = 0; /* Total number of tests performed */ |
︙ | ︙ | |||
892 893 894 895 896 897 898 899 900 901 902 903 904 905 | if( strcmp(z,"export-sql")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zExpSql = argv[++i]; }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"limit-mem")==0 ){ #if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3", argv[i]); #else if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); | > > > | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | if( strcmp(z,"export-sql")==0 ){ if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); zExpSql = argv[++i]; }else if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"info")==0 ){ infoFlag = 1; }else if( strcmp(z,"limit-mem")==0 ){ #if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3", argv[i]); #else if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); |
︙ | ︙ | |||
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 | for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){ rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db, openFlags4Data, pDfltVfs->zName); if( rc ){ fatalError("cannot open source database %s - %s", azSrcDb[iSrcDb], sqlite3_errmsg(db)); } rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS db(\n" " dbid INTEGER PRIMARY KEY, -- database id\n" " dbcontent BLOB -- database disk file image\n" ");\n" "CREATE TABLE IF NOT EXISTS xsql(\n" " sqlid INTEGER PRIMARY KEY, -- SQL script id\n" | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 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 | for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){ rc = sqlite3_open_v2(azSrcDb[iSrcDb], &db, openFlags4Data, pDfltVfs->zName); if( rc ){ fatalError("cannot open source database %s - %s", azSrcDb[iSrcDb], sqlite3_errmsg(db)); } /* Print the description, if there is one */ if( infoFlag ){ int n; zDbName = azSrcDb[iSrcDb]; i = (int)strlen(zDbName) - 1; while( i>0 && zDbName[i-1]!='/' && zDbName[i-1]!='\\' ){ i--; } zDbName += i; sqlite3_prepare_v2(db, "SELECT msg FROM readme", -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ printf("%s: %s", zDbName, sqlite3_column_text(pStmt,0)); }else{ printf("%s: (empty \"readme\")", zDbName); } sqlite3_finalize(pStmt); sqlite3_prepare_v2(db, "SELECT count(*) FROM db", -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW && (n = sqlite3_column_int(pStmt,0))>0 ){ printf(" - %d DBs", n); } sqlite3_finalize(pStmt); sqlite3_prepare_v2(db, "SELECT count(*) FROM xsql", -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW && (n = sqlite3_column_int(pStmt,0))>0 ){ printf(" - %d scripts", n); } sqlite3_finalize(pStmt); printf("\n"); sqlite3_close(db); continue; } rc = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS db(\n" " dbid INTEGER PRIMARY KEY, -- database id\n" " dbcontent BLOB -- database disk file image\n" ");\n" "CREATE TABLE IF NOT EXISTS xsql(\n" " sqlid INTEGER PRIMARY KEY, -- SQL script id\n" |
︙ | ︙ |
Changes to test/fuzzdata2.db.
cannot compute difference between binary files
Changes to test/fuzzdata4.db.
cannot compute difference between binary files
Changes to test/fuzzdata5.db.
cannot compute difference between binary files
Changes to test/incrblob_err.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # $Id: incrblob_err.test,v 1.14 2008/07/18 17:16:27 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix incrblob_err | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # $Id: incrblob_err.test,v 1.14 2008/07/18 17:16:27 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix incrblob_err ifcapable {!incrblob || !tclvar} { finish_test return } source $testdir/malloc_common.tcl unset -nocomplain ::fd ::data |
︙ | ︙ |
Changes to test/indexexpr2.test.
︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 | do_execsql_test 3.4.5eqp { EXPLAIN QUERY PLAN SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; } {/SCAN TABLE t4 USING INDEX i4/} do_execsql_test 3.4.6 { SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary; } {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 3.4.5eqp { EXPLAIN QUERY PLAN SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE nocase; } {/SCAN TABLE t4 USING INDEX i4/} do_execsql_test 3.4.6 { SELECT * FROM t4 ORDER BY Substr(a,-2) COLLATE binary; } {.ABC1 1 .ABC3 3 .abc2 2 .abc4 4} # 2014-09-15: Verify that UPDATEs of columns not referenced by a # index on expression do not modify the index. # unset -nocomplain cnt set cnt 0 proc refcnt {x} { global cnt incr cnt return $x } db close sqlite3 db :memory: db function refcnt -deterministic refcnt do_test 4.100 { db eval { CREATE TABLE t1(a,b,c,d,e,f); CREATE INDEX t1abc ON t1(refcnt(a+b+c)); } set ::cnt } {0} do_test 4.110 { db eval {INSERT INTO t1 VALUES(1,2,3,4,5,6);} set ::cnt # The refcnt() function is invoked once to compute the index value } {1} do_test 4.120 { set ::cnt 0 db eval {UPDATE t1 SET b=b+1;} set ::cnt # The refcnt() function is invoked twice, once to remove the old index # entry and a second time to insert the new one. } {2} do_test 4.130 { set ::cnt 0 db eval {UPDATE t1 SET d=d+1;} set ::cnt # Refcnt() should not be invoked because that index does not change. } {0} # Additional test cases to show that UPDATE does not modify indexes that # do not involve unchanged columns. # load_static_extension db explain do_execsql_test 4.200 { CREATE TABLE t2(a,b,c,d,e,f); INSERT INTO t2 VALUES(2,3,4,5,6,7); CREATE INDEX t2abc ON t2(a+b+c); CREATE INDEX t2cd ON t2(c*d); CREATE INDEX t2def ON t2(d,e+25*f); SELECT sqlite_master.name FROM sqlite_master, explain('UPDATE t2 SET b=b+1') WHERE explain.opcode LIKE 'Open%' AND sqlite_master.rootpage=explain.p2 ORDER BY 1; } {t2 t2abc} do_execsql_test 4.210 { SELECT sqlite_master.name FROM sqlite_master, explain('UPDATE t2 SET c=c+1') WHERE explain.opcode LIKE 'Open%' AND sqlite_master.rootpage=explain.p2 ORDER BY 1; } {t2 t2abc t2cd} do_execsql_test 4.220 { SELECT sqlite_master.name FROM sqlite_master, explain('UPDATE t2 SET c=c+1, f=NULL') WHERE explain.opcode LIKE 'Open%' AND sqlite_master.rootpage=explain.p2 ORDER BY 1; } {t2 t2abc t2cd t2def} finish_test |
Changes to test/like3.test.
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 | } {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} do_execsql_test like3-4.2 { SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x ASC; } {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} do_execsql_test like3-4.2ck { SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x ASC; } {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {X'616265' X'616264' X'616263' 'abe' 'abd' 'abc'} do_execsql_test like3-4.2 { SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY x ASC; } {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} do_execsql_test like3-4.2ck { SELECT quote(x) FROM t4 WHERE x LIKE 'ab%' ORDER BY +x ASC; } {'abc' 'abd' 'abe' X'616263' X'616264' X'616265'} # 2018-09-10 ticket https://www.sqlite.org/src/tktview/c94369cae9b561b1f996 # The like optimization fails for a column with numeric affinity if # the pattern '/%' or begins with the escape character. # do_execsql_test like3-5.100 { CREATE TABLE t5a(x INT UNIQUE COLLATE nocase); INSERT INTO t5a(x) VALUES('/abc'),(123),(-234); SELECT x FROM t5a WHERE x LIKE '/%'; } {/abc} do_eqp_test like3-5.101 { SELECT x FROM t5a WHERE x LIKE '/%'; } { QUERY PLAN `--SCAN TABLE t5a } do_execsql_test like3-5.110 { SELECT x FROM t5a WHERE x LIKE '/a%'; } {/abc} do_eqp_test like3-5.111 { SELECT x FROM t5a WHERE x LIKE '/a%'; } { QUERY PLAN `--SEARCH TABLE t5a USING COVERING INDEX sqlite_autoindex_t5a_1 (x>? AND x<?) } do_execsql_test like3-5.120 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } {123} do_eqp_test like3-5.121 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } { QUERY PLAN `--SCAN TABLE t5a } do_execsql_test like3-5.122 { SELECT x FROM t5a WHERE x LIKE '^-2%' ESCAPE '^'; } {-234} do_eqp_test like3-5.123 { SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^'; } { QUERY PLAN `--SCAN TABLE t5a } do_execsql_test like3-5.200 { CREATE TABLE t5b(x INT UNIQUE COLLATE binary); INSERT INTO t5b(x) VALUES('/abc'),(123),(-234); SELECT x FROM t5b WHERE x GLOB '/*'; } {/abc} do_eqp_test like3-5.201 { SELECT x FROM t5b WHERE x GLOB '/*'; } { QUERY PLAN `--SCAN TABLE t5b } do_execsql_test like3-5.210 { SELECT x FROM t5b WHERE x GLOB '/a*'; } {/abc} do_eqp_test like3-5.211 { SELECT x FROM t5b WHERE x GLOB '/a*'; } { QUERY PLAN `--SEARCH TABLE t5b USING COVERING INDEX sqlite_autoindex_t5b_1 (x>? AND x<?) } finish_test |
Changes to test/limit2.test.
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 | DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1,2); DROP TABLE IF EXISTS t2; CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1,3); CREATE INDEX t1ab ON t1(a,b); SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC; } {3} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1,2); DROP TABLE IF EXISTS t2; CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1,3); CREATE INDEX t1ab ON t1(a,b); SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC; } {3} # Ticket https://www.sqlite.org/src/info/9936b2fa443fec03 2018-09-08 # Infinite loop due to the ORDER BY LIMIT optimization. # do_execsql_test 700 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(aa VARCHAR PRIMARY KEY NOT NULL,bb,cc,x VARCHAR(400)); INSERT INTO t1(aa,bb,cc) VALUES('maroon','meal','lecture'); INSERT INTO t1(aa,bb,cc) VALUES('reality','meal','catsear'); CREATE TABLE t2(aa VARCHAR PRIMARY KEY, dd INT DEFAULT 1, ee, x VARCHAR(100)); INSERT INTO t2(aa,dd,ee) VALUES('maroon',0,'travel'),('reality',0,'hour'); CREATE INDEX t2x1 ON t2(dd,ee); ANALYZE; DROP TABLE IF EXISTS sqlite_stat4; DELETE FROM sqlite_stat1; INSERT INTO sqlite_stat1 VALUES ('t2','t2x1','3 3 3'), ('t2','sqlite_autoindex_t2_1','3 1'), ('t1','sqlite_autoindex_t1_1','2 1'); ANALYZE sqlite_master; SELECT * FROM t1 LEFT JOIN t2 ON t1.aa=t2.aa WHERE t1.bb='meal' ORDER BY t2.dd DESC LIMIT 1; } {maroon meal lecture {} maroon 0 travel {}} do_execsql_test 710 { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(aa, bb); INSERT INTO t1 VALUES('maroon','meal'); CREATE TABLE t2(cc, dd, ee, x VARCHAR(100)); INSERT INTO t2(cc,dd,ee) VALUES('maroon',1,'one'); INSERT INTO t2(cc,dd,ee) VALUES('maroon',2,'two'); INSERT INTO t2(cc,dd,ee) VALUES('maroon',0,'zero'); CREATE INDEX t2ddee ON t2(dd,ee); CREATE INDEX t2cc ON t2(cc); ANALYZE; SELECT t2.cc, t2.dd, t2.ee FROM t1 CROSS JOIN t2 ON t1.aa=t2.cc ORDER BY t2.dd LIMIT 1; } {maroon 0 zero} do_execsql_test 720 { SELECT t2.cc, t2.dd, t2.ee FROM t1 CROSS JOIN t2 ON t1.aa=t2.cc WHERE t1.bb='meal' ORDER BY t2.dd LIMIT 1; } {maroon 0 zero} finish_test |
Changes to test/lookaside.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | finish_test return } # The tests in this file configure the lookaside allocator after a # connection is opened. This will not work if there is any "presql" # configured (SQL run within the [sqlite3] wrapper in tester.tcl). | | > > | 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 | finish_test return } # The tests in this file configure the lookaside allocator after a # connection is opened. This will not work if there is any "presql" # configured (SQL run within the [sqlite3] wrapper in tester.tcl). if {[info exists ::G(perm:dbconfig)] && $::G(perm:dbconfig)!=""} { finish_test return } test_set_config_pagecache 0 0 catch {db close} sqlite3_shutdown sqlite3_initialize autoinstall_test_functions sqlite3 db test.db db cache size 4 # Make sure sqlite3_db_config() and sqlite3_db_status are working. # do_test lookaside-1.1 { catch {sqlite3_config_error db} } {0} |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 | } {0} do_test lookaside-2.2 { db eval {CREATE TABLE t2(x);} foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break expr {$x==0 && $y<$z && $z>10 && $z<100} } {1} do_test lookaside-2.3 { sqlite3_db_config_lookaside db 0 50 50 } {5} ;# SQLITE_BUSY do_test lookaside-2.4 { db cache flush sqlite3_db_config_lookaside db 0 50 50 } {0} ;# SQLITE_OK do_test lookaside-2.5 { | > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } {0} do_test lookaside-2.2 { db eval {CREATE TABLE t2(x);} foreach {x y z} [sqlite3_db_status db DBSTATUS_LOOKASIDE_USED 0] break expr {$x==0 && $y<$z && $z>10 && $z<100} } {1} do_test lookaside-2.3 { db eval {SELECT 1} sqlite3_db_config_lookaside db 0 50 50 } {5} ;# SQLITE_BUSY do_test lookaside-2.4 { db cache flush sqlite3_db_config_lookaside db 0 50 50 } {0} ;# SQLITE_OK do_test lookaside-2.5 { |
︙ | ︙ |
Added test/malloctraceviewer.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 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 | package require sqlite3 package require Tk ############################################################################# # Code to set up scrollbars for widgets. This is generic, boring stuff. # namespace eval autoscroll { proc scrollable {widget path args} { ::ttk::frame $path set w [$widget ${path}.widget {*}$args] set vs [::ttk::scrollbar ${path}.vs] set hs [::ttk::scrollbar ${path}.hs -orient horizontal] grid $w -row 0 -column 0 -sticky nsew grid rowconfigure $path 0 -weight 1 grid columnconfigure $path 0 -weight 1 set grid [list grid $vs -row 0 -column 1 -sticky nsew] $w configure -yscrollcommand [list ::autoscroll::scrollcommand $grid $vs] $vs configure -command [list $w yview] set grid [list grid $hs -row 1 -column 0 -sticky nsew] $w configure -xscrollcommand [list ::autoscroll::scrollcommand $grid $hs] $hs configure -command [list $w xview] return $w } proc scrollcommand {grid sb args} { $sb set {*}$args set isRequired [expr {[lindex $args 0] != 0.0 || [lindex $args 1] != 1.0}] if {$isRequired && ![winfo ismapped $sb]} { {*}$grid } if {!$isRequired && [winfo ismapped $sb]} { grid forget $sb } } namespace export scrollable } namespace import ::autoscroll::* ############################################################################# proc populate_text_widget {db} { $::O(text) configure -state normal set id [lindex [$::O(tree) selection] 0] set frame [lindex $id end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] if {$line ne ""} { foreach {file line} [split $line :] {} set content [$db one "SELECT content FROM file WHERE name = '$file'"] $::O(text) delete 0.0 end set iLine 1 foreach L [split $content "\n"] { if {$iLine == $line} { $::O(text) insert end "$L\n" highlight } else { $::O(text) insert end "$L\n" } incr iLine } $::O(text) yview -pickplace ${line}.0 } $::O(text) configure -state disabled } proc populate_index {db} { $::O(text) configure -state normal $::O(text) delete 0.0 end $::O(text) insert end "\n\n" set L [format " % -40s%12s%12s\n" "Test Case" "Allocations" "Bytes"] $::O(text) insert end $L $::O(text) insert end " [string repeat - 64]\n" $db eval { SELECT 'TOTAL' AS ztest, sum(ncall) AS calls, sum(nbyte) AS bytes FROM malloc UNION ALL SELECT ztest AS ztest, sum(ncall) AS calls, sum(nbyte) AS bytes FROM malloc GROUP BY ztest ORDER BY 3 DESC } { set tags [list $ztest] if {$ztest eq $::O(current)} { lappend tags highlight } set L [format " % -40s%12s%12s\n" $ztest $calls $bytes] $::O(text) insert end $L $tags $::O(text) tag bind $ztest <1> [list populate_tree_widget $db $ztest] $::O(text) tag bind $ztest <Enter> [list $::O(text) configure -cursor hand2] $::O(text) tag bind $ztest <Leave> [list $::O(text) configure -cursor ""] } $::O(text) configure -state disabled } proc sort_tree_compare {iLeft iRight} { global O switch -- [expr (int($O(tree_sort)/2))] { 0 { set left [$O(tree) item $iLeft -text] set right [$O(tree) item $iRight -text] set res [string compare $left $right] } 1 { set left [lindex [$O(tree) item $iLeft -values] 0] set right [lindex [$O(tree) item $iRight -values] 0] set res [expr $left - $right] } 2 { set left [lindex [$O(tree) item $iLeft -values] 1] set right [lindex [$O(tree) item $iRight -values] 1] set res [expr $left - $right] } } if {$O(tree_sort)&0x01} { set res [expr -1 * $res] } return $res } proc sort_tree {iMode} { global O if {$O(tree_sort) == $iMode} { incr O(tree_sort) } else { set O(tree_sort) $iMode } set T $O(tree) set items [$T children {}] set items [lsort -command sort_tree_compare $items] for {set ii 0} {$ii < [llength $items]} {incr ii} { $T move [lindex $items $ii] {} $ii } } proc trim_frames {stack} { while {[info exists ::O(ignore.[lindex $stack 0])]} { set stack [lrange $stack 1 end] } return $stack } proc populate_tree_widget {db zTest} { $::O(tree) delete [$::O(tree) children {}] for {set ii 0} {$ii < 15} {incr ii} { $db eval { SELECT sum(ncall) AS calls, sum(nbyte) AS bytes, trim_frames(lrange(lstack, 0, $ii)) AS stack FROM malloc WHERE (zTest = $zTest OR $zTest = 'TOTAL') AND llength(lstack)>$ii GROUP BY stack HAVING stack != '' } { set parent_id [lrange $stack 0 end-1] set frame [lindex $stack end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] set line [lindex [split $line /] end] set v [list $calls $bytes] catch { $::O(tree) insert $parent_id end -id $stack -text $line -values $v } } } set ::O(current) $zTest populate_index $db } set O(tree_sort) 0 ::ttk::panedwindow .pan -orient horizontal set O(tree) [scrollable ::ttk::treeview .pan.tree] frame .pan.right set O(text) [scrollable text .pan.right.text] button .pan.right.index -command {populate_index mddb} -text "Show Index" pack .pan.right.index -side top -fill x pack .pan.right.text -fill both -expand true $O(text) tag configure highlight -background wheat $O(text) configure -wrap none -height 35 .pan add .pan.tree .pan add .pan.right $O(tree) configure -columns {calls bytes} $O(tree) heading #0 -text Line -anchor w -command {sort_tree 0} $O(tree) heading calls -text Calls -anchor w -command {sort_tree 2} $O(tree) heading bytes -text Bytes -anchor w -command {sort_tree 4} $O(tree) column #0 -width 150 $O(tree) column calls -width 100 $O(tree) column bytes -width 100 pack .pan -fill both -expand 1 #-------------------------------------------------------------------- # Open the database containing the malloc data. The user specifies the # database to use by passing the file-name on the command line. # proc open_database {} { if {[info exists ::BUILTIN]} { sqlite3 mddb :memory: mddb eval $::BUILTIN wm title . $::argv0 } else { set zFilename [lindex $::argv 0] if {$zFilename eq ""} { set zFilename mallocs.sql } set fd [open $zFilename] set zHdr [read $fd 15] if {$zHdr eq "SQLite format 3"} { close $fd sqlite3 mddb $zFilename } else { seek $fd 0 sqlite3 mddb :memory: mddb eval [read $fd] close $fd } wm title . $zFilename } mddb function lrange -argcount 3 lrange mddb function llength -argcount 1 llength mddb function trim_frames -argcount 1 trim_frames mddb eval { SELECT frame FROM frame WHERE line LIKE '%malloc.c:%' OR line LIKE '%mem2.c:%' } { set ::O(ignore.$frame) 1 } } open_database bind $O(tree) <<TreeviewSelect>> [list populate_text_widget mddb] populate_tree_widget mddb [mddb one {SELECT zTest FROM malloc LIMIT 1}] |
Changes to test/mmap1.test.
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 | sqlite3_column_text $::STMT 0 } $bbb do_test 5.5 { sqlite3_finalize $::STMT } SQLITE_OK finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_column_text $::STMT 0 } $bbb do_test 5.5 { sqlite3_finalize $::STMT } SQLITE_OK # # The "6.*" tests are designed to test the interaction of mmap with file # truncation (e.g. on Win32) via the VACUUM command. # forcedelete test2.db sqlite3 db2 test2.db do_test 6.0 { db2 eval { PRAGMA auto_vacuum = 0; PRAGMA page_size = 4096; } } {} do_test 6.1 { db2 eval { CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(randomblob(1000000)); } } {} do_test 6.2 { db2 eval { PRAGMA mmap_size = 1048576; } } {1048576} do_test 6.3 { expr {[file size test2.db] > 1000000} } {1} do_test 6.4 { db2 eval { DELETE FROM t1; } } {} do_test 6.5 { expr {[file size test2.db] > 1000000} } {1} do_test 6.6 { db2 eval { VACUUM; } } {} do_test 6.7 { expr {[file size test2.db] < 1000000} } {1} db2 close finish_test |
Changes to test/orderby5.test.
︙ | ︙ | |||
79 80 81 82 83 84 85 | EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c; } {~/B-TREE/} do_execsql_test 2.1b { EXPLAIN QUERY PLAN | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c; } {~/B-TREE/} do_execsql_test 2.1b { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE likelihood(a=0, 0.03) ORDER BY a, b, c; } {/B-TREE/} do_execsql_test 2.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c; } {/B-TREE/} do_execsql_test 2.3 { |
︙ | ︙ |
Changes to test/permutations.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 50 51 52 53 54 55 56 | } foreach {k v} $args { set o [array names options ${k}*] if {[llength $o]>1} { error "ambiguous option: $k" } if {[llength $o]==0} { error "unknown option: $k" } set options([lindex $o 0]) $v } set ::testspec($name) [array get options] lappend ::testsuitelist $name } #------------------------------------------------------------------------- # test_set ARGS... | > > > > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | } foreach {k v} $args { set o [array names options ${k}*] if {[llength $o]>1} { error "ambiguous option: $k" } if {[llength $o]==0} { error "unknown option: $k" } set options([lindex $o 0]) $v } # Transform "-presql" into a "dbconfig" script # if {[info exists options(-presql)]} { append options(-dbconfig) "\n\$::dbhandle eval { $options(-presql) }" unset options(-presql) } set ::testspec($name) [array get options] lappend ::testsuitelist $name } #------------------------------------------------------------------------- # test_set ARGS... |
︙ | ︙ | |||
100 101 102 103 104 105 106 | if {$::tcl_platform(platform)!="unix"} { set alltests [test_set $alltests -exclude crash.test crash2.test] } set alltests [test_set $alltests -exclude { all.test async.test quick.test veryquick.test memleak.test permutations.test soak.test fts3.test mallocAll.test rtree.test full.test extraquick.test | | | | 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 | if {$::tcl_platform(platform)!="unix"} { set alltests [test_set $alltests -exclude crash.test crash2.test] } set alltests [test_set $alltests -exclude { all.test async.test quick.test veryquick.test memleak.test permutations.test soak.test fts3.test mallocAll.test rtree.test full.test extraquick.test session.test rbu.test }] set allquicktests [test_set $alltests -exclude { async2.test async3.test backup_ioerr.test corrupt.test corruptC.test crash.test crash2.test crash3.test crash4.test crash5.test crash6.test crash7.test delete3.test e_fts3.test fts3rnd.test fkey_malloc.test fuzz.test fuzz3.test fuzz_malloc.test in2.test loadext.test misc7.test mutex2.test notify2.test onefile.test pagerfault2.test savepoint4.test savepoint6.test select9.test speed1.test speed1p.test speed2.test speed3.test speed4.test speed4p.test sqllimits1.test tkt2686.test thread001.test thread002.test thread003.test thread004.test thread005.test trans2.test vacuum3.test incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test vtab_err.test walslow.test walcrash.test walcrash3.test walthread.test rtree3.test indexfault.test securedel2.test sort3.test sort4.test fts4growth.test fts4growth2.test bigsort.test walprotocol.test mmap4.test fuzzer2.test walcrash2.test e_fkey.test backup.test fts4merge.test fts4merge2.test fts4merge4.test fts4check.test fts3cov.test fts3snippet.test fts3corrupt2.test fts3an.test fts3defer.test fts4langid.test fts3sort.test fts5unicode.test rtree4.test |
︙ | ︙ | |||
549 550 551 552 553 554 555 | sqlite3_initialize autoinstall_test_functions } test_suite "nomutex" -description { Tests run with the SQLITE_OPEN_MULTITHREADED flag passed to sqlite3_open(). } -initialize { | < < < | < < < < < < | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | sqlite3_initialize autoinstall_test_functions } test_suite "nomutex" -description { Tests run with the SQLITE_OPEN_MULTITHREADED flag passed to sqlite3_open(). } -initialize { set ::G(perm:sqlite3_args) [list -fullmutex 0 -nomutex 1] } -files { delete.test delete2.test insert.test rollback.test select1.test select2.test trans.test update.test vacuum.test types.test types2.test types3.test } # Run some tests in SQLITE_CONFIG_MULTITHREAD mode. # test_suite "multithread" -description { Tests run in SQLITE_CONFIG_MULTITHREAD mode } -initialize { catch {db close} |
︙ | ︙ | |||
592 593 594 595 596 597 598 | } # Run some tests in SQLITE_OPEN_FULLMUTEX mode. # test_suite "fullmutex" -description { Tests run in SQLITE_OPEN_FULLMUTEX mode } -initialize { | < < < | < < < < < < < < < | < < < < < < | 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 | } # Run some tests in SQLITE_OPEN_FULLMUTEX mode. # test_suite "fullmutex" -description { Tests run in SQLITE_OPEN_FULLMUTEX mode } -initialize { set ::G(perm:sqlite3_args) [list -nomutex 0 -fullmutex 1] } -files { delete.test delete2.test insert.test rollback.test select1.test select2.test trans.test update.test vacuum.test types.test types2.test types3.test } # Run some tests using the "onefile" demo. # test_suite "onefile" -description { Run some tests using the "test_onefile.c" demo } -initialize { set ::G(perm:sqlite3_args) [list -vfs fs] } -files { conflict.test insert.test insert2.test insert3.test rollback.test select1.test select2.test select3.test } # Run some tests using UTF-16 databases. # test_suite "utf16" -description { Run tests using UTF-16 databases } -presql { |
︙ | ︙ | |||
927 928 929 930 931 932 933 | # rename crashsql {} # rename sa_crashsql crashsql # } -files crash.test test_suite "safe_append" -description { Run some tests on a SAFE_APPEND file-system. } -initialize { | < < < | < < < < < < | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | # rename crashsql {} # rename sa_crashsql crashsql # } -files crash.test test_suite "safe_append" -description { Run some tests on a SAFE_APPEND file-system. } -initialize { set ::G(perm:sqlite3_args) [list -vfs devsym] sqlite3_simulate_device -char safe_append } -files [ test_set $::allquicktests shared_err.test -exclude async3.test ] # The set of tests to run on the alternative-pcache set perm-alt-pcache-testset { async.test |
︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 | # run_tests NAME OPTIONS # # where available options are: # # -description TITLE # -initialize SCRIPT # -shutdown SCRIPT | < > > > > > > < > > < > > | < > > | > > | < > | > | < > | > > | > > > > > | > > > > > > > > > > > > > > > > > > > | > > | | 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 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 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 | # run_tests NAME OPTIONS # # where available options are: # # -description TITLE # -initialize SCRIPT # -shutdown SCRIPT # -files LIST-OF-FILES # -prefix NAME # -dbconfig SCRIPT # proc run_tests {name args} { set options(-initialize) "" set options(-shutdown) "" set options(-prefix) "" set options(-dbconfig) "" array set options $args set ::G(perm:name) $name set ::G(perm:prefix) $options(-prefix) set ::G(isquick) 1 set ::G(perm:dbconfig) $options(-dbconfig) foreach file [lsort $options(-files)] { uplevel $options(-initialize) if {[file tail $file] == $file} { set file [file join $::testdir $file] } slave_test_file $file uplevel $options(-shutdown) unset -nocomplain ::G(perm:sqlite3_args) } unset ::G(perm:name) unset ::G(perm:prefix) unset ::G(perm:dbconfig) } proc run_test_suite {name} { if {[info exists ::testspec($name)]==0} { error "No such test suite: $name" } uplevel run_tests $name $::testspec($name) } proc help {} { puts "Usage: $::argv0 TESTSUITE ?TESTFILE?" puts "" puts "Available test-suites are:" set iPos 0 foreach k $::testsuitelist { if {[info exists ::testspec($k)]} { switch $iPos { 0 { puts "" puts -nonewline " [format %-30s $k]" } 1 { puts -nonewline [format %-30s $k] } 2 { puts -nonewline $k } } set iPos [expr (($iPos+1) % 3)] } } puts "" exit -1 } if {[file tail $argv0] == "permutations.test"} { proc main {argv} { if {[llength $argv]==0} { help } else { # See if the first argument is a named test-suite. # set suite [file tail [lindex $argv 0]] if {[info exists ::testspec($suite)]} { set S $::testspec($suite) set i 1 } else { set S [list] set i 0 } set extra "" if {$i < [llength $argv] && [string range [lindex $argv $i] 0 0]!="-" } { set files [list] for {} {$i < [llength $argv]} {incr i} { set pattern [string map {% *} [lindex $argv $i]] if {[string range $pattern 0 0]=="-"} break foreach f $::alltests { set tail [file tail $f] if {[lsearch $files $f]<0 && [string match $pattern $tail]} { lappend files $f } } } set extra [list -files $files] } eval run_tests $suite $S $extra } } main $argv finish_test } |
Changes to test/printf.test.
︙ | ︙ | |||
3753 3754 3755 3756 3757 3758 3759 | } {} do_test printf-15.3 { sqlite3_snprintf_int 0 {} 0 } {abcdefghijklmnopqrstuvwxyz} # Now test malloc() failure within a sqlite3_mprintf(): # | < | | | | | | | | | | | | | | | | | < | 3753 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 | } {} do_test printf-15.3 { sqlite3_snprintf_int 0 {} 0 } {abcdefghijklmnopqrstuvwxyz} # Now test malloc() failure within a sqlite3_mprintf(): # foreach var {a b c d} { set $var [string repeat $var 400] } set str1 "[string repeat A 360]%d%d%s" set str2 [string repeat B 5000] set zSuccess "[string repeat A 360]11[string repeat B 5000]" foreach ::iRepeat {0 1} { set nTestNum 1 while {1} { sqlite3_memdebug_fail $nTestNum -repeat $::iRepeat set z [sqlite3_mprintf_str $str1 1 1 $str2] set nFail [sqlite3_memdebug_fail -1 -benign nBenign] do_test printf-malloc-$::iRepeat.$nTestNum { expr {($nFail>0 && $z eq "") || ($nFail==$nBenign && $z eq $zSuccess)} } {1} if {$nFail == 0} break incr nTestNum } } finish_test |
Changes to test/releasetest.tcl.
︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 | -DHAVE_UTIME=0 } "Unlock-Notify" { -O2 -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_THREADSAFE -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 } "Secure-Delete" { -O2 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 } "Update-Delete-Limit" { | > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | -DHAVE_UTIME=0 } "Unlock-Notify" { -O2 -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_THREADSAFE -DSQLITE_TCL_DEFAULT_FULLMUTEX=1 -DSQLITE_USER_AUTHENTICATION=1 } "Secure-Delete" { -O2 -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 } "Update-Delete-Limit" { |
︙ | ︙ | |||
264 265 266 267 268 269 270 | FuzzFail1 {-O0} FuzzFail2 {-O0} }] array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols" checksymbols | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | FuzzFail1 {-O0} FuzzFail2 {-O0} }] array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols" checksymbols "Fast-One" "fuzztest test" "Debug-One" "mptest test" "Have-Not" test "Secure-Delete" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Update-Delete-Limit" test "Extra-Robustness" test "Device-Two" test |
︙ | ︙ |
Changes to test/resetdb.test.
︙ | ︙ | |||
203 204 205 206 207 208 209 | set res } {1 2 3 4} do_execsql_test -db db2 630 { SELECT * FROM sqlite_master } {} | > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > | 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 | set res } {1 2 3 4} do_execsql_test -db db2 630 { SELECT * FROM sqlite_master } {} #------------------------------------------------------------------------- db2 close reset_db do_execsql_test 700 { PRAGMA page_size=512; PRAGMA auto_vacuum = 0; CREATE TABLE t1(a,b,c); CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b,c); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10) INSERT INTO t1(a,b,c) SELECT x, randomblob(100),randomblob(100) FROM c; PRAGMA page_count; PRAGMA integrity_check; } {19 ok} if {[nonzero_reserved_bytes]} { finish_test return } do_execsql_test 710 { UPDATE sqlite_dbpage SET data= X'53514C69746520666F726D61742033000200030100402020000000000000001300000000000000000000000300000004000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000D00000003017C0001D801AC017C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E03061715110145696E6465787431626374310443524541544520494E4445582074316263204F4E20743128622C63292A0206171311013F696E64657874316174310343524541544520494E44455820743161204F4E20743128612926010617111101397461626C657431743102435245415445205441424C4520743128612C622C6329' WHERE pgno=1; } do_execsql_test 720 { PRAGMA integrity_check; } {ok} do_test 730 { sqlite3_db_config db RESET_DB 1 db eval VACUUM sqlite3_db_config db RESET_DB 0 } {0} do_execsql_test 740 { PRAGMA page_count; PRAGMA integrity_check; } {1 ok} finish_test |
Changes to test/server1.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # Skip this whole file if the server testing code is not enabled # if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} { finish_test return } # The sample server implementation does not work right when memory # management is enabled. # ifcapable (memorymanage||mutex_noop) { finish_test return | > > > > > > > > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # Skip this whole file if the server testing code is not enabled # if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} { finish_test return } # This test does not work on older PPC Macs due to problems in the # pthreads library. So skip it. # if {$tcl_platform(machine)=="Power Macintosh" && $tcl_platform(byteOrder)=="bigEndian"} { finish_test return } # The sample server implementation does not work right when memory # management is enabled. # ifcapable (memorymanage||mutex_noop) { finish_test return |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
374 375 376 377 378 379 380 | # look for a few of the possible help commands list [regexp {.help} $res] \ [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} do_test shell1-3.10.2 { # we allow .help to take extra args (it is help after all) | | | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | # look for a few of the possible help commands list [regexp {.help} $res] \ [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} do_test shell1-3.10.2 { # we allow .help to take extra args (it is help after all) set res [catchcmd "test.db" ".help *"] # look for a few of the possible help commands list [regexp {.help} $res] \ [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} # .import FILE TABLE Import data from FILE into TABLE |
︙ | ︙ |
Changes to test/snapshot.test.
︙ | ︙ | |||
213 214 215 216 217 218 219 | do_test $tn.3.2.1 { execsql { BEGIN; SELECT * FROM t2; } } {a b c d e f} | > > > | > | > > > > > > | > > > > > | | 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 | do_test $tn.3.2.1 { execsql { BEGIN; SELECT * FROM t2; } } {a b c d e f} # Update - it is no longer an error to have a read-transaction open, # provided there are no active SELECT statements. do_test $tn.3.2.2a { db eval "SELECT * FROM t2" { set res [list [catch {snapshot_open db main $snapshot } msg] $msg] break } set res } {1 SQLITE_ERROR} do_test $tn.3.2.2b { snapshot_open db main $snapshot } {} do_test $tn.3.2.3 { execsql { COMMIT; BEGIN; INSERT INTO t2 VALUES('g', 'h'); } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} do_execsql_test $tn.3.2.4 COMMIT do_test $tn.3.3.1a { execsql { PRAGMA journal_mode = DELETE } execsql { BEGIN } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} do_test $tn.3.3.1b { execsql { COMMIT ; BEGIN ; SELECT * FROM t2 } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} do_test $tn.$tn.3.3.2 { snapshot_free $snapshot execsql COMMIT } {} #------------------------------------------------------------------------- # Check that SQLITE_ERROR_SNAPSHOT is returned if the specified snapshot # no longer exists because the wal file has been checkpointed. # # 1. Reading a snapshot from the middle of a wal file is not possible # after the wal file has been checkpointed. # # 2. That a snapshot from the end of a wal file can not be read once # the wal file has been wrapped. |
︙ | ︙ | |||
277 278 279 280 281 282 283 | do_test $tn.4.1.3 { execsql { COMMIT; PRAGMA wal_checkpoint; BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | do_test $tn.4.1.3 { execsql { COMMIT; PRAGMA wal_checkpoint; BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_test $tn.4.1.4 { snapshot_free $snapshot execsql COMMIT } {} do_test $tn.4.2.1 { execsql { |
︙ | ︙ | |||
308 309 310 311 312 313 314 | do_test $tn.4.2.3 { execsql { COMMIT; INSERT INTO t3 VALUES('e', 't'); BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg | | | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 | do_test $tn.4.2.3 { execsql { COMMIT; INSERT INTO t3 VALUES('e', 't'); BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_test $tn.4.2.4 { snapshot_free $snapshot } {} #------------------------------------------------------------------------- # Check that SQLITE_BUSY is returned if a checkpoint is running when # sqlite3_snapshot_open() is called. |
︙ | ︙ |
Changes to test/snapshot2.test.
︙ | ︙ | |||
106 107 108 109 110 111 112 | sqlite3_db_config db NO_CKPT_ON_CLOSE 1 db close sqlite3 db test.db execsql {SELECT * FROM sqlite_master} execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | sqlite3_db_config db NO_CKPT_ON_CLOSE 1 db close sqlite3 db test.db execsql {SELECT * FROM sqlite_master} execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_test 2.3 { execsql COMMIT sqlite3_snapshot_recover db main execsql BEGIN sqlite3_snapshot_open_blob db main $snap execsql { SELECT * FROM t1 } |
︙ | ︙ | |||
130 131 132 133 134 135 136 | sqlite3_db_config db NO_CKPT_ON_CLOSE 1 db close sqlite3 db test.db sqlite3_snapshot_recover db main execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | sqlite3_db_config db NO_CKPT_ON_CLOSE 1 db close sqlite3 db test.db sqlite3_snapshot_recover db main execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} #------------------------------------------------------------------------- # Check that calling sqlite3_snapshot_recover() does not confuse the # pager cache. reset_db do_execsql_test 3.0 { PRAGMA journal_mode = wal; |
︙ | ︙ | |||
230 231 232 233 234 235 236 | db2 eval { SELECT * FROM t2 ; END } } {abc def ghi} do_test 5.4 { execsql { INSERT INTO t2 VALUES('jkl') } execsql BEGIN db2 list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg | | | 230 231 232 233 234 235 236 237 238 239 240 241 | db2 eval { SELECT * FROM t2 ; END } } {abc def ghi} do_test 5.4 { execsql { INSERT INTO t2 VALUES('jkl') } execsql BEGIN db2 list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} finish_test |
Changes to test/snapshot3.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | execsql { PRAGMA wal_checkpoint = truncate } file size test.db-wal } 0 do_test 1.8 { execsql BEGIN db3 list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg | | | 90 91 92 93 94 95 96 97 98 99 100 | execsql { PRAGMA wal_checkpoint = truncate } file size test.db-wal } 0 do_test 1.8 { execsql BEGIN db3 list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} finish_test |
Added test/snapshot4.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 | # 2018 August 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 implements regression tests for SQLite library. The focus # of this file is the sqlite3_snapshot_xxx() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !snapshot {finish_test; return} set testprefix snapshot4 # This test does not work with the inmemory_journal permutation. The reason # is that each connection opened as part of this permutation executes # "PRAGMA journal_mode=memory", which fails if the database is in wal mode # and there are one or more existing connections. if {[permutation]=="inmemory_journal"} { finish_test return } sqlite3 db2 test.db do_execsql_test 1.0 { PRAGMA cache_size = 10; CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, randomblob(400)); PRAGMA journal_mode = wal; WITH s(i) AS ( SELECT 2 UNION ALL SELECT i+1 FROM s WHERE i<100 ) INSERT INTO t1 SELECT i, randomblob(400) FROM s; } {wal} do_test 1.1 { execsql { BEGIN; SELECT count(*) FROM t1; } } {100} do_test 1.2 { db2 eval { SELECT count(*) FROM t1; CREATE TABLE t2(x); } } {100} do_test 1.3 { set ::snap [sqlite3_snapshot_get_blob db main] db2 eval { PRAGMA wal_checkpoint } } {0 54 52} do_test 1.4 { execsql { COMMIT; SELECT * FROM sqlite_master; BEGIN; } sqlite3_snapshot_open_blob db main $::snap execsql { SELECT count(*) FROM t1 } } {100} finish_test |
Changes to test/snapshot_fault.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 | INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); } } -body { db eval { PRAGMA wal_checkpoint } } -test { db2 eval BEGIN if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} { | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); } } -body { db eval { PRAGMA wal_checkpoint } } -test { db2 eval BEGIN if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} { if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else { set res [db2 eval { SELECT a FROM t1; PRAGMA integrity_check; }] |
︙ | ︙ | |||
94 95 96 97 98 99 100 | db_save db close db_restore_and_reopen db eval { SELECT * FROM t1 } db eval BEGIN if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} { | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | db_save db close db_restore_and_reopen db eval { SELECT * FROM t1 } db eval BEGIN if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} { if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else { # This branch should actually never be taken. But it was useful in # determining whether or not this test was actually working (by # running a modified version of SQLite that allowed snapshots to be # opened following a recovery). |
︙ | ︙ |
Added test/snapshot_up.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 | # 2018 August 6 # # 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. # #*********************************************************************** # # Tests for calling sqlite3_snapshot_open() when there is already # a read transaction open on the database. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !snapshot {finish_test; return} set testprefix snapshot_up # This test does not work with the inmemory_journal permutation. The reason # is that each connection opened as part of this permutation executes # "PRAGMA journal_mode=memory", which fails if the database is in wal mode # and there are one or more existing connections. if {[permutation]=="inmemory_journal"} { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a, b, c); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t1 VALUES(7, 8, 9); } {wal} do_test 1.1 { execsql BEGIN set ::snap1 [sqlite3_snapshot_get db main] execsql COMMIT execsql { INSERT INTO t1 VALUES(10, 11, 12); } execsql BEGIN set ::snap2 [sqlite3_snapshot_get db main] execsql COMMIT execsql { INSERT INTO t1 VALUES(13, 14, 15); } execsql BEGIN set ::snap3 [sqlite3_snapshot_get db main] execsql COMMIT } {} do_execsql_test 1.2 { BEGIN; SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15} do_test 1.3 { sqlite3_snapshot_open db main $::snap1 execsql { SELECT * FROM t1 } } {1 2 3 4 5 6 7 8 9} do_test 1.4 { sqlite3_snapshot_open db main $::snap2 execsql { SELECT * FROM t1 } } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 1.5 { sqlite3 db2 test.db execsql { PRAGMA wal_checkpoint } db2 } {0 5 4} do_execsql_test 1.6 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 1.7 { list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_execsql_test 1.8 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 1.9 { execsql { COMMIT ; BEGIN } list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_test 1.10 { execsql { COMMIT } execsql { PRAGMA wal_checkpoint; DELETE FROM t1 WHERE a = 1; } db2 execsql BEGIN set ::snap4 [sqlite3_snapshot_get db main] execsql COMMIT execsql { DELETE FROM t1 WHERE a = 4; } db2 } {} do_test 1.11 { execsql { BEGIN; SELECT * FROM t1 } } {7 8 9 10 11 12 13 14 15} do_test 1.12 { sqlite3_snapshot_open db main $::snap4 execsql { SELECT * FROM t1 } } {4 5 6 7 8 9 10 11 12 13 14 15} do_test 1.13 { list [catch { sqlite3_snapshot_open db main $::snap3 } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_test 1.14 { execsql { SELECT * FROM t1 } } {4 5 6 7 8 9 10 11 12 13 14 15} db close db2 close sqlite3 db test.db do_execsql_test 1.15 { BEGIN; SELECT * FROM t1 } {7 8 9 10 11 12 13 14 15} do_test 1.16 { list [catch { sqlite3_snapshot_open db main $::snap4 } msg] $msg } {1 SQLITE_ERROR_SNAPSHOT} do_execsql_test 1.17 { COMMIT } sqlite3_snapshot_free $::snap1 sqlite3_snapshot_free $::snap2 sqlite3_snapshot_free $::snap3 sqlite3_snapshot_free $::snap4 #------------------------------------------------------------------------- catch { db close } sqlite3 db test.db sqlite3 db2 test.db sqlite3 db3 test.db proc xBusy {args} { return 1 } db3 busy xBusy do_test 2.1 { execsql { INSERT INTO t1 VALUES(16, 17, 18) } db2 execsql BEGIN set ::snap1 [sqlite3_snapshot_get db main] execsql COMMIT execsql { INSERT INTO t1 VALUES(19, 20, 21) } db2 execsql BEGIN set ::snap2 [sqlite3_snapshot_get db main] execsql COMMIT set {} {} } {} do_execsql_test -db db2 2.2 { BEGIN; INSERT INTO t1 VALUES(19, 20, 21); } do_test 2.3 { execsql BEGIN sqlite3_snapshot_open db main $::snap1 execsql { SELECT * FROM t1 } } {7 8 9 10 11 12 13 14 15 16 17 18} proc xBusy {args} { set ::res [list [catch { sqlite3_snapshot_open db main $::snap2 } msg] $msg] return 1 } db3 busy xBusy do_test 2.4 { execsql {PRAGMA wal_checkpoint = restart} db3 set ::res } {1 SQLITE_BUSY} sqlite3_snapshot_free $::snap1 sqlite3_snapshot_free $::snap2 finish_test |
Changes to test/tableapi.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | source $testdir/tester.tcl ifcapable !gettable { finish_test return } | < | < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | source $testdir/tester.tcl ifcapable !gettable { finish_test return } source $testdir/malloc_common.tcl do_test tableapi-1.0 { set ::dbx [sqlite3_open test.db] catch {sqlite_exec_printf $::dbx {DROP TABLE xyz} {}} sqlite3_exec_printf $::dbx {CREATE TABLE %s(a int, b text)} xyz } {0 {}} do_test tableapi-1.1 { |
︙ | ︙ | |||
235 236 237 238 239 240 241 | # each iteration. $::dbx is a seperate connection, and on Windows, will # cause the file deletion of test.db to fail, so we move the close of $::dbx # up to here before the do_malloc_test. do_test tableapi-99.0 { sqlite3_close $::dbx } {SQLITE_OK} | < | | | | | | | | | | < | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | # each iteration. $::dbx is a seperate connection, and on Windows, will # cause the file deletion of test.db to fail, so we move the close of $::dbx # up to here before the do_malloc_test. do_test tableapi-99.0 { sqlite3_close $::dbx } {SQLITE_OK} do_malloc_test tableapi-7 -sqlprep { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); INSERT INTO t1 VALUES(3,4); INSERT INTO t1 SELECT a+4, b+4 FROM t1; INSERT INTO t1 SELECT a+8, b+8 FROM t1; } -tclbody { set r [sqlite3_get_table_printf db {SELECT rowid, a, b FROM t1} {}] if {[llength $r]<26} {error "out of memory"} } finish_test |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
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 | # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Check the error messages generated by tclsqlite # set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" } do_test tcl-1.1 { 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, deserialize, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, 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] | > > > > > > > | 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 | # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $ catch {sqlite3} set testdir [file dirname $argv0] source $testdir/tester.tcl # Check the error messages generated by tclsqlite # set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" } do_test tcl-1.1 { 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.1.1 { set v [catch {sqlite3} 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, deserialize, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, serialize, 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] |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
452 453 454 455 456 457 458 459 460 461 462 463 464 465 | } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break if {$cmdlinearg(malloctrace)} { sqlite3_memdebug_log start } } {^-+backtrace=.+$} { foreach {dummy cmdlinearg(backtrace)} [split $a =] break sqlite3_memdebug_backtrace $cmdlinearg(backtrace) } | > > > > > | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | } {^-+maxerror=.+$} { foreach {dummy cmdlinearg(maxerror)} [split $a =] break } {^-+malloctrace=.+$} { foreach {dummy cmdlinearg(malloctrace)} [split $a =] break if {$cmdlinearg(malloctrace)} { if {0==$::sqlite_options(memdebug)} { set err "Error: --malloctrace=1 requires an SQLITE_MEMDEBUG build" puts stderr $err exit 1 } sqlite3_memdebug_log start } } {^-+backtrace=.+$} { foreach {dummy cmdlinearg(backtrace)} [split $a =] break sqlite3_memdebug_backtrace $cmdlinearg(backtrace) } |
︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 | incr nErr } if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || [sqlite3_memory_used]>0} { output2 "Unfreed memory: [sqlite3_memory_used] bytes in\ [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations" incr nErr | | | | | < | | | 1259 1260 1261 1262 1263 1264 1265 1266 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 1294 1295 1296 1297 | incr nErr } if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || [sqlite3_memory_used]>0} { output2 "Unfreed memory: [sqlite3_memory_used] bytes in\ [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations" incr nErr ifcapable mem5||(mem3&&debug) { output2 "Writing unfreed memory log to \"./memleak.txt\"" sqlite3_memdebug_dump ./memleak.txt } } else { output2 "All memory allocations freed - no leaks" ifcapable mem5 { sqlite3_memdebug_dump ./memusage.txt } } show_memstats output2 "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" output2 "Current memory usage: [sqlite3_memory_highwater] bytes" if {[info commands sqlite3_memdebug_malloc_count] ne ""} { output2 "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" } if {$::cmdlinearg(malloctrace)} { output2 "Writing mallocs.tcl..." memdebug_log_sql mallocs.tcl sqlite3_memdebug_log stop sqlite3_memdebug_log clear if {[sqlite3_memory_used]>0} { output2 "Writing leaks.tcl..." sqlite3_memdebug_log sync memdebug_log_sql leaks.tcl } } foreach f [glob -nocomplain test.db-*-journal] { forcedelete $f } foreach f [glob -nocomplain test.db-mj*] { forcedelete $f |
︙ | ︙ | |||
2015 2016 2017 2018 2019 2020 2021 | set txt [$db eval "SELECT * FROM $master"]\n foreach tab $alltab { append txt [$db eval "SELECT * FROM $dbname.$tab"]\n } return [md5 $txt] } | | | 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | set txt [$db eval "SELECT * FROM $master"]\n foreach tab $alltab { append txt [$db eval "SELECT * FROM $dbname.$tab"]\n } return [md5 $txt] } proc memdebug_log_sql {filename} { set data [sqlite3_memdebug_log dump] set nFrame [expr [llength [lindex $data 0]]-2] if {$nFrame < 0} { return "" } set database temp |
︙ | ︙ | |||
2061 2062 2063 2064 2065 2066 2067 2068 | set contents [read $fd] close $fd } set contents [string map {' ''} $contents] append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n" } set fd [open $filename w] | > > > > > | > > > > > | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 | set contents [read $fd] close $fd } set contents [string map {' ''} $contents] append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n" } set escaped "BEGIN; ${tbl}${tbl2}${tbl3}${sql} ; COMMIT;" set escaped [string map [list "{" "\\{" "}" "\\}"] $escaped] set fd [open $filename w] puts $fd "set BUILTIN {" puts $fd $escaped puts $fd "}" puts $fd {set BUILTIN [string map [list "\\{" "{" "\\}" "}"] $BUILTIN]} set mtv [open $::testdir/malloctraceviewer.tcl] set txt [read $mtv] close $mtv puts $fd $txt close $fd } # Drop all tables in database [db] proc drop_all_tables {{db db}} { ifcapable trigger&&foreignkey { set pk [$db one "PRAGMA foreign_keys"] |
︙ | ︙ |
Added test/tkt-c694113d5.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 | # 2018-07-24 # # 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. Specifically, # it tests that ticket [c694113e50321afdf952e2d1235b08ba663f8399]: # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-c694113d5.100 { sqlite3 db :memory: db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY); CREATE TABLE t2(d INTEGER PRIMARY KEY,e,f); INSERT INTO t1(a) VALUES(1),(2),(3),(4); } set answer {} db eval {SELECT a FROM t1 WHERE NOT EXISTS(SELECT 1 FROM t2 WHERE d=a)} { if {$a==3} { lappend answer "CREATE INDEX" db eval {CREATE INDEX t2e ON t2(e);} } lappend answer "a=$a" } set answer } {a=1 a=2 {CREATE INDEX} a=3 a=4} finish_test |
Changes to test/trigger7.test.
︙ | ︙ | |||
109 110 111 112 113 114 115 | execsql { PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='nonsense'; } db close catch { sqlite3 db test.db } catchsql { DROP TRIGGER t2r5 } | | | 109 110 111 112 113 114 115 116 117 118 | execsql { PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='nonsense'; } db close catch { sqlite3 db test.db } catchsql { DROP TRIGGER t2r5 } } {/1 {malformed database schema .*}/} finish_test |
Changes to test/triggerA.test.
︙ | ︙ | |||
196 197 198 199 200 201 202 | db eval { DELETE FROM result4; UPDATE v5 SET b = main.v5.b+9900000 WHERE main.v5.x BETWEEN 3 AND 5; SELECT * FROM result4 ORDER BY a; } } {3 305 3 9900305 4 404 4 9900404 5 504 5 9900504} | < < < < < < < | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | db eval { DELETE FROM result4; UPDATE v5 SET b = main.v5.b+9900000 WHERE main.v5.x BETWEEN 3 AND 5; SELECT * FROM result4 ORDER BY a; } } {3 305 3 9900305 4 404 4 9900404 5 504 5 9900504} source $testdir/malloc_common.tcl # Save a copy of the current database configuration. # db close forcedelete test.db-triggerA copy_file test.db test.db-triggerA |
︙ | ︙ |
Changes to test/upsert1.test.
︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 | PRAGMA integrity_check; } {ok} do_execsql_test upsert1-610 { DELETE FROM t1; INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING; PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | PRAGMA integrity_check; } {ok} do_execsql_test upsert1-610 { DELETE FROM t1; INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING; PRAGMA integrity_check; } {ok} # 2018-08-14 # Ticket https://www.sqlite.org/src/info/908f001483982c43 # If there are multiple uniqueness contraints, the UPSERT should fire # if the one constraint it targets fails, regardless of whether or not # the other constraints pass or fail. In other words, the UPSERT constraint # should be tested first. # do_execsql_test upsert1-700 { DROP TABLE t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT, d INT, e INT); CREATE UNIQUE INDEX t1b ON t1(b); CREATE UNIQUE INDEX t1e ON t1(e); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(e) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-710 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(a) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-720 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-730 { DROP TABLE t1; CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT); CREATE UNIQUE INDEX t1a ON t1(a); CREATE UNIQUE INDEX t1b ON t1(b); CREATE UNIQUE INDEX t1e ON t1(e); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(e) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-740 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(a) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-750 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-760 { DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT, d INT, e INT) WITHOUT ROWID; CREATE UNIQUE INDEX t1a ON t1(a); CREATE UNIQUE INDEX t1b ON t1(b); CREATE UNIQUE INDEX t1e ON t1(e); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(e) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-770 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(a) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} do_execsql_test upsert1-780 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); INSERT INTO t1(a,b,c,d,e) VALUES(1,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} finish_test |
Changes to test/view.test.
︙ | ︙ | |||
670 671 672 673 674 675 676 677 678 | } {123 234 345} do_test view-22.2 { unset -nocomplain x db eval {SELECT * FROM x1} x break lsort [array names x] } {{} * :1 :2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {123 234 345} do_test view-22.2 { unset -nocomplain x db eval {SELECT * FROM x1} x break lsort [array names x] } {{} * :1 :2} do_test view-25.1 { db eval { CREATE TABLE t25 (x); INSERT INTO t25 (x) VALUES (1); ANALYZE; } proc authLogDelete {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_DELETE" && [string match sqlite_stat* $arg1]} { # lappend ::log [list $code $arg1 $arg2 $arg3 $arg4 $args] lappend ::log [list $code $arg1 $arg2 $arg3 $arg4] } return SQLITE_OK } set log "" db authorizer ::authLogDelete db eval {DROP VIEW x1;} set log } {} set res [list {SQLITE_DELETE sqlite_stat1 {} main {}}] ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {}} } do_test view-25.2 { set log "" db eval {DROP TABLE t25;} set log } $res finish_test |
Changes to test/vtab_err.test.
︙ | ︙ | |||
36 37 38 39 40 41 42 | BEGIN; CREATE TABLE r2(a, b, c); INSERT INTO r2 SELECT * FROM e; INSERT INTO e SELECT a||'x', b, c FROM r2; COMMIT; } | < < < < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | BEGIN; CREATE TABLE r2(a, b, c); INSERT INTO r2 SELECT * FROM e; INSERT INTO e SELECT a||'x', b, c FROM r2; COMMIT; } source $testdir/malloc_common.tcl do_malloc_test vtab_err-2 -tclprep { register_echo_module [sqlite3_connection_pointer db] } -sqlbody { BEGIN; |
︙ | ︙ |
Changes to test/where.test.
︙ | ︙ | |||
578 579 580 581 582 583 584 | SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 10 } } {/1 100 4 2 99 9 3 98 16 .* nosort/} do_test where-6.7.2 { cksort { SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 1 } | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 10 } } {/1 100 4 2 99 9 3 98 16 .* nosort/} do_test where-6.7.2 { cksort { SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 1 } } {1 100 4 nosort} ifcapable subquery { do_test where-6.8a { cksort { SELECT * FROM t3 WHERE a IN (3,5,7,1,9,4,2) ORDER BY a LIMIT 3 } } {1 100 4 2 99 9 3 98 16 nosort} do_test where-6.8b { |
︙ | ︙ |
Added test/whereL.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 | # 2018-07-26 # # 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 WHERE-clause constant propagation # optimization. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix whereL do_execsql_test 100 { CREATE TABLE t1(a INT PRIMARY KEY, b, c, d, e); CREATE TABLE t2(a INT PRIMARY KEY, f, g, h, i); CREATE TABLE t3(a INT PRIMARY KEY, j, k, l, m); CREATE VIEW v4 AS SELECT * FROM t2 UNION ALL SELECT * FROM t3; } do_eqp_test 110 { SELECT * FROM t1, v4 WHERE t1.a=?1 AND v4.a=t1.a; } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) | `--UNION ALL | `--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?) |--SCAN SUBQUERY xxxxxx `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) } # The scan of the t1 table goes first since that enables the ORDER BY # sort to be omitted. This would not be possible without constant # propagation because without it the t1 table would depend on t3. # do_eqp_test 120 { SELECT * FROM t1, t2, t3 WHERE t1.a=t2.a AND t2.a=t3.j AND t3.j=5 ORDER BY t1.a; } { QUERY PLAN |--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) |--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) `--SCAN TABLE t3 } # Constant propagation in the face of collating sequences: # do_execsql_test 200 { CREATE TABLE c3(x COLLATE binary, y COLLATE nocase, z COLLATE binary); CREATE INDEX c3x ON c3(x); INSERT INTO c3 VALUES('ABC', 'ABC', 'abc'); SELECT * FROM c3 WHERE x=y AND y=z AND z='abc'; } {ABC ABC abc} # If the constants are blindly propagated, as shown in the following # query, the wrong answer results: # do_execsql_test 201 { SELECT * FROM c3 WHERE x='abc' AND y='abc' AND z='abc'; } {} # Constant propagation caused an incorrect answer in the following # query. (Reported by Bentley system on 2018-08-09.) # do_execsql_test 300 { CREATE TABLE A(id INTEGER PRIMARY KEY, label TEXT); CREATE TABLE B(id INTEGER PRIMARY KEY, label TEXT, Aid INTEGER); CREATE TABLE C( id INTEGER PRIMARY KEY, xx INTEGER NOT NULL, yy INTEGER, zz INTEGER ); CREATE UNIQUE INDEX x2 ON C(yy); CREATE UNIQUE INDEX x4 ON C(yy, zz); INSERT INTO A(id) VALUES(1); INSERT INTO B(id) VALUES(2); INSERT INTO C(id,xx,yy,zz) VALUES(99,50,1,2); SELECT 1 FROM A, (SELECT id,xx,yy,zz FROM C) subq, B WHERE A.id='1' AND A.id=subq.yy AND B.id=subq.zz; } {1} do_execsql_test 301 { SELECT 1 FROM A, (SELECT id,xx,yy,zz FROM C) subq, B WHERE A.id=1 AND A.id=subq.yy AND B.id=subq.zz; } {1} do_execsql_test 302 { SELECT 1 FROM A, (SELECT id,yy,zz FROM C) subq, B WHERE A.id='1' AND A.id=subq.yy AND B.id=subq.zz; } {1} finish_test |
Changes to test/window1.test.
︙ | ︙ | |||
522 523 524 525 526 527 528 | do_catchsql_test 11.3 { CREATE INDEX t6i ON t6(sum(b) OVER ()); } {1 {misuse of window function sum()}} do_catchsql_test 11.4 { CREATE INDEX t6i ON t6(lead(b) OVER ()); } {1 {misuse of window function lead()}} | > > > | > > > > > > > > > > > > > > > > > > > | 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 | do_catchsql_test 11.3 { CREATE INDEX t6i ON t6(sum(b) OVER ()); } {1 {misuse of window function sum()}} do_catchsql_test 11.4 { CREATE INDEX t6i ON t6(lead(b) OVER ()); } {1 {misuse of window function lead()}} # 2018-09-17 ticket 510cde277783b5fb5de628393959849dff377eb3 # Endless loop on a query with window functions and a limit # do_execsql_test 12.100 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(id INT, b VARCHAR, c VARCHAR); INSERT INTO t1 VALUES(1, 'A', 'one'); INSERT INTO t1 VALUES(2, 'B', 'two'); INSERT INTO t1 VALUES(3, 'C', 'three'); INSERT INTO t1 VALUES(4, 'D', 'one'); INSERT INTO t1 VALUES(5, 'E', 'two'); SELECT id, b, lead(c,1) OVER(ORDER BY c) AS x FROM t1 WHERE id>1 ORDER BY b LIMIT 1; } {2 B two} do_execsql_test 12.110 { INSERT INTO t1 VALUES(6, 'F', 'three'); INSERT INTO t1 VALUES(7, 'G', 'one'); SELECT id, b, lead(c,1) OVER(ORDER BY c) AS x FROM t1 WHERE id>1 ORDER BY b LIMIT 2; } {2 B two 3 C three} finish_test |
Changes to test/window4.tcl.
︙ | ︙ | |||
354 355 356 357 358 359 360 361 362 363 364 | execsql_test 10.2 { SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } execsql_test 10.3 { SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | execsql_test 10.2 { SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } execsql_test 10.3 { SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } execsql_test 11.0 { DROP VIEW IF EXISTS v8; DROP TABLE IF EXISTS t8; CREATE TABLE t8(t INT, total INT); INSERT INTO t8 VALUES(0,2); INSERT INTO t8 VALUES(5,1); INSERT INTO t8 VALUES(10,1); } execsql_test 11.1 { SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8; } execsql_test 11.2 { CREATE VIEW v8 AS SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8; } execsql_test 11.3 { SELECT * FROM v8; } execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } finish_test |
Changes to test/window4.test.
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 | do_execsql_test 9.1 { SELECT rank() OVER () FROM t2 } {1 1 1 1 1 1 1} do_execsql_test 9.2 { SELECT dense_rank() OVER (PARTITION BY x) FROM t2 } {1 1 1 1 1 1 1} do_test 9.3 { set myres {} foreach r [db eval {SELECT x, percent_rank() OVER (PARTITION BY x ORDER BY x) FROM t2}] { | > | > > > > > > | < > > | > > > > > > | > | | > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 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 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 1320 | do_execsql_test 9.1 { SELECT rank() OVER () FROM t2 } {1 1 1 1 1 1 1} do_execsql_test 9.2 { SELECT dense_rank() OVER (PARTITION BY x) FROM t2 } {1 1 1 1 1 1 1} do_test 9.3 { set myres {} foreach r [db eval {SELECT x, percent_rank() OVER (PARTITION BY x ORDER BY x) FROM t2}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 0.0000 1.0000 0.0000 1.0000 0.0000 4.0000 0.0000 4.0000 0.0000 6.0000 0.0000 7.0000 0.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_execsql_test 9.4 { SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 1 1 1 1 4 4 4 4 6 6 7 7} do_execsql_test 9.5 { SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2 } {1 1 4 4 6 6 7 7} do_test 9.6 { set myres {} foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {0.0000 0.0000 0.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_test 9.7 { set myres {} foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] { lappend myres [format %.4f [set r]] } set res2 {1.0000 1.0000 1.0000} foreach r [set myres] r2 [set res2] { if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} { error "list element [set i] does not match: got=[set r] expected=[set r2]" } } set {} {} } {} do_execsql_test 10.0 { DROP TABLE IF EXISTS t7; CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER); INSERT INTO t7(id, a, b) VALUES (1, 1, 2), (2, 1, NULL), (3, 1, 4), (4, 3, NULL), (5, 3, 8), (6, 3, 1); } {} do_execsql_test 10.1 { SELECT id, min(b) OVER (PARTITION BY a ORDER BY id) FROM t7; } {1 2 2 2 3 2 4 {} 5 8 6 1} do_execsql_test 10.2 { SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } {1 {} 2 2 3 {} 4 {} 5 {} 6 8} do_execsql_test 10.3 { SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7; } {1 {} 2 4 3 {} 4 8 5 1 6 {}} do_execsql_test 11.0 { DROP VIEW IF EXISTS v8; DROP TABLE IF EXISTS t8; CREATE TABLE t8(t INT, total INT); INSERT INTO t8 VALUES(0,2); INSERT INTO t8 VALUES(5,1); INSERT INTO t8 VALUES(10,1); } {} do_execsql_test 11.1 { SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8; } {0 1 2} do_execsql_test 11.2 { CREATE VIEW v8 AS SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8; } {} do_execsql_test 11.3 { SELECT * FROM v8; } {0 1 2} do_execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } {0 1 2} finish_test |
Changes to test/with1.test.
︙ | ︙ | |||
860 861 862 863 864 865 866 867 868 869 870 871 872 873 | # 2015-07-05: Do not allow aggregate recursive queries # do_catchsql_test 16.1 { WITH RECURSIVE i(x) AS (VALUES(1) UNION SELECT count(*) FROM i) SELECT * FROM i; } {1 {recursive aggregate queries not supported}} #------------------------------------------------------------------------- do_execsql_test 17.1 { WITH x(a) AS ( WITH y(b) AS (SELECT 10) SELECT 9 UNION ALL SELECT * FROM y ) | > > > > > > > > > > > > > > > > > > > > > | 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 | # 2015-07-05: Do not allow aggregate recursive queries # do_catchsql_test 16.1 { WITH RECURSIVE i(x) AS (VALUES(1) UNION SELECT count(*) FROM i) SELECT * FROM i; } {1 {recursive aggregate queries not supported}} # Or window-function recursive queries. Ticket e8275b41. # ifcapable windowfunc { do_catchsql_test 16.2 { WITH RECURSIVE i(x) AS (VALUES(1) UNION SELECT count(*) OVER () FROM i) SELECT * FROM i; } {1 {cannot use window functions in recursive queries}} do_catchsql_test 16.3 { WITH RECURSIVE t(id, parent) AS (VALUES(1,2)), q(id, parent, rn) AS ( VALUES(1,2,3) UNION ALL SELECT t.*, ROW_NUMBER() OVER (ORDER BY t.id) AS rn FROM q JOIN t ON t.parent = q.id ) SELECT * FROM q; } {1 {cannot use window functions in recursive queries}} } #------------------------------------------------------------------------- do_execsql_test 17.1 { WITH x(a) AS ( WITH y(b) AS (SELECT 10) SELECT 9 UNION ALL SELECT * FROM y ) |
︙ | ︙ |
Changes to test/without_rowid3.test.
︙ | ︙ | |||
945 946 947 948 949 950 951 | } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { | | > > | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 | } } {{CREATE TABLE t2(a, b, c REFERENCES t1, d DEFAULT NULL REFERENCES t1, e REFERENCES t1 DEFAULT NULL, h DEFAULT 'text' REFERENCES t1)}} # Test the sqlite_rename_parent() function directly. # proc test_rename_parent {zCreate zOld zNew} { db eval {SELECT sqlite_rename_table( 'main', 'table', 't1', $zCreate, $zOld, $zNew, 0 )} } do_test without_rowid3-14.2.1.1 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t2 t3 } {{CREATE TABLE t1(a REFERENCES "t3")}} do_test without_rowid3-14.2.1.2 { test_rename_parent {CREATE TABLE t1(a REFERENCES t2)} t4 t3 } {{CREATE TABLE t1(a REFERENCES t2)}} |
︙ | ︙ |
Changes to tool/lemon.c.
︙ | ︙ | |||
2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 | } fseek(fp,0,2); filesize = ftell(fp); rewind(fp); filebuf = (char *)malloc( filesize+1 ); if( filesize>100000000 || filebuf==0 ){ ErrorMsg(ps.filename,0,"Input file too large."); gp->errorcnt++; fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", filesize); | > | 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 | } fseek(fp,0,2); filesize = ftell(fp); rewind(fp); filebuf = (char *)malloc( filesize+1 ); if( filesize>100000000 || filebuf==0 ){ ErrorMsg(ps.filename,0,"Input file too large."); free(filebuf); gp->errorcnt++; fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", filesize); |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
571 572 573 574 575 576 577 | }while(1); } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ | | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | }while(1); } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. */ static YYACTIONTYPE yy_find_reduce_action( YYACTIONTYPE stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; #ifdef YYERRORSYMBOL if( stateno>YY_REDUCE_COUNT ){ return yy_default[stateno]; |
︙ | ︙ | |||
711 712 713 714 715 716 717 | yyParser *yypParser, /* The parser */ unsigned int yyruleno, /* Number of the rule by which to reduce */ int yyLookahead, /* Lookahead token, or YYNOCODE if none */ ParseTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ ParseCTX_PDECL /* %extra_context */ ){ int yygoto; /* The next state */ | | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | yyParser *yypParser, /* The parser */ unsigned int yyruleno, /* Number of the rule by which to reduce */ int yyLookahead, /* Lookahead token, or YYNOCODE if none */ ParseTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ ParseCTX_PDECL /* %extra_context */ ){ int yygoto; /* The next state */ YYACTIONTYPE yyact; /* The next action */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; #ifndef NDEBUG |
︙ | ︙ | |||
923 924 925 926 927 928 929 | yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif do{ assert( yyact==yypParser->yytos->stateno ); | | | | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 | yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif do{ assert( yyact==yypParser->yytos->stateno ); yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor, yyminor ParseCTX_PARAM); }else if( yyact <= YY_MAX_SHIFTREDUCE ){ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; #endif break; }else if( yyact==YY_ACCEPT_ACTION ){ yypParser->yytos--; yy_accept(yypParser); |
︙ | ︙ |
Changes to tool/mkopcodeh.tcl.
︙ | ︙ | |||
20 21 22 23 24 25 26 | # during code generation, we need to generate corresponding opcodes like # OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, # code to translate from one to the other is avoided. This makes the # code generator smaller and faster. # # This script also scans for lines of the form: # | | > > | 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 | # during code generation, we need to generate corresponding opcodes like # OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, # code to translate from one to the other is avoided. This makes the # code generator smaller and faster. # # This script also scans for lines of the form: # # case OP_aaaa: /* jump, in1, in2, in3, out2, out3 */ # # When such comments are found on an opcode, it means that certain # properties apply to that opcode. Set corresponding flags using the # OPFLG_INITIALIZER macro. # set in stdin set currentOp {} set prevName {} set nOp 0 set nGroup 0 while {![eof $in]} { set line [gets $in] # Remember the TK_ values from the parse.h file. # NB: The "TK_" prefix stands for "ToKen", not the graphical Tk toolkit # commonly associated with TCL. # |
︙ | ︙ | |||
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 | # Scan for "case OP_aaaa:" lines in the vdbe.c file # if {[regexp {^case OP_} $line]} { set line [split $line] set name [string trim [lindex $line 1] :] if {$name=="OP_Abortable"} continue; # put OP_Abortable last set op($name) -1 set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 for {set i 3} {$i<[llength $line]-1} {incr i} { switch [string trim [lindex $line $i] ,] { same { incr i if {[lindex $line $i]=="as"} { incr i set sym [string trim [lindex $line $i] ,] set val $tk($sym) set op($name) $val set used($val) 1 set sameas($val) $sym set def($val) $name } } | > > | | | | | | > > > > > > > > > > > > > > > | 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 | # Scan for "case OP_aaaa:" lines in the vdbe.c file # if {[regexp {^case OP_} $line]} { set line [split $line] set name [string trim [lindex $line 1] :] if {$name=="OP_Abortable"} continue; # put OP_Abortable last set op($name) -1 set group($name) 0 set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 for {set i 3} {$i<[llength $line]-1} {incr i} { switch [string trim [lindex $line $i] ,] { same { incr i if {[lindex $line $i]=="as"} { incr i set sym [string trim [lindex $line $i] ,] set val $tk($sym) set op($name) $val set used($val) 1 set sameas($val) $sym set def($val) $name } } group {set group($name) 1} jump {set jump($name) 1} in1 {set in1($name) 1} in2 {set in2($name) 1} in3 {set in3($name) 1} out2 {set out2($name) 1} out3 {set out3($name) 1} } } if {$group($name)} { set newGroup 0 if {[info exists groups($nGroup)]} { if {$prevName=="" || !$group($prevName)} { set newGroup 1 } } lappend groups($nGroup) $name if {$newGroup} {incr nGroup} } else { if {$prevName!="" && $group($prevName)} { incr nGroup } } set order($nOp) $name set prevName $name incr nOp } } # Assign numbers to all opcodes and output the result. # puts "/* Automatically generated. Do not edit */" |
︙ | ︙ | |||
177 178 179 180 181 182 183 | set mxJump -1 for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | set mxJump -1 for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} } # Generate the numeric values for all remaining opcodes, while # preserving any groupings of opcodes (i.e. those that must be # together). # for {set g 0} {$g<$nGroup} {incr g} { set gLen [llength $groups($g)] set ok 0; set start -1 while {!$ok} { set seek $cnt; incr seek while {[info exists used($seek)]} {incr seek} set ok 1; set start $seek for {set j 0} {$j<$gLen} {incr j} { incr seek if {[info exists used($seek)]} { set ok 0; break } } } if {$ok} { set next $start for {set j 0} {$j<$gLen} {incr j} { set name [lindex $groups($g) $j] if {$op($name)>=0} continue set op($name) $next set used($next) 1 set def($next) $name incr next } } else { error "cannot find opcodes for group: $groups($g)" } } for {set i 0} {$i<$nOp} {incr i} { set name $order($i) if {$op($name)<0} { incr cnt while {[info exists used($cnt)]} {incr cnt} set op($name) $cnt set used($cnt) 1 set def($cnt) $name } } set max [lindex [lsort -decr -integer [array names used]] 0] for {set i 0} {$i<=$max} {incr i} { if {![info exists used($i)]} { set def($i) "OP_NotUsed_$i" } if {$i>$max} {set max $i} set name $def($i) puts -nonewline [format {#define %-16s %3d} $name $i] set com {} if {[info exists jump($name)] && $jump($name)} { lappend com "jump" } if {[info exists sameas($i)]} { lappend com "same as $sameas($i)" } if {[info exists synopsis($name)]} { lappend com "synopsis: $synopsis($name)" |
︙ | ︙ |
Changes to tool/mkpragmatab.tcl.
︙ | ︙ | |||
384 385 386 387 388 389 390 391 392 393 394 395 396 397 | FLAG: Result0 NAME: threads FLAG: Result0 NAME: optimize FLAG: Result1 NeedSchema } # Open the output file # set destfile "[file dir [file dir [file normal $argv0]]]/src/pragma.h" puts "Overwriting $destfile with new pragma table..." set fd [open $destfile wb] | > > > > > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | FLAG: Result0 NAME: threads FLAG: Result0 NAME: optimize FLAG: Result1 NeedSchema NAME: legacy_alter_table TYPE: FLAG ARG: SQLITE_LegacyAlter IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) } # Open the output file # set destfile "[file dir [file dir [file normal $argv0]]]/src/pragma.h" puts "Overwriting $destfile with new pragma table..." set fd [open $destfile wb] |
︙ | ︙ |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 | foreach hdr { btree.h btreeInt.h fts3.h fts3Int.h fts3_hash.h fts3_tokenizer.h hash.h hwtime.h keywordhash.h msvc.h mutex.h opcodes.h os_common.h | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | foreach hdr { btree.h btreeInt.h fts3.h fts3Int.h fts3_hash.h fts3_tokenizer.h geopoly.c hash.h hwtime.h keywordhash.h msvc.h mutex.h opcodes.h os_common.h |
︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 397 398 399 400 401 | fts3_tokenizer1.c fts3_tokenize_vtab.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c rtree.c icu.c fts3_icu.c sqlite3rbu.c dbstat.c dbpage.c sqlite3session.c | > < | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 | fts3_tokenizer1.c fts3_tokenize_vtab.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c json1.c rtree.c icu.c fts3_icu.c sqlite3rbu.c dbstat.c dbpage.c sqlite3session.c fts5.c stmt.c } { copy_file tsrc/$file } # Synthesize an alternative sqlite3_sourceid() implementation that |
︙ | ︙ |