Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge the latest enhancements from trunk. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | memdb |
Files: | files | file ages | folders |
SHA3-256: |
c8083de14b54fba1071385f8530d03d5 |
User & Date: | drh 2018-03-01 13:44:40.762 |
Context
2018-03-01
| ||
22:18 | Allow the zSchema argument to sqlite3_serialize() to be NULL to mean the main database. (check-in: 5b01b9914f user: drh tags: memdb) | |
13:44 | Merge the latest enhancements from trunk. (check-in: c8083de14b user: drh tags: memdb) | |
12:05 | Fix some crashes in the sqlite3changeset_apply() function that could be caused by corrupt changeset blobs. (check-in: 745a9a7fef user: dan tags: trunk) | |
2018-01-24
| ||
15:02 | Merge changes from trunk. (check-in: 6ef3de810d user: drh tags: memdb) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
437 438 439 440 441 442 443 444 445 446 447 448 449 450 | $(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 \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ | > | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | $(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 \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ |
︙ | ︙ | |||
587 588 589 590 591 592 593 594 595 596 597 598 599 600 | SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c DBFUZZ_OPT = # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) | > | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c DBFUZZ_OPT = # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # all: sqlite3.h libsqlite3.la sqlite3$(TEXE) $(HAVE_TCL:1=libtclsqlite3.la) |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 | $(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 \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\remember.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\unionvtab.c \ | > | 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 | $(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 \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\normalize.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\remember.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\unionvtab.c \ |
︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 | !ENDIF # <<mark>> # Extra compiler options for various test tools. # MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 | | | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 | !ENDIF # <<mark>> # Extra compiler options for various test tools. # MPTESTER_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 FUZZERSHELL_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 FUZZCHECK_COMPILE_OPTS = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ -DSQLITE_MAX_MEMORY=50000000 -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION KV_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ DBSELFTEST_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 ST_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 |
︙ | ︙ | |||
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 | 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 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB 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 | > | 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 | 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 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1 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 |
︙ | ︙ |
Changes to README.md.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ## Obtaining The Code SQLite sources are managed using the [Fossil](https://www.fossil-scm.org/), a distributed version control system that was specifically designed to support SQLite development. If you do not want to use Fossil, you can download tarballs or ZIP | | | | | > | | | > | 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 | ## Obtaining The Code SQLite sources are managed using the [Fossil](https://www.fossil-scm.org/), a distributed version control system that was specifically designed to support SQLite development. If you do not want to use Fossil, you can download tarballs or ZIP archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows: * Lastest trunk check-in as [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz), [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip), or [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar). * Latest release as [Tarball](https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release), [ZIP-archive](https://www.sqlite.org/src/zip/sqlite.zip?r=release), or [SQLite-archive](https://www.sqlite.org/src/sqlar/sqlite.sqlar?r=release). * For other check-ins, substitute an appropriate branch name or tag or hash prefix for "release" in the URLs of the previous bullet. Or browse the [timeline](https://www.sqlite.org/src/timeline) to locate the check-in desired, click on its information page link, then click on the "Tarball" or "ZIP Archive" links on the information page. |
︙ | ︙ |
Changes to autoconf/Makefile.am.
1 2 3 4 5 6 7 8 9 10 11 12 | AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ @ZLIB_FLAGS@ @SESSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE lib_LTLIBRARIES = libsqlite3.la libsqlite3_la_SOURCES = sqlite3.c libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 sqlite3_SOURCES = shell.c sqlite3.h EXTRA_sqlite3_SOURCES = sqlite3.c sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ @ZLIB_FLAGS@ @SESSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE lib_LTLIBRARIES = libsqlite3.la libsqlite3_la_SOURCES = sqlite3.c libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 sqlite3_SOURCES = shell.c sqlite3.h EXTRA_sqlite3_SOURCES = sqlite3.c sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS) include_HEADERS = sqlite3.h sqlite3ext.h EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs pkgconfigdir = ${libdir}/pkgconfig pkgconfig_DATA = sqlite3.pc |
︙ | ︙ |
Changes to autoconf/configure.ac.
︙ | ︙ | |||
164 165 166 167 168 169 170 171 172 173 174 175 176 177 | #----------------------------------------------------------------------- AC_CHECK_FUNCS(posix_fallocate) AC_CHECK_HEADERS(zlib.h,[ AC_SEARCH_LIBS(deflate,z,[ZLIB_FLAGS="-DSQLITE_HAVE_ZLIB"]) ]) AC_SUBST(ZLIB_FLAGS) #----------------------------------------------------------------------- # UPDATE: Maybe it's better if users just set CFLAGS before invoking # configure. This option doesn't really add much... # # --enable-tempstore # | > > > | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | #----------------------------------------------------------------------- AC_CHECK_FUNCS(posix_fallocate) AC_CHECK_HEADERS(zlib.h,[ AC_SEARCH_LIBS(deflate,z,[ZLIB_FLAGS="-DSQLITE_HAVE_ZLIB"]) ]) AC_SUBST(ZLIB_FLAGS) AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"]) AC_SUBST(SHELL_CFLAGS) #----------------------------------------------------------------------- # UPDATE: Maybe it's better if users just set CFLAGS before invoking # configure. This option doesn't really add much... # # --enable-tempstore # |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 | sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, iBlock); sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); } return rc; } /* ** Find the largest relative level number in the table. If successful, set ** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, | > | 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 | sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pStmt, 1, iBlock); sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 2); } return rc; } /* ** Find the largest relative level number in the table. If successful, set ** *pnMax to this value and return SQLITE_OK. Otherwise, if an error occurs, |
︙ | ︙ | |||
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 | char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); if( !zEnd ) return SQLITE_NOMEM; sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); } sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); } return rc; } /* ** Return the size of the common prefix (if any) shared by zPrev and ** zNext, in bytes. For example, | > | 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 | char *zEnd = sqlite3_mprintf("%lld %lld", iEndBlock, nLeafData); if( !zEnd ) return SQLITE_NOMEM; sqlite3_bind_text(pStmt, 5, zEnd, -1, sqlite3_free); } sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC); sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 6); } return rc; } /* ** Return the size of the common prefix (if any) shared by zPrev and ** zNext, in bytes. For example, |
︙ | ︙ | |||
3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 | *pRC = rc; return; } sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); sqlite3_step(pStmt); *pRC = sqlite3_reset(pStmt); sqlite3_free(a); } /* ** Merge the entire database so that there is one segment for each ** iIndex/iLangid combination. */ | > | 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 | *pRC = rc; return; } sqlite3_bind_int(pStmt, 1, FTS_STAT_DOCTOTAL); sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC); sqlite3_step(pStmt); *pRC = sqlite3_reset(pStmt); sqlite3_bind_null(pStmt, 2); sqlite3_free(a); } /* ** Merge the entire database so that there is one segment for each ** iIndex/iLangid combination. */ |
︙ | ︙ | |||
4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 | if( rc==SQLITE_OK ){ sqlite3_bind_int64(pChomp, 1, iNewStart); sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); sqlite3_bind_int64(pChomp, 3, iAbsLevel); sqlite3_bind_int(pChomp, 4, iIdx); sqlite3_step(pChomp); rc = sqlite3_reset(pChomp); } } sqlite3_free(root.a); sqlite3_free(block.a); return rc; } | > | 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 | if( rc==SQLITE_OK ){ sqlite3_bind_int64(pChomp, 1, iNewStart); sqlite3_bind_blob(pChomp, 2, root.a, root.n, SQLITE_STATIC); sqlite3_bind_int64(pChomp, 3, iAbsLevel); sqlite3_bind_int(pChomp, 4, iIdx); sqlite3_step(pChomp); rc = sqlite3_reset(pChomp); sqlite3_bind_null(pChomp, 2); } } sqlite3_free(root.a); sqlite3_free(block.a); return rc; } |
︙ | ︙ | |||
4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 | rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); } return rc; } /* ** Load an incr-merge hint from the database. The incr-merge hint, if one | > | 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 | rc = fts3SqlStmt(p, SQL_REPLACE_STAT, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int(pReplace, 1, FTS_STAT_INCRMERGEHINT); sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); sqlite3_bind_null(pReplace, 2); } return rc; } /* ** Load an incr-merge hint from the database. The incr-merge hint, if one |
︙ | ︙ | |||
5520 5521 5522 5523 5524 5525 5526 | sqlite3_vtab *pVtab, /* FTS3 vtab object */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return Code */ | < | 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 | sqlite3_vtab *pVtab, /* FTS3 vtab object */ int nArg, /* Size of argument array */ sqlite3_value **apVal, /* Array of arguments */ sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts3Table *p = (Fts3Table *)pVtab; int rc = SQLITE_OK; /* Return Code */ u32 *aSzIns = 0; /* Sizes of inserted documents */ u32 *aSzDel = 0; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; /* At this point it must be known if the %_stat table exists or not. ** So bHasStat may not be 2. */ |
︙ | ︙ | |||
5618 5619 5620 5621 5622 5623 5624 | goto update_out; } /* If this is a DELETE or UPDATE operation, remove the old record. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); | < | | 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 | goto update_out; } /* If this is a DELETE or UPDATE operation, remove the old record. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); } /* If this is an INSERT or UPDATE operation, insert the new record. */ if( nArg>1 && rc==SQLITE_OK ){ int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } } if( rc==SQLITE_OK ){ rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid); } if( rc==SQLITE_OK ){ assert( p->iPrevDocid==*pRowid ); rc = fts3InsertTerms(p, iLangid, apVal, aSzIns); } if( p->bHasDocsize ){ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
754 755 756 757 758 759 760 761 762 763 764 765 766 767 | if( p->rc ) return; } sqlite3_bind_int64(p->pWriter, 1, iRowid); sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC); sqlite3_step(p->pWriter); p->rc = sqlite3_reset(p->pWriter); } /* ** Execute the following SQL: ** ** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast */ | > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | if( p->rc ) return; } sqlite3_bind_int64(p->pWriter, 1, iRowid); sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC); sqlite3_step(p->pWriter); p->rc = sqlite3_reset(p->pWriter); sqlite3_bind_null(p->pWriter, 2); } /* ** Execute the following SQL: ** ** DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast */ |
︙ | ︙ | |||
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 | sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){ i64 val = sqlite3_column_int(pIdxSelect, 0); iPg = (int)(val>>1); bDlidx = (val & 0x0001); } p->rc = sqlite3_reset(pIdxSelect); if( iPg<pSeg->pgnoFirst ){ iPg = pSeg->pgnoFirst; bDlidx = 0; } pIter->iLeafPgno = iPg - 1; | > | 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 | sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC); if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){ i64 val = sqlite3_column_int(pIdxSelect, 0); iPg = (int)(val>>1); bDlidx = (val & 0x0001); } p->rc = sqlite3_reset(pIdxSelect); sqlite3_bind_null(pIdxSelect, 2); if( iPg<pSeg->pgnoFirst ){ iPg = pSeg->pgnoFirst; bDlidx = 0; } pIter->iLeafPgno = iPg - 1; |
︙ | ︙ | |||
3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 | sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); if( p->rc==SQLITE_OK ){ u8 aBlob[2] = {0xff, 0xff}; sqlite3_bind_int(pIdxSelect, 1, iSegid); sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); p->rc = sqlite3_reset(pIdxSelect); } } #endif } } return iSegid; | > | 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 | sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p); if( p->rc==SQLITE_OK ){ u8 aBlob[2] = {0xff, 0xff}; sqlite3_bind_int(pIdxSelect, 1, iSegid); sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC); assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW ); p->rc = sqlite3_reset(pIdxSelect); sqlite3_bind_null(pIdxSelect, 2); } } #endif } } return iSegid; |
︙ | ︙ | |||
3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 | const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:""); /* The following was already done in fts5WriteInit(): */ /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */ sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC); sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1)); sqlite3_step(p->pIdxWriter); p->rc = sqlite3_reset(p->pIdxWriter); } pWriter->iBtPage = 0; } /* ** This is called once for each leaf page except the first that contains ** at least one term. Argument (nTerm/pTerm) is the split-key - a term that | > | 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 | const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:""); /* The following was already done in fts5WriteInit(): */ /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */ sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC); sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1)); sqlite3_step(p->pIdxWriter); p->rc = sqlite3_reset(p->pIdxWriter); sqlite3_bind_null(p->pIdxWriter, 2); } pWriter->iBtPage = 0; } /* ** This is called once for each leaf page except the first that contains ** at least one term. Argument (nTerm/pTerm) is the split-key - a term that |
︙ | ︙ |
Changes to ext/fts5/fts5_storage.c.
︙ | ︙ | |||
454 455 456 457 458 459 460 461 462 463 464 465 466 467 | sqlite3_stmt *pReplace = 0; rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pReplace, 1, iRowid); sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); } } return rc; } /* ** Load the contents of the "averages" record from disk into the | > | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | sqlite3_stmt *pReplace = 0; rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0); if( rc==SQLITE_OK ){ sqlite3_bind_int64(pReplace, 1, iRowid); sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); sqlite3_bind_null(pReplace, 2); } } return rc; } /* ** Load the contents of the "averages" record from disk into the |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 | if( pVal ){ sqlite3_bind_value(pReplace, 2, pVal); }else{ sqlite3_bind_int(pReplace, 2, iVal); } sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); } if( rc==SQLITE_OK && pVal ){ int iNew = p->pConfig->iCookie + 1; rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); if( rc==SQLITE_OK ){ p->pConfig->iCookie = iNew; } } return rc; } | > | 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | if( pVal ){ sqlite3_bind_value(pReplace, 2, pVal); }else{ sqlite3_bind_int(pReplace, 2, iVal); } sqlite3_step(pReplace); rc = sqlite3_reset(pReplace); sqlite3_bind_null(pReplace, 1); } if( rc==SQLITE_OK && pVal ){ int iNew = p->pConfig->iCookie + 1; rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew); if( rc==SQLITE_OK ){ p->pConfig->iCookie = iNew; } } return rc; } |
Changes to ext/fts5/test/fts5aa.test.
︙ | ︙ | |||
589 590 591 592 593 594 595 | do_execsql_test 22.1 { SELECT rowid FROM t9('a*') } {1} } | | | 589 590 591 592 593 594 595 596 597 | do_execsql_test 22.1 { SELECT rowid FROM t9('a*') } {1} } expand_all_sql db finish_test |
Changes to ext/misc/fileio.c.
︙ | ︙ | |||
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | int i; for(i=0; i<=pCur->iLvl; i++){ FsdirLevel *pLvl = &pCur->aLvl[i]; if( pLvl->pDir ) closedir(pLvl->pDir); sqlite3_free(pLvl->zDir); } sqlite3_free(pCur->zPath); pCur->aLvl = 0; pCur->zPath = 0; pCur->zBase = 0; pCur->nBase = 0; pCur->iLvl = -1; pCur->iRowid = 1; } /* ** Destructor for an fsdir_cursor. */ static int fsdirClose(sqlite3_vtab_cursor *cur){ fsdir_cursor *pCur = (fsdir_cursor*)cur; fsdirResetCursor(pCur); | > < | 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 | int i; for(i=0; i<=pCur->iLvl; i++){ FsdirLevel *pLvl = &pCur->aLvl[i]; if( pLvl->pDir ) closedir(pLvl->pDir); sqlite3_free(pLvl->zDir); } sqlite3_free(pCur->zPath); sqlite3_free(pCur->aLvl); pCur->aLvl = 0; pCur->zPath = 0; pCur->zBase = 0; pCur->nBase = 0; pCur->iLvl = -1; pCur->iRowid = 1; } /* ** Destructor for an fsdir_cursor. */ static int fsdirClose(sqlite3_vtab_cursor *cur){ fsdir_cursor *pCur = (fsdir_cursor*)cur; fsdirResetCursor(pCur); sqlite3_free(pCur); return SQLITE_OK; } /* ** Set the error message for the virtual table associated with cursor ** pCur to the results of vprintf(zFmt, ...). |
︙ | ︙ |
Added ext/misc/normalize.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 | /* ** 2018-01-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 file contains code to implement the sqlite3_normalize() function. ** ** char *sqlite3_normalize(const char *zSql); ** ** This function takes an SQL string as input and returns a "normalized" ** version of that string in memory obtained from sqlite3_malloc64(). The ** caller is responsible for ensuring that the returned memory is freed. ** ** If a memory allocation error occurs, this routine returns NULL. ** ** The normalization consists of the following transformations: ** ** (1) Convert every literal (string, blob literal, numeric constant, ** or "NULL" constant) into a ? ** ** (2) Remove all superfluous whitespace, including comments. Change ** all required whitespace to a single space character. ** ** (3) Lowercase all ASCII characters. ** ** (4) If an IN or NOT IN operator is followed by a list of 1 or more ** values, convert that list into "(?,?,?)". ** ** The purpose of normalization is two-fold: ** ** (1) Sanitize queries by removing potentially private or sensitive ** information contained in literals. ** ** (2) Identify structurally identical queries by comparing their ** normalized forms. ** ** Command-Line Utility ** -------------------- ** ** This file also contains code for a command-line utility that converts ** SQL queries in text files into their normalized forms. To build the ** command-line program, compile this file with -DSQLITE_NORMALIZE_CLI ** and link it against the SQLite library. */ #include <sqlite3.h> #include <string.h> /* ** Implementation note: ** ** Much of the tokenizer logic is copied out of the tokenize.c source file ** of SQLite. That logic could be simplified for this particular application, ** but that would impose a risk of introducing subtle errors. It is best to ** keep the code as close to the original as possible. ** ** The tokenize code is in sync with the SQLite core as of 2018-01-08. ** Any future changes to the core tokenizer might require corresponding ** adjustments to the tokenizer logic in this module. */ /* Character classes for tokenizing ** ** In the sqlite3GetToken() function, a switch() on aiClass[c] is implemented ** using a lookup table, whereas a switch() directly on c uses a binary search. ** The lookup table is much faster. To maximize speed, and to ensure that ** a lookup table is used, all of the classes need to be small integers and ** all of them need to be used within the switch. */ #define CC_X 0 /* The letter 'x', or start of BLOB literal */ #define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */ #define CC_ID 2 /* unicode characters usable in IDs */ #define CC_DIGIT 3 /* Digits */ #define CC_DOLLAR 4 /* '$' */ #define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */ #define CC_VARNUM 6 /* '?'. Numeric SQL variables */ #define CC_SPACE 7 /* Space characters */ #define CC_QUOTE 8 /* '"', '\'', or '`'. String literals, quoted ids */ #define CC_QUOTE2 9 /* '['. [...] style quoted ids */ #define CC_PIPE 10 /* '|'. Bitwise OR or concatenate */ #define CC_MINUS 11 /* '-'. Minus or SQL-style comment */ #define CC_LT 12 /* '<'. Part of < or <= or <> */ #define CC_GT 13 /* '>'. Part of > or >= */ #define CC_EQ 14 /* '='. Part of = or == */ #define CC_BANG 15 /* '!'. Part of != */ #define CC_SLASH 16 /* '/'. / or c-style comment */ #define CC_LP 17 /* '(' */ #define CC_RP 18 /* ')' */ #define CC_SEMI 19 /* ';' */ #define CC_PLUS 20 /* '+' */ #define CC_STAR 21 /* '*' */ #define CC_PERCENT 22 /* '%' */ #define CC_COMMA 23 /* ',' */ #define CC_AND 24 /* '&' */ #define CC_TILDA 25 /* '~' */ #define CC_DOT 26 /* '.' */ #define CC_ILLEGAL 27 /* Illegal character */ static const unsigned char aiClass[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, /* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1, /* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27, /* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; /* An array to map all upper-case characters into their corresponding ** lower-case character. ** ** SQLite only considers US-ASCII (or EBCDIC) characters. We do not ** handle case conversions for the UTF character set since the tables ** involved are nearly as big or bigger than SQLite itself. */ static const unsigned char sqlite3UpperToLower[] = { 0, 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, 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, 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 }; /* ** The following 256 byte lookup table is used to support SQLites built-in ** equivalents to the following standard library functions: ** ** isspace() 0x01 ** isalpha() 0x02 ** isdigit() 0x04 ** isalnum() 0x06 ** isxdigit() 0x08 ** toupper() 0x20 ** SQLite identifier character 0x40 ** Quote character 0x80 ** ** Bit 0x20 is set if the mapped character requires translation to upper ** case. i.e. if the character is a lower-case ASCII character. ** If x is a lower-case ASCII character, then its upper-case equivalent ** is (x - 0x20). Therefore toupper() can be implemented as: ** ** (x & ~(map[x]&0x20)) ** ** The equivalent of tolower() is implemented using the sqlite3UpperToLower[] ** array. tolower() is used more often than toupper() by SQLite. ** ** Bit 0x40 is set if the character is non-alphanumeric and can be used in an ** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any ** non-ASCII UTF character. Hence the test for whether or not a character is ** part of an identifier is 0x46. */ static const unsigned char sqlite3CtypeMap[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */ 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */ 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */ 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */ 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */ 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */ 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 80..87 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 88..8f ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 90..97 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 98..9f ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a0..a7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* a8..af ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b0..b7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* b8..bf ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c0..c7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* c8..cf ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d0..d7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* d8..df ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e0..e7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* e8..ef ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ }; #define sqlite3Toupper(x) ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20)) #define sqlite3Isspace(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x01) #define sqlite3Isalnum(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x06) #define sqlite3Isalpha(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x02) #define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04) #define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08) #define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)]) #define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80) /* ** If X is a character that can be used in an identifier then ** IdChar(X) will be true. Otherwise it is false. ** ** For ASCII, any character with the high-order bit set is ** allowed in an identifier. For 7-bit characters, ** sqlite3IsIdChar[X] must be 1. ** ** For EBCDIC, the rules are more complex but have the same ** end result. ** ** Ticket #1066. the SQL standard does not allow '$' in the ** middle of identifiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ #define IdChar(C) ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0) /* ** Ignore testcase() macros */ #define testcase(X) /* ** Token values */ #define TK_SPACE 0 #define TK_NAME 1 #define TK_LITERAL 2 #define TK_PUNCT 3 #define TK_ERROR 4 #define TK_MINUS TK_PUNCT #define TK_LP TK_PUNCT #define TK_RP TK_PUNCT #define TK_SEMI TK_PUNCT #define TK_PLUS TK_PUNCT #define TK_STAR TK_PUNCT #define TK_SLASH TK_PUNCT #define TK_REM TK_PUNCT #define TK_EQ TK_PUNCT #define TK_LE TK_PUNCT #define TK_NE TK_PUNCT #define TK_LSHIFT TK_PUNCT #define TK_LT TK_PUNCT #define TK_GE TK_PUNCT #define TK_RSHIFT TK_PUNCT #define TK_GT TK_PUNCT #define TK_GE TK_PUNCT #define TK_BITOR TK_PUNCT #define TK_CONCAT TK_PUNCT #define TK_COMMA TK_PUNCT #define TK_BITAND TK_PUNCT #define TK_BITNOT TK_PUNCT #define TK_STRING TK_LITERAL #define TK_ID TK_NAME #define TK_ILLEGAL TK_ERROR #define TK_DOT TK_PUNCT #define TK_INTEGER TK_LITERAL #define TK_FLOAT TK_LITERAL #define TK_VARIABLE TK_LITERAL #define TK_BLOB TK_LITERAL /* ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ static int sqlite3GetToken(const unsigned char *z, int *tokenType){ int i, c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte ** of the token. See the comment on the CC_ defines ** above. */ case CC_SPACE: { for(i=1; sqlite3Isspace(z[i]); i++){} *tokenType = TK_SPACE; return i; } case CC_MINUS: { if( z[1]=='-' ){ for(i=2; (c=z[i])!=0 && c!='\n'; i++){} *tokenType = TK_SPACE; return i; } *tokenType = TK_MINUS; return 1; } case CC_LP: { *tokenType = TK_LP; return 1; } case CC_RP: { *tokenType = TK_RP; return 1; } case CC_SEMI: { *tokenType = TK_SEMI; return 1; } case CC_PLUS: { *tokenType = TK_PLUS; return 1; } case CC_STAR: { *tokenType = TK_STAR; return 1; } case CC_SLASH: { if( z[1]!='*' || z[2]==0 ){ *tokenType = TK_SLASH; return 1; } for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} if( c ) i++; *tokenType = TK_SPACE; return i; } case CC_PERCENT: { *tokenType = TK_REM; return 1; } case CC_EQ: { *tokenType = TK_EQ; return 1 + (z[1]=='='); } case CC_LT: { if( (c=z[1])=='=' ){ *tokenType = TK_LE; return 2; }else if( c=='>' ){ *tokenType = TK_NE; return 2; }else if( c=='<' ){ *tokenType = TK_LSHIFT; return 2; }else{ *tokenType = TK_LT; return 1; } } case CC_GT: { if( (c=z[1])=='=' ){ *tokenType = TK_GE; return 2; }else if( c=='>' ){ *tokenType = TK_RSHIFT; return 2; }else{ *tokenType = TK_GT; return 1; } } case CC_BANG: { if( z[1]!='=' ){ *tokenType = TK_ILLEGAL; return 1; }else{ *tokenType = TK_NE; return 2; } } case CC_PIPE: { if( z[1]!='|' ){ *tokenType = TK_BITOR; return 1; }else{ *tokenType = TK_CONCAT; return 2; } } case CC_COMMA: { *tokenType = TK_COMMA; return 1; } case CC_AND: { *tokenType = TK_BITAND; return 1; } case CC_TILDA: { *tokenType = TK_BITNOT; return 1; } case CC_QUOTE: { int delim = z[0]; testcase( delim=='`' ); testcase( delim=='\'' ); testcase( delim=='"' ); for(i=1; (c=z[i])!=0; i++){ if( c==delim ){ if( z[i+1]==delim ){ i++; }else{ break; } } } if( c=='\'' ){ *tokenType = TK_STRING; return i+1; }else if( c!=0 ){ *tokenType = TK_ID; return i+1; }else{ *tokenType = TK_ILLEGAL; return i; } } case CC_DOT: { if( !sqlite3Isdigit(z[1]) ){ *tokenType = TK_DOT; return 1; } /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ } case CC_DIGIT: { *tokenType = TK_INTEGER; if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){ for(i=3; sqlite3Isxdigit(z[i]); i++){} return i; } for(i=0; sqlite3Isdigit(z[i]); i++){} if( z[i]=='.' ){ i++; while( sqlite3Isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; } if( (z[i]=='e' || z[i]=='E') && ( sqlite3Isdigit(z[i+1]) || ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2])) ) ){ i += 2; while( sqlite3Isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; } while( IdChar(z[i]) ){ *tokenType = TK_ILLEGAL; i++; } return i; } case CC_QUOTE2: { for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} *tokenType = c==']' ? TK_ID : TK_ILLEGAL; return i; } case CC_VARNUM: { *tokenType = TK_VARIABLE; for(i=1; sqlite3Isdigit(z[i]); i++){} return i; } case CC_DOLLAR: case CC_VARALPHA: { int n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); *tokenType = TK_VARIABLE; for(i=1; (c=z[i])!=0; i++){ if( IdChar(c) ){ n++; }else if( c=='(' && n>0 ){ do{ i++; }while( (c=z[i])!=0 && !sqlite3Isspace(c) && c!=')' ); if( c==')' ){ i++; }else{ *tokenType = TK_ILLEGAL; } break; }else if( c==':' && z[i+1]==':' ){ i++; }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } case CC_KYWD: { for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} if( IdChar(z[i]) ){ /* This token started out using characters that can appear in keywords, ** but z[i] is a character not allowed within keywords, so this must ** be an identifier instead */ i++; break; } *tokenType = TK_ID; return i; } case CC_X: { testcase( z[0]=='x' ); testcase( z[0]=='X' ); if( z[1]=='\'' ){ *tokenType = TK_BLOB; for(i=2; sqlite3Isxdigit(z[i]); i++){} if( z[i]!='\'' || i%2 ){ *tokenType = TK_ILLEGAL; while( z[i] && z[i]!='\'' ){ i++; } } if( z[i] ) i++; return i; } /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ } case CC_ID: { i = 1; break; } default: { *tokenType = TK_ILLEGAL; return 1; } } while( IdChar(z[i]) ){ i++; } *tokenType = TK_ID; return i; } char *sqlite3_normalize(const char *zSql){ char *z; /* The output string */ sqlite3_int64 nZ; /* Size of the output string in bytes */ sqlite3_int64 nSql; /* Size of the input string in bytes */ int i; /* Next character to read from zSql[] */ int j; /* Next slot to fill in on z[] */ int tokenType; /* Type of the next token */ int n; /* Size of the next token */ int k; /* Loop counter */ nSql = strlen(zSql); nZ = nSql; z = sqlite3_malloc64( nZ+2 ); if( z==0 ) return 0; for(i=j=0; zSql[i]; i += n){ n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType); switch( tokenType ){ case TK_SPACE: { break; } case TK_ERROR: { sqlite3_free(z); return 0; } case TK_LITERAL: { z[j++] = '?'; break; } case TK_PUNCT: case TK_NAME: { if( n==4 && sqlite3_strnicmp(zSql+i,"NULL",4)==0 ){ if( (j>=3 && strncmp(z+j-2,"is",2)==0 && !IdChar(z[j-3])) || (j>=4 && strncmp(z+j-3,"not",3)==0 && !IdChar(z[j-4])) ){ /* NULL is a keyword in this case, not a literal value */ }else{ /* Here the NULL is a literal value */ z[j++] = '?'; break; } } if( j>0 && IdChar(z[j-1]) && IdChar(zSql[i]) ) z[j++] = ' '; for(k=0; k<n; k++){ z[j++] = sqlite3Tolower(zSql[i+k]); } break; } } } while( j>0 && z[j-1]==' ' ){ j--; } if( i>0 && z[j-1]!=';' ){ z[j++] = ';'; } z[j] = 0; /* Make a second pass converting "in(...)" where the "..." is not a ** SELECT statement into "in(?,?,?)" */ for(i=0; i<j; i=n){ char *zIn = strstr(z+i, "in("); int nParen; if( zIn==0 ) break; n = (int)(zIn-z)+3; /* Index of first char past "in(" */ if( n && IdChar(zIn[-1]) ) continue; if( strncmp(zIn, "in(select",9)==0 && !IdChar(zIn[9]) ) continue; if( strncmp(zIn, "in(with",7)==0 && !IdChar(zIn[7]) ) continue; for(nParen=1, k=0; z[n+k]; k++){ if( z[n+k]=='(' ) nParen++; if( z[n+k]==')' ){ nParen--; if( nParen==0 ) break; } } /* k is the number of bytes in the "..." within "in(...)" */ if( k<5 ){ z = sqlite3_realloc64(z, j+(5-k)+1); if( z==0 ) return 0; memmove(z+n+5, z+n+k, j-(n+k)); }else if( k>5 ){ memmove(z+n+5, z+n+k, j-(n+k)); } j = j-k+5; z[j] = 0; memcpy(z+n, "?,?,?", 5); } return z; } /* ** For testing purposes, or to build a stand-alone SQL normalizer program, ** compile this one source file with the -DSQLITE_NORMALIZE_CLI and link ** it against any SQLite library. The resulting command-line program will ** run sqlite3_normalize() over the text of all files named on the command- ** line and show the result on standard output. */ #ifdef SQLITE_NORMALIZE_CLI #include <stdio.h> #include <stdlib.h> /* ** Break zIn up into separate SQL statements and run sqlite3_normalize() ** on each one. Print the result of each run. */ static void normalizeFile(char *zIn){ int i; if( zIn==0 ) return; for(i=0; zIn[i]; i++){ char cSaved; if( zIn[i]!=';' ) continue; cSaved = zIn[i+1]; zIn[i+1] = 0; if( sqlite3_complete(zIn) ){ char *zOut = sqlite3_normalize(zIn); if( zOut ){ printf("%s\n", zOut); sqlite3_free(zOut); }else{ fprintf(stderr, "ERROR: %s\n", zIn); } zIn[i+1] = cSaved; zIn += i+1; i = -1; }else{ zIn[i+1] = cSaved; } } } /* ** The main routine for "sql_normalize". Read files named on the ** command-line and run the text of each through sqlite3_normalize(). */ int main(int argc, char **argv){ int i; FILE *in; char *zBuf = 0; sqlite3_int64 sz, got; for(i=1; i<argc; i++){ in = fopen(argv[i], "rb"); if( in==0 ){ fprintf(stderr, "cannot open \"%s\"\n", argv[i]); continue; } fseek(in, 0, SEEK_END); sz = ftell(in); rewind(in); zBuf = sqlite3_realloc64(zBuf, sz+1); if( zBuf==0 ){ fprintf(stderr, "failed to malloc for %lld bytes\n", sz); exit(1); } got = fread(zBuf, 1, sz, in); fclose(in); if( got!=sz ){ fprintf(stderr, "only able to read %lld of %lld bytes from \"%s\"\n", got, sz, argv[i]); }else{ zBuf[got] = 0; normalizeFile(zBuf); } } sqlite3_free(zBuf); } #endif /* SQLITE_NORMALIZE_CLI */ |
Changes to ext/misc/spellfix.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** to search a large vocabulary for close matches. See separate ** documentation (http://www.sqlite.org/spellfix1.html) for details. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> # define ALWAYS(X) 1 # define NEVER(X) 0 typedef unsigned char u8; | > > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** to search a large vocabulary for close matches. See separate ** documentation (http://www.sqlite.org/spellfix1.html) for details. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 # endif # if defined(NDEBUG) && defined(SQLITE_DEBUG) # undef NDEBUG # endif # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> # define ALWAYS(X) 1 # define NEVER(X) 0 typedef unsigned char u8; |
︙ | ︙ | |||
647 648 649 650 651 652 653 654 655 656 657 658 659 660 | memset(p, 0, sizeof(*p)); } static void editDist3ConfigDelete(void *pIn){ EditDist3Config *p = (EditDist3Config*)pIn; editDist3ConfigClear(p); sqlite3_free(p); } /* ** Load all edit-distance weights from a table. */ static int editDist3ConfigLoad( EditDist3Config *p, /* The edit distance configuration to load */ sqlite3 *db, /* Load from this database */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | memset(p, 0, sizeof(*p)); } static void editDist3ConfigDelete(void *pIn){ EditDist3Config *p = (EditDist3Config*)pIn; editDist3ConfigClear(p); sqlite3_free(p); } /* Compare the FROM values of two EditDist3Cost objects, for sorting. ** Return negative, zero, or positive if the A is less than, equal to, ** or greater than B. */ static int editDist3CostCompare(EditDist3Cost *pA, EditDist3Cost *pB){ int n = pA->nFrom; int rc; if( n>pB->nFrom ) n = pB->nFrom; rc = strncmp(pA->a, pB->a, n); if( rc==0 ) rc = pA->nFrom - pB->nFrom; return rc; } /* ** Merge together two sorted lists of EditDist3Cost objects, in order ** of increasing FROM. */ static EditDist3Cost *editDist3CostMerge( EditDist3Cost *pA, EditDist3Cost *pB ){ EditDist3Cost *pHead = 0; EditDist3Cost **ppTail = &pHead; EditDist3Cost *p; while( pA && pB ){ if( editDist3CostCompare(pA,pB)<=0 ){ p = pA; pA = pA->pNext; }else{ p = pB; pB = pB->pNext; } *ppTail = p; ppTail = &p->pNext; } if( pA ){ *ppTail = pA; }else{ *ppTail = pB; } return pHead; } /* ** Sort a list of EditDist3Cost objects into order of increasing FROM */ static EditDist3Cost *editDist3CostSort(EditDist3Cost *pList){ EditDist3Cost *ap[60], *p; int i; int mx = 0; ap[0] = 0; ap[1] = 0; while( pList ){ p = pList; pList = p->pNext; p->pNext = 0; for(i=0; ap[i]; i++){ p = editDist3CostMerge(ap[i],p); ap[i] = 0; } ap[i] = p; if( i>mx ){ mx = i; ap[i+1] = 0; } } p = 0; for(i=0; i<=mx; i++){ if( ap[i] ) p = editDist3CostMerge(p,ap[i]); } return p; } /* ** Load all edit-distance weights from a table. */ static int editDist3ConfigLoad( EditDist3Config *p, /* The edit distance configuration to load */ sqlite3 *db, /* Load from this database */ |
︙ | ︙ | |||
681 682 683 684 685 686 687 688 689 690 691 692 693 694 | int nTo = zTo ? sqlite3_column_bytes(pStmt, 2) : 0; int iCost = sqlite3_column_int(pStmt, 3); assert( zFrom!=0 || nFrom==0 ); assert( zTo!=0 || nTo==0 ); if( nFrom>100 || nTo>100 ) continue; if( iCost<0 ) continue; if( pLang==0 || iLang!=iLangPrev ){ EditDist3Lang *pNew; pNew = sqlite3_realloc64(p->a, (p->nLang+1)*sizeof(p->a[0])); if( pNew==0 ){ rc = SQLITE_NOMEM; break; } p->a = pNew; pLang = &p->a[p->nLang]; p->nLang++; | > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 | int nTo = zTo ? sqlite3_column_bytes(pStmt, 2) : 0; int iCost = sqlite3_column_int(pStmt, 3); assert( zFrom!=0 || nFrom==0 ); assert( zTo!=0 || nTo==0 ); if( nFrom>100 || nTo>100 ) continue; if( iCost<0 ) continue; if( iCost>10000 ) continue; /* Costs above 10K are considered infinite */ if( pLang==0 || iLang!=iLangPrev ){ EditDist3Lang *pNew; pNew = sqlite3_realloc64(p->a, (p->nLang+1)*sizeof(p->a[0])); if( pNew==0 ){ rc = SQLITE_NOMEM; break; } p->a = pNew; pLang = &p->a[p->nLang]; p->nLang++; |
︙ | ︙ | |||
718 719 720 721 722 723 724 725 726 727 728 729 730 731 | memcpy(pCost->a + nFrom, zTo, nTo); pCost->pNext = pLang->pCost; pLang->pCost = pCost; } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; return rc; } /* ** Return the length (in bytes) of a utf-8 character. Or return a maximum ** of N. */ | > > > > > > | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | memcpy(pCost->a + nFrom, zTo, nTo); pCost->pNext = pLang->pCost; pLang->pCost = pCost; } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; if( rc==SQLITE_OK ){ int iLang; for(iLang=0; iLang<p->nLang; iLang++){ p->a[iLang].pCost = editDist3CostSort(p->a[iLang].pCost); } } return rc; } /* ** Return the length (in bytes) of a utf-8 character. Or return a maximum ** of N. */ |
︙ | ︙ | |||
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 | } /* ** Return TRUE (non-zero) if the To side of the given cost matches ** the given string. */ static int matchTo(EditDist3Cost *p, const char *z, int n){ if( p->nTo>n ) return 0; if( strncmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) if the From side of the given cost matches ** the given string. */ static int matchFrom(EditDist3Cost *p, const char *z, int n){ assert( p->nFrom<=n ); if( strncmp(p->a, z, p->nFrom)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) of the next FROM character and the next TO ** character are the same. */ static int matchFromTo( EditDist3FromString *pStr, /* Left hand string */ int n1, /* Index of comparison character on the left */ const char *z2, /* Right-handl comparison character */ int n2 /* Bytes remaining in z2[] */ ){ int b1 = pStr->a[n1].nByte; if( b1>n2 ) return 0; | > > > | | 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 | } /* ** Return TRUE (non-zero) if the To side of the given cost matches ** the given string. */ static int matchTo(EditDist3Cost *p, const char *z, int n){ if( p->a[p->nFrom]!=z[0] ) return 0; if( p->nTo>n ) return 0; if( strncmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) if the From side of the given cost matches ** the given string. */ static int matchFrom(EditDist3Cost *p, const char *z, int n){ assert( p->nFrom<=n ); if( p->a[0]!=z[0] ) return 0; if( strncmp(p->a, z, p->nFrom)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) of the next FROM character and the next TO ** character are the same. */ static int matchFromTo( EditDist3FromString *pStr, /* Left hand string */ int n1, /* Index of comparison character on the left */ const char *z2, /* Right-handl comparison character */ int n2 /* Bytes remaining in z2[] */ ){ int b1 = pStr->a[n1].nByte; if( b1>n2 ) return 0; if( pStr->z[n1]!=z2[0] ) return 0; if( strncmp(pStr->z+n1, z2, b1)!=0 ) return 0; return 1; } /* ** Delete an EditDist3FromString objecct */ static void editDist3FromStringDelete(EditDist3FromString *p){ |
︙ | ︙ | |||
854 855 856 857 858 859 860 | } return pStr; } /* ** Update entry m[i] such that it is the minimum of its current value ** and m[j]+iCost. | < < < > | | | < | 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 | } return pStr; } /* ** Update entry m[i] such that it is the minimum of its current value ** and m[j]+iCost. */ static void updateCost( unsigned int *m, int i, int j, int iCost ){ unsigned int b; assert( iCost>=0 ); assert( iCost<10000 ); b = m[j] + iCost; if( b<m[i] ) m[i] = b; } /* ** How much stack space (int bytes) to use for Wagner matrix in ** editDist3Core(). If more space than this is required, the entire ** matrix is taken from the heap. To reduce the load on the memory ** allocator, make this value as large as practical for the |
︙ | ︙ | |||
932 933 934 935 936 937 938 | memset(a2, 0, sizeof(a2[0])*n2); /* Fill in the a1[] matrix for all characters of the TO string */ for(i2=0; i2<n2; i2++){ a2[i2].nByte = utf8Len((unsigned char)z2[i2], n2-i2); for(p=pLang->pCost; p; p=p->pNext){ EditDist3Cost **apNew; | | > | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 | memset(a2, 0, sizeof(a2[0])*n2); /* Fill in the a1[] matrix for all characters of the TO string */ for(i2=0; i2<n2; i2++){ a2[i2].nByte = utf8Len((unsigned char)z2[i2], n2-i2); for(p=pLang->pCost; p; p=p->pNext){ EditDist3Cost **apNew; if( p->nFrom>0 ) break; if( i2+p->nTo>n2 ) continue; if( p->a[0]>z2[i2] ) break; if( matchTo(p, z2+i2, n2-i2)==0 ) continue; a2[i2].nIns++; apNew = sqlite3_realloc64(a2[i2].apIns, sizeof(*apNew)*a2[i2].nIns); if( apNew==0 ){ res = -1; /* Out of memory */ goto editDist3Abort; } |
︙ | ︙ | |||
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 | int sz; utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz); i += sz; } return nChar; } /* ** Table of translations from unicode characters into ASCII. */ | > > > > > > | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > | 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 | int sz; utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz); i += sz; } 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 */ { 0x00B5, 0x75, 0x00, 0x00, 0x00 }, /* µ to u */ { 0x00C0, 0x41, 0x00, 0x00, 0x00 }, /* À to A */ { 0x00C1, 0x41, 0x00, 0x00, 0x00 }, /* Á to A */ { 0x00C2, 0x41, 0x00, 0x00, 0x00 }, /*  to A */ { 0x00C3, 0x41, 0x00, 0x00, 0x00 }, /* à to A */ { 0x00C4, 0x41, 0x65, 0x00, 0x00 }, /* Ä to Ae */ { 0x00C5, 0x41, 0x61, 0x00, 0x00 }, /* Å to Aa */ { 0x00C6, 0x41, 0x45, 0x00, 0x00 }, /* Æ to AE */ { 0x00C7, 0x43, 0x00, 0x00, 0x00 }, /* Ç to C */ { 0x00C8, 0x45, 0x00, 0x00, 0x00 }, /* È to E */ { 0x00C9, 0x45, 0x00, 0x00, 0x00 }, /* É to E */ { 0x00CA, 0x45, 0x00, 0x00, 0x00 }, /* Ê to E */ { 0x00CB, 0x45, 0x00, 0x00, 0x00 }, /* Ë to E */ { 0x00CC, 0x49, 0x00, 0x00, 0x00 }, /* Ì to I */ { 0x00CD, 0x49, 0x00, 0x00, 0x00 }, /* Í to I */ { 0x00CE, 0x49, 0x00, 0x00, 0x00 }, /* Î to I */ { 0x00CF, 0x49, 0x00, 0x00, 0x00 }, /* Ï to I */ { 0x00D0, 0x44, 0x00, 0x00, 0x00 }, /* Ð to D */ { 0x00D1, 0x4E, 0x00, 0x00, 0x00 }, /* Ñ to N */ { 0x00D2, 0x4F, 0x00, 0x00, 0x00 }, /* Ò to O */ { 0x00D3, 0x4F, 0x00, 0x00, 0x00 }, /* Ó to O */ { 0x00D4, 0x4F, 0x00, 0x00, 0x00 }, /* Ô to O */ { 0x00D5, 0x4F, 0x00, 0x00, 0x00 }, /* Õ to O */ { 0x00D6, 0x4F, 0x65, 0x00, 0x00 }, /* Ö to Oe */ { 0x00D7, 0x78, 0x00, 0x00, 0x00 }, /* × to x */ { 0x00D8, 0x4F, 0x00, 0x00, 0x00 }, /* Ø to O */ { 0x00D9, 0x55, 0x00, 0x00, 0x00 }, /* Ù to U */ { 0x00DA, 0x55, 0x00, 0x00, 0x00 }, /* Ú to U */ { 0x00DB, 0x55, 0x00, 0x00, 0x00 }, /* Û to U */ { 0x00DC, 0x55, 0x65, 0x00, 0x00 }, /* Ü to Ue */ { 0x00DD, 0x59, 0x00, 0x00, 0x00 }, /* Ý to Y */ { 0x00DE, 0x54, 0x68, 0x00, 0x00 }, /* Þ to Th */ { 0x00DF, 0x73, 0x73, 0x00, 0x00 }, /* ß to ss */ { 0x00E0, 0x61, 0x00, 0x00, 0x00 }, /* à to a */ { 0x00E1, 0x61, 0x00, 0x00, 0x00 }, /* á to a */ { 0x00E2, 0x61, 0x00, 0x00, 0x00 }, /* â to a */ { 0x00E3, 0x61, 0x00, 0x00, 0x00 }, /* ã to a */ { 0x00E4, 0x61, 0x65, 0x00, 0x00 }, /* ä to ae */ { 0x00E5, 0x61, 0x61, 0x00, 0x00 }, /* å to aa */ { 0x00E6, 0x61, 0x65, 0x00, 0x00 }, /* æ to ae */ { 0x00E7, 0x63, 0x00, 0x00, 0x00 }, /* ç to c */ { 0x00E8, 0x65, 0x00, 0x00, 0x00 }, /* è to e */ { 0x00E9, 0x65, 0x00, 0x00, 0x00 }, /* é to e */ { 0x00EA, 0x65, 0x00, 0x00, 0x00 }, /* ê to e */ { 0x00EB, 0x65, 0x00, 0x00, 0x00 }, /* ë to e */ { 0x00EC, 0x69, 0x00, 0x00, 0x00 }, /* ì to i */ { 0x00ED, 0x69, 0x00, 0x00, 0x00 }, /* í to i */ { 0x00EE, 0x69, 0x00, 0x00, 0x00 }, /* î to i */ { 0x00EF, 0x69, 0x00, 0x00, 0x00 }, /* ï to i */ { 0x00F0, 0x64, 0x00, 0x00, 0x00 }, /* ð to d */ { 0x00F1, 0x6E, 0x00, 0x00, 0x00 }, /* ñ to n */ { 0x00F2, 0x6F, 0x00, 0x00, 0x00 }, /* ò to o */ { 0x00F3, 0x6F, 0x00, 0x00, 0x00 }, /* ó to o */ { 0x00F4, 0x6F, 0x00, 0x00, 0x00 }, /* ô to o */ { 0x00F5, 0x6F, 0x00, 0x00, 0x00 }, /* õ to o */ { 0x00F6, 0x6F, 0x65, 0x00, 0x00 }, /* ö to oe */ { 0x00F7, 0x3A, 0x00, 0x00, 0x00 }, /* ÷ to : */ { 0x00F8, 0x6F, 0x00, 0x00, 0x00 }, /* ø to o */ { 0x00F9, 0x75, 0x00, 0x00, 0x00 }, /* ù to u */ { 0x00FA, 0x75, 0x00, 0x00, 0x00 }, /* ú to u */ { 0x00FB, 0x75, 0x00, 0x00, 0x00 }, /* û to u */ { 0x00FC, 0x75, 0x65, 0x00, 0x00 }, /* ü to ue */ { 0x00FD, 0x79, 0x00, 0x00, 0x00 }, /* ý to y */ { 0x00FE, 0x74, 0x68, 0x00, 0x00 }, /* þ to th */ { 0x00FF, 0x79, 0x00, 0x00, 0x00 }, /* ÿ to y */ { 0x0100, 0x41, 0x00, 0x00, 0x00 }, /* Ā to A */ { 0x0101, 0x61, 0x00, 0x00, 0x00 }, /* ā to a */ { 0x0102, 0x41, 0x00, 0x00, 0x00 }, /* Ă to A */ { 0x0103, 0x61, 0x00, 0x00, 0x00 }, /* ă to a */ { 0x0104, 0x41, 0x00, 0x00, 0x00 }, /* Ą to A */ { 0x0105, 0x61, 0x00, 0x00, 0x00 }, /* ą to a */ { 0x0106, 0x43, 0x00, 0x00, 0x00 }, /* Ć to C */ { 0x0107, 0x63, 0x00, 0x00, 0x00 }, /* ć to c */ { 0x0108, 0x43, 0x68, 0x00, 0x00 }, /* Ĉ to Ch */ { 0x0109, 0x63, 0x68, 0x00, 0x00 }, /* ĉ to ch */ { 0x010A, 0x43, 0x00, 0x00, 0x00 }, /* Ċ to C */ { 0x010B, 0x63, 0x00, 0x00, 0x00 }, /* ċ to c */ { 0x010C, 0x43, 0x00, 0x00, 0x00 }, /* Č to C */ { 0x010D, 0x63, 0x00, 0x00, 0x00 }, /* č to c */ { 0x010E, 0x44, 0x00, 0x00, 0x00 }, /* Ď to D */ { 0x010F, 0x64, 0x00, 0x00, 0x00 }, /* ď to d */ { 0x0110, 0x44, 0x00, 0x00, 0x00 }, /* Đ to D */ { 0x0111, 0x64, 0x00, 0x00, 0x00 }, /* đ to d */ { 0x0112, 0x45, 0x00, 0x00, 0x00 }, /* Ē to E */ { 0x0113, 0x65, 0x00, 0x00, 0x00 }, /* ē to e */ { 0x0114, 0x45, 0x00, 0x00, 0x00 }, /* Ĕ to E */ { 0x0115, 0x65, 0x00, 0x00, 0x00 }, /* ĕ to e */ { 0x0116, 0x45, 0x00, 0x00, 0x00 }, /* Ė to E */ { 0x0117, 0x65, 0x00, 0x00, 0x00 }, /* ė to e */ { 0x0118, 0x45, 0x00, 0x00, 0x00 }, /* Ę to E */ { 0x0119, 0x65, 0x00, 0x00, 0x00 }, /* ę to e */ { 0x011A, 0x45, 0x00, 0x00, 0x00 }, /* Ě to E */ { 0x011B, 0x65, 0x00, 0x00, 0x00 }, /* ě to e */ { 0x011C, 0x47, 0x68, 0x00, 0x00 }, /* Ĝ to Gh */ { 0x011D, 0x67, 0x68, 0x00, 0x00 }, /* ĝ to gh */ { 0x011E, 0x47, 0x00, 0x00, 0x00 }, /* Ğ to G */ { 0x011F, 0x67, 0x00, 0x00, 0x00 }, /* ğ to g */ { 0x0120, 0x47, 0x00, 0x00, 0x00 }, /* Ġ to G */ { 0x0121, 0x67, 0x00, 0x00, 0x00 }, /* ġ to g */ { 0x0122, 0x47, 0x00, 0x00, 0x00 }, /* Ģ to G */ { 0x0123, 0x67, 0x00, 0x00, 0x00 }, /* ģ to g */ { 0x0124, 0x48, 0x68, 0x00, 0x00 }, /* Ĥ to Hh */ { 0x0125, 0x68, 0x68, 0x00, 0x00 }, /* ĥ to hh */ { 0x0126, 0x48, 0x00, 0x00, 0x00 }, /* Ħ to H */ { 0x0127, 0x68, 0x00, 0x00, 0x00 }, /* ħ to h */ { 0x0128, 0x49, 0x00, 0x00, 0x00 }, /* Ĩ to I */ { 0x0129, 0x69, 0x00, 0x00, 0x00 }, /* ĩ to i */ { 0x012A, 0x49, 0x00, 0x00, 0x00 }, /* Ī to I */ { 0x012B, 0x69, 0x00, 0x00, 0x00 }, /* ī to i */ { 0x012C, 0x49, 0x00, 0x00, 0x00 }, /* Ĭ to I */ { 0x012D, 0x69, 0x00, 0x00, 0x00 }, /* ĭ to i */ { 0x012E, 0x49, 0x00, 0x00, 0x00 }, /* Į to I */ { 0x012F, 0x69, 0x00, 0x00, 0x00 }, /* į to i */ { 0x0130, 0x49, 0x00, 0x00, 0x00 }, /* İ to I */ { 0x0131, 0x69, 0x00, 0x00, 0x00 }, /* ı to i */ { 0x0132, 0x49, 0x4A, 0x00, 0x00 }, /* IJ to IJ */ { 0x0133, 0x69, 0x6A, 0x00, 0x00 }, /* ij to ij */ { 0x0134, 0x4A, 0x68, 0x00, 0x00 }, /* Ĵ to Jh */ { 0x0135, 0x6A, 0x68, 0x00, 0x00 }, /* ĵ to jh */ { 0x0136, 0x4B, 0x00, 0x00, 0x00 }, /* Ķ to K */ { 0x0137, 0x6B, 0x00, 0x00, 0x00 }, /* ķ to k */ { 0x0138, 0x6B, 0x00, 0x00, 0x00 }, /* ĸ to k */ { 0x0139, 0x4C, 0x00, 0x00, 0x00 }, /* Ĺ to L */ { 0x013A, 0x6C, 0x00, 0x00, 0x00 }, /* ĺ to l */ { 0x013B, 0x4C, 0x00, 0x00, 0x00 }, /* Ļ to L */ { 0x013C, 0x6C, 0x00, 0x00, 0x00 }, /* ļ to l */ { 0x013D, 0x4C, 0x00, 0x00, 0x00 }, /* Ľ to L */ { 0x013E, 0x6C, 0x00, 0x00, 0x00 }, /* ľ to l */ { 0x013F, 0x4C, 0x2E, 0x00, 0x00 }, /* Ŀ to L. */ { 0x0140, 0x6C, 0x2E, 0x00, 0x00 }, /* ŀ to l. */ { 0x0141, 0x4C, 0x00, 0x00, 0x00 }, /* Ł to L */ { 0x0142, 0x6C, 0x00, 0x00, 0x00 }, /* ł to l */ { 0x0143, 0x4E, 0x00, 0x00, 0x00 }, /* Ń to N */ { 0x0144, 0x6E, 0x00, 0x00, 0x00 }, /* ń to n */ { 0x0145, 0x4E, 0x00, 0x00, 0x00 }, /* Ņ to N */ { 0x0146, 0x6E, 0x00, 0x00, 0x00 }, /* ņ to n */ { 0x0147, 0x4E, 0x00, 0x00, 0x00 }, /* Ň to N */ { 0x0148, 0x6E, 0x00, 0x00, 0x00 }, /* ň to n */ { 0x0149, 0x27, 0x6E, 0x00, 0x00 }, /* ʼn to 'n */ { 0x014A, 0x4E, 0x47, 0x00, 0x00 }, /* Ŋ to NG */ { 0x014B, 0x6E, 0x67, 0x00, 0x00 }, /* ŋ to ng */ { 0x014C, 0x4F, 0x00, 0x00, 0x00 }, /* Ō to O */ { 0x014D, 0x6F, 0x00, 0x00, 0x00 }, /* ō to o */ { 0x014E, 0x4F, 0x00, 0x00, 0x00 }, /* Ŏ to O */ { 0x014F, 0x6F, 0x00, 0x00, 0x00 }, /* ŏ to o */ { 0x0150, 0x4F, 0x00, 0x00, 0x00 }, /* Ő to O */ { 0x0151, 0x6F, 0x00, 0x00, 0x00 }, /* ő to o */ { 0x0152, 0x4F, 0x45, 0x00, 0x00 }, /* Œ to OE */ { 0x0153, 0x6F, 0x65, 0x00, 0x00 }, /* œ to oe */ { 0x0154, 0x52, 0x00, 0x00, 0x00 }, /* Ŕ to R */ { 0x0155, 0x72, 0x00, 0x00, 0x00 }, /* ŕ to r */ { 0x0156, 0x52, 0x00, 0x00, 0x00 }, /* Ŗ to R */ { 0x0157, 0x72, 0x00, 0x00, 0x00 }, /* ŗ to r */ { 0x0158, 0x52, 0x00, 0x00, 0x00 }, /* Ř to R */ { 0x0159, 0x72, 0x00, 0x00, 0x00 }, /* ř to r */ { 0x015A, 0x53, 0x00, 0x00, 0x00 }, /* Ś to S */ { 0x015B, 0x73, 0x00, 0x00, 0x00 }, /* ś to s */ { 0x015C, 0x53, 0x68, 0x00, 0x00 }, /* Ŝ to Sh */ { 0x015D, 0x73, 0x68, 0x00, 0x00 }, /* ŝ to sh */ { 0x015E, 0x53, 0x00, 0x00, 0x00 }, /* Ş to S */ { 0x015F, 0x73, 0x00, 0x00, 0x00 }, /* ş to s */ { 0x0160, 0x53, 0x00, 0x00, 0x00 }, /* Š to S */ { 0x0161, 0x73, 0x00, 0x00, 0x00 }, /* š to s */ { 0x0162, 0x54, 0x00, 0x00, 0x00 }, /* Ţ to T */ { 0x0163, 0x74, 0x00, 0x00, 0x00 }, /* ţ to t */ { 0x0164, 0x54, 0x00, 0x00, 0x00 }, /* Ť to T */ { 0x0165, 0x74, 0x00, 0x00, 0x00 }, /* ť to t */ { 0x0166, 0x54, 0x00, 0x00, 0x00 }, /* Ŧ to T */ { 0x0167, 0x74, 0x00, 0x00, 0x00 }, /* ŧ to t */ { 0x0168, 0x55, 0x00, 0x00, 0x00 }, /* Ũ to U */ { 0x0169, 0x75, 0x00, 0x00, 0x00 }, /* ũ to u */ { 0x016A, 0x55, 0x00, 0x00, 0x00 }, /* Ū to U */ { 0x016B, 0x75, 0x00, 0x00, 0x00 }, /* ū to u */ { 0x016C, 0x55, 0x00, 0x00, 0x00 }, /* Ŭ to U */ { 0x016D, 0x75, 0x00, 0x00, 0x00 }, /* ŭ to u */ { 0x016E, 0x55, 0x00, 0x00, 0x00 }, /* Ů to U */ { 0x016F, 0x75, 0x00, 0x00, 0x00 }, /* ů to u */ { 0x0170, 0x55, 0x00, 0x00, 0x00 }, /* Ű to U */ { 0x0171, 0x75, 0x00, 0x00, 0x00 }, /* ű to u */ { 0x0172, 0x55, 0x00, 0x00, 0x00 }, /* Ų to U */ { 0x0173, 0x75, 0x00, 0x00, 0x00 }, /* ų to u */ { 0x0174, 0x57, 0x00, 0x00, 0x00 }, /* Ŵ to W */ { 0x0175, 0x77, 0x00, 0x00, 0x00 }, /* ŵ to w */ { 0x0176, 0x59, 0x00, 0x00, 0x00 }, /* Ŷ to Y */ { 0x0177, 0x79, 0x00, 0x00, 0x00 }, /* ŷ to y */ { 0x0178, 0x59, 0x00, 0x00, 0x00 }, /* Ÿ to Y */ { 0x0179, 0x5A, 0x00, 0x00, 0x00 }, /* Ź to Z */ { 0x017A, 0x7A, 0x00, 0x00, 0x00 }, /* ź to z */ { 0x017B, 0x5A, 0x00, 0x00, 0x00 }, /* Ż to Z */ { 0x017C, 0x7A, 0x00, 0x00, 0x00 }, /* ż to z */ { 0x017D, 0x5A, 0x00, 0x00, 0x00 }, /* Ž to Z */ { 0x017E, 0x7A, 0x00, 0x00, 0x00 }, /* ž to z */ { 0x017F, 0x73, 0x00, 0x00, 0x00 }, /* ſ to s */ { 0x0192, 0x66, 0x00, 0x00, 0x00 }, /* ƒ to f */ { 0x0218, 0x53, 0x00, 0x00, 0x00 }, /* Ș to S */ { 0x0219, 0x73, 0x00, 0x00, 0x00 }, /* ș to s */ { 0x021A, 0x54, 0x00, 0x00, 0x00 }, /* Ț to T */ { 0x021B, 0x74, 0x00, 0x00, 0x00 }, /* ț to t */ { 0x0386, 0x41, 0x00, 0x00, 0x00 }, /* Ά to A */ { 0x0388, 0x45, 0x00, 0x00, 0x00 }, /* Έ to E */ { 0x0389, 0x49, 0x00, 0x00, 0x00 }, /* Ή to I */ { 0x038A, 0x49, 0x00, 0x00, 0x00 }, /* Ί to I */ { 0x038C, 0x4f, 0x00, 0x00, 0x00 }, /* Ό to O */ { 0x038E, 0x59, 0x00, 0x00, 0x00 }, /* Ύ to Y */ { 0x038F, 0x4f, 0x00, 0x00, 0x00 }, /* Ώ to O */ { 0x0390, 0x69, 0x00, 0x00, 0x00 }, /* ΐ to i */ { 0x0391, 0x41, 0x00, 0x00, 0x00 }, /* Α to A */ { 0x0392, 0x42, 0x00, 0x00, 0x00 }, /* Β to B */ { 0x0393, 0x47, 0x00, 0x00, 0x00 }, /* Γ to G */ { 0x0394, 0x44, 0x00, 0x00, 0x00 }, /* Δ to D */ { 0x0395, 0x45, 0x00, 0x00, 0x00 }, /* Ε to E */ { 0x0396, 0x5a, 0x00, 0x00, 0x00 }, /* Ζ to Z */ { 0x0397, 0x49, 0x00, 0x00, 0x00 }, /* Η to I */ { 0x0398, 0x54, 0x68, 0x00, 0x00 }, /* Θ to Th */ { 0x0399, 0x49, 0x00, 0x00, 0x00 }, /* Ι to I */ { 0x039A, 0x4b, 0x00, 0x00, 0x00 }, /* Κ to K */ { 0x039B, 0x4c, 0x00, 0x00, 0x00 }, /* Λ to L */ { 0x039C, 0x4d, 0x00, 0x00, 0x00 }, /* Μ to M */ { 0x039D, 0x4e, 0x00, 0x00, 0x00 }, /* Ν to N */ { 0x039E, 0x58, 0x00, 0x00, 0x00 }, /* Ξ to X */ { 0x039F, 0x4f, 0x00, 0x00, 0x00 }, /* Ο to O */ { 0x03A0, 0x50, 0x00, 0x00, 0x00 }, /* Π to P */ { 0x03A1, 0x52, 0x00, 0x00, 0x00 }, /* Ρ to R */ { 0x03A3, 0x53, 0x00, 0x00, 0x00 }, /* Σ to S */ { 0x03A4, 0x54, 0x00, 0x00, 0x00 }, /* Τ to T */ { 0x03A5, 0x59, 0x00, 0x00, 0x00 }, /* Υ to Y */ { 0x03A6, 0x46, 0x00, 0x00, 0x00 }, /* Φ to F */ { 0x03A7, 0x43, 0x68, 0x00, 0x00 }, /* Χ to Ch */ { 0x03A8, 0x50, 0x73, 0x00, 0x00 }, /* Ψ to Ps */ { 0x03A9, 0x4f, 0x00, 0x00, 0x00 }, /* Ω to O */ { 0x03AA, 0x49, 0x00, 0x00, 0x00 }, /* Ϊ to I */ { 0x03AB, 0x59, 0x00, 0x00, 0x00 }, /* Ϋ to Y */ { 0x03AC, 0x61, 0x00, 0x00, 0x00 }, /* ά to a */ { 0x03AD, 0x65, 0x00, 0x00, 0x00 }, /* έ to e */ { 0x03AE, 0x69, 0x00, 0x00, 0x00 }, /* ή to i */ { 0x03AF, 0x69, 0x00, 0x00, 0x00 }, /* ί to i */ { 0x03B1, 0x61, 0x00, 0x00, 0x00 }, /* α to a */ { 0x03B2, 0x62, 0x00, 0x00, 0x00 }, /* β to b */ { 0x03B3, 0x67, 0x00, 0x00, 0x00 }, /* γ to g */ { 0x03B4, 0x64, 0x00, 0x00, 0x00 }, /* δ to d */ { 0x03B5, 0x65, 0x00, 0x00, 0x00 }, /* ε to e */ { 0x03B6, 0x7a, 0x00, 0x00, 0x00 }, /* ζ to z */ { 0x03B7, 0x69, 0x00, 0x00, 0x00 }, /* η to i */ { 0x03B8, 0x74, 0x68, 0x00, 0x00 }, /* θ to th */ { 0x03B9, 0x69, 0x00, 0x00, 0x00 }, /* ι to i */ { 0x03BA, 0x6b, 0x00, 0x00, 0x00 }, /* κ to k */ { 0x03BB, 0x6c, 0x00, 0x00, 0x00 }, /* λ to l */ { 0x03BC, 0x6d, 0x00, 0x00, 0x00 }, /* μ to m */ { 0x03BD, 0x6e, 0x00, 0x00, 0x00 }, /* ν to n */ { 0x03BE, 0x78, 0x00, 0x00, 0x00 }, /* ξ to x */ { 0x03BF, 0x6f, 0x00, 0x00, 0x00 }, /* ο to o */ { 0x03C0, 0x70, 0x00, 0x00, 0x00 }, /* π to p */ { 0x03C1, 0x72, 0x00, 0x00, 0x00 }, /* ρ to r */ { 0x03C3, 0x73, 0x00, 0x00, 0x00 }, /* σ to s */ { 0x03C4, 0x74, 0x00, 0x00, 0x00 }, /* τ to t */ { 0x03C5, 0x79, 0x00, 0x00, 0x00 }, /* υ to y */ { 0x03C6, 0x66, 0x00, 0x00, 0x00 }, /* φ to f */ { 0x03C7, 0x63, 0x68, 0x00, 0x00 }, /* χ to ch */ { 0x03C8, 0x70, 0x73, 0x00, 0x00 }, /* ψ to ps */ { 0x03C9, 0x6f, 0x00, 0x00, 0x00 }, /* ω to o */ { 0x03CA, 0x69, 0x00, 0x00, 0x00 }, /* ϊ to i */ { 0x03CB, 0x79, 0x00, 0x00, 0x00 }, /* ϋ to y */ { 0x03CC, 0x6f, 0x00, 0x00, 0x00 }, /* ό to o */ { 0x03CD, 0x79, 0x00, 0x00, 0x00 }, /* ύ to y */ { 0x03CE, 0x69, 0x00, 0x00, 0x00 }, /* ώ to i */ { 0x0400, 0x45, 0x00, 0x00, 0x00 }, /* Ѐ to E */ { 0x0401, 0x45, 0x00, 0x00, 0x00 }, /* Ё to E */ { 0x0402, 0x44, 0x00, 0x00, 0x00 }, /* Ђ to D */ { 0x0403, 0x47, 0x00, 0x00, 0x00 }, /* Ѓ to G */ { 0x0404, 0x45, 0x00, 0x00, 0x00 }, /* Є to E */ { 0x0405, 0x5a, 0x00, 0x00, 0x00 }, /* Ѕ to Z */ { 0x0406, 0x49, 0x00, 0x00, 0x00 }, /* І to I */ { 0x0407, 0x49, 0x00, 0x00, 0x00 }, /* Ї to I */ { 0x0408, 0x4a, 0x00, 0x00, 0x00 }, /* Ј to J */ { 0x0409, 0x49, 0x00, 0x00, 0x00 }, /* Љ to I */ { 0x040A, 0x4e, 0x00, 0x00, 0x00 }, /* Њ to N */ { 0x040B, 0x44, 0x00, 0x00, 0x00 }, /* Ћ to D */ { 0x040C, 0x4b, 0x00, 0x00, 0x00 }, /* Ќ to K */ { 0x040D, 0x49, 0x00, 0x00, 0x00 }, /* Ѝ to I */ { 0x040E, 0x55, 0x00, 0x00, 0x00 }, /* Ў to U */ { 0x040F, 0x44, 0x00, 0x00, 0x00 }, /* Џ to D */ { 0x0410, 0x41, 0x00, 0x00, 0x00 }, /* А to A */ { 0x0411, 0x42, 0x00, 0x00, 0x00 }, /* Б to B */ { 0x0412, 0x56, 0x00, 0x00, 0x00 }, /* В to V */ { 0x0413, 0x47, 0x00, 0x00, 0x00 }, /* Г to G */ { 0x0414, 0x44, 0x00, 0x00, 0x00 }, /* Д to D */ { 0x0415, 0x45, 0x00, 0x00, 0x00 }, /* Е to E */ { 0x0416, 0x5a, 0x68, 0x00, 0x00 }, /* Ж to Zh */ { 0x0417, 0x5a, 0x00, 0x00, 0x00 }, /* З to Z */ { 0x0418, 0x49, 0x00, 0x00, 0x00 }, /* И to I */ { 0x0419, 0x49, 0x00, 0x00, 0x00 }, /* Й to I */ { 0x041A, 0x4b, 0x00, 0x00, 0x00 }, /* К to K */ { 0x041B, 0x4c, 0x00, 0x00, 0x00 }, /* Л to L */ { 0x041C, 0x4d, 0x00, 0x00, 0x00 }, /* М to M */ { 0x041D, 0x4e, 0x00, 0x00, 0x00 }, /* Н to N */ { 0x041E, 0x4f, 0x00, 0x00, 0x00 }, /* О to O */ { 0x041F, 0x50, 0x00, 0x00, 0x00 }, /* П to P */ { 0x0420, 0x52, 0x00, 0x00, 0x00 }, /* Р to R */ { 0x0421, 0x53, 0x00, 0x00, 0x00 }, /* С to S */ { 0x0422, 0x54, 0x00, 0x00, 0x00 }, /* Т to T */ { 0x0423, 0x55, 0x00, 0x00, 0x00 }, /* У to U */ { 0x0424, 0x46, 0x00, 0x00, 0x00 }, /* Ф to F */ { 0x0425, 0x4b, 0x68, 0x00, 0x00 }, /* Х to Kh */ { 0x0426, 0x54, 0x63, 0x00, 0x00 }, /* Ц to Tc */ { 0x0427, 0x43, 0x68, 0x00, 0x00 }, /* Ч to Ch */ { 0x0428, 0x53, 0x68, 0x00, 0x00 }, /* Ш to Sh */ { 0x0429, 0x53, 0x68, 0x63, 0x68 }, /* Щ to Shch */ { 0x042A, 0x61, 0x00, 0x00, 0x00 }, /* to A */ { 0x042B, 0x59, 0x00, 0x00, 0x00 }, /* Ы to Y */ { 0x042C, 0x59, 0x00, 0x00, 0x00 }, /* to Y */ { 0x042D, 0x45, 0x00, 0x00, 0x00 }, /* Э to E */ { 0x042E, 0x49, 0x75, 0x00, 0x00 }, /* Ю to Iu */ { 0x042F, 0x49, 0x61, 0x00, 0x00 }, /* Я to Ia */ { 0x0430, 0x61, 0x00, 0x00, 0x00 }, /* а to a */ { 0x0431, 0x62, 0x00, 0x00, 0x00 }, /* б to b */ { 0x0432, 0x76, 0x00, 0x00, 0x00 }, /* в to v */ { 0x0433, 0x67, 0x00, 0x00, 0x00 }, /* г to g */ { 0x0434, 0x64, 0x00, 0x00, 0x00 }, /* д to d */ { 0x0435, 0x65, 0x00, 0x00, 0x00 }, /* е to e */ { 0x0436, 0x7a, 0x68, 0x00, 0x00 }, /* ж to zh */ { 0x0437, 0x7a, 0x00, 0x00, 0x00 }, /* з to z */ { 0x0438, 0x69, 0x00, 0x00, 0x00 }, /* и to i */ { 0x0439, 0x69, 0x00, 0x00, 0x00 }, /* й to i */ { 0x043A, 0x6b, 0x00, 0x00, 0x00 }, /* к to k */ { 0x043B, 0x6c, 0x00, 0x00, 0x00 }, /* л to l */ { 0x043C, 0x6d, 0x00, 0x00, 0x00 }, /* м to m */ { 0x043D, 0x6e, 0x00, 0x00, 0x00 }, /* н to n */ { 0x043E, 0x6f, 0x00, 0x00, 0x00 }, /* о to o */ { 0x043F, 0x70, 0x00, 0x00, 0x00 }, /* п to p */ { 0x0440, 0x72, 0x00, 0x00, 0x00 }, /* р to r */ { 0x0441, 0x73, 0x00, 0x00, 0x00 }, /* с to s */ { 0x0442, 0x74, 0x00, 0x00, 0x00 }, /* т to t */ { 0x0443, 0x75, 0x00, 0x00, 0x00 }, /* у to u */ { 0x0444, 0x66, 0x00, 0x00, 0x00 }, /* ф to f */ { 0x0445, 0x6b, 0x68, 0x00, 0x00 }, /* х to kh */ { 0x0446, 0x74, 0x63, 0x00, 0x00 }, /* ц to tc */ { 0x0447, 0x63, 0x68, 0x00, 0x00 }, /* ч to ch */ { 0x0448, 0x73, 0x68, 0x00, 0x00 }, /* ш to sh */ { 0x0449, 0x73, 0x68, 0x63, 0x68 }, /* щ to shch */ { 0x044A, 0x61, 0x00, 0x00, 0x00 }, /* to a */ { 0x044B, 0x79, 0x00, 0x00, 0x00 }, /* ы to y */ { 0x044C, 0x79, 0x00, 0x00, 0x00 }, /* to y */ { 0x044D, 0x65, 0x00, 0x00, 0x00 }, /* э to e */ { 0x044E, 0x69, 0x75, 0x00, 0x00 }, /* ю to iu */ { 0x044F, 0x69, 0x61, 0x00, 0x00 }, /* я to ia */ { 0x0450, 0x65, 0x00, 0x00, 0x00 }, /* ѐ to e */ { 0x0451, 0x65, 0x00, 0x00, 0x00 }, /* ё to e */ { 0x0452, 0x64, 0x00, 0x00, 0x00 }, /* ђ to d */ { 0x0453, 0x67, 0x00, 0x00, 0x00 }, /* ѓ to g */ { 0x0454, 0x65, 0x00, 0x00, 0x00 }, /* є to e */ { 0x0455, 0x7a, 0x00, 0x00, 0x00 }, /* ѕ to z */ { 0x0456, 0x69, 0x00, 0x00, 0x00 }, /* і to i */ { 0x0457, 0x69, 0x00, 0x00, 0x00 }, /* ї to i */ { 0x0458, 0x6a, 0x00, 0x00, 0x00 }, /* ј to j */ { 0x0459, 0x69, 0x00, 0x00, 0x00 }, /* љ to i */ { 0x045A, 0x6e, 0x00, 0x00, 0x00 }, /* њ to n */ { 0x045B, 0x64, 0x00, 0x00, 0x00 }, /* ћ to d */ { 0x045C, 0x6b, 0x00, 0x00, 0x00 }, /* ќ to k */ { 0x045D, 0x69, 0x00, 0x00, 0x00 }, /* ѝ to i */ { 0x045E, 0x75, 0x00, 0x00, 0x00 }, /* ў to u */ { 0x045F, 0x64, 0x00, 0x00, 0x00 }, /* џ to d */ { 0x1E02, 0x42, 0x00, 0x00, 0x00 }, /* Ḃ to B */ { 0x1E03, 0x62, 0x00, 0x00, 0x00 }, /* ḃ to b */ { 0x1E0A, 0x44, 0x00, 0x00, 0x00 }, /* Ḋ to D */ { 0x1E0B, 0x64, 0x00, 0x00, 0x00 }, /* ḋ to d */ { 0x1E1E, 0x46, 0x00, 0x00, 0x00 }, /* Ḟ to F */ { 0x1E1F, 0x66, 0x00, 0x00, 0x00 }, /* ḟ to f */ { 0x1E40, 0x4D, 0x00, 0x00, 0x00 }, /* Ṁ to M */ { 0x1E41, 0x6D, 0x00, 0x00, 0x00 }, /* ṁ to m */ { 0x1E56, 0x50, 0x00, 0x00, 0x00 }, /* Ṗ to P */ { 0x1E57, 0x70, 0x00, 0x00, 0x00 }, /* ṗ to p */ { 0x1E60, 0x53, 0x00, 0x00, 0x00 }, /* Ṡ to S */ { 0x1E61, 0x73, 0x00, 0x00, 0x00 }, /* ṡ to s */ { 0x1E6A, 0x54, 0x00, 0x00, 0x00 }, /* Ṫ to T */ { 0x1E6B, 0x74, 0x00, 0x00, 0x00 }, /* ṫ to t */ { 0x1E80, 0x57, 0x00, 0x00, 0x00 }, /* Ẁ to W */ { 0x1E81, 0x77, 0x00, 0x00, 0x00 }, /* ẁ to w */ { 0x1E82, 0x57, 0x00, 0x00, 0x00 }, /* Ẃ to W */ { 0x1E83, 0x77, 0x00, 0x00, 0x00 }, /* ẃ to w */ { 0x1E84, 0x57, 0x00, 0x00, 0x00 }, /* Ẅ to W */ { 0x1E85, 0x77, 0x00, 0x00, 0x00 }, /* ẅ to w */ { 0x1EF2, 0x59, 0x00, 0x00, 0x00 }, /* Ỳ to Y */ { 0x1EF3, 0x79, 0x00, 0x00, 0x00 }, /* ỳ to y */ { 0xFB00, 0x66, 0x66, 0x00, 0x00 }, /* ff to ff */ { 0xFB01, 0x66, 0x69, 0x00, 0x00 }, /* fi to fi */ { 0xFB02, 0x66, 0x6C, 0x00, 0x00 }, /* fl to fl */ { 0xFB05, 0x73, 0x74, 0x00, 0x00 }, /* ſt to st */ { 0xFB06, 0x73, 0x74, 0x00, 0x00 }, /* st to st */ }; static const Transliteration *spellfixFindTranslit(int c, int *pxTop){ *pxTop = (sizeof(translit)/sizeof(translit[0])) - 1; return translit; } /* ** Convert the input string from UTF-8 into pure ASCII by converting ** all non-ASCII characters to some combination of characters in the ** ASCII subset. ** ** The returned string might contain more characters than the input. |
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 | c = utf8Read(zIn, nIn, &sz); zIn += sz; nIn -= sz; if( c<=127 ){ zOut[nOut++] = (unsigned char)c; }else{ int xTop, xBtm, x; | | | | | | < | | > | > | | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 | c = utf8Read(zIn, nIn, &sz); zIn += sz; nIn -= sz; if( c<=127 ){ zOut[nOut++] = (unsigned char)c; }else{ int xTop, xBtm, x; const Transliteration *tbl = spellfixFindTranslit(c, &xTop); xBtm = 0; while( xTop>=xBtm ){ x = (xTop + xBtm)/2; if( tbl[x].cFrom==c ){ 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; }else{ xBtm = x+1; } } if( c ) zOut[nOut++] = '?'; } |
︙ | ︙ | |||
1664 1665 1666 1667 1668 1669 1670 | for(nChar=0; i<nIn && nOut<nTrans; nChar++){ c = utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz); i += sz; nOut++; if( c>=128 ){ int xTop, xBtm, x; | | | | | > > > > > > > | | 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 | for(nChar=0; i<nIn && nOut<nTrans; nChar++){ c = utf8Read((const unsigned char *)&zIn[i], nIn-i, &sz); i += sz; nOut++; if( c>=128 ){ int xTop, xBtm, x; const Transliteration *tbl = spellfixFindTranslit(c, &xTop); xBtm = 0; while( xTop>=xBtm ){ x = (xTop + xBtm)/2; if( tbl[x].cFrom==c ){ if( tbl[x].cTo1 ){ nOut++; if( tbl[x].cTo2 ){ nOut++; if( tbl[x].cTo3 ){ nOut++; } } } break; }else if( tbl[x].cFrom>c ){ xTop = x-1; }else{ xBtm = x+1; } } } } |
︙ | ︙ | |||
2472 2473 2474 2475 2476 2477 2478 | if( zPattern==0 ){ x.rc = SQLITE_NOMEM; goto filter_exit; } nPattern = (int)strlen(zPattern); if( zPattern[nPattern-1]=='*' ) nPattern--; zSql = sqlite3_mprintf( | | | 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 | if( zPattern==0 ){ x.rc = SQLITE_NOMEM; goto filter_exit; } nPattern = (int)strlen(zPattern); if( zPattern[nPattern-1]=='*' ) nPattern--; zSql = sqlite3_mprintf( "SELECT id, word, rank, coalesce(k1,word)" " FROM \"%w\".\"%w_vocab\"" " WHERE langid=%d AND k2>=?1 AND k2<?2", p->zDbName, p->zTableName, iLang ); if( zSql==0 ){ x.rc = SQLITE_NOMEM; pStmt = 0; |
︙ | ︙ | |||
2806 2807 2808 2809 2810 2811 2812 | sqlite3_free(zK1); return SQLITE_NOMEM; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ spellfix1DbExec(&rc, db, "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " | | | | | | | | 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 | sqlite3_free(zK1); return SQLITE_NOMEM; } if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ spellfix1DbExec(&rc, db, "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " "VALUES(%d,%d,%Q,nullif(%Q,%Q),%Q)", p->zDbName, p->zTableName, iRank, iLang, zWord, zK1, zWord, zK2 ); }else{ newRowid = sqlite3_value_int64(argv[1]); spellfix1DbExec(&rc, db, "INSERT OR %s INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) " "VALUES(%lld,%d,%d,%Q,nullif(%Q,%Q),%Q)", zConflict, p->zDbName, p->zTableName, newRowid, iRank, iLang, zWord, zK1, zWord, zK2 ); } *pRowid = sqlite3_last_insert_rowid(db); }else{ rowid = sqlite3_value_int64(argv[0]); newRowid = *pRowid = sqlite3_value_int64(argv[1]); spellfix1DbExec(&rc, db, "UPDATE OR %s \"%w\".\"%w_vocab\" SET id=%lld, rank=%d, langid=%d," " word=%Q, k1=nullif(%Q,%Q), k2=%Q WHERE id=%lld", zConflict, p->zDbName, p->zTableName, newRowid, iRank, iLang, zWord, zK1, zWord, zK2, rowid ); } sqlite3_free(zK1); sqlite3_free(zK2); } return rc; } |
︙ | ︙ |
Changes to ext/misc/zipfile.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdio.h> #include <string.h> #include <assert.h> | < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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 | */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <stdio.h> #include <string.h> #include <assert.h> #include <zlib.h> #ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_AMALGAMATION typedef sqlite3_int64 i64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; #define MIN(a,b) ((a)<(b) ? (a) : (b)) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #endif /* SQLITE_AMALGAMATION */ /* ** Definitions for mode bitmasks S_IFDIR, S_IFREG and S_IFLNK. ** ** In some ways it would be better to obtain these values from system ** header files. But, the dependency is undesirable and (a) these ** have been stable for decades, (b) the values are part of POSIX and ** are also made explicit in [man stat], and (c) are part of the ** file format for zip archives. */ #ifndef S_IFDIR # define S_IFDIR 0040000 #endif #ifndef S_IFREG # define S_IFREG 0100000 #endif #ifndef S_IFLNK # define S_IFLNK 0120000 #endif static const char ZIPFILE_SCHEMA[] = "CREATE TABLE y(" "name PRIMARY KEY," /* 0: Name of file in zip archive */ "mode," /* 1: POSIX mode for file */ "mtime," /* 2: Last modification time (secs since 1970)*/ |
︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | ** 11 means "utf-8 filename and comment". ** ** ZIPFILE_SIGNATURE_CDS: ** First 4 bytes of a valid CDS record. ** ** ZIPFILE_SIGNATURE_LFH: ** First 4 bytes of a valid LFH record. */ #define ZIPFILE_EXTRA_TIMESTAMP 0x5455 #define ZIPFILE_NEWENTRY_MADEBY ((3<<8) + 30) #define ZIPFILE_NEWENTRY_REQUIRED 20 #define ZIPFILE_NEWENTRY_FLAGS 0x800 #define ZIPFILE_SIGNATURE_CDS 0x02014b50 #define ZIPFILE_SIGNATURE_LFH 0x04034b50 #define ZIPFILE_SIGNATURE_EOCD 0x06054b50 | > > > < < > | > | < < < < < < < < | | 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 | ** 11 means "utf-8 filename and comment". ** ** ZIPFILE_SIGNATURE_CDS: ** First 4 bytes of a valid CDS record. ** ** ZIPFILE_SIGNATURE_LFH: ** First 4 bytes of a valid LFH record. ** ** ZIPFILE_SIGNATURE_EOCD ** First 4 bytes of a valid EOCD record. */ #define ZIPFILE_EXTRA_TIMESTAMP 0x5455 #define ZIPFILE_NEWENTRY_MADEBY ((3<<8) + 30) #define ZIPFILE_NEWENTRY_REQUIRED 20 #define ZIPFILE_NEWENTRY_FLAGS 0x800 #define ZIPFILE_SIGNATURE_CDS 0x02014b50 #define ZIPFILE_SIGNATURE_LFH 0x04034b50 #define ZIPFILE_SIGNATURE_EOCD 0x06054b50 /* ** The sizes of the fixed-size part of each of the three main data ** structures in a zip archive. */ #define ZIPFILE_LFH_FIXED_SZ 30 #define ZIPFILE_EOCD_FIXED_SZ 22 #define ZIPFILE_CDS_FIXED_SZ 46 /* *** 4.3.16 End of central directory record: *** *** end of central dir signature 4 bytes (0x06054b50) *** number of this disk 2 bytes *** number of the disk with the |
︙ | ︙ | |||
218 219 220 221 222 223 224 | u32 szUncompressed; u16 nFile; u16 nExtra; }; typedef struct ZipfileEntry ZipfileEntry; struct ZipfileEntry { | | | | | > | | > | | < < < < < < < < < < < > > > > > > > > > > > > > > > > > > < > | < | < | 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 | u32 szUncompressed; u16 nFile; u16 nExtra; }; typedef struct ZipfileEntry ZipfileEntry; struct ZipfileEntry { ZipfileCDS cds; /* Parsed CDS record */ u32 mUnixTime; /* Modification time, in UNIX format */ u8 *aExtra; /* cds.nExtra+cds.nComment bytes of extra data */ i64 iDataOff; /* Offset to data in file (if aData==0) */ u8 *aData; /* cds.szCompressed bytes of compressed data */ ZipfileEntry *pNext; /* Next element in in-memory CDS */ }; /* ** Cursor type for zipfile tables. */ typedef struct ZipfileCsr ZipfileCsr; struct ZipfileCsr { sqlite3_vtab_cursor base; /* Base class - must be first */ i64 iId; /* Cursor ID */ u8 bEof; /* True when at EOF */ u8 bNoop; /* If next xNext() call is no-op */ /* Used outside of write transactions */ FILE *pFile; /* Zip file */ i64 iNextOff; /* Offset of next record in central directory */ ZipfileEOCD eocd; /* Parse of central directory record */ ZipfileEntry *pFreeEntry; /* Free this list when cursor is closed or reset */ ZipfileEntry *pCurrent; /* Current entry */ ZipfileCsr *pCsrNext; /* Next cursor on same virtual table */ }; typedef struct ZipfileTab ZipfileTab; struct ZipfileTab { sqlite3_vtab base; /* Base class - must be first */ char *zFile; /* Zip file this table accesses (may be NULL) */ u8 *aBuffer; /* Temporary buffer used for various tasks */ ZipfileCsr *pCsrList; /* List of cursors */ i64 iNextCsrid; /* The following are used by write transactions only */ ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */ ZipfileEntry *pLastEntry; /* Last element in pFirstEntry list */ FILE *pWriteFd; /* File handle open on zip archive */ i64 szCurrent; /* Current size of zip archive */ i64 szOrig; /* Size of archive at start of transaction */ }; /* ** Set the error message contained in context ctx to the results of ** vprintf(zFmt, ...). */ static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ char *zMsg = 0; va_list ap; va_start(ap, zFmt); zMsg = sqlite3_vmprintf(zFmt, ap); sqlite3_result_error(ctx, zMsg, -1); sqlite3_free(zMsg); va_end(ap); } /* ** If string zIn is quoted, dequote it in place. Otherwise, if the string ** is not quoted, do nothing. */ static void zipfileDequote(char *zIn){ char q = zIn[0]; if( q=='"' || q=='\'' || q=='`' || q=='[' ){ int iIn = 1; int iOut = 0; if( q=='[' ) q = ']'; while( ALWAYS(zIn[iIn]) ){ char c = zIn[iIn++]; if( c==q && zIn[iIn++]!=q ) break; zIn[iOut++] = c; } zIn[iOut] = '\0'; } } /* |
︙ | ︙ | |||
309 310 311 312 313 314 315 316 317 318 319 320 321 322 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; if( argc>3 ){ zFile = argv[3]; nFile = (int)strlen(zFile)+1; } rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); | > > > > > > > > > > > > > > > | 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 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; /* If the table name is not "zipfile", require that the argument be ** specified. This stops zipfile tables from being created as: ** ** CREATE VIRTUAL TABLE zzz USING zipfile(); ** ** It does not prevent: ** ** CREATE VIRTUAL TABLE zipfile USING zipfile(); */ assert( 0==sqlite3_stricmp(argv[0], "zipfile") ); if( (0!=sqlite3_stricmp(argv[2], "zipfile") && argc<4) || argc>4 ){ *pzErr = sqlite3_mprintf("zipfile constructor requires one argument"); return SQLITE_ERROR; } if( argc>3 ){ zFile = argv[3]; nFile = (int)strlen(zFile)+1; } rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); |
︙ | ︙ | |||
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | memcpy(pNew->zFile, zFile, nFile); zipfileDequote(pNew->zFile); } } *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** This method is the destructor for zipfile vtab objects. */ static int zipfileDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new ZipfileCsr object. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | memcpy(pNew->zFile, zFile, nFile); zipfileDequote(pNew->zFile); } } *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** Free the ZipfileEntry structure indicated by the only argument. */ static void zipfileEntryFree(ZipfileEntry *p){ if( p ){ sqlite3_free(p->cds.zFile); sqlite3_free(p); } } /* ** Release resources that should be freed at the end of a write ** transaction. */ static void zipfileCleanupTransaction(ZipfileTab *pTab){ ZipfileEntry *pEntry; ZipfileEntry *pNext; if( pTab->pWriteFd ){ fclose(pTab->pWriteFd); pTab->pWriteFd = 0; } for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){ pNext = pEntry->pNext; zipfileEntryFree(pEntry); } pTab->pFirstEntry = 0; pTab->pLastEntry = 0; pTab->szCurrent = 0; pTab->szOrig = 0; } /* ** This method is the destructor for zipfile vtab objects. */ static int zipfileDisconnect(sqlite3_vtab *pVtab){ zipfileCleanupTransaction((ZipfileTab*)pVtab); sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new ZipfileCsr object. */ |
︙ | ︙ | |||
362 363 364 365 366 367 368 | } /* ** Reset a cursor back to the state it was in when first returned ** by zipfileOpen(). */ static void zipfileResetCursor(ZipfileCsr *pCsr){ | | > | > > > > > > > | < | < < < > > > > > > > > > > | 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 | } /* ** Reset a cursor back to the state it was in when first returned ** by zipfileOpen(). */ static void zipfileResetCursor(ZipfileCsr *pCsr){ ZipfileEntry *p; ZipfileEntry *pNext; pCsr->bEof = 0; if( pCsr->pFile ){ fclose(pCsr->pFile); pCsr->pFile = 0; zipfileEntryFree(pCsr->pCurrent); pCsr->pCurrent = 0; } for(p=pCsr->pFreeEntry; p; p=pNext){ pNext = p->pNext; zipfileEntryFree(p); } } /* ** Destructor for an ZipfileCsr. */ static int zipfileClose(sqlite3_vtab_cursor *cur){ ZipfileCsr *pCsr = (ZipfileCsr*)cur; ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab); ZipfileCsr **pp; zipfileResetCursor(pCsr); /* Remove this cursor from the ZipfileTab.pCsrList list. */ for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext)); *pp = pCsr->pCsrNext; sqlite3_free(pCsr); return SQLITE_OK; } /* ** Set the error message for the virtual table associated with cursor ** pCsr to the results of vprintf(zFmt, ...). */ static void zipfileSetErrmsg(ZipfileCsr *pCsr, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); va_end(ap); } /* ** Read nRead bytes of data from offset iOff of file pFile into buffer ** aRead[]. Return SQLITE_OK if successful, or an SQLite error code ** otherwise. ** ** If an error does occur, output variable (*pzErrmsg) may be set to point ** to an English language error message. It is the responsibility of the ** caller to eventually free this buffer using ** sqlite3_free(). */ static int zipfileReadData( FILE *pFile, /* Read from this file */ u8 *aRead, /* Read into this buffer */ int nRead, /* Number of bytes to read */ i64 iOff, /* Offset to read from */ char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */ ){ |
︙ | ︙ | |||
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 | pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); return SQLITE_ERROR; } pTab->szCurrent += nWrite; return SQLITE_OK; } static u16 zipfileGetU16(const u8 *aBuf){ return (aBuf[1] << 8) + aBuf[0]; } static u32 zipfileGetU32(const u8 *aBuf){ return ((u32)(aBuf[3]) << 24) + ((u32)(aBuf[2]) << 16) + ((u32)(aBuf[1]) << 8) + ((u32)(aBuf[0]) << 0); } static void zipfilePutU16(u8 *aBuf, u16 val){ aBuf[0] = val & 0xFF; aBuf[1] = (val>>8) & 0xFF; } static void zipfilePutU32(u8 *aBuf, u32 val){ aBuf[0] = val & 0xFF; aBuf[1] = (val>>8) & 0xFF; aBuf[2] = (val>>16) & 0xFF; aBuf[3] = (val>>24) & 0xFF; } #define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) ) #define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) ) #define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; } #define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; } | > > > > > > > > > > > > > > < < < < | | | 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 | pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); return SQLITE_ERROR; } pTab->szCurrent += nWrite; return SQLITE_OK; } /* ** Read and return a 16-bit little-endian unsigned integer from buffer aBuf. */ static u16 zipfileGetU16(const u8 *aBuf){ return (aBuf[1] << 8) + aBuf[0]; } /* ** Read and return a 32-bit little-endian unsigned integer from buffer aBuf. */ static u32 zipfileGetU32(const u8 *aBuf){ return ((u32)(aBuf[3]) << 24) + ((u32)(aBuf[2]) << 16) + ((u32)(aBuf[1]) << 8) + ((u32)(aBuf[0]) << 0); } /* ** Write a 16-bit little endiate integer into buffer aBuf. */ static void zipfilePutU16(u8 *aBuf, u16 val){ aBuf[0] = val & 0xFF; aBuf[1] = (val>>8) & 0xFF; } /* ** Write a 32-bit little endiate integer into buffer aBuf. */ static void zipfilePutU32(u8 *aBuf, u32 val){ aBuf[0] = val & 0xFF; aBuf[1] = (val>>8) & 0xFF; aBuf[2] = (val>>16) & 0xFF; aBuf[3] = (val>>24) & 0xFF; } #define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) ) #define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) ) #define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; } #define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; } /* ** Magic numbers used to read CDS records. */ #define ZIPFILE_CDS_NFILE_OFF 28 #define ZIPFILE_CDS_SZCOMPRESSED_OFF 20 /* ** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR ** if the record is not well-formed, or SQLITE_OK otherwise. */ static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){ u8 *aRead = aBuf; |
︙ | ︙ | |||
508 509 510 511 512 513 514 | assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] ); } return rc; } /* | < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < | < < | | < | | | | | | | | | | | | < | < < < < < < < < < < < > > > | > > > > > > > > > | < | | | < < < < | < < < < | < | > | > > > > > > | > | < < < < | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > | | | | > > > > > | | | | | | < < < > > | < | | < < | > | > | < < | | > | < < > > > > > > > | | 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 | assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] ); } return rc; } /* ** Decode the LFH record in buffer aBuf into (*pLFH). Return SQLITE_ERROR ** if the record is not well-formed, or SQLITE_OK otherwise. */ static int zipfileReadLFH( u8 *aBuffer, ZipfileLFH *pLFH ){ u8 *aRead = aBuffer; int rc = SQLITE_OK; u32 sig = zipfileRead32(aRead); if( sig!=ZIPFILE_SIGNATURE_LFH ){ rc = SQLITE_ERROR; }else{ pLFH->iVersionExtract = zipfileRead16(aRead); pLFH->flags = zipfileRead16(aRead); pLFH->iCompression = zipfileRead16(aRead); pLFH->mTime = zipfileRead16(aRead); pLFH->mDate = zipfileRead16(aRead); pLFH->crc32 = zipfileRead32(aRead); pLFH->szCompressed = zipfileRead32(aRead); pLFH->szUncompressed = zipfileRead32(aRead); pLFH->nFile = zipfileRead16(aRead); pLFH->nExtra = zipfileRead16(aRead); } return rc; } /* ** Buffer aExtra (size nExtra bytes) contains zip archive "extra" fields. ** Scan through this buffer to find an "extra-timestamp" field. If one ** exists, extract the 32-bit modification-timestamp from it and store ** the value in output parameter *pmTime. ** ** Zero is returned if no extra-timestamp record could be found (and so ** *pmTime is left unchanged), or non-zero otherwise. ** ** The general format of an extra field is: ** ** Header ID 2 bytes ** Data Size 2 bytes ** Data N bytes */ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){ int ret = 0; u8 *p = aExtra; u8 *pEnd = &aExtra[nExtra]; while( p<pEnd ){ u16 id = zipfileRead16(p); u16 nByte = zipfileRead16(p); switch( id ){ case ZIPFILE_EXTRA_TIMESTAMP: { u8 b = p[0]; if( b & 0x01 ){ /* 0x01 -> modtime is present */ *pmTime = zipfileGetU32(&p[1]); ret = 1; } break; } } p += nByte; } return ret; } /* ** Convert the standard MS-DOS timestamp stored in the mTime and mDate ** fields of the CDS structure passed as the only argument to a 32-bit ** UNIX seconds-since-the-epoch timestamp. Return the result. ** ** "Standard" MS-DOS time format: ** ** File modification time: ** Bits 00-04: seconds divided by 2 ** Bits 05-10: minute ** Bits 11-15: hour ** File modification date: ** Bits 00-04: day ** Bits 05-08: month (1-12) ** Bits 09-15: years from 1980 ** ** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx */ static u32 zipfileMtime(ZipfileCDS *pCDS){ int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); int M = ((pCDS->mDate >> 5) & 0x0F); int D = (pCDS->mDate & 0x1F); int B = -13; int sec = (pCDS->mTime & 0x1F)*2; int min = (pCDS->mTime >> 5) & 0x3F; int hr = (pCDS->mTime >> 11) & 0x1F; i64 JD; /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */ /* Calculate the JD in seconds for noon on the day in question */ if( M<3 ){ Y = Y-1; M = M+12; } JD = (i64)(24*60*60) * ( (int)(365.25 * (Y + 4716)) + (int)(30.6001 * (M + 1)) + D + B - 1524 ); /* Correct the JD for the time within the day */ JD += (hr-12) * 3600 + min * 60 + sec; /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */ return (u32)(JD - (i64)(24405875) * 24*60*6); } /* ** The opposite of zipfileMtime(). This function populates the mTime and ** mDate fields of the CDS structure passed as the first argument according ** to the UNIX timestamp value passed as the second. */ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){ /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */ i64 JD = (i64)2440588 + mUnixTime / (24*60*60); int A, B, C, D, E; int yr, mon, day; int hr, min, sec; A = (int)((JD - 1867216.25)/36524.25); A = (int)(JD + 1 + A - (A/4)); B = A + 1524; C = (int)((B - 122.1)/365.25); D = (36525*(C&32767))/100; E = (int)((B-D)/30.6001); day = B - D - (int)(30.6001*E); mon = (E<14 ? E-1 : E-13); yr = mon>2 ? C-4716 : C-4715; hr = (mUnixTime % (24*60*60)) / (60*60); min = (mUnixTime % (60*60)) / 60; sec = (mUnixTime % 60); pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9)); pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11)); assert( mUnixTime<315507600 || mUnixTime==zipfileMtime(pCds) || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds)) /* || (mUnixTime % 2) */ ); } /* ** If aBlob is not NULL, then it is a pointer to a buffer (nBlob bytes in ** size) containing an entire zip archive image. Or, if aBlob is NULL, ** then pFile is a file-handle open on a zip file. In either case, this ** function creates a ZipfileEntry object based on the zip archive entry ** for which the CDS record is at offset iOff. ** ** If successful, SQLITE_OK is returned and (*ppEntry) set to point to ** the new object. Otherwise, an SQLite error code is returned and the ** final value of (*ppEntry) undefined. */ static int zipfileGetEntry( ZipfileTab *pTab, /* Store any error message here */ const u8 *aBlob, /* Pointer to in-memory file image */ int nBlob, /* Size of aBlob[] in bytes */ FILE *pFile, /* If aBlob==0, read from this file */ i64 iOff, /* Offset of CDS record */ ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ u8 *aRead; char **pzErr = &pTab->base.zErrMsg; int rc = SQLITE_OK; if( aBlob==0 ){ aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } if( rc==SQLITE_OK ){ int nAlloc; ZipfileEntry *pNew; int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]); int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]); nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]); nAlloc = sizeof(ZipfileEntry) + nExtra; if( aBlob ){ nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]); } pNew = (ZipfileEntry*)sqlite3_malloc(nAlloc); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(pNew, 0, sizeof(ZipfileEntry)); rc = zipfileReadCDS(aRead, &pNew->cds); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff); }else if( aBlob==0 ){ rc = zipfileReadData( pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr ); }else{ aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ]; } } if( rc==SQLITE_OK ){ u32 *pt = &pNew->mUnixTime; pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); pNew->aExtra = (u8*)&pNew[1]; memcpy(pNew->aExtra, &aRead[nFile], nExtra); if( pNew->cds.zFile==0 ){ rc = SQLITE_NOMEM; }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ pNew->mUnixTime = zipfileMtime(&pNew->cds); } } if( rc==SQLITE_OK ){ static const int szFix = ZIPFILE_LFH_FIXED_SZ; ZipfileLFH lfh; if( pFile ){ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); }else{ aRead = (u8*)&aBlob[pNew->cds.iOffset]; } rc = zipfileReadLFH(aRead, &lfh); if( rc==SQLITE_OK ){ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; pNew->iDataOff += lfh.nFile + lfh.nExtra; if( aBlob && pNew->cds.szCompressed ){ pNew->aData = &pNew->aExtra[nExtra]; memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); } }else{ *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", (int)pNew->cds.iOffset ); } } if( rc!=SQLITE_OK ){ zipfileEntryFree(pNew); }else{ *ppEntry = pNew; } } return rc; } /* ** Advance an ZipfileCsr to its next row of output. */ static int zipfileNext(sqlite3_vtab_cursor *cur){ ZipfileCsr *pCsr = (ZipfileCsr*)cur; int rc = SQLITE_OK; if( pCsr->pFile ){ i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize; zipfileEntryFree(pCsr->pCurrent); pCsr->pCurrent = 0; if( pCsr->iNextOff>=iEof ){ pCsr->bEof = 1; }else{ ZipfileEntry *p = 0; ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab); rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p); if( rc==SQLITE_OK ){ pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ; pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment; } pCsr->pCurrent = p; } }else{ if( !pCsr->bNoop ){ pCsr->pCurrent = pCsr->pCurrent->pNext; } if( pCsr->pCurrent==0 ){ pCsr->bEof = 1; } } pCsr->bNoop = 0; return rc; } static void zipfileFree(void *p) { sqlite3_free(p); } /* ** Buffer aIn (size nIn bytes) contains compressed data. Uncompressed, the ** size is nOut bytes. This function uncompresses the data and sets the ** return value in context pCtx to the result (a blob). ** ** If an error occurs, an error code is left in pCtx instead. */ static void zipfileInflate( sqlite3_context *pCtx, /* Store result here */ const u8 *aIn, /* Compressed data */ int nIn, /* Size of buffer aIn[] in bytes */ int nOut /* Expected output size */ ){ u8 *aRes = sqlite3_malloc(nOut); if( aRes==0 ){ sqlite3_result_error_nomem(pCtx); |
︙ | ︙ | |||
743 744 745 746 747 748 749 | if( err!=Z_OK ){ zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err); }else{ err = inflate(&str, Z_NO_FLUSH); if( err!=Z_STREAM_END ){ zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err); }else{ | | > > > > > > > > > > > > > < | > | 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 | if( err!=Z_OK ){ zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err); }else{ err = inflate(&str, Z_NO_FLUSH); if( err!=Z_STREAM_END ){ zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err); }else{ sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree); aRes = 0; } } sqlite3_free(aRes); inflateEnd(&str); } } /* ** Buffer aIn (size nIn bytes) contains uncompressed data. This function ** compresses it and sets (*ppOut) to point to a buffer containing the ** compressed data. The caller is responsible for eventually calling ** sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut) ** is set to the size of buffer (*ppOut) in bytes. ** ** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error ** code is returned and an error message left in virtual-table handle ** pTab. The values of (*ppOut) and (*pnOut) are left unchanged in this ** case. */ static int zipfileDeflate( const u8 *aIn, int nIn, /* Input */ u8 **ppOut, int *pnOut, /* Output */ char **pzErr /* OUT: Error message */ ){ int nAlloc = (int)compressBound(nIn); u8 *aOut; int rc = SQLITE_OK; aOut = (u8*)sqlite3_malloc(nAlloc); if( aOut==0 ){ |
︙ | ︙ | |||
780 781 782 783 784 785 786 | res = deflate(&str, Z_FINISH); if( res==Z_STREAM_END ){ *ppOut = aOut; *pnOut = (int)str.total_out; }else{ sqlite3_free(aOut); | | > | | < | < < < | | | | | > > > > > | | | | > > > | | | | > | < > | | | | > < < < < < < < < | < > > > > > > > > > > | < < | > > > | | | | | | | | > > > > | | | 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 | res = deflate(&str, Z_FINISH); if( res==Z_STREAM_END ){ *ppOut = aOut; *pnOut = (int)str.total_out; }else{ sqlite3_free(aOut); *pzErr = sqlite3_mprintf("zipfile: deflate() error"); rc = SQLITE_ERROR; } deflateEnd(&str); } return rc; } /* ** Return values of columns for the row at which the series_cursor ** is currently pointing. */ static int zipfileColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ ZipfileCsr *pCsr = (ZipfileCsr*)cur; ZipfileCDS *pCDS = &pCsr->pCurrent->cds; int rc = SQLITE_OK; switch( i ){ case 0: /* name */ sqlite3_result_text(ctx, pCDS->zFile, -1, SQLITE_TRANSIENT); break; case 1: /* mode */ /* TODO: Whether or not the following is correct surely depends on ** the platform on which the archive was created. */ sqlite3_result_int(ctx, pCDS->iExternalAttr >> 16); break; case 2: { /* mtime */ sqlite3_result_int64(ctx, pCsr->pCurrent->mUnixTime); break; } case 3: { /* sz */ if( sqlite3_vtab_nochange(ctx)==0 ){ sqlite3_result_int64(ctx, pCDS->szUncompressed); } break; } case 4: /* rawdata */ if( sqlite3_vtab_nochange(ctx) ) break; case 5: { /* data */ if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){ int sz = pCDS->szCompressed; int szFinal = pCDS->szUncompressed; if( szFinal>0 ){ u8 *aBuf; u8 *aFree = 0; if( pCsr->pCurrent->aData ){ aBuf = pCsr->pCurrent->aData; }else{ aBuf = aFree = sqlite3_malloc(sz); if( aBuf==0 ){ rc = SQLITE_NOMEM; }else{ FILE *pFile = pCsr->pFile; if( pFile==0 ){ pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd; } rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff, &pCsr->base.pVtab->zErrMsg ); } } if( rc==SQLITE_OK ){ if( i==5 && pCDS->iCompression ){ zipfileInflate(ctx, aBuf, sz, szFinal); }else{ sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); } } sqlite3_free(aFree); }else{ /* Figure out if this is a directory or a zero-sized file. Consider ** it to be a directory either if the mode suggests so, or if ** the final character in the name is '/'. */ u32 mode = pCDS->iExternalAttr >> 16; if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){ sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC); } } } break; } case 6: /* method */ sqlite3_result_int(ctx, pCDS->iCompression); break; default: /* z */ assert( i==7 ); sqlite3_result_int64(ctx, pCsr->iId); break; } return rc; } /* ** Return TRUE if the cursor is at EOF. */ static int zipfileEof(sqlite3_vtab_cursor *cur){ ZipfileCsr *pCsr = (ZipfileCsr*)cur; return pCsr->bEof; } /* ** If aBlob is not NULL, then it points to a buffer nBlob bytes in size ** containing an entire zip archive image. Or, if aBlob is NULL, then pFile ** is guaranteed to be a file-handle open on a zip file. ** ** This function attempts to locate the EOCD record within the zip archive ** and populate *pEOCD with the results of decoding it. SQLITE_OK is ** returned if successful. Otherwise, an SQLite error code is returned and ** an English language error message may be left in virtual-table pTab. */ static int zipfileReadEOCD( ZipfileTab *pTab, /* Return errors here */ const u8 *aBlob, /* Pointer to in-memory file image */ int nBlob, /* Size of aBlob[] in bytes */ FILE *pFile, /* Read from this file if aBlob==0 */ ZipfileEOCD *pEOCD /* Object to populate */ ){ u8 *aRead = pTab->aBuffer; /* Temporary buffer */ int nRead; /* Bytes to read from file */ int rc = SQLITE_OK; if( aBlob==0 ){ i64 iOff; /* Offset to read from */ i64 szFile; /* Total size of file in bytes */ fseek(pFile, 0, SEEK_END); szFile = (i64)ftell(pFile); if( szFile==0 ){ memset(pEOCD, 0, sizeof(ZipfileEOCD)); return SQLITE_OK; } nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); iOff = szFile - nRead; rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg); }else{ nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE)); aRead = (u8*)&aBlob[nBlob-nRead]; } if( rc==SQLITE_OK ){ int i; /* Scan backwards looking for the signature bytes */ for(i=nRead-20; i>=0; i--){ if( aRead[i]==0x50 && aRead[i+1]==0x4b && aRead[i+2]==0x05 && aRead[i+3]==0x06 |
︙ | ︙ | |||
936 937 938 939 940 941 942 | aRead += i+4; pEOCD->iDisk = zipfileRead16(aRead); pEOCD->iFirstDisk = zipfileRead16(aRead); pEOCD->nEntry = zipfileRead16(aRead); pEOCD->nEntryTotal = zipfileRead16(aRead); pEOCD->nSize = zipfileRead32(aRead); pEOCD->iOffset = zipfileRead32(aRead); | | | > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > | | > > > | | | | > < < | > > > > > > > > > | | < < | | < | 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 | aRead += i+4; pEOCD->iDisk = zipfileRead16(aRead); pEOCD->iFirstDisk = zipfileRead16(aRead); pEOCD->nEntry = zipfileRead16(aRead); pEOCD->nEntryTotal = zipfileRead16(aRead); pEOCD->nSize = zipfileRead32(aRead); pEOCD->iOffset = zipfileRead32(aRead); } return rc; } /* ** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry ** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added ** to the end of the list. Otherwise, it is added to the list immediately ** before pBefore (which is guaranteed to be a part of said list). */ static void zipfileAddEntry( ZipfileTab *pTab, ZipfileEntry *pBefore, ZipfileEntry *pNew ){ assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) ); assert( pNew->pNext==0 ); if( pBefore==0 ){ if( pTab->pFirstEntry==0 ){ pTab->pFirstEntry = pTab->pLastEntry = pNew; }else{ assert( pTab->pLastEntry->pNext==0 ); pTab->pLastEntry->pNext = pNew; pTab->pLastEntry = pNew; } }else{ ZipfileEntry **pp; for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext)); pNew->pNext = pBefore; *pp = pNew; } } static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){ ZipfileEOCD eocd; int rc; int i; i64 iOff; rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd); iOff = eocd.iOffset; for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){ ZipfileEntry *pNew = 0; rc = zipfileGetEntry(pTab, aBlob, nBlob, pTab->pWriteFd, iOff, &pNew); if( rc==SQLITE_OK ){ zipfileAddEntry(pTab, 0, pNew); iOff += ZIPFILE_CDS_FIXED_SZ; iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment; } } return rc; } /* ** xFilter callback. */ static int zipfileFilter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; ZipfileCsr *pCsr = (ZipfileCsr*)cur; const char *zFile = 0; /* Zip file to scan */ int rc = SQLITE_OK; /* Return Code */ int bInMemory = 0; /* True for an in-memory zipfile */ zipfileResetCursor(pCsr); if( pTab->zFile ){ zFile = pTab->zFile; }else if( idxNum==0 ){ zipfileSetErrmsg(pCsr, "zipfile() function requires an argument"); return SQLITE_ERROR; }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]); assert( pTab->pFirstEntry==0 ); rc = zipfileLoadDirectory(pTab, aBlob, nBlob); pCsr->pFreeEntry = pTab->pFirstEntry; pTab->pFirstEntry = pTab->pLastEntry = 0; if( rc!=SQLITE_OK ) return rc; bInMemory = 1; }else{ zFile = (const char*)sqlite3_value_text(argv[0]); } if( 0==pTab->pWriteFd && 0==bInMemory ){ pCsr->pFile = fopen(zFile, "rb"); if( pCsr->pFile==0 ){ zipfileSetErrmsg(pCsr, "cannot open file: %s", zFile); rc = SQLITE_ERROR; }else{ rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd); if( rc==SQLITE_OK ){ if( pCsr->eocd.nEntry==0 ){ pCsr->bEof = 1; }else{ pCsr->iNextOff = pCsr->eocd.iOffset; rc = zipfileNext(cur); } } } }else{ pCsr->bNoop = 1; pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry; rc = zipfileNext(cur); } return rc; } /* ** xBestIndex callback. |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50); pIdxInfo->idxNum = 0; } return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < | < < | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | < > < < | < < < < < < < < < < < | < < | | < < < < < < < < < | | > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | > > | > > < | < < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < | < | | | < < < | < | | | | | | | | | | | | | | | | | < | | | | | | | | > > > | | | | | | | | | | | | | | < | | | | | | | > > > > > | | < > > | > > > > > > > > > > > > > > > < | < < < < < < < < | < | < > > > > | > | < | | < < < < < < | | | > | | | | | | | > | < | | | > > > | > > < < < < < | | < | | | | | < | < | | | | | | 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 1740 1741 | pIdxInfo->estimatedCost = (double)(((sqlite3_int64)1) << 50); pIdxInfo->idxNum = 0; } return SQLITE_OK; } static ZipfileEntry *zipfileNewEntry(const char *zPath){ ZipfileEntry *pNew; pNew = sqlite3_malloc(sizeof(ZipfileEntry)); if( pNew ){ memset(pNew, 0, sizeof(ZipfileEntry)); pNew->cds.zFile = sqlite3_mprintf("%s", zPath); if( pNew->cds.zFile==0 ){ sqlite3_free(pNew); pNew = 0; } } return pNew; } static int zipfileSerializeLFH(ZipfileEntry *pEntry, u8 *aBuf){ ZipfileCDS *pCds = &pEntry->cds; u8 *a = aBuf; pCds->nExtra = 9; /* Write the LFH itself */ zipfileWrite32(a, ZIPFILE_SIGNATURE_LFH); zipfileWrite16(a, pCds->iVersionExtract); zipfileWrite16(a, pCds->flags); zipfileWrite16(a, pCds->iCompression); zipfileWrite16(a, pCds->mTime); zipfileWrite16(a, pCds->mDate); zipfileWrite32(a, pCds->crc32); zipfileWrite32(a, pCds->szCompressed); zipfileWrite32(a, pCds->szUncompressed); zipfileWrite16(a, (u16)pCds->nFile); zipfileWrite16(a, pCds->nExtra); assert( a==&aBuf[ZIPFILE_LFH_FIXED_SZ] ); /* Add the file name */ memcpy(a, pCds->zFile, (int)pCds->nFile); a += (int)pCds->nFile; /* The "extra" data */ zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); zipfileWrite16(a, 5); *a++ = 0x01; zipfileWrite32(a, pEntry->mUnixTime); return a-aBuf; } static int zipfileAppendEntry( ZipfileTab *pTab, ZipfileEntry *pEntry, const u8 *pData, int nData ){ u8 *aBuf = pTab->aBuffer; int nBuf; int rc; nBuf = zipfileSerializeLFH(pEntry, aBuf); rc = zipfileAppendData(pTab, aBuf, nBuf); if( rc==SQLITE_OK ){ pEntry->iDataOff = pTab->szCurrent; rc = zipfileAppendData(pTab, pData, nData); } return rc; } static int zipfileGetMode( sqlite3_value *pVal, int bIsDir, /* If true, default to directory */ u32 *pMode, /* OUT: Mode value */ char **pzErr /* OUT: Error message */ ){ const char *z = (const char*)sqlite3_value_text(pVal); u32 mode = 0; if( z==0 ){ mode = (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)); }else if( z[0]>='0' && z[0]<='9' ){ mode = (unsigned int)sqlite3_value_int(pVal); }else{ const char zTemplate[11] = "-rwxrwxrwx"; int i; if( strlen(z)!=10 ) goto parse_error; switch( z[0] ){ case '-': mode |= S_IFREG; break; case 'd': mode |= S_IFDIR; break; #if !defined(_WIN32) && !defined(WIN32) case 'l': mode |= S_IFLNK; break; #endif default: goto parse_error; } for(i=1; i<10; i++){ if( z[i]==zTemplate[i] ) mode |= 1 << (9-i); else if( z[i]!='-' ) goto parse_error; } } if( (bIsDir == ((mode & S_IFDIR)==0)) ){ /* The "mode" attribute is a directory, but data has been specified. ** Or vice-versa - no data but "mode" is a file or symlink. */ return SQLITE_CONSTRAINT; } *pMode = mode; return SQLITE_OK; parse_error: *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z); return SQLITE_ERROR; } /* ** Both (const char*) arguments point to nul-terminated strings. Argument ** nB is the value of strlen(zB). This function returns 0 if the strings are ** identical, ignoring any trailing '/' character in either path. */ static int zipfileComparePath(const char *zA, const char *zB, int nB){ int nA = (int)strlen(zA); if( zA[nA-1]=='/' ) nA--; if( zB[nB-1]=='/' ) nB--; if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; return 1; } static int zipfileBegin(sqlite3_vtab *pVtab){ ZipfileTab *pTab = (ZipfileTab*)pVtab; int rc = SQLITE_OK; assert( pTab->pWriteFd==0 ); /* Open a write fd on the file. Also load the entire central directory ** structure into memory. During the transaction any new file data is ** appended to the archive file, but the central directory is accumulated ** in main-memory until the transaction is committed. */ pTab->pWriteFd = fopen(pTab->zFile, "ab+"); if( pTab->pWriteFd==0 ){ pTab->base.zErrMsg = sqlite3_mprintf( "zipfile: failed to open file %s for writing", pTab->zFile ); rc = SQLITE_ERROR; }else{ fseek(pTab->pWriteFd, 0, SEEK_END); pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd); rc = zipfileLoadDirectory(pTab, 0, 0); } if( rc!=SQLITE_OK ){ zipfileCleanupTransaction(pTab); } return rc; } /* ** Return the current time as a 32-bit timestamp in UNIX epoch format (like ** time(2)). */ static u32 zipfileTime(void){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); u32 ret; if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ i64 ms; pVfs->xCurrentTimeInt64(pVfs, &ms); ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); }else{ double day; pVfs->xCurrentTime(pVfs, &day); ret = (u32)((day - 2440587.5) * 86400); } return ret; } /* ** Return a 32-bit timestamp in UNIX epoch format. ** ** If the value passed as the only argument is either NULL or an SQL NULL, ** return the current time. Otherwise, return the value stored in (*pVal) ** cast to a 32-bit unsigned integer. */ static u32 zipfileGetTime(sqlite3_value *pVal){ if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){ return zipfileTime(); } return (u32)sqlite3_value_int64(pVal); } /* ** xUpdate method. */ static int zipfileUpdate( sqlite3_vtab *pVtab, int nVal, sqlite3_value **apVal, sqlite_int64 *pRowid ){ ZipfileTab *pTab = (ZipfileTab*)pVtab; int rc = SQLITE_OK; /* Return Code */ ZipfileEntry *pNew = 0; /* New in-memory CDS entry */ u32 mode = 0; /* Mode for new entry */ u32 mTime = 0; /* Modification time for new entry */ i64 sz = 0; /* Uncompressed size */ const char *zPath = 0; /* Path for new entry */ int nPath = 0; /* strlen(zPath) */ const u8 *pData = 0; /* Pointer to buffer containing content */ int nData = 0; /* Size of pData buffer in bytes */ int iMethod = 0; /* Compression method for new entry */ u8 *pFree = 0; /* Free this */ char *zFree = 0; /* Also free this */ ZipfileEntry *pOld = 0; int bIsDir = 0; u32 iCrc32 = 0; if( pTab->pWriteFd==0 ){ rc = zipfileBegin(pVtab); if( rc!=SQLITE_OK ) return rc; } /* If this is a DELETE or UPDATE, find the archive entry to delete. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ const char *zDelete = (const char*)sqlite3_value_text(apVal[0]); int nDelete = (int)strlen(zDelete); for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ break; } assert( pOld->pNext ); } } if( nVal>1 ){ /* Check that "sz" and "rawdata" are both NULL: */ if( sqlite3_value_type(apVal[5])!=SQLITE_NULL || sqlite3_value_type(apVal[6])!=SQLITE_NULL ){ rc = SQLITE_CONSTRAINT; } if( rc==SQLITE_OK ){ if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){ /* data=NULL. A directory */ bIsDir = 1; }else{ /* Value specified for "data", and possibly "method". This must be ** a regular file or a symlink. */ const u8 *aIn = sqlite3_value_blob(apVal[7]); int nIn = sqlite3_value_bytes(apVal[7]); int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL; iMethod = sqlite3_value_int(apVal[8]); sz = nIn; pData = aIn; nData = nIn; if( iMethod!=0 && iMethod!=8 ){ rc = SQLITE_CONSTRAINT; }else{ if( bAuto || iMethod ){ int nCmp; rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg); if( rc==SQLITE_OK ){ if( iMethod || nCmp<nIn ){ iMethod = 8; pData = pFree; nData = nCmp; } } } iCrc32 = crc32(0, aIn, nIn); } } } if( rc==SQLITE_OK ){ rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); } if( rc==SQLITE_OK ){ zPath = (const char*)sqlite3_value_text(apVal[2]); nPath = (int)strlen(zPath); mTime = zipfileGetTime(apVal[4]); } if( rc==SQLITE_OK && bIsDir ){ /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories ** otherwise. */ if( zPath[nPath-1]!='/' ){ zFree = sqlite3_mprintf("%s/", zPath); if( zFree==0 ){ rc = SQLITE_NOMEM; } zPath = (const char*)zFree; nPath++; } } /* Check that we're not inserting a duplicate entry */ if( pOld==0 && rc==SQLITE_OK ){ ZipfileEntry *p; for(p=pTab->pFirstEntry; p; p=p->pNext){ if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){ rc = SQLITE_CONSTRAINT; break; } } } if( rc==SQLITE_OK ){ /* Create the new CDS record. */ pNew = zipfileNewEntry(zPath); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS; pNew->cds.iCompression = (u16)iMethod; zipfileMtimeToDos(&pNew->cds, mTime); pNew->cds.crc32 = iCrc32; pNew->cds.szCompressed = nData; pNew->cds.szUncompressed = (u32)sz; pNew->cds.iExternalAttr = (mode<<16); pNew->cds.iOffset = (u32)pTab->szCurrent; pNew->cds.nFile = (u16)nPath; pNew->mUnixTime = (u32)mTime; rc = zipfileAppendEntry(pTab, pNew, pData, nData); zipfileAddEntry(pTab, pOld, pNew); } } } if( rc==SQLITE_OK && pOld ){ ZipfileEntry **pp; ZipfileCsr *pCsr; for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ if( pCsr->pCurrent==pOld ){ pCsr->pCurrent = pOld->pNext; pCsr->bNoop = 1; } } for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext)); *pp = (*pp)->pNext; zipfileEntryFree(pOld); } sqlite3_free(pFree); sqlite3_free(zFree); return rc; } static int zipfileSerializeEOCD(ZipfileEOCD *p, u8 *aBuf){ u8 *a = aBuf; zipfileWrite32(a, ZIPFILE_SIGNATURE_EOCD); zipfileWrite16(a, p->iDisk); zipfileWrite16(a, p->iFirstDisk); zipfileWrite16(a, p->nEntry); zipfileWrite16(a, p->nEntryTotal); zipfileWrite32(a, p->nSize); zipfileWrite32(a, p->iOffset); zipfileWrite16(a, 0); /* Size of trailing comment in bytes*/ return a-aBuf; } static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){ int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer); assert( nBuf==ZIPFILE_EOCD_FIXED_SZ ); return zipfileAppendData(pTab, pTab->aBuffer, nBuf); } /* ** Serialize the CDS structure into buffer aBuf[]. Return the number ** of bytes written. */ static int zipfileSerializeCDS(ZipfileEntry *pEntry, u8 *aBuf){ u8 *a = aBuf; ZipfileCDS *pCDS = &pEntry->cds; if( pEntry->aExtra==0 ){ pCDS->nExtra = 9; } zipfileWrite32(a, ZIPFILE_SIGNATURE_CDS); zipfileWrite16(a, pCDS->iVersionMadeBy); zipfileWrite16(a, pCDS->iVersionExtract); zipfileWrite16(a, pCDS->flags); zipfileWrite16(a, pCDS->iCompression); zipfileWrite16(a, pCDS->mTime); zipfileWrite16(a, pCDS->mDate); zipfileWrite32(a, pCDS->crc32); zipfileWrite32(a, pCDS->szCompressed); zipfileWrite32(a, pCDS->szUncompressed); assert( a==&aBuf[ZIPFILE_CDS_NFILE_OFF] ); zipfileWrite16(a, pCDS->nFile); zipfileWrite16(a, pCDS->nExtra); zipfileWrite16(a, pCDS->nComment); zipfileWrite16(a, pCDS->iDiskStart); zipfileWrite16(a, pCDS->iInternalAttr); zipfileWrite32(a, pCDS->iExternalAttr); zipfileWrite32(a, pCDS->iOffset); memcpy(a, pCDS->zFile, pCDS->nFile); a += pCDS->nFile; if( pEntry->aExtra ){ int n = (int)pCDS->nExtra + (int)pCDS->nComment; memcpy(a, pEntry->aExtra, n); a += n; }else{ assert( pCDS->nExtra==9 ); zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); zipfileWrite16(a, 5); *a++ = 0x01; zipfileWrite32(a, pEntry->mUnixTime); } return a-aBuf; } static int zipfileCommit(sqlite3_vtab *pVtab){ ZipfileTab *pTab = (ZipfileTab*)pVtab; int rc = SQLITE_OK; if( pTab->pWriteFd ){ i64 iOffset = pTab->szCurrent; ZipfileEntry *p; ZipfileEOCD eocd; int nEntry = 0; /* Write out all entries */ for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){ int n = zipfileSerializeCDS(p, pTab->aBuffer); rc = zipfileAppendData(pTab, pTab->aBuffer, n); nEntry++; } /* Write out the EOCD record */ eocd.iDisk = 0; eocd.iFirstDisk = 0; eocd.nEntry = (u16)nEntry; |
︙ | ︙ | |||
1553 1554 1555 1556 1557 1558 1559 | ){ ZipfileCsr *pCsr; ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context); assert( argc>0 ); pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0])); if( pCsr ){ | | | 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | ){ ZipfileCsr *pCsr; ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context); assert( argc>0 ); pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0])); if( pCsr ){ ZipfileCDS *p = &pCsr->pCurrent->cds; char *zRes = sqlite3_mprintf("{" "\"version-made-by\" : %u, " "\"version-to-extract\" : %u, " "\"flags\" : %u, " "\"compression\" : %u, " "\"time\" : %u, " "\"date\" : %u, " |
︙ | ︙ | |||
1590 1591 1592 1593 1594 1595 1596 | }else{ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); sqlite3_free(zRes); } } } | < < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > | > > | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 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 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 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 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 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 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | }else{ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); sqlite3_free(zRes); } } } /* ** xFindFunction method. */ static int zipfileFindFunction( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ *pxFunc = zipfileFunctionCds; *ppArg = (void*)pVtab; return 1; } return 0; } typedef struct ZipfileBuffer ZipfileBuffer; struct ZipfileBuffer { u8 *a; /* Pointer to buffer */ int n; /* Size of buffer in bytes */ int nAlloc; /* Byte allocated at a[] */ }; typedef struct ZipfileCtx ZipfileCtx; struct ZipfileCtx { int nEntry; ZipfileBuffer body; ZipfileBuffer cds; }; static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){ if( pBuf->n+nByte>pBuf->nAlloc ){ u8 *aNew; int nNew = pBuf->n ? pBuf->n*2 : 512; int nReq = pBuf->n + nByte; while( nNew<nReq ) nNew = nNew*2; aNew = sqlite3_realloc(pBuf->a, nNew); if( aNew==0 ) return SQLITE_NOMEM; pBuf->a = aNew; pBuf->nAlloc = nNew; } return SQLITE_OK; } /* ** xStep() callback for the zipfile() aggregate. This can be called in ** any of the following ways: ** ** SELECT zipfile(name,data) ... ** SELECT zipfile(name,mode,mtime,data) ... ** SELECT zipfile(name,mode,mtime,data,method) ... */ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){ ZipfileCtx *p; /* Aggregate function context */ ZipfileEntry e; /* New entry to add to zip archive */ sqlite3_value *pName = 0; sqlite3_value *pMode = 0; sqlite3_value *pMtime = 0; sqlite3_value *pData = 0; sqlite3_value *pMethod = 0; int bIsDir = 0; u32 mode; int rc = SQLITE_OK; char *zErr = 0; int iMethod = -1; /* Compression method to use (0 or 8) */ const u8 *aData = 0; /* Possibly compressed data for new entry */ int nData = 0; /* Size of aData[] in bytes */ int szUncompressed = 0; /* Size of data before compression */ u8 *aFree = 0; /* Free this before returning */ u32 iCrc32 = 0; /* crc32 of uncompressed data */ char *zName = 0; /* Path (name) of new entry */ int nName = 0; /* Size of zName in bytes */ char *zFree = 0; /* Free this before returning */ int nByte; memset(&e, 0, sizeof(e)); p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); if( p==0 ) return; /* Martial the arguments into stack variables */ if( nVal!=2 && nVal!=4 && nVal!=5 ){ zErr = sqlite3_mprintf("wrong number of arguments to function zipfile()"); rc = SQLITE_ERROR; goto zipfile_step_out; } pName = apVal[0]; if( nVal==2 ){ pData = apVal[1]; }else{ pMode = apVal[1]; pMtime = apVal[2]; pData = apVal[3]; if( nVal==5 ){ pMethod = apVal[4]; } } /* Check that the 'name' parameter looks ok. */ zName = (char*)sqlite3_value_text(pName); nName = sqlite3_value_bytes(pName); if( zName==0 ){ zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL"); rc = SQLITE_ERROR; goto zipfile_step_out; } /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use ** deflate compression) or NULL (choose automatically). */ if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){ iMethod = (int)sqlite3_value_int64(pMethod); if( iMethod!=0 && iMethod!=8 ){ zErr = sqlite3_mprintf("illegal method value: %d", iMethod); rc = SQLITE_ERROR; goto zipfile_step_out; } } /* Now inspect the data. If this is NULL, then the new entry must be a ** directory. Otherwise, figure out whether or not the data should ** be deflated or simply stored in the zip archive. */ if( sqlite3_value_type(pData)==SQLITE_NULL ){ bIsDir = 1; iMethod = 0; }else{ aData = sqlite3_value_blob(pData); szUncompressed = nData = sqlite3_value_bytes(pData); iCrc32 = crc32(0, aData, nData); if( iMethod<0 || iMethod==8 ){ int nOut = 0; rc = zipfileDeflate(aData, nData, &aFree, &nOut, &zErr); if( rc!=SQLITE_OK ){ goto zipfile_step_out; } if( iMethod==8 || nOut<nData ){ aData = aFree; nData = nOut; iMethod = 8; }else{ iMethod = 0; } } } /* Decode the "mode" argument. */ rc = zipfileGetMode(pMode, bIsDir, &mode, &zErr); if( rc ) goto zipfile_step_out; /* Decode the "mtime" argument. */ e.mUnixTime = zipfileGetTime(pMtime); /* If this is a directory entry, ensure that there is exactly one '/' ** at the end of the path. Or, if this is not a directory and the path ** ends in '/' it is an error. */ if( bIsDir==0 ){ if( zName[nName-1]=='/' ){ zErr = sqlite3_mprintf("non-directory name must not end with /"); rc = SQLITE_ERROR; goto zipfile_step_out; } }else{ if( zName[nName-1]!='/' ){ zName = zFree = sqlite3_mprintf("%s/", zName); nName++; if( zName==0 ){ rc = SQLITE_NOMEM; goto zipfile_step_out; } }else{ while( nName>1 && zName[nName-2]=='/' ) nName--; } } /* Assemble the ZipfileEntry object for the new zip archive entry */ e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; e.cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; e.cds.flags = ZIPFILE_NEWENTRY_FLAGS; e.cds.iCompression = (u16)iMethod; zipfileMtimeToDos(&e.cds, (u32)e.mUnixTime); e.cds.crc32 = iCrc32; e.cds.szCompressed = nData; e.cds.szUncompressed = szUncompressed; e.cds.iExternalAttr = (mode<<16); e.cds.iOffset = p->body.n; e.cds.nFile = (u16)nName; e.cds.zFile = zName; /* Append the LFH to the body of the new archive */ nByte = ZIPFILE_LFH_FIXED_SZ + e.cds.nFile + 9; if( (rc = zipfileBufferGrow(&p->body, nByte)) ) goto zipfile_step_out; p->body.n += zipfileSerializeLFH(&e, &p->body.a[p->body.n]); /* Append the data to the body of the new archive */ if( (rc = zipfileBufferGrow(&p->body, nData)) ) goto zipfile_step_out; memcpy(&p->body.a[p->body.n], aData, nData); p->body.n += nData; /* Append the CDS record to the directory of the new archive */ nByte = ZIPFILE_CDS_FIXED_SZ + e.cds.nFile + 9; if( (rc = zipfileBufferGrow(&p->cds, nByte)) ) goto zipfile_step_out; p->cds.n += zipfileSerializeCDS(&e, &p->cds.a[p->cds.n]); /* Increment the count of entries in the archive */ p->nEntry++; zipfile_step_out: sqlite3_free(aFree); sqlite3_free(zFree); if( rc ){ if( zErr ){ sqlite3_result_error(pCtx, zErr, -1); }else{ sqlite3_result_error_code(pCtx, rc); } } sqlite3_free(zErr); } /* ** xFinalize() callback for zipfile aggregate function. */ void zipfileFinal(sqlite3_context *pCtx){ ZipfileCtx *p; ZipfileEOCD eocd; int nZip; u8 *aZip; p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); if( p==0 ) return; if( p->nEntry>0 ){ memset(&eocd, 0, sizeof(eocd)); eocd.nEntry = (u16)p->nEntry; eocd.nEntryTotal = (u16)p->nEntry; eocd.nSize = p->cds.n; eocd.iOffset = p->body.n; nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; aZip = (u8*)sqlite3_malloc(nZip); if( aZip==0 ){ sqlite3_result_error_nomem(pCtx); }else{ memcpy(aZip, p->body.a, p->body.n); memcpy(&aZip[p->body.n], p->cds.a, p->cds.n); zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]); sqlite3_result_blob(pCtx, aZip, nZip, zipfileFree); } } sqlite3_free(p->body.a); sqlite3_free(p->cds.a); } /* ** Register the "zipfile" virtual table. */ static int zipfileRegister(sqlite3 *db){ static sqlite3_module zipfileModule = { 1, /* iVersion */ zipfileConnect, /* xCreate */ zipfileConnect, /* xConnect */ zipfileBestIndex, /* xBestIndex */ zipfileDisconnect, /* xDisconnect */ zipfileDisconnect, /* xDestroy */ zipfileOpen, /* xOpen - open a cursor */ zipfileClose, /* xClose - close a cursor */ zipfileFilter, /* xFilter - configure scan constraints */ zipfileNext, /* xNext - advance a cursor */ zipfileEof, /* xEof - check for end of scan */ zipfileColumn, /* xColumn - read data */ 0, /* xRowid - read data */ zipfileUpdate, /* xUpdate */ zipfileBegin, /* xBegin */ 0, /* xSync */ zipfileCommit, /* xCommit */ zipfileRollback, /* xRollback */ zipfileFindFunction, /* xFindMethod */ 0, /* xRename */ }; int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0, zipfileStep, zipfileFinal ); } return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ # define zipfileRegister(x) SQLITE_OK #endif |
︙ | ︙ |
Added ext/misc/zorder.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 | /* ** 2018-02-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. ** ****************************************************************************** ** ** SQL functions for z-order (Morton code) transformations. ** ** zorder(X0,X0,..,xN) Generate an N+1 dimension Morton code ** ** unzorder(Z,N,I) Extract the I-th dimension from N-dimensional ** Morton code Z. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* ** Functions: zorder(X0,X1,....) ** ** Convert integers X0, X1, ... into morton code. ** ** The output is a signed 64-bit integer. If any argument is too large, ** an error is thrown. */ static void zorderFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_int64 z, x[63]; int i, j; z = 0; for(i=0; i<argc; i++){ x[i] = sqlite3_value_int64(argv[i]); } if( argc>0 ){ for(i=0; i<63; i++){ j = i%argc; z |= (x[j]&1)<<i; x[j] >>= 1; } } sqlite3_result_int64(context, z); for(i=0; i<argc; i++){ if( x[i] ){ sqlite3_result_error(context, "parameter too large", -1); } } } /* ** Functions: unzorder(Z,N,I) ** ** Assuming that Z is an N-dimensional Morton code, extract the I-th ** dimension. */ static void unzorderFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3_int64 z, n, i, x; int j, k; z = sqlite3_value_int64(argv[0]); n = sqlite3_value_int64(argv[1]); i = sqlite3_value_int64(argv[2]); x = 0; for(k=0, j=i; j<63; j+=n, k++){ x |= ((z>>j)&1)<<k; } sqlite3_result_int64(context, x); } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_zorder_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "zorder", -1, SQLITE_UTF8, 0, zorderFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "unzorder", 3, SQLITE_UTF8, 0, unzorderFunc, 0, 0); } return rc; } |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
781 782 783 784 785 786 787 788 789 790 791 792 793 794 | }else{ sqlite3_bind_null(p, 1); } sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); sqlite3_step(p); pNode->isDirty = 0; rc = sqlite3_reset(p); if( pNode->iNode==0 && rc==SQLITE_OK ){ pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); nodeHashInsert(pRtree, pNode); } } return rc; } | > | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | }else{ sqlite3_bind_null(p, 1); } sqlite3_bind_blob(p, 2, pNode->zData, pRtree->iNodeSize, SQLITE_STATIC); sqlite3_step(p); pNode->isDirty = 0; rc = sqlite3_reset(p); sqlite3_bind_null(p, 2); if( pNode->iNode==0 && rc==SQLITE_OK ){ pNode->iNode = sqlite3_last_insert_rowid(pRtree->db); nodeHashInsert(pRtree, pNode); } } return rc; } |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
605 606 607 608 609 610 611 612 | INSERT INTO rt VALUES(1,2,3,4,5); } do_execsql_test 15.2 { DROP TABLE t13; COMMIT; } finish_test | > | 605 606 607 608 609 610 611 612 613 | INSERT INTO rt VALUES(1,2,3,4,5); } do_execsql_test 15.2 { DROP TABLE t13; COMMIT; } expand_all_sql db finish_test |
Changes to ext/rtree/rtree4.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 253 | list $where [db eval "SELECT id FROM rx $where ORDER BY id"] } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]] } do_rtree_integrity_test rtree4-$nDim.3 rx } finish_test | > | 246 247 248 249 250 251 252 253 254 | list $where [db eval "SELECT id FROM rx $where ORDER BY id"] } [list $where [db eval "SELECT id FROM bx $where ORDER BY id"]] } do_rtree_integrity_test rtree4-$nDim.3 rx } expand_all_sql db finish_test |
Changes to ext/rtree/rtree5.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 82 | SELECT * FROM t1 WHERE x1=2147483643 AND x2=2147483647 AND y1=-2147483648 AND y2=-2147483643 } } {2 2147483643 2147483647 -2147483648 -2147483643} do_rtree_integrity_test rtree5-1.14 t1 finish_test | > | 75 76 77 78 79 80 81 82 83 | SELECT * FROM t1 WHERE x1=2147483643 AND x2=2147483647 AND y1=-2147483648 AND y2=-2147483643 } } {2 2147483643 2147483647 -2147483648 -2147483643} do_rtree_integrity_test rtree5-1.14 t1 expand_all_sql db finish_test |
Changes to ext/rtree/rtree6.test.
︙ | ︙ | |||
154 155 156 157 158 159 160 | x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>1.1 } {} | | | 154 155 156 157 158 159 160 161 162 | x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>1.1 } {} expand_all_sql db finish_test |
Changes to ext/rtree/rtreeG.test.
︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 | do_execsql_test rtreeG-1.4 { DROP TABLE t1; } {} do_test rtreeG-1.4log { set ::log } {} db close sqlite3_shutdown test_sqlite3_log sqlite3_initialize sqlite3 db test.db finish_test | > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | do_execsql_test rtreeG-1.4 { DROP TABLE t1; } {} do_test rtreeG-1.4log { set ::log } {} expand_all_sql db db close sqlite3_shutdown test_sqlite3_log sqlite3_initialize sqlite3 db test.db finish_test |
Changes to ext/session/session4.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 | list [catch { sqlite3changeset_invert $x } msg] $msg } {1 SQLITE_CORRUPT} do_test 1.3 { set x [binary format "ca*" 0 [string range $changeset 1 end]] list [catch { sqlite3changeset_apply db $x xConflict } msg] $msg } {1 SQLITE_CORRUPT} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | list [catch { sqlite3changeset_invert $x } msg] $msg } {1 SQLITE_CORRUPT} do_test 1.3 { set x [binary format "ca*" 0 [string range $changeset 1 end]] list [catch { sqlite3changeset_apply db $x xConflict } msg] $msg } {1 SQLITE_CORRUPT} #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d); CREATE TABLE t2(e TEXT PRIMARY KEY NOT NULL,f,g); CREATE TABLE t3(w REAL PRIMARY KEY NOT NULL,x,y); CREATE TABLE t4(z PRIMARY KEY) WITHOUT ROWID; } foreach {tn blob} { 1 {54010174340012000000} 2 {54fefe8bcb0012000300} 3 {5480809280808001017434001200fb} 4 {50af9c939c9c9cb09c9c6400b09c9c6400} 5 {12000300} 6 {09847304} 7 {5401017434001208} } { if {$tn==7} breakpoint do_test 2.$tn { set changeset [binary decode hex $blob] list [catch { sqlite3changeset_apply db $changeset xConflict } msg] $msg } {1 SQLITE_CORRUPT} } finish_test |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
2714 2715 2716 2717 2718 2719 2720 | ){ int i; /* Used to iterate through columns */ int rc = SQLITE_OK; for(i=0; i<nCol && rc==SQLITE_OK; i++){ int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */ if( abPK && abPK[i]==0 ) continue; | > > > | > < < | | | | > | 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 | ){ int i; /* Used to iterate through columns */ int rc = SQLITE_OK; for(i=0; i<nCol && rc==SQLITE_OK; i++){ int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */ if( abPK && abPK[i]==0 ) continue; if( pIn->iNext>=pIn->nData ){ rc = SQLITE_CORRUPT; }else{ rc = sessionInputBuffer(pIn, 9); } if( rc==SQLITE_OK ){ eType = pIn->aData[pIn->iNext++]; assert( apOut[i]==0 ); if( eType ){ apOut[i] = sqlite3ValueNew(0); if( !apOut[i] ) rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ u8 *aVal = &pIn->aData[pIn->iNext]; if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int nByte; pIn->iNext += sessionVarintGet(aVal, &nByte); |
︙ | ︙ | |||
2853 2854 2855 2856 2857 2858 2859 | assert( p->rc==SQLITE_OK ); rc = sessionChangesetBufferTblhdr(&p->in, &nCopy); if( rc==SQLITE_OK ){ int nByte; int nVarint; nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol); | > | | | | | > > > | 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 | assert( p->rc==SQLITE_OK ); rc = sessionChangesetBufferTblhdr(&p->in, &nCopy); if( rc==SQLITE_OK ){ int nByte; int nVarint; nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol); if( p->nCol>0 ){ nCopy -= nVarint; p->in.iNext += nVarint; nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy; p->tblhdr.nBuf = 0; sessionBufferGrow(&p->tblhdr, nByte, &rc); }else{ rc = SQLITE_CORRUPT; } } if( rc==SQLITE_OK ){ int iPK = sizeof(sqlite3_value*)*p->nCol*2; memset(p->tblhdr.aBuf, 0, iPK); memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy); p->in.iNext += nCopy; |
︙ | ︙ | |||
2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 | p->bPatchset = (op=='P'); if( sessionChangesetReadTblhdr(p) ) return p->rc; if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc; p->in.iCurrent = p->in.iNext; if( p->in.iNext>=p->in.nData ) return SQLITE_DONE; op = p->in.aData[p->in.iNext++]; } p->op = op; p->bIndirect = p->in.aData[p->in.iNext++]; if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ return (p->rc = SQLITE_CORRUPT_BKPT); } | > > > > > > > | 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 | p->bPatchset = (op=='P'); if( sessionChangesetReadTblhdr(p) ) return p->rc; if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc; p->in.iCurrent = p->in.iNext; if( p->in.iNext>=p->in.nData ) return SQLITE_DONE; op = p->in.aData[p->in.iNext++]; } if( p->zTab==0 ){ /* The first record in the changeset is not a table header. Must be a ** corrupt changeset. */ assert( p->in.iNext==1 ); return (p->rc = SQLITE_CORRUPT_BKPT); } p->op = op; p->bIndirect = p->in.aData[p->in.iNext++]; if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ return (p->rc = SQLITE_CORRUPT_BKPT); } |
︙ | ︙ | |||
3704 3705 3706 3707 3708 3709 3710 | ** in the code below. */ assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); for(i=0; rc==SQLITE_OK && i<nCol; i++){ if( !abPK || abPK[i] ){ sqlite3_value *pVal; (void)xValue(pIter, i, &pVal); | > > > > > | > | 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 | ** in the code below. */ assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new ); for(i=0; rc==SQLITE_OK && i<nCol; i++){ if( !abPK || abPK[i] ){ sqlite3_value *pVal; (void)xValue(pIter, i, &pVal); if( pVal==0 ){ /* The value in the changeset was "undefined". This indicates a ** corrupt changeset blob. */ rc = SQLITE_CORRUPT; }else{ rc = sessionBindValue(pStmt, i+1, pVal); } } } return rc; } /* ** SQL statement pSelect is as generated by the sessionSelectRow() function. |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | extern "C" { #endif #include "sqlite3.h" /* ** CAPI3REF: Session Object Handle */ typedef struct sqlite3_session sqlite3_session; /* ** CAPI3REF: Changeset Iterator Handle */ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; /* ** CAPI3REF: Create A New Session Object ** ** Create a new session object attached to database handle db. If successful, ** a pointer to the new object is written to *ppSession and SQLITE_OK is ** returned. If an error occurs, *ppSession is set to NULL and an SQLite ** error code (e.g. SQLITE_NOMEM) is returned. ** ** It is possible to create multiple session objects attached to a single | > > > > > > > | 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 | extern "C" { #endif #include "sqlite3.h" /* ** CAPI3REF: Session Object Handle ** ** An instance of this object is a [session] that can be used to ** record changes to a database. */ typedef struct sqlite3_session sqlite3_session; /* ** CAPI3REF: Changeset Iterator Handle ** ** An instance of this object is as as a cursor for iterating ** over the elements of a [changeset] or [patchset]. */ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; /* ** CAPI3REF: Create A New Session Object ** CONSTRUCTOR: sqlite3_session ** ** Create a new session object attached to database handle db. If successful, ** a pointer to the new object is written to *ppSession and SQLITE_OK is ** returned. If an error occurs, *ppSession is set to NULL and an SQLite ** error code (e.g. SQLITE_NOMEM) is returned. ** ** It is possible to create multiple session objects attached to a single |
︙ | ︙ | |||
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 | sqlite3 *db, /* Database handle */ const char *zDb, /* Name of db (e.g. "main") */ sqlite3_session **ppSession /* OUT: New session object */ ); /* ** CAPI3REF: Delete A Session Object ** ** Delete a session object previously allocated using ** [sqlite3session_create()]. Once a session object has been deleted, the ** results of attempting to use pSession with any other session module ** function are undefined. ** ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPI3REF: Enable Or Disable A Session Object ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When ** disabled - it does not. A newly created session object is enabled. ** Refer to the documentation for [sqlite3session_changeset()] for further ** details regarding how enabling and disabling a session object affects ** the eventual changesets. ** ** Passing zero to this function disables the session. Passing a value ** greater than zero enables it. Passing a value less than zero is a ** no-op, and may be used to query the current state of the session. ** ** The return value indicates the final state of the session object: 0 if ** the session is disabled, or 1 if it is enabled. */ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Set Or Clear the Indirect Change Flag ** ** Each change recorded by a session object is marked as either direct or ** indirect. A change is marked as indirect if either: ** ** <ul> ** <li> The session object "indirect" flag is set when the change is ** made, or | > > > | 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 | sqlite3 *db, /* Database handle */ const char *zDb, /* Name of db (e.g. "main") */ sqlite3_session **ppSession /* OUT: New session object */ ); /* ** CAPI3REF: Delete A Session Object ** DESTRUCTOR: sqlite3_session ** ** Delete a session object previously allocated using ** [sqlite3session_create()]. Once a session object has been deleted, the ** results of attempting to use pSession with any other session module ** function are undefined. ** ** Session objects must be deleted before the database handle to which they ** are attached is closed. Refer to the documentation for ** [sqlite3session_create()] for details. */ void sqlite3session_delete(sqlite3_session *pSession); /* ** CAPI3REF: Enable Or Disable A Session Object ** METHOD: sqlite3_session ** ** Enable or disable the recording of changes by a session object. When ** enabled, a session object records changes made to the database. When ** disabled - it does not. A newly created session object is enabled. ** Refer to the documentation for [sqlite3session_changeset()] for further ** details regarding how enabling and disabling a session object affects ** the eventual changesets. ** ** Passing zero to this function disables the session. Passing a value ** greater than zero enables it. Passing a value less than zero is a ** no-op, and may be used to query the current state of the session. ** ** The return value indicates the final state of the session object: 0 if ** the session is disabled, or 1 if it is enabled. */ int sqlite3session_enable(sqlite3_session *pSession, int bEnable); /* ** CAPI3REF: Set Or Clear the Indirect Change Flag ** METHOD: sqlite3_session ** ** Each change recorded by a session object is marked as either direct or ** indirect. A change is marked as indirect if either: ** ** <ul> ** <li> The session object "indirect" flag is set when the change is ** made, or |
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 | ** The return value indicates the final state of the indirect flag: 0 if ** it is clear, or 1 if it is set. */ int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); /* ** CAPI3REF: Attach A Table To A Session Object ** ** If argument zTab is not NULL, then it is the name of a table to attach ** to the session object passed as the first argument. All subsequent changes ** made to the table while the session object is enabled will be recorded. See ** documentation for [sqlite3session_changeset()] for further details. ** ** Or, if argument zTab is NULL, then changes are recorded for all tables | > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ** The return value indicates the final state of the indirect flag: 0 if ** it is clear, or 1 if it is set. */ int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect); /* ** CAPI3REF: Attach A Table To A Session Object ** METHOD: sqlite3_session ** ** If argument zTab is not NULL, then it is the name of a table to attach ** to the session object passed as the first argument. All subsequent changes ** made to the table while the session object is enabled will be recorded. See ** documentation for [sqlite3session_changeset()] for further details. ** ** Or, if argument zTab is NULL, then changes are recorded for all tables |
︙ | ︙ | |||
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 | int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zTab /* Table name */ ); /* ** CAPI3REF: Set a table filter on a Session Object. ** ** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called ** to determine whether changes to the table's rows should be tracked or not. ** If xFilter returns 0, changes is not tracked. Note that once a table is ** attached, xFilter will not be called again. */ void sqlite3session_table_filter( sqlite3_session *pSession, /* Session object */ int(*xFilter)( void *pCtx, /* Copy of third arg to _filter_table() */ const char *zTab /* Table name */ ), void *pCtx /* First argument passed to xFilter */ ); /* ** CAPI3REF: Generate A Changeset From A Session Object ** ** Obtain a changeset containing changes to the tables attached to the ** session object passed as the first argument. If successful, ** set *ppChangeset to point to a buffer containing the changeset ** and *pnChangeset to the size of the changeset in bytes before returning ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to ** zero and return an SQLite error code. | > > | 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 | int sqlite3session_attach( sqlite3_session *pSession, /* Session object */ const char *zTab /* Table name */ ); /* ** CAPI3REF: Set a table filter on a Session Object. ** METHOD: sqlite3_session ** ** The second argument (xFilter) is the "filter callback". For changes to rows ** in tables that are not attached to the Session object, the filter is called ** to determine whether changes to the table's rows should be tracked or not. ** If xFilter returns 0, changes is not tracked. Note that once a table is ** attached, xFilter will not be called again. */ void sqlite3session_table_filter( sqlite3_session *pSession, /* Session object */ int(*xFilter)( void *pCtx, /* Copy of third arg to _filter_table() */ const char *zTab /* Table name */ ), void *pCtx /* First argument passed to xFilter */ ); /* ** CAPI3REF: Generate A Changeset From A Session Object ** METHOD: sqlite3_session ** ** Obtain a changeset containing changes to the tables attached to the ** session object passed as the first argument. If successful, ** set *ppChangeset to point to a buffer containing the changeset ** and *pnChangeset to the size of the changeset in bytes before returning ** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to ** zero and return an SQLite error code. |
︙ | ︙ | |||
307 308 309 310 311 312 313 | int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); /* | | > | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); /* ** CAPI3REF: Load The Difference Between Tables Into A Session ** METHOD: sqlite3_session ** ** If it is not already attached to the session object passed as the first ** argument, this function attaches table zTbl in the same manner as the ** [sqlite3session_attach()] function. If zTbl does not exist, or if it ** does not have a primary key, this function is a no-op (but does not return ** an error). ** |
︙ | ︙ | |||
372 373 374 375 376 377 378 379 380 381 382 383 384 385 | const char *zTbl, char **pzErrMsg ); /* ** CAPI3REF: Generate A Patchset From A Session Object ** ** The differences between a patchset and a changeset are that: ** ** <ul> ** <li> DELETE records consist of the primary key fields only. The ** original values of other fields are omitted. ** <li> The original values of any modified fields are omitted from | > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | const char *zTbl, char **pzErrMsg ); /* ** CAPI3REF: Generate A Patchset From A Session Object ** METHOD: sqlite3_session ** ** The differences between a patchset and a changeset are that: ** ** <ul> ** <li> DELETE records consist of the primary key fields only. The ** original values of other fields are omitted. ** <li> The original values of any modified fields are omitted from |
︙ | ︙ | |||
423 424 425 426 427 428 429 430 431 432 433 434 435 436 | ** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ int sqlite3session_isempty(sqlite3_session *pSession); /* ** CAPI3REF: Create An Iterator To Traverse A Changeset ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an ** SQLite error code is returned. ** ** The following functions can be used to advance and query a changeset | > | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | ** guaranteed that a call to sqlite3session_changeset() will return a ** changeset containing zero changes. */ int sqlite3session_isempty(sqlite3_session *pSession); /* ** CAPI3REF: Create An Iterator To Traverse A Changeset ** CONSTRUCTOR: sqlite3_changeset_iter ** ** Create an iterator used to iterate through the contents of a changeset. ** If successful, *pp is set to point to the iterator handle and SQLITE_OK ** is returned. Otherwise, if an error occurs, *pp is set to zero and an ** SQLite error code is returned. ** ** The following functions can be used to advance and query a changeset |
︙ | ︙ | |||
463 464 465 466 467 468 469 470 471 472 473 474 475 476 | int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); /* ** CAPI3REF: Advance A Changeset Iterator ** ** This function may only be used with iterators created by function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. ** ** Immediately after an iterator is created by sqlite3changeset_start(), it | > | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function may only be used with iterators created by function ** [sqlite3changeset_start()]. If it is called on an iterator passed to ** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE ** is returned and the call has no effect. ** ** Immediately after an iterator is created by sqlite3changeset_start(), it |
︙ | ︙ | |||
487 488 489 490 491 492 493 494 495 496 497 498 499 500 | ** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or ** SQLITE_NOMEM. */ int sqlite3changeset_next(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** | > | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | ** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or ** SQLITE_NOMEM. */ int sqlite3changeset_next(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Obtain The Current Operation From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this ** is not the case, this function returns [SQLITE_MISUSE]. ** |
︙ | ︙ | |||
521 522 523 524 525 526 527 528 529 530 531 532 533 534 | int *pnCol, /* OUT: Number of columns in table */ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ int *pbIndirect /* OUT: True for an 'indirect' change */ ); /* ** CAPI3REF: Obtain The Primary Key Definition Of A Table ** ** For each modified table, a changeset includes the following: ** ** <ul> ** <li> The number of columns in the table, and ** <li> Which of those columns make up the tables PRIMARY KEY. ** </ul> | > | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | int *pnCol, /* OUT: Number of columns in table */ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ int *pbIndirect /* OUT: True for an 'indirect' change */ ); /* ** CAPI3REF: Obtain The Primary Key Definition Of A Table ** METHOD: sqlite3_changeset_iter ** ** For each modified table, a changeset includes the following: ** ** <ul> ** <li> The number of columns in the table, and ** <li> Which of those columns make up the tables PRIMARY KEY. ** </ul> |
︙ | ︙ | |||
552 553 554 555 556 557 558 559 560 561 562 563 564 565 | sqlite3_changeset_iter *pIter, /* Iterator object */ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ int *pnCol /* OUT: Number of entries in output array */ ); /* ** CAPI3REF: Obtain old.* Values From A Changeset Iterator ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, | > | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 | sqlite3_changeset_iter *pIter, /* Iterator object */ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ int *pnCol /* OUT: Number of entries in output array */ ); /* ** CAPI3REF: Obtain old.* Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise, |
︙ | ︙ | |||
582 583 584 585 586 587 588 589 590 591 592 593 594 595 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain new.* Values From A Changeset Iterator ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, | > | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain new.* Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** The pIter argument passed to this function may either be an iterator ** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator ** created by [sqlite3changeset_start()]. In the latter case, the most recent ** call to [sqlite3changeset_next()] must have returned SQLITE_ROW. ** Furthermore, it may only be called if the type of change that the iterator ** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise, |
︙ | ︙ | |||
615 616 617 618 619 620 621 622 623 624 625 626 627 628 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator ** ** This function should only be used with iterator objects passed to a ** conflict-handler callback by [sqlite3changeset_apply()] with either ** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function ** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue ** is set to NULL. ** | > | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ ); /* ** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function should only be used with iterator objects passed to a ** conflict-handler callback by [sqlite3changeset_apply()] with either ** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function ** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue ** is set to NULL. ** |
︙ | ︙ | |||
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 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Value from conflicting row */ ); /* ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations ** ** This function may only be called with an iterator passed to an ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case ** it sets the output variable to the total number of known foreign key ** violations in the destination database and returns SQLITE_OK. ** ** In all other cases this function returns SQLITE_MISUSE. */ int sqlite3changeset_fk_conflicts( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int *pnOut /* OUT: Number of FK violations */ ); /* ** CAPI3REF: Finalize A Changeset Iterator ** ** This function is used to finalize an iterator allocated with ** [sqlite3changeset_start()]. ** ** This function should only be called on iterators created using the ** [sqlite3changeset_start()] function. If an application calls this ** function with an iterator passed to a conflict-handler by ** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the ** call has no effect. ** ** If an error was encountered within a call to an sqlite3changeset_xxx() ** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding ** to that error is returned by this function. Otherwise, SQLITE_OK is ** returned. This is to allow the following pattern (pseudo-code): ** ** sqlite3changeset_start(); ** while( SQLITE_ROW==sqlite3changeset_next() ){ ** // Do something with change. ** } ** rc = sqlite3changeset_finalize(); ** if( rc!=SQLITE_OK ){ ** // An error has occurred ** } */ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Invert A Changeset ** ** This function is used to "invert" a changeset object. Applying an inverted | > > > > | 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 | sqlite3_changeset_iter *pIter, /* Changeset iterator */ int iVal, /* Column number */ sqlite3_value **ppValue /* OUT: Value from conflicting row */ ); /* ** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations ** METHOD: sqlite3_changeset_iter ** ** This function may only be called with an iterator passed to an ** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case ** it sets the output variable to the total number of known foreign key ** violations in the destination database and returns SQLITE_OK. ** ** In all other cases this function returns SQLITE_MISUSE. */ int sqlite3changeset_fk_conflicts( sqlite3_changeset_iter *pIter, /* Changeset iterator */ int *pnOut /* OUT: Number of FK violations */ ); /* ** CAPI3REF: Finalize A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function is used to finalize an iterator allocated with ** [sqlite3changeset_start()]. ** ** This function should only be called on iterators created using the ** [sqlite3changeset_start()] function. If an application calls this ** function with an iterator passed to a conflict-handler by ** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the ** call has no effect. ** ** If an error was encountered within a call to an sqlite3changeset_xxx() ** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an ** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding ** to that error is returned by this function. Otherwise, SQLITE_OK is ** returned. This is to allow the following pattern (pseudo-code): ** ** <pre> ** sqlite3changeset_start(); ** while( SQLITE_ROW==sqlite3changeset_next() ){ ** // Do something with change. ** } ** rc = sqlite3changeset_finalize(); ** if( rc!=SQLITE_OK ){ ** // An error has occurred ** } ** </pre> */ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); /* ** CAPI3REF: Invert A Changeset ** ** This function is used to "invert" a changeset object. Applying an inverted |
︙ | ︙ | |||
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 | ** single changeset. The result is a changeset equivalent to applying ** changeset A followed by changeset B. ** ** This function combines the two input changesets using an ** sqlite3_changegroup object. Calling it produces similar results as the ** following code fragment: ** ** sqlite3_changegroup *pGrp; ** rc = sqlite3_changegroup_new(&pGrp); ** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); ** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); ** if( rc==SQLITE_OK ){ ** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); ** }else{ ** *ppOut = 0; ** *pnOut = 0; ** } ** ** Refer to the sqlite3_changegroup documentation below for details. */ int sqlite3changeset_concat( int nA, /* Number of bytes in buffer pA */ void *pA, /* Pointer to buffer containing changeset A */ int nB, /* Number of bytes in buffer pB */ void *pB, /* Pointer to buffer containing changeset B */ int *pnOut, /* OUT: Number of bytes in output changeset */ void **ppOut /* OUT: Buffer containing output changeset */ ); /* ** CAPI3REF: Changegroup Handle */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* ** CAPI3REF: Create A New Changegroup Object ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup ** object may combine changesets or patchsets, but not both. The output is ** always in the same format as the input. ** ** If successful, this function returns SQLITE_OK and populates (*pp) with | > > > > > > | 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 | ** single changeset. The result is a changeset equivalent to applying ** changeset A followed by changeset B. ** ** This function combines the two input changesets using an ** sqlite3_changegroup object. Calling it produces similar results as the ** following code fragment: ** ** <pre> ** sqlite3_changegroup *pGrp; ** rc = sqlite3_changegroup_new(&pGrp); ** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA); ** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB); ** if( rc==SQLITE_OK ){ ** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut); ** }else{ ** *ppOut = 0; ** *pnOut = 0; ** } ** </pre> ** ** Refer to the sqlite3_changegroup documentation below for details. */ int sqlite3changeset_concat( int nA, /* Number of bytes in buffer pA */ void *pA, /* Pointer to buffer containing changeset A */ int nB, /* Number of bytes in buffer pB */ void *pB, /* Pointer to buffer containing changeset B */ int *pnOut, /* OUT: Number of bytes in output changeset */ void **ppOut /* OUT: Buffer containing output changeset */ ); /* ** CAPI3REF: Changegroup Handle ** ** A changegroup is an object used to combine two or more ** [changesets] or [patchsets] */ typedef struct sqlite3_changegroup sqlite3_changegroup; /* ** CAPI3REF: Create A New Changegroup Object ** CONSTRUCTOR: sqlite3_changegroup ** ** An sqlite3_changegroup object is used to combine two or more changesets ** (or patchsets) into a single changeset (or patchset). A single changegroup ** object may combine changesets or patchsets, but not both. The output is ** always in the same format as the input. ** ** If successful, this function returns SQLITE_OK and populates (*pp) with |
︙ | ︙ | |||
796 797 798 799 800 801 802 803 804 805 806 807 808 809 | ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add A Changeset To A Changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size ** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if ** the buffer contains a changeset, so must have the earlier calls to this | > | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | ** sqlite3changegroup_output() functions, also available are the streaming ** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm(). */ int sqlite3changegroup_new(sqlite3_changegroup **pp); /* ** CAPI3REF: Add A Changeset To A Changegroup ** METHOD: sqlite3_changegroup ** ** Add all changes within the changeset (or patchset) in buffer pData (size ** nData bytes) to the changegroup. ** ** If the buffer contains a patchset, then all prior calls to this function ** on the same changegroup object must also have specified patchsets. Or, if ** the buffer contains a changeset, so must have the earlier calls to this |
︙ | ︙ | |||
873 874 875 876 877 878 879 880 881 882 883 884 885 886 | ** ** If no error occurs, SQLITE_OK is returned. */ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup ** were themselves changesets, the output is a changeset. Or, if the ** inputs were patchsets, the output is also a patchset. ** ** As with the output of the sqlite3session_changeset() and | > | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | ** ** If no error occurs, SQLITE_OK is returned. */ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData); /* ** CAPI3REF: Obtain A Composite Changeset From A Changegroup ** METHOD: sqlite3_changegroup ** ** Obtain a buffer containing a changeset (or patchset) representing the ** current contents of the changegroup. If the inputs to the changegroup ** were themselves changesets, the output is a changeset. Or, if the ** inputs were patchsets, the output is also a patchset. ** ** As with the output of the sqlite3session_changeset() and |
︙ | ︙ | |||
903 904 905 906 907 908 909 910 911 912 913 914 915 916 | sqlite3_changegroup*, int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ ); /* ** CAPI3REF: Delete A Changegroup Object */ void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database ** ** Apply a changeset to a database. This function attempts to update the | > | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 | sqlite3_changegroup*, int *pnData, /* OUT: Size of output buffer in bytes */ void **ppData /* OUT: Pointer to output buffer */ ); /* ** CAPI3REF: Delete A Changegroup Object ** DESTRUCTOR: sqlite3_changegroup */ void sqlite3changegroup_delete(sqlite3_changegroup*); /* ** CAPI3REF: Apply A Changeset To A Database ** ** Apply a changeset to a database. This function attempts to update the |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
358 359 360 361 362 363 364 365 366 367 368 369 370 371 | $(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/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ | > | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | $(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 \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/unionvtab.c \ |
︙ | ︙ | |||
515 516 517 518 519 520 521 522 523 524 525 526 527 528 | SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 DBFUZZ_OPT = KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ ST_OPT = -DSQLITE_THREADSAFE=0 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # | > | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 DBFUZZ_OPT = KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ ST_OPT = -DSQLITE_THREADSAFE=0 # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # |
︙ | ︙ |
Changes to src/attach.c.
︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 535 536 537 | return 1; } if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pLimit) ){ return 1; } pSelect = pSelect->pPrior; } return 0; } int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ | > > > > > > > > | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | return 1; } if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pLimit) ){ return 1; } if( pSelect->pWith ){ int i; for(i=0; i<pSelect->pWith->nCte; i++){ if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){ return 1; } } } pSelect = pSelect->pPrior; } return 0; } int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
4341 4342 4343 4344 4345 4346 4347 | ** ** The simple approach here would be to memset() the entire object ** to zero. But it turns out that the apPage[] and aiIdx[] arrays ** do not need to be zeroed and they are large, so we can save a lot ** of run-time by skipping the initialization of those elements. */ void sqlite3BtreeCursorZero(BtCursor *p){ | | | 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 | ** ** The simple approach here would be to memset() the entire object ** to zero. But it turns out that the apPage[] and aiIdx[] arrays ** do not need to be zeroed and they are large, so we can save a lot ** of run-time by skipping the initialization of those elements. */ void sqlite3BtreeCursorZero(BtCursor *p){ memset(p, 0, offsetof(BtCursor, BTCURSOR_FIRST_UNINIT)); } /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ |
︙ | ︙ | |||
4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 | ** BtCursor.info structure. If it is not already valid, call ** btreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to btreeParseCell(). */ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; memset(&info, 0, sizeof(info)); btreeParseCell(pCur->pPage, pCur->ix, &info); | > > > > > > > > | | 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 | ** BtCursor.info structure. If it is not already valid, call ** btreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to btreeParseCell(). */ #ifndef NDEBUG static int cellInfoEqual(CellInfo *a, CellInfo *b){ if( a->nKey!=b->nKey ) return 0; if( a->pPayload!=b->pPayload ) return 0; if( a->nPayload!=b->nPayload ) return 0; if( a->nLocal!=b->nLocal ) return 0; if( a->nSize!=b->nSize ) return 0; return 1; } static void assertCellInfo(BtCursor *pCur){ CellInfo info; memset(&info, 0, sizeof(info)); btreeParseCell(pCur->pPage, pCur->ix, &info); assert( CORRUPT_DB || cellInfoEqual(&info, &pCur->info) ); } #else #define assertCellInfo(x) #endif static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ pCur->curFlags |= BTCF_ValidNKey; |
︙ | ︙ | |||
4664 4665 4666 4667 4668 4669 4670 | ** The aOverflow[] array is sized at one entry for each overflow page ** in the overflow chain. The page number of the first overflow page is ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array ** means "not yet known" (the cache is lazily populated). */ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; | | > > < | 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 | ** The aOverflow[] array is sized at one entry for each overflow page ** in the overflow chain. The page number of the first overflow page is ** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array ** means "not yet known" (the cache is lazily populated). */ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; if( pCur->aOverflow==0 || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow) ){ Pgno *aNew = (Pgno*)sqlite3Realloc( pCur->aOverflow, nOvfl*2*sizeof(Pgno) ); if( aNew==0 ){ return SQLITE_NOMEM_BKPT; }else{ pCur->aOverflow = aNew; } } memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno)); pCur->curFlags |= BTCF_ValidOvfl; }else{ /* If the overflow page-list cache has been allocated and the |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
499 500 501 502 503 504 505 | ** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ u8 hints; /* As configured by CursorSetHints() */ | | > < < < < < < < > > > > > > | 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 | ** eState==FAULT: Cursor fault with skipNext as error code. */ struct BtCursor { u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */ u8 hints; /* As configured by CursorSetHints() */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive. ** Error code if eState==CURSOR_FAULT */ Btree *pBtree; /* The Btree to which this cursor belongs */ Pgno *aOverflow; /* Cache of overflow page locations */ void *pKey; /* Saved key that was cursor last known position */ /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ #define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext; /* Forms a linked list of all cursors */ CellInfo info; /* A parse of the cell we are pointing at */ i64 nKey; /* Size of pKey, or last integer key */ Pgno pgnoRoot; /* The root page of this tree */ i8 iPage; /* Index of current page in apPage */ u8 curIntKey; /* Value of apPage[0]->intKey */ u16 ix; /* Current index for apPage[iPage] */ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */ struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */ MemPage *pPage; /* Current page */ MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */ |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 1121 1122 | ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has ** been seen on a column. This routine sets the notNull flag on ** the column currently under construction. */ void sqlite3AddNotNull(Parse *pParse, int onError){ Table *p; p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; | > > | > > > > > > > > > > > > | 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 | ** This routine is called by the parser while in the middle of ** parsing a CREATE TABLE statement. A "NOT NULL" constraint has ** been seen on a column. This routine sets the notNull flag on ** the column currently under construction. */ void sqlite3AddNotNull(Parse *pParse, int onError){ Table *p; Column *pCol; p = pParse->pNewTable; if( p==0 || NEVER(p->nCol<1) ) return; pCol = &p->aCol[p->nCol-1]; pCol->notNull = (u8)onError; p->tabFlags |= TF_HasNotNull; /* Set the uniqNotNull flag on any UNIQUE or PK indexes already created ** on this column. */ if( pCol->colFlags & COLFLAG_UNIQUE ){ Index *pIdx; for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pIdx->nKeyCol==1 && pIdx->onError!=OE_None ); if( pIdx->aiColumn[0]==p->nCol-1 ){ pIdx->uniqNotNull = 1; } } } } /* ** Scan the column type name zType (length nType) and return the ** associated affinity type. ** ** This routine does a case-independent search of zType for the |
︙ | ︙ | |||
3081 3082 3083 3084 3085 3086 3087 | /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; | > > | | 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 | /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; Column *pCol = &pTab->aCol[pTab->nCol-1]; pCol->colFlags |= COLFLAG_UNIQUE; sqlite3TokenInit(&prevCol, pCol->zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); sqlite3ExprListSetSortOrder(pList, sortOrder); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 | ** This callback is used by multiple expression walkers. */ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking ** for. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 | ** This callback is used by multiple expression walkers. */ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } /* ** If the input expression is an ID with the name "true" or "false" ** then convert it into an TK_TRUEFALSE term. Return non-zero if ** the conversion happened, and zero if the expression is unaltered. */ int sqlite3ExprIdToTrueFalse(Expr *pExpr){ assert( pExpr->op==TK_ID || pExpr->op==TK_STRING ); if( sqlite3StrICmp(pExpr->u.zToken, "true")==0 || sqlite3StrICmp(pExpr->u.zToken, "false")==0 ){ pExpr->op = TK_TRUEFALSE; return 1; } return 0; } /* ** The argument must be a TK_TRUEFALSE Expr node. Return 1 if it is TRUE ** and 0 if it is FALSE. */ int sqlite3ExprTruthValue(const Expr *pExpr){ assert( pExpr->op==TK_TRUEFALSE ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } /* ** These routines are Walker callbacks used to check expressions to ** see if they are "constant" for some definition of constant. The ** Walker.eCode value determines the type of "constant" we are looking ** for. ** |
︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 | if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){ return WRC_Continue; }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: 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 ); | > > > > > > | 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 | if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){ return WRC_Continue; }else{ pWalker->eCode = 0; return WRC_Abort; } case TK_ID: /* Convert "true" or "false" in a DEFAULT clause into the ** appropriate TK_TRUEFALSE operator */ if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } /* Fall thru */ 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 ); |
︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 | return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, iTab, target, pExpr->op2); } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pExpr->u.zToken, 0, target); return target; } | > > > > | 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 | return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, pExpr->iColumn, iTab, target, pExpr->op2); } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } case TK_TRUEFALSE: { sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target); return target; } #ifndef SQLITE_OMIT_FLOATING_POINT case TK_FLOAT: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); codeReal(v, pExpr->u.zToken, 0, target); return target; } |
︙ | ︙ | |||
3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 | case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT ); assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); sqlite3VdbeAddOp2(v, op, r1, inReg); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); | > > > > > > > > > > > > | 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 3756 | case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); testcase( op==TK_BITNOT ); assert( TK_NOT==OP_Not ); testcase( op==TK_NOT ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); sqlite3VdbeAddOp2(v, op, r1, inReg); break; } case TK_TRUTH: { int isTrue; /* IS TRUE or IS NOT TRUE */ int bNormal; /* IS TRUE or IS FALSE */ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); testcase( regFree1==0 ); isTrue = sqlite3ExprTruthValue(pExpr->pRight); bNormal = pExpr->op2==TK_IS; testcase( isTrue && bNormal); testcase( !isTrue && bNormal); sqlite3VdbeAddOp4Int(v, OP_IsTrue, r1, inReg, !isTrue, isTrue ^ bNormal); break; } case TK_ISNULL: case TK_NOTNULL: { int addr; assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); sqlite3VdbeAddOp2(v, OP_Integer, 1, target); |
︙ | ︙ | |||
4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 | sqlite3ExprCachePop(pParse); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; | > > > > > > > > > > > > > > > > > | 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 | sqlite3ExprCachePop(pParse); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_TRUTH: { int isNot; /* IS NOT TRUE or IS NOT FALSE */ int isTrue; /* IS TRUE or IS NOT TRUE */ testcase( jumpIfNull==0 ); isNot = pExpr->op2==TK_ISNOT; isTrue = sqlite3ExprTruthValue(pExpr->pRight); testcase( isTrue && isNot ); testcase( !isTrue && isNot ); if( isTrue ^ isNot ){ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, isNot ? SQLITE_JUMPIFNULL : 0); }else{ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, isNot ? SQLITE_JUMPIFNULL : 0); } break; } case TK_IS: case TK_ISNOT: testcase( op==TK_IS ); testcase( op==TK_ISNOT ); op = (op==TK_IS) ? TK_EQ : TK_NE; jumpIfNull = SQLITE_NULLEQ; |
︙ | ︙ | |||
4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 | sqlite3ExprCachePop(pParse); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; | > > > > > > > > > > > > > > > > > > > > | 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 | sqlite3ExprCachePop(pParse); break; } case TK_NOT: { testcase( jumpIfNull==0 ); sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); break; } case TK_TRUTH: { int isNot; /* IS NOT TRUE or IS NOT FALSE */ int isTrue; /* IS TRUE or IS NOT TRUE */ testcase( jumpIfNull==0 ); isNot = pExpr->op2==TK_ISNOT; isTrue = sqlite3ExprTruthValue(pExpr->pRight); testcase( isTrue && isNot ); testcase( !isTrue && isNot ); if( isTrue ^ isNot ){ /* IS TRUE and IS NOT FALSE */ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, isNot ? 0 : SQLITE_JUMPIFNULL); }else{ /* IS FALSE and IS NOT TRUE */ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, isNot ? 0 : SQLITE_JUMPIFNULL); } break; } case TK_IS: case TK_ISNOT: testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; jumpIfNull = SQLITE_NULLEQ; |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | unsigned char *zOut; /* The output */ int nStr; /* Size of zStr */ int nPattern; /* Size of zPattern */ int nRep; /* Size of zRep */ i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ int i, j; /* Loop counters */ assert( argc==3 ); UNUSED_PARAMETER(argc); zStr = sqlite3_value_text(argv[0]); if( zStr==0 ) return; nStr = sqlite3_value_bytes(argv[0]); assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */ | > > | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 | unsigned char *zOut; /* The output */ int nStr; /* Size of zStr */ int nPattern; /* Size of zPattern */ int nRep; /* Size of zRep */ i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ int i, j; /* Loop counters */ unsigned cntExpand; /* Number zOut expansions */ sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==3 ); UNUSED_PARAMETER(argc); zStr = sqlite3_value_text(argv[0]); if( zStr==0 ) return; nStr = sqlite3_value_bytes(argv[0]); assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */ |
︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | nOut = nStr + 1; assert( nOut<SQLITE_MAX_LENGTH ); zOut = contextMalloc(context, (i64)nOut); if( zOut==0 ){ return; } loopLimit = nStr - nPattern; for(i=j=0; i<=loopLimit; i++){ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ zOut[j++] = zStr[i]; }else{ | > < | | | | | | | | | > > > > > | | | | | | > > | | 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 | nOut = nStr + 1; assert( nOut<SQLITE_MAX_LENGTH ); zOut = contextMalloc(context, (i64)nOut); if( zOut==0 ){ return; } loopLimit = nStr - nPattern; cntExpand = 0; for(i=j=0; i<=loopLimit; i++){ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){ zOut[j++] = zStr[i]; }else{ if( nRep>nPattern ){ nOut += nRep - nPattern; testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] ); if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); sqlite3_free(zOut); return; } cntExpand++; if( (cntExpand&(cntExpand-1))==0 ){ /* Grow the size of the output buffer only on substitutions ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */ u8 *zOld; zOld = zOut; zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1)); if( zOut==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(zOld); return; } } } memcpy(&zOut[j], zRep, nRep); j += nRep; i += nPattern-1; } } assert( j+nStr-i+1<=nOut ); memcpy(&zOut[j], &zStr[i], nStr-i); j += nStr - i; assert( j<=nOut ); zOut[j] = 0; sqlite3_result_text(context, (char*)zOut, j, sqlite3_free); } |
︙ | ︙ |
Changes to src/global.c.
︙ | ︙ | |||
254 255 256 257 258 259 260 261 262 263 264 265 266 267 | ** Constant tokens for values 0 and 1. */ const Token sqlite3IntTokens[] = { { "0", 1 }, { "1", 1 } }; /* ** The value of the "pending" byte must be 0x40000000 (1 byte past the ** 1-gibabyte boundary) in a compatible database. SQLite never uses ** the database page that contains the pending byte. It never attempts ** to read or write that page. The pending byte page is set aside ** for use by the VFS layers as space for managing file locks. | > > > > > > > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | ** Constant tokens for values 0 and 1. */ const Token sqlite3IntTokens[] = { { "0", 1 }, { "1", 1 } }; #ifdef VDBE_PROFILE /* ** The following performance counter can be used in place of ** sqlite3Hwtime() for profiling. This is a no-op on standard builds. */ sqlite3_uint64 sqlite3NProfileCnt = 0; #endif /* ** The value of the "pending" byte must be 0x40000000 (1 byte past the ** 1-gibabyte boundary) in a compatible database. SQLite never uses ** the database page that contains the pending byte. It never attempts ** to read or write that page. The pending byte page is set aside ** for use by the VFS layers as space for managing file locks. |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 | #else /* SQLITE_NOLFS */ 0, #endif /* SQLITE_AUTH */ "authorization denied", /* SQLITE_FORMAT */ 0, /* SQLITE_RANGE */ "column index out of range", /* SQLITE_NOTADB */ "file is not a database", }; const char *zErr = "unknown error"; switch( rc ){ case SQLITE_ABORT_ROLLBACK: { zErr = "abort due to ROLLBACK"; break; } default: { rc &= 0xff; if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){ zErr = aMsg[rc]; } break; | > > > > > > > > > > | 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 | #else /* SQLITE_NOLFS */ 0, #endif /* SQLITE_AUTH */ "authorization denied", /* SQLITE_FORMAT */ 0, /* SQLITE_RANGE */ "column index out of range", /* SQLITE_NOTADB */ "file is not a database", /* SQLITE_NOTICE */ "notification message", /* SQLITE_WARNING */ "warning message", }; const char *zErr = "unknown error"; switch( rc ){ case SQLITE_ABORT_ROLLBACK: { zErr = "abort due to ROLLBACK"; break; } case SQLITE_ROW: { zErr = "another row available"; break; } case SQLITE_DONE: { zErr = "no more rows available"; break; } default: { rc &= 0xff; if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){ zErr = aMsg[rc]; } break; |
︙ | ︙ |
Changes to src/mutex_unix.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | #if SQLITE_MUTEX_NREF volatile int nRef; /* Number of entrances */ volatile pthread_t owner; /* Thread that is within this mutex */ int trace; /* True to trace changes */ #endif }; #if SQLITE_MUTEX_NREF | | > | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #if SQLITE_MUTEX_NREF volatile int nRef; /* Number of entrances */ volatile pthread_t owner; /* Thread that is within this mutex */ int trace; /* True to trace changes */ #endif }; #if SQLITE_MUTEX_NREF # define SQLITE3_MUTEX_INITIALIZER(id) \ {PTHREAD_MUTEX_INITIALIZER,id,0,(pthread_t)0,0} #elif defined(SQLITE_ENABLE_API_ARMOR) # define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER, id } #else #define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER } #endif /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use only inside assert() statements. On some platforms, ** there might be race conditions that can cause these routines to ** deliver incorrect results. In particular, if pthread_equal() is |
︙ | ︙ | |||
147 148 149 150 151 152 153 | ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ static sqlite3_mutex *pthreadMutexAlloc(int iType){ static sqlite3_mutex staticMutexes[] = { | | | | | | | | | | | | | > > > > > > | | 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 | ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ static sqlite3_mutex *pthreadMutexAlloc(int iType){ static sqlite3_mutex staticMutexes[] = { SQLITE3_MUTEX_INITIALIZER(2), SQLITE3_MUTEX_INITIALIZER(3), SQLITE3_MUTEX_INITIALIZER(4), SQLITE3_MUTEX_INITIALIZER(5), SQLITE3_MUTEX_INITIALIZER(6), SQLITE3_MUTEX_INITIALIZER(7), SQLITE3_MUTEX_INITIALIZER(8), SQLITE3_MUTEX_INITIALIZER(9), SQLITE3_MUTEX_INITIALIZER(10), SQLITE3_MUTEX_INITIALIZER(11), SQLITE3_MUTEX_INITIALIZER(12), SQLITE3_MUTEX_INITIALIZER(13) }; sqlite3_mutex *p; switch( iType ){ case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX /* If recursive mutexes are not available, we will have to ** build our own. See below. */ pthread_mutex_init(&p->mutex, 0); #else /* Use a recursive mutex if it is available */ pthread_mutexattr_t recursiveAttr; pthread_mutexattr_init(&recursiveAttr); pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&p->mutex, &recursiveAttr); pthread_mutexattr_destroy(&recursiveAttr); #endif #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) p->id = SQLITE_MUTEX_RECURSIVE; #endif } break; } case SQLITE_MUTEX_FAST: { p = sqlite3MallocZero( sizeof(*p) ); if( p ){ pthread_mutex_init(&p->mutex, 0); #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) p->id = SQLITE_MUTEX_FAST; #endif } break; } default: { #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2<0 || iType-2>=ArraySize(staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &staticMutexes[iType-2]; break; } } #if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR) assert( p==0 || p->id==iType ); #endif return p; } /* ** This routine deallocates a previously |
︙ | ︙ |
Changes to src/mutex_w32.c.
︙ | ︙ | |||
36 37 38 39 40 41 42 | */ struct sqlite3_mutex { CRITICAL_SECTION mutex; /* Mutex controlling the lock */ int id; /* Mutex type */ #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ | | | | | 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 | */ struct sqlite3_mutex { CRITICAL_SECTION mutex; /* Mutex controlling the lock */ int id; /* Mutex type */ #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ volatile LONG trace; /* True to trace changes */ #endif }; /* ** These are the initializer values used when declaring a "static" mutex ** on Win32. It should be noted that all mutexes require initialization ** on the Win32 platform. */ #define SQLITE_W32_MUTEX_INITIALIZER { 0 } #ifdef SQLITE_DEBUG #define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \ 0L, (DWORD)0, 0 } #else #define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id } #endif #ifdef SQLITE_DEBUG /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are ** intended for use only inside assert() statements. */ |
︙ | ︙ | |||
94 95 96 97 98 99 100 | #endif } /* ** Initialize and deinitialize the mutex subsystem. */ static sqlite3_mutex winMutex_staticMutexes[] = { | | | | | | | | | | | | | | 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 | #endif } /* ** Initialize and deinitialize the mutex subsystem. */ static sqlite3_mutex winMutex_staticMutexes[] = { SQLITE3_MUTEX_INITIALIZER(2), SQLITE3_MUTEX_INITIALIZER(3), SQLITE3_MUTEX_INITIALIZER(4), SQLITE3_MUTEX_INITIALIZER(5), SQLITE3_MUTEX_INITIALIZER(6), SQLITE3_MUTEX_INITIALIZER(7), SQLITE3_MUTEX_INITIALIZER(8), SQLITE3_MUTEX_INITIALIZER(9), SQLITE3_MUTEX_INITIALIZER(10), SQLITE3_MUTEX_INITIALIZER(11), SQLITE3_MUTEX_INITIALIZER(12), SQLITE3_MUTEX_INITIALIZER(13) }; static int winMutex_isInit = 0; static int winMutex_isNt = -1; /* <0 means "need to query" */ /* As the winMutexInit() and winMutexEnd() functions are called as part ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the |
︙ | ︙ | |||
235 236 237 238 239 240 241 | #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &winMutex_staticMutexes[iType-2]; | < | > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | #ifdef SQLITE_ENABLE_API_ARMOR if( iType-2<0 || iType-2>=ArraySize(winMutex_staticMutexes) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif p = &winMutex_staticMutexes[iType-2]; #ifdef SQLITE_DEBUG #ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC InterlockedCompareExchange(&p->trace, 1, 0); #endif #endif break; } } assert( p==0 || p->id==iType ); return p; } /* ** This routine deallocates a previously ** allocated mutex. SQLite is careful to deallocate every |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | #if defined(HAVE_FCHOWN) { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, #else { "fchown", (sqlite3_syscall_ptr)0, 0 }, #endif #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #else { "mmap", (sqlite3_syscall_ptr)0, 0 }, #endif | > > > > | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | #if defined(HAVE_FCHOWN) { "fchown", (sqlite3_syscall_ptr)fchown, 0 }, #else { "fchown", (sqlite3_syscall_ptr)0, 0 }, #endif #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) #if defined(HAVE_FCHOWN) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #else { "geteuid", (sqlite3_syscall_ptr)0, 0 }, #endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #else { "mmap", (sqlite3_syscall_ptr)0, 0 }, #endif |
︙ | ︙ | |||
692 693 694 695 696 697 698 699 | ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() */ static void unixEnterMutex(void){ | > | | | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | ** 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 #ifdef SQLITE_HAVE_OS_TRACE /* ** Helper function for printing out trace information from debugging |
︙ | ︙ | |||
4171 4172 4173 4174 4175 4176 4177 | assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); if( pShmNode->h>=0 ){ /* Initialize the locking parameters */ | < < | 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 | assert( n==1 || lockType!=F_RDLCK ); /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); if( pShmNode->h>=0 ){ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; rc = osFcntl(pShmNode->h, F_SETLK, &f); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG { u16 mask; |
︙ | ︙ | |||
5842 5843 5844 5845 5846 5847 5848 | ** the same instant might all reset the PRNG. But multiple resets ** are harmless. */ if( randomnessPid!=osGetpid(0) ){ randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } | < | 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 | ** the same instant might all reset the PRNG. But multiple resets ** are harmless. */ if( randomnessPid!=osGetpid(0) ){ randomnessPid = osGetpid(0); sqlite3_randomness(0,0); } memset(p, 0, sizeof(unixFile)); if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); if( pUnused ){ fd = pUnused->fd; |
︙ | ︙ | |||
7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 | ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } return SQLITE_OK; } /* ** Shutdown the operating system interface. ** ** Some operating systems might need to do some cleanup in this routine, ** to release dynamically allocated objects. But not on unix. ** This routine is a no-op for unix. */ int sqlite3_os_end(void){ return SQLITE_OK; } #endif /* SQLITE_OS_UNIX */ | > > | 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 | ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); return SQLITE_OK; } /* ** Shutdown the operating system interface. ** ** Some operating systems might need to do some cleanup in this routine, ** to release dynamically allocated objects. But not on unix. ** This routine is a no-op for unix. */ int sqlite3_os_end(void){ unixBigLock = 0; return SQLITE_OK; } #endif /* SQLITE_OS_UNIX */ |
Changes to src/os_win.c.
︙ | ︙ | |||
3627 3628 3629 3630 3631 3632 3633 3634 | ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** winShmEnterMutex() ** assert( winShmMutexHeld() ); ** winShmLeaveMutex() */ static void winShmEnterMutex(void){ | > | | | | 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 | ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** winShmEnterMutex() ** assert( winShmMutexHeld() ); ** winShmLeaveMutex() */ static sqlite3_mutex *winBigLock = 0; static void winShmEnterMutex(void){ sqlite3_mutex_enter(winBigLock); } static void winShmLeaveMutex(void){ sqlite3_mutex_leave(winBigLock); } #ifndef NDEBUG static int winShmMutexHeld(void) { return sqlite3_mutex_held(winBigLock); } #endif /* ** Object used to represent a single file opened and mmapped to provide ** shared memory. When multiple threads all reference the same ** log-summary, each thread has its own winFile object, but they all |
︙ | ︙ | |||
6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 | #endif sqlite3_vfs_register(&winNolockVfs, 0); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathNolockVfs, 0); #endif return SQLITE_OK; } int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); sleepObj = NULL; } #endif return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ | > > > > > > > > > | 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 | #endif sqlite3_vfs_register(&winNolockVfs, 0); #if defined(SQLITE_WIN32_HAS_WIDE) sqlite3_vfs_register(&winLongPathNolockVfs, 0); #endif #ifndef SQLITE_OMIT_WAL winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); #endif return SQLITE_OK; } int sqlite3_os_end(void){ #if SQLITE_OS_WINRT if( sleepObj!=NULL ){ osCloseHandle(sleepObj); sleepObj = NULL; } #endif #ifndef SQLITE_OMIT_WAL winBigLock = 0; #endif return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ |
Changes to src/pager.c.
︙ | ︙ | |||
4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 | PgHdr *pNext; for(p=pPager->pMmapFreelist; p; p=pNext){ pNext = p->pDirty; sqlite3_free(p); } } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ | > > > > > > > > > > > > > > > > > > > > > > > > | < > > | < | > | > > > | > | 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 | PgHdr *pNext; for(p=pPager->pMmapFreelist; p; p=pNext){ pNext = p->pDirty; sqlite3_free(p); } } /* Verify that the database file has not be deleted or renamed out from ** under the pager. Return SQLITE_OK if the database is still where it ought ** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error ** code from sqlite3OsAccess()) if the database has gone missing. */ static int databaseIsUnmoved(Pager *pPager){ int bHasMoved = 0; int rc; if( pPager->tempFile ) return SQLITE_OK; if( pPager->dbSize==0 ) return SQLITE_OK; assert( pPager->zFilename && pPager->zFilename[0] ); rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved); if( rc==SQLITE_NOTFOUND ){ /* If the HAS_MOVED file-control is unimplemented, assume that the file ** has not been moved. That is the historical behavior of SQLite: prior to ** version 3.8.3, it never checked */ rc = SQLITE_OK; }else if( rc==SQLITE_OK && bHasMoved ){ rc = SQLITE_READONLY_DBMOVED; } return rc; } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. ** ** This function always succeeds. If a transaction is active an attempt ** is made to roll it back. If an error occurs during the rollback ** a hot journal may be left in the filesystem but no error is returned ** to the caller. */ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ u8 *pTmp = (u8*)pPager->pTmpSpace; assert( db || pagerUseWal(pPager)==0 ); assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL { u8 *a = 0; assert( db || pPager->pWal==0 ); if( db && 0==(db->flags & SQLITE_NoCkptOnClose) && SQLITE_OK==databaseIsUnmoved(pPager) ){ a = pTmp; } sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } #endif pager_reset(pPager); if( MEMDB ){ pager_unlock(pPager); }else{ /* If it is open, sync the journal file before calling UnlockAndRollback. ** If this is not done, then an unsynced portion of the open journal |
︙ | ︙ | |||
4965 4966 4967 4968 4969 4970 4971 | /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < | 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 | /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } /* ** This function is called after transitioning from PAGER_UNLOCK to ** PAGER_SHARED state. It tests if there is a hot journal present in ** the file-system for the given pager. A hot journal is one that ** needs to be played back. According to this function, a hot-journal ** file exists if the following criteria are met: |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
309 310 311 312 313 314 315 316 317 318 319 320 321 322 | {sqlite3AddDefaultValue(pParse,X,A.z,Z);} ccons ::= DEFAULT MINUS(A) term(X) scanpt(Z). { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0); sqlite3AddDefaultValue(pParse,p,A.z,Z); } ccons ::= DEFAULT scanpt id(X). { Expr *p = tokenExpr(pParse, TK_STRING, X); 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. | > > > > | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | {sqlite3AddDefaultValue(pParse,X,A.z,Z);} ccons ::= DEFAULT MINUS(A) term(X) scanpt(Z). { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0); sqlite3AddDefaultValue(pParse,p,A.z,Z); } 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. |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
202 203 204 205 206 207 208 209 210 211 212 213 214 215 | double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ #endif PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ bufpt = 0; if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ pArgList = va_arg(ap, PrintfArguments*); bArgList = 1; }else{ bArgList = 0; } | > > > > > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ #endif PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */ char buf[etBUFSIZE]; /* Conversion buffer */ /* pAccum never starts out with an empty buffer that was obtained from ** malloc(). This precondition is required by the mprintf("%z...") ** optimization. */ assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); bufpt = 0; if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){ pArgList = va_arg(ap, PrintfArguments*); bArgList = 1; }else{ bArgList = 0; } |
︙ | ︙ | |||
620 621 622 623 624 625 626 | buf[0] = '%'; bufpt = buf; length = 1; break; case etCHARX: if( bArgList ){ bufpt = getTextArg(pArgList); | > | > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > | > | < < > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | | | > > > > > > > > | 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 | buf[0] = '%'; bufpt = buf; length = 1; break; case etCHARX: if( bArgList ){ bufpt = getTextArg(pArgList); length = 1; if( bufpt ){ buf[0] = c = *(bufpt++); if( (c&0xc0)==0xc0 ){ while( length<4 && (bufpt[0]&0xc0)==0x80 ){ buf[length++] = *(bufpt++); } } }else{ buf[0] = 0; } }else{ unsigned int ch = va_arg(ap,unsigned int); if( ch<0x00080 ){ buf[0] = ch & 0xff; length = 1; }else if( ch<0x00800 ){ buf[0] = 0xc0 + (u8)((ch>>6)&0x1f); buf[1] = 0x80 + (u8)(ch & 0x3f); length = 2; }else if( ch<0x10000 ){ buf[0] = 0xe0 + (u8)((ch>>12)&0x0f); buf[1] = 0x80 + (u8)((ch>>6) & 0x3f); buf[2] = 0x80 + (u8)(ch & 0x3f); length = 3; }else{ buf[0] = 0xf0 + (u8)((ch>>18) & 0x07); buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3AppendChar(pAccum, width-1, ' '); width = 0; } while( precision-- > 1 ){ sqlite3StrAccumAppend(pAccum, buf, length); } } bufpt = buf; flag_altform2 = 1; goto adjust_width_for_utf8; case etSTRING: case etDYNSTRING: if( bArgList ){ bufpt = getTextArg(pArgList); 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 ){ /* 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); pAccum->printfFlags |= SQLITE_PRINTF_MALLOCED; length = 0; break; } zExtra = bufpt; } if( precision>=0 ){ if( flag_altform2 ){ /* Set length to the number of bytes needed in order to display ** precision characters */ unsigned char *z = (unsigned char*)bufpt; while( precision-- > 0 && z[0] ){ SQLITE_SKIP_UTF8(z); } length = (int)(z - (unsigned char*)bufpt); }else{ for(length=0; length<precision && bufpt[length]; length++){} } }else{ length = 0x7fffffff & (int)strlen(bufpt); } adjust_width_for_utf8: if( flag_altform2 && width>0 ){ /* Adjust width to account for extra bytes in UTF-8 characters */ int ii = length - 1; while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE3: { /* %w: Escape " characters */ int i, j, k, n, isnull; int needQuote; char ch; char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; if( bArgList ){ escarg = getTextArg(pArgList); }else{ escarg = va_arg(ap,char*); } isnull = escarg==0; if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)"); /* For %q, %Q, and %w, the precision is the number of byte (or ** characters if the ! flags is present) to use from the input. ** Because of the extra quoting characters inserted, the number ** of output characters may be larger than the precision. */ k = precision; for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){ if( ch==q ) n++; if( flag_altform2 && (ch&0xc0)==0xc0 ){ while( (escarg[i+1]&0xc0)==0x80 ){ i++; } } } needQuote = !isnull && xtype==etSQLESCAPE2; n += i + 3; if( n>etBUFSIZE ){ bufpt = zExtra = sqlite3Malloc( n ); if( bufpt==0 ){ setStrAccumError(pAccum, STRACCUM_NOMEM); |
︙ | ︙ | |||
696 697 698 699 700 701 702 | for(i=0; i<k; i++){ bufpt[j++] = ch = escarg[i]; if( ch==q ) bufpt[j++] = ch; } if( needQuote ) bufpt[j++] = q; bufpt[j] = 0; length = j; | | < < < | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | for(i=0; i<k; i++){ bufpt[j++] = ch = escarg[i]; if( ch==q ) bufpt[j++] = ch; } if( needQuote ) bufpt[j++] = q; bufpt[j] = 0; length = j; goto adjust_width_for_utf8; } case etTOKEN: { Token *pToken; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; pToken = va_arg(ap, Token*); assert( bArgList==0 ); if( pToken && pToken->n ){ |
︙ | ︙ | |||
738 739 740 741 742 743 744 | assert( xtype==etINVALID ); return; } }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do | | > > > | 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | assert( xtype==etINVALID ); return; } }/* End switch over the format type */ /* ** The text of the conversion is pointed to by "bufpt" and is ** "length" characters long. The field width is "width". Do ** the output. Both length and width are in bytes, not characters, ** at this point. If the "!" flag was present on string conversions ** indicating that width and precision should be expressed in characters, ** then the values have been translated prior to reaching this point. */ width -= length; if( width>0 ){ if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); sqlite3StrAccumAppend(pAccum, bufpt, length); if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); }else{ |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
427 428 429 430 431 432 433 | ** Z is a string literal if it doesn't match any column names. In that ** case, we need to return right away and not make any changes to ** pExpr. ** ** Because no reference was made to outer contexts, the pNC->nRef ** fields are not changed in any context. */ | | > > | | | > > > > | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | ** Z is a string literal if it doesn't match any column names. In that ** case, we need to return right away and not make any changes to ** pExpr. ** ** 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->pTab = 0; return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } } /* ** cnt==0 means there was not match. cnt>1 means there were two or ** more matches. Either way, we have an error. */ if( cnt!=1 ){ |
︙ | ︙ | |||
779 780 781 782 783 784 785 786 787 788 789 790 791 | } break; } case TK_VARIABLE: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } case TK_BETWEEN: case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: | > > > > > > > > > > > > > > > > > | < < | 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 | } break; } case TK_VARIABLE: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } case TK_IS: case TK_ISNOT: { Expr *pRight; assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ if( (pRight = pExpr->pRight)->op==TK_ID ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ pExpr->op2 = pExpr->op; pExpr->op = TK_TRUTH; return WRC_Continue; } } /* Fall thru */ } case TK_BETWEEN: case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { int nLeft, nRight; if( pParse->db->mallocFailed ) break; assert( pExpr->pLeft!=0 ); nLeft = sqlite3ExprVectorSize(pExpr->pLeft); if( pExpr->op==TK_BETWEEN ){ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr); if( nRight==nLeft ){ |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 | bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; } | | > > > | | 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 | bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; } for(i=0, iCol=nKey+bSeq-1; i<nSortData; i++){ if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++; } for(i=nSortData-1; i>=0; i--){ int iRead; if( aOutEx[i].u.x.iOrderByCol ){ iRead = aOutEx[i].u.x.iOrderByCol-1; }else{ iRead = iCol--; } sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { |
︙ | ︙ |
Changes to src/shell.c.in.
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | /* Allowed values for ShellState.openMode */ #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ #define SHELL_OPEN_NORMAL 1 /* Normal database file */ #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ /* ** These are the allowed shellFlgs values */ #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ | > | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | /* Allowed values for ShellState.openMode */ #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ #define SHELL_OPEN_NORMAL 1 /* Normal database file */ #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ #define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ /* ** These are the allowed shellFlgs values */ #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */ #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */ #define SHFLG_Backslash 0x00000004 /* The --backslash option is used */ |
︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | ** (4) Delete the temporary file ** ** If the EDITOR argument is omitted, use the value in the VISUAL ** environment variable. If still there is no EDITOR, through an error. ** ** Also throw an error if the EDITOR program returns a non-zero exit code. */ static void editFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zEditor; char *zTempFile = 0; | > | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | ** (4) Delete the temporary file ** ** If the EDITOR argument is omitted, use the value in the VISUAL ** environment variable. If still there is no EDITOR, through an error. ** ** Also throw an error if the EDITOR program returns a non-zero exit code. */ #ifndef SQLITE_NOHAVE_SYSTEM static void editFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zEditor; char *zTempFile = 0; |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 | edit_func_end: if( f ) fclose(f); unlink(zTempFile); sqlite3_free(zTempFile); sqlite3_free(p); } /* ** Save or restore the current output mode */ static void outputModePush(ShellState *p){ p->modePrior = p->mode; memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); | > | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 | edit_func_end: if( f ) fclose(f); unlink(zTempFile); sqlite3_free(zTempFile); sqlite3_free(p); } #endif /* SQLITE_NOHAVE_SYSTEM */ /* ** Save or restore the current output mode */ static void outputModePush(ShellState *p){ p->modePrior = p->mode; memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); |
︙ | ︙ | |||
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 | " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".once (-e|-x|FILE) Output for the next SQL command only to FILE\n" " or invoke system text editor (-e) or spreadsheet (-x)\n" " on the output.\n" ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n" " The --new option starts with an empty file\n" ".output ?FILE? Send output to FILE or stdout\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n" " Add --indent for pretty-printing\n" ".selftest ?--init? Run tests defined in the SELFTEST table\n" ".separator COL ?ROW? Change the column separator and optionally the row\n" " separator for both the output mode and .import\n" #if defined(SQLITE_ENABLE_SESSION) ".session CMD ... Create or control sessions\n" #endif ".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n" ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" ".show Show the current values for various settings\n" ".stats ?on|off? Show stats or turn stats on or off\n" ".system CMD ARGS... Run CMD ARGS... in a system shell\n" ".tables ?TABLE? List names of tables\n" " If TABLE specified, only list tables matching\n" " LIKE pattern TABLE.\n" ".testcase NAME Begin redirecting output to 'testcase-out.txt'\n" ".timeout MS Try opening locked tables for MS milliseconds\n" ".timer on|off Turn SQL timer on or off\n" ".trace FILE|off Output each SQL statement as it is run\n" | > > > > > | 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 | " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".once (-e|-x|FILE) Output for the next SQL command only to FILE\n" " or invoke system text editor (-e) or spreadsheet (-x)\n" " on the output.\n" ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n" " The --new option starts with an empty file\n" " Other options: --readonly --append --zip\n" ".output ?FILE? Send output to FILE or stdout\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".save FILE Write in-memory database into FILE\n" ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n" ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n" " Add --indent for pretty-printing\n" ".selftest ?--init? Run tests defined in the SELFTEST table\n" ".separator COL ?ROW? Change the column separator and optionally the row\n" " separator for both the output mode and .import\n" #if defined(SQLITE_ENABLE_SESSION) ".session CMD ... Create or control sessions\n" #endif ".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n" #ifndef SQLITE_NOHAVE_SYSTEM ".shell CMD ARGS... Run CMD ARGS... in a system shell\n" #endif ".show Show the current values for various settings\n" ".stats ?on|off? Show stats or turn stats on or off\n" #ifndef SQLITE_NOHAVE_SYSTEM ".system CMD ARGS... Run CMD ARGS... in a system shell\n" #endif ".tables ?TABLE? List names of tables\n" " If TABLE specified, only list tables matching\n" " LIKE pattern TABLE.\n" ".testcase NAME Begin redirecting output to 'testcase-out.txt'\n" ".timeout MS Try opening locked tables for MS milliseconds\n" ".timer on|off Turn SQL timer on or off\n" ".trace FILE|off Output each SQL statement as it is run\n" |
︙ | ︙ | |||
3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 | sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs"); break; } case SHELL_OPEN_ZIPFILE: { sqlite3_open(":memory:", &p->db); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open(p->zDbFilename, &p->db); break; } } | > > > > | 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 | sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs"); break; } case SHELL_OPEN_ZIPFILE: { sqlite3_open(":memory:", &p->db); break; } case SHELL_OPEN_READONLY: { sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open(p->zDbFilename, &p->db); break; } } |
︙ | ︙ | |||
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 | #endif sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, shellAddSchemaName, 0, 0); sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, shellModuleSchema, 0, 0); sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, shellPutsFunc, 0, 0); sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, editFunc, 0, 0); sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, editFunc, 0, 0); if( p->openMode==SHELL_OPEN_ZIPFILE ){ char *zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } } | > > | 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 | #endif sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, shellAddSchemaName, 0, 0); sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, shellModuleSchema, 0, 0); sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, shellPutsFunc, 0, 0); #ifndef SQLITE_NOHAVE_SYSTEM sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, editFunc, 0, 0); sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, editFunc, 0, 0); #endif if( p->openMode==SHELL_OPEN_ZIPFILE ){ char *zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } } |
︙ | ︙ | |||
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 | static void output_reset(ShellState *p){ if( p->outfile[0]=='|' ){ #ifndef SQLITE_OMIT_POPEN pclose(p->out); #endif }else{ output_file_close(p->out); if( p->doXdgOpen ){ const char *zXdgOpenCmd = #if defined(_WIN32) "start"; #elif defined(__APPLE__) "open"; #else "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ utf8_printf(stderr, "Failed: [%s]\n", zCmd); } sqlite3_free(zCmd); outputModePop(p); p->doXdgOpen = 0; } } p->outfile[0] = 0; p->out = stdout; } /* ** Run an SQL command and return the single integer result. | > > | 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 | static void output_reset(ShellState *p){ if( p->outfile[0]=='|' ){ #ifndef SQLITE_OMIT_POPEN pclose(p->out); #endif }else{ output_file_close(p->out); #ifndef SQLITE_NOHAVE_SYSTEM if( p->doXdgOpen ){ const char *zXdgOpenCmd = #if defined(_WIN32) "start"; #elif defined(__APPLE__) "open"; #else "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ utf8_printf(stderr, "Failed: [%s]\n", zCmd); } sqlite3_free(zCmd); outputModePop(p); p->doXdgOpen = 0; } #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ } p->outfile[0] = 0; p->out = stdout; } /* ** Run an SQL command and return the single integer result. |
︙ | ︙ | |||
6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 | newFlag = 1; #ifdef SQLITE_HAVE_ZIP }else if( optionMatch(z, "zip") ){ p->openMode = SHELL_OPEN_ZIPFILE; #endif }else if( optionMatch(z, "append") ){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; goto meta_command_exit; } } /* If a filename is specified, try to open it first */ | > > | 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 | newFlag = 1; #ifdef SQLITE_HAVE_ZIP }else if( optionMatch(z, "zip") ){ p->openMode = SHELL_OPEN_ZIPFILE; #endif }else if( optionMatch(z, "append") ){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ p->openMode = SHELL_OPEN_READONLY; }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; goto meta_command_exit; } } /* If a filename is specified, try to open it first */ |
︙ | ︙ | |||
6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 | } p->outCount = 2; }else{ p->outCount = 0; } output_reset(p); if( zFile[0]=='-' && zFile[1]=='-' ) zFile++; if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){ p->doXdgOpen = 1; outputModePush(p); if( zFile[1]=='x' ){ newTempFile(p, "csv"); p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else{ newTempFile(p, "txt"); bTxtMode = 1; } zFile = p->zTempFile; } if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = stdout; #else p->out = popen(zFile + 1, "w"); | > > | 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 | } p->outCount = 2; }else{ p->outCount = 0; } output_reset(p); if( zFile[0]=='-' && zFile[1]=='-' ) zFile++; #ifndef SQLITE_NOHAVE_SYSTEM if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){ p->doXdgOpen = 1; outputModePush(p); if( zFile[1]=='x' ){ newTempFile(p, "csv"); p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else{ newTempFile(p, "txt"); bTxtMode = 1; } zFile = p->zTempFile; } #endif /* SQLITE_NOHAVE_SYSTEM */ if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); rc = 1; p->out = stdout; #else p->out = popen(zFile + 1, "w"); |
︙ | ︙ | |||
6481 6482 6483 6484 6485 6486 6487 | rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } sqlite3_close(pSrc); }else | < | 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 | rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } sqlite3_close(pSrc); }else if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ p->scanstatsOn = (u8)booleanValue(azArg[1]); #ifndef SQLITE_ENABLE_STMT_SCANSTATUS raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); #endif |
︙ | ︙ | |||
7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 | utf8_printf(p->out, "%s\n", zSql); }else{ shell_exec(p->db, zSql, shell_callback, p, 0); } sqlite3_free(zSql); }else if( c=='s' && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) ){ char *zCmd; int i, x; if( nArg<2 ){ raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; goto meta_command_exit; } zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; i<nArg; i++){ zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"", zCmd, azArg[i]); } x = system(zCmd); sqlite3_free(zCmd); if( x ) raw_printf(stderr, "System command returns %d\n", x); }else if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ static const char *azBool[] = { "off", "on", "trigger", "full"}; int i; if( nArg!=1 ){ raw_printf(stderr, "Usage: .show\n"); rc = 1; | > > | 7097 7098 7099 7100 7101 7102 7103 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 | utf8_printf(p->out, "%s\n", zSql); }else{ shell_exec(p->db, zSql, shell_callback, p, 0); } sqlite3_free(zSql); }else #ifndef SQLITE_NOHAVE_SYSTEM if( c=='s' && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) ){ char *zCmd; int i, x; if( nArg<2 ){ raw_printf(stderr, "Usage: .system COMMAND\n"); rc = 1; goto meta_command_exit; } zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); for(i=2; i<nArg; i++){ zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"", zCmd, azArg[i]); } x = system(zCmd); sqlite3_free(zCmd); if( x ) raw_printf(stderr, "System command returns %d\n", x); }else #endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ static const char *azBool[] = { "off", "on", "trigger", "full"}; int i; if( nArg!=1 ){ raw_printf(stderr, "Usage: .show\n"); rc = 1; |
︙ | ︙ | |||
7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 | #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -newline SEP set output row separator. Default: '\\n'\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -quote set output mode to 'quote'\n" " -separator SEP set output column separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" #endif | > | 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 | #ifdef SQLITE_ENABLE_MULTIPLEX " -multiplex enable the multiplexor VFS\n" #endif " -newline SEP set output row separator. Default: '\\n'\n" " -nullvalue TEXT set text string for NULL values. Default ''\n" " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" " -quote set output mode to 'quote'\n" " -readonly open the database read-only\n" " -separator SEP set output column separator. Default: '|'\n" " -stats print memory stats before each finalize\n" " -version show SQLite version\n" " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE " -vfstrace enable tracing of all VFS calls\n" #endif |
︙ | ︙ | |||
8077 8078 8079 8080 8081 8082 8083 8084 8085 | 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); } #endif main_init(&data); #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); | > > > > > > > | | > > > > > > > > > > > | 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 | 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); } #endif main_init(&data); /* On Windows, we must translate command-line arguments into UTF-8. ** The SQLite memory allocator subsystem has to be enabled in order to ** do this. But we want to run an sqlite3_shutdown() afterwards so that ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); argv = malloc(sizeof(argv[0])*argc); if( argv==0 ){ raw_printf(stderr, "out of memory\n"); exit(1); } for(i=0; i<argc; i++){ char *z = sqlite3_win32_unicode_to_utf8(wargv[i]); int n; if( z==0 ){ raw_printf(stderr, "out of memory\n"); exit(1); } n = (int)strlen(z); argv[i] = malloc( n+1 ); if( argv[i]==0 ){ raw_printf(stderr, "out of memory\n"); exit(1); } memcpy(argv[i], z, n+1); sqlite3_free(z); } sqlite3_shutdown(); #endif assert( argc>=1 && argv && argv[0] ); Argv0 = argv[0]; /* Make sure we have a valid signal handler early, before anything ** else is done. */ #ifdef SIGINT |
︙ | ︙ | |||
8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 | } #ifdef SQLITE_HAVE_ZIP }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; } } if( data.zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB data.zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else | > > | 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 | } #ifdef SQLITE_HAVE_ZIP }else if( strcmp(z,"-zip")==0 ){ data.openMode = SHELL_OPEN_ZIPFILE; #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; } } if( data.zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB data.zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else |
︙ | ︙ | |||
8444 8445 8446 8447 8448 8449 8450 | } sqlite3_free(data.zFreeOnClose); find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 | | | | 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 | } sqlite3_free(data.zFreeOnClose); find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 for(i=0; i<argc; i++) free(argv[i]); free(argv); #endif return rc; } |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
2492 2493 2494 2495 2496 2497 2498 | void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. | | > | < | | | | 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 | void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. ** These routines understand most of the common formatting options from ** the standard library printf() ** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]). ** See the [built-in printf()] documentation for details. ** ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their ** results into memory obtained from [sqlite3_malloc64()]. ** The strings returned by these two routines should be ** released by [sqlite3_free()]. ^Both routines return a ** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough ** memory to hold the resulting string. ** ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from ** the standard C library. The result is written into the ** buffer supplied as the second parameter whose size is given by ** the first parameter. Note that the order of the ** first two parameters is reversed from snprintf().)^ This is an |
︙ | ︙ | |||
2525 2526 2527 2528 2529 2530 2531 | ** guarantees that the buffer is always zero-terminated. ^The first ** parameter "n" is the total size of the buffer, including space for ** the zero terminator. So the longest string that can be completely ** written will be n-1 characters. ** ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). ** | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 | ** guarantees that the buffer is always zero-terminated. ^The first ** parameter "n" is the total size of the buffer, including space for ** the zero terminator. So the longest string that can be completely ** written will be n-1 characters. ** ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). ** ** See also: [built-in printf()], [printf() SQL function] */ char *sqlite3_mprintf(const char*,...); char *sqlite3_vmprintf(const char*, va_list); char *sqlite3_snprintf(int,char*,const char*, ...); char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | }; /* Allowed values for Column.colFlags: */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ #define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** ** If CollSeq.xCmp is NULL, it means that the | > | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 | }; /* Allowed values for Column.colFlags: */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ #define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ #define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** ** If CollSeq.xCmp is NULL, it means that the |
︙ | ︙ | |||
3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 | void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); void sqlite3BeginTransaction(Parse*, int); void sqlite3EndTransaction(Parse*,int); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*, u8); int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS int sqlite3ExprContainsSubquery(Expr*); | > > | 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 | void sqlite3CodeVerifySchema(Parse*, int); void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); void sqlite3BeginTransaction(Parse*, int); void sqlite3EndTransaction(Parse*,int); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); void sqlite3LeaveMutexAndCloseZombie(sqlite3*); int sqlite3ExprIdToTrueFalse(Expr*); int sqlite3ExprTruthValue(const Expr*); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*, u8); int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*); int sqlite3ExprIsTableConstant(Expr*,int); #ifdef SQLITE_ENABLE_CURSOR_HINTS int sqlite3ExprContainsSubquery(Expr*); |
︙ | ︙ | |||
4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 | extern const Token sqlite3IntTokens[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD extern int sqlite3PendingByte; #endif #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*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); | > > > | 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 | extern const Token sqlite3IntTokens[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD extern int sqlite3PendingByte; #endif #endif #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*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 | } zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf))); #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_step STMT ** ** Advance the statement to the next row. */ static int SQLITE_TCLAPI test_step( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 | } zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf))); #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_normalize SQL ** ** Return the normalized value for an SQL statement. */ static int SQLITE_TCLAPI test_normalize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *zSql; char *zNorm; extern char *sqlite3_normalize(const char*); if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SQL"); return TCL_ERROR; } zSql = (char*)Tcl_GetString(objv[1]); zNorm = sqlite3_normalize(zSql); if( zNorm ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(zNorm, -1)); sqlite3_free(zNorm); } return TCL_OK; } /* ** Usage: sqlite3_step STMT ** ** Advance the statement to the next row. */ static int SQLITE_TCLAPI test_step( |
︙ | ︙ | |||
7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 | { "sqlite3_extended_errcode", test_ex_errcode ,0 }, { "sqlite3_errmsg", test_errmsg ,0 }, { "sqlite3_errmsg16", test_errmsg16 ,0 }, { "sqlite3_open", test_open ,0 }, { "sqlite3_open16", test_open16 ,0 }, { "sqlite3_open_v2", test_open_v2 ,0 }, { "sqlite3_complete16", test_complete16 ,0 }, { "sqlite3_prepare", test_prepare ,0 }, { "sqlite3_prepare16", test_prepare16 ,0 }, { "sqlite3_prepare_v2", test_prepare_v2 ,0 }, { "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0}, { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 }, { "sqlite3_finalize", test_finalize ,0 }, | > | 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 | { "sqlite3_extended_errcode", test_ex_errcode ,0 }, { "sqlite3_errmsg", test_errmsg ,0 }, { "sqlite3_errmsg16", test_errmsg16 ,0 }, { "sqlite3_open", test_open ,0 }, { "sqlite3_open16", test_open16 ,0 }, { "sqlite3_open_v2", test_open_v2 ,0 }, { "sqlite3_complete16", test_complete16 ,0 }, { "sqlite3_normalize", test_normalize ,0 }, { "sqlite3_prepare", test_prepare ,0 }, { "sqlite3_prepare16", test_prepare16 ,0 }, { "sqlite3_prepare_v2", test_prepare_v2 ,0 }, { "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0}, { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 }, { "sqlite3_finalize", test_finalize ,0 }, |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
502 503 504 505 506 507 508 509 510 511 512 513 514 515 | #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); #ifdef SQLITE_OMIT_OR_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY); #endif | > > > > > > | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY); #endif Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); #ifdef SQLITE_ENABLE_NULL_TRIM Tcl_SetVar2(interp, "sqlite_options", "null_trim", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "null_trim", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
287 288 289 290 291 292 293 294 295 296 297 298 299 300 | case TK_STRING: { sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { sqlite3TreeViewLine(pView,"NULL"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif | > > > > > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | case TK_STRING: { sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { sqlite3TreeViewLine(pView,"NULL"); break; } case TK_TRUEFALSE: { sqlite3TreeViewLine(pView, sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif |
︙ | ︙ | |||
343 344 345 346 347 348 349 350 351 352 353 354 355 356 | case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_SPAN: { sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } | > > > > > > > > > > > > > | 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 | case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; case TK_BITNOT: zUniOp = "BITNOT"; break; case TK_NOT: zUniOp = "NOT"; break; case TK_ISNULL: zUniOp = "ISNULL"; break; case TK_NOTNULL: zUniOp = "NOTNULL"; break; case TK_TRUTH: { int x; const char *azOp[] = { "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE" }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); assert( pExpr->pRight->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; } case TK_SPAN: { sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
591 592 593 594 595 596 597 | /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed ** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is ** given by enc. */ |
︙ | ︙ | |||
634 635 636 637 638 639 640 641 642 643 644 645 646 647 | } } zStart = zNum; while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ u = u*10 + c - '0'; } if( u>LARGEST_INT64 ){ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } | > > > > > > > | < < < | | | > > > > | | | < < > | | > > | | | | | | | | > | 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 | } } zStart = zNum; while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ u = u*10 + c - '0'; } testcase( i==18*incr ); testcase( i==19*incr ); testcase( i==20*incr ); if( u>LARGEST_INT64 ){ /* This test and assignment is needed only to suppress UB warnings ** from clang and -fsanitize=undefined. This test and assignment make ** the code a little larger and slower, and no harm comes from omitting ** them, but we must appaise the undefined-behavior pharisees. */ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } rc = 0; if( (i==0 && zStart==zNum) /* No digits */ || nonNum /* UTF16 with high-order bytes non-zero */ ){ rc = 1; }else if( &zNum[i]<zEnd ){ /* Extra bytes at the end */ int jj = i; do{ if( !sqlite3Isspace(zNum[jj]) ){ rc = 1; /* Extra non-space text after the integer */ break; } jj += incr; }while( &zNum[jj]<zEnd ); } if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ assert( u<=LARGEST_INT64 ); return rc; }else{ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */ c = i>19*incr ? 1 : compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); return rc; }else{ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; if( c>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ return 2; }else{ /* zNum is exactly 9223372036854775808. Fits if negative. The ** special case 2 overflow if positive */ assert( u-1==LARGEST_INT64 ); return neg ? rc : 3; } } } } /* ** Transform a UTF-8 integer literal, in either decimal or hexadecimal, ** into a 64-bit signed integer. This routine accepts hexadecimal literals, |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); | > | < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* printf("SQL: [%s]\n", zSql); fflush(stdout); */ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0); assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 ); assert( sqlite3_strnicmp(zSubSql,"SELECT",6)!=0 || CORRUPT_DB ); if( zSubSql && zSubSql[0]!='S' ){ rc = execSql(db, pzErrMsg, zSubSql); if( rc!=SQLITE_OK ) break; } } assert( rc!=SQLITE_ROW ); if( rc==SQLITE_DONE ) rc = SQLITE_OK; if( rc ){ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
260 261 262 263 264 265 266 267 268 269 270 271 272 273 | pRec->u.i = iValue; pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; pRec->flags |= MEM_Real; if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } } /* ** Processing is determine by the affinity parameter: ** ** SQLITE_AFF_INTEGER: ** SQLITE_AFF_REAL: | > > > > > | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | pRec->u.i = iValue; pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; pRec->flags |= MEM_Real; if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec); } /* TEXT->NUMERIC is many->one. Hence, it is important to invalidate the ** string representation after computing a numeric equivalent, because the ** string representation might not be the canonical representation for the ** numeric value. Ticket [343634942dd54ab57b7024] 2018-01-31. */ pRec->flags &= ~MEM_Str; } /* ** Processing is determine by the affinity parameter: ** ** SQLITE_AFF_INTEGER: ** SQLITE_AFF_REAL: |
︙ | ︙ | |||
639 640 641 642 643 644 645 | for(pOp=&aOp[p->pc]; 1; pOp++){ /* Errors are detected by individual opcodes, with an immediate ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); #ifdef VDBE_PROFILE | | | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | for(pOp=&aOp[p->pc]; 1; pOp++){ /* Errors are detected by individual opcodes, with an immediate ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); #ifdef VDBE_PROFILE start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); #endif nVmStep++; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS if( p->anExec ) p->anExec[(int)(pOp-aOp)]++; #endif /* Only allow tracing if SQLITE_DEBUG is defined. |
︙ | ︙ | |||
2163 2164 2165 2166 2167 2168 2169 | ** give a NULL output. */ case OP_And: /* same as TK_AND, in1, in2, out3 */ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ | | < < < < < | < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | > | | 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 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 | ** give a NULL output. */ case OP_And: /* same as TK_AND, in1, in2, out3 */ case OP_Or: { /* same as TK_OR, in1, in2, out3 */ int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */ v1 = sqlite3VdbeBooleanValue(&aMem[pOp->p1], 2); v2 = sqlite3VdbeBooleanValue(&aMem[pOp->p2], 2); if( pOp->opcode==OP_And ){ static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; v1 = and_logic[v1*3+v2]; }else{ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; v1 = or_logic[v1*3+v2]; } pOut = &aMem[pOp->p3]; if( v1==2 ){ MemSetTypeFlag(pOut, MEM_Null); }else{ pOut->u.i = v1; MemSetTypeFlag(pOut, MEM_Int); } break; } /* Opcode: IsTrue P1 P2 P3 P4 * ** Synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 ** ** This opcode implements the IS TRUE, IS FALSE, IS NOT TRUE, and ** IS NOT FALSE operators. ** ** Interpret the value in register P1 as a boolean value. Store that ** boolean (a 0 or 1) in register P2. Or if the value in register P1 is ** NULL, then the P3 is stored in register P2. Invert the answer if P4 ** is 1. ** ** The logic is summarized like this: ** ** <ul> ** <li> If P3==0 and P4==0 then r[P2] := r[P1] IS TRUE ** <li> If P3==1 and P4==1 then r[P2] := r[P1] IS FALSE ** <li> If P3==0 and P4==1 then r[P2] := r[P1] IS NOT TRUE ** <li> If P3==1 and P4==0 then r[P2] := r[P1] IS NOT FALSE ** </ul> */ case OP_IsTrue: { /* in1, out2 */ assert( pOp->p4type==P4_INT32 ); assert( pOp->p4.i==0 || pOp->p4.i==1 ); assert( pOp->p3==0 || pOp->p3==1 ); sqlite3VdbeMemSetInt64(&aMem[pOp->p2], sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3) ^ pOp->p4.i); break; } /* Opcode: Not P1 P2 * * * ** Synopsis: r[P2]= !r[P1] ** ** Interpret the value in register P1 as a boolean value. Store the ** boolean complement in register P2. If the value in register P1 is ** NULL, then a NULL is stored in P2. */ case OP_Not: { /* same as TK_NOT, in1, out2 */ pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; if( (pIn1->flags & MEM_Null)==0 ){ sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeBooleanValue(pIn1,0)); }else{ sqlite3VdbeMemSetNull(pOut); } break; } /* Opcode: BitNot P1 P2 * * * ** Synopsis: r[P1]= ~r[P1] ** |
︙ | ︙ | |||
2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 | /* Opcode: If P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ | > > > > > > > > < | < < < < < < < < < < < | < | 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 | /* Opcode: If P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_If: { /* jump, in1 */ int c; c = sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3); VdbeBranchTaken(c!=0, 2); if( c ) goto jump_to_p2; break; } /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value ** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_IfNot: { /* jump, in1 */ int c; c = !sqlite3VdbeBooleanValue(&aMem[pOp->p1], !pOp->p3); VdbeBranchTaken(c!=0, 2); if( c ) goto jump_to_p2; break; } /* Opcode: IsNull P1 P2 * * * ** Synopsis: if r[P1]==NULL goto P2 ** ** Jump to P2 if the value in register P1 is NULL. |
︙ | ︙ | |||
6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 | pDest->u.nZero = 0; }else{ MemSetTypeFlag(pDest, MEM_Null); } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError>0 ){ rc = sContext.isError; } sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); if( sqlite3VdbeMemTooBig(pDest) ){ | > | 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 | pDest->u.nZero = 0; }else{ MemSetTypeFlag(pDest, MEM_Null); } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pDest)); rc = sContext.isError; } sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); if( sqlite3VdbeMemTooBig(pDest) ){ |
︙ | ︙ | |||
7223 7224 7225 7226 7227 7228 7229 | ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } #ifdef VDBE_PROFILE { | | | 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 | ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } #ifdef VDBE_PROFILE { u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); if( endTime>start ) pOrigOp->cycles += endTime - start; pOrigOp->cnt++; } #endif /* The following code adds nothing to the actual functionality ** of the program. It is only here for testing and debugging. |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
482 483 484 485 486 487 488 489 490 491 492 493 494 495 | void sqlite3VdbeMemSetZeroBlob(Mem*,int); void sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); 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*); | > | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | void sqlite3VdbeMemSetZeroBlob(Mem*,int); void 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*); |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 | ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. ** ** If pMem is not a string object, or the encoding of the string | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif #ifdef SQLITE_DEBUG /* ** Check that string value of pMem agrees with its integer or real value. ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. ** If a table contains a numeric value and an index is based on the ** corresponding string value, then it is important that the string be ** derived from the numeric value, not the other way around, to ensure ** that the index and table are consistent. See ticket ** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for ** an example. ** ** This routine looks at pMem to verify that if it has both a numeric ** representation and a string representation then the string rep has ** been derived from the numeric and not the other way around. It returns ** true if everything is ok and false if there is a problem. ** ** This routine is for use inside of assert() statements only. */ int sqlite3VdbeMemConsistentDualRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1; if( p->flags & MEM_Int ){ sqlite3_snprintf(sizeof(zBuf),zBuf,"%lld",p->u.i); }else{ sqlite3_snprintf(sizeof(zBuf),zBuf,"%!.15g",p->u.r); } z = p->z; i = j = 0; incr = 1; if( p->enc!=SQLITE_UTF8 ){ incr = 2; if( p->enc==SQLITE_UTF16BE ) z++; } while( zBuf[j] ){ if( zBuf[j++]!=z[i] ) return 0; i += incr; } return 1; } #endif /* SQLITE_DEBUG */ /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. ** ** If pMem is not a string object, or the encoding of the string |
︙ | ︙ | |||
522 523 524 525 526 527 528 529 530 531 532 533 534 535 | }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; } } /* ** 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; | > > > > > > > > > > | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; } } /* ** Return 1 if pMem represents true, and return 0 if pMem represents false. ** Return the value ifNull if pMem is NULL. */ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ if( pMem->flags & MEM_Int ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; } /* ** 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; |
︙ | ︙ | |||
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | }else{ sqlite3VdbeMemStringify(pVal, enc, 0); assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ return pVal->z; }else{ return 0; } } /* This function is only available internally, it is not part of the | > | 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 | }else{ sqlite3VdbeMemStringify(pVal, enc, 0); assert( 0==(1&SQLITE_PTR_TO_INT(pVal->z)) ); } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; }else{ return 0; } } /* This function is only available internally, it is not part of the |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 | */ 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( (pVal->flags & MEM_RowSet)==0 ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ return pVal->z; } if( pVal->flags&MEM_Null ){ return 0; } return valueToText(pVal, enc); } | > | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | */ 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( (pVal->flags & MEM_RowSet)==0 ); 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; } return valueToText(pVal, enc); } |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
550 551 552 553 554 555 556 | ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** ** If this call is successful, *ppPage is set to point to the wal-index ** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, ** then an SQLite error code is returned and *ppPage is set to 0. */ | > > > | > | | | | | | | | | | | | | | < > > > > > > > > > > | 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 | ** so. It is safe to enlarge the wal-index if pWal->writeLock is true ** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE. ** ** If this call is successful, *ppPage is set to point to the wal-index ** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, ** then an SQLite error code is returned and *ppPage is set to 0. */ static SQLITE_NOINLINE int walIndexPageRealloc( Wal *pWal, /* The WAL context */ int iPage, /* The page we seek */ volatile u32 **ppPage /* Write the page pointer here */ ){ int rc = SQLITE_OK; /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ int nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); if( !apNew ){ *ppPage = 0; return SQLITE_NOMEM_BKPT; } memset((void*)&apNew[pWal->nWiData], 0, sizeof(u32*)*(iPage+1-pWal->nWiData)); pWal->apWiData = apNew; pWal->nWiData = iPage+1; } /* Request a pointer to the required page from the VFS */ assert( pWal->apWiData[iPage]==0 ); if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ); if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT; }else{ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, pWal->writeLock, (void volatile **)&pWal->apWiData[iPage] ); assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( (rc&0xff)==SQLITE_READONLY ){ pWal->readOnly |= WAL_SHM_RDONLY; if( rc==SQLITE_READONLY ){ rc = SQLITE_OK; } } } *ppPage = pWal->apWiData[iPage]; assert( iPage==0 || *ppPage || rc!=SQLITE_OK ); return rc; } static int walIndexPage( Wal *pWal, /* The WAL context */ int iPage, /* The page we seek */ volatile u32 **ppPage /* Write the page pointer here */ ){ if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){ return walIndexPageRealloc(pWal, iPage, ppPage); } return SQLITE_OK; } /* ** Return a pointer to the WalCkptInfo structure in the wal-index. */ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){ assert( pWal->nWiData>0 && pWal->apWiData[0] ); |
︙ | ︙ | |||
2864 2865 2866 2867 2868 2869 2870 | ** This condition filters out normal hash-table collisions. ** ** (iFrame<=iLast): ** This condition filters out entries that were added to the hash ** table after the current read-transaction had started. */ iMinHash = walFramePage(pWal->minFrame); | | | 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 | ** This condition filters out normal hash-table collisions. ** ** (iFrame<=iLast): ** This condition filters out entries that were added to the hash ** table after the current read-transaction had started. */ iMinHash = walFramePage(pWal->minFrame); for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){ volatile ht_slot *aHash; /* Pointer to hash table */ volatile u32 *aPgno; /* Pointer to array of page numbers */ u32 iZero; /* Frame number corresponding to aPgno[0] */ int iKey; /* Hash slot index */ int nCollide; /* Number of hash collisions remaining */ int rc; /* Error code */ |
︙ | ︙ | |||
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 | assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ return SQLITE_CORRUPT_BKPT; } } } #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* If expensive assert() statements are available, do a linear search ** of the wal-index file content. Make sure the results agree with the ** result obtained using the hash indexes above. */ { | > | 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 | assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ return SQLITE_CORRUPT_BKPT; } } if( iRead ) break; } #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT /* If expensive assert() statements are available, do a linear search ** of the wal-index file content. Make sure the results agree with the ** result obtained using the hash indexes above. */ { |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
2477 2478 2479 2480 2481 2482 2483 | }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); if( iCol==XN_ROWID || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ | | > > | | | 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 | }else if( eOp & (WO_EQ|WO_IS) ){ int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); if( iCol==XN_ROWID || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol==XN_ROWID || pProbe->uniqNotNull || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ) ){ pNew->wsFlags |= WHERE_ONEROW; }else{ pNew->wsFlags |= WHERE_UNQ_WANTED; } } }else if( eOp & WO_ISNULL ){ pNew->wsFlags |= WHERE_COLUMN_NULL; }else if( eOp & (WO_GT|WO_GE) ){ testcase( eOp & WO_GT ); testcase( eOp & WO_GE ); |
︙ | ︙ | |||
4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 | ** preserves SQLite's legacy behaviour in the following two cases: ** ** FROM ... WHERE random()>0; -- eval random() once per row ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ for(ii=0; ii<sWLB.pWC->nTerm; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } if( wctrlFlags & WHERE_WANT_DISTINCT ){ | > | 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 | ** preserves SQLite's legacy behaviour in the following two cases: ** ** FROM ... WHERE random()>0; -- eval random() once per row ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ for(ii=0; ii<sWLB.pWC->nTerm; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->wtFlags & TERM_VIRTUAL ) continue; if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } if( wctrlFlags & WHERE_WANT_DISTINCT ){ |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
1391 1392 1393 1394 1395 1396 1397 | testcase( pStart->wtFlags & TERM_VIRTUAL ); pX = pStart->pExpr; assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ if( sqlite3ExprIsVector(pX->pRight) ){ r1 = rTemp = sqlite3GetTempReg(pParse); codeExprOrVector(pParse, pX->pRight, r1, 1); | > > > > | > > > > | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 | testcase( pStart->wtFlags & TERM_VIRTUAL ); pX = pStart->pExpr; assert( pX!=0 ); testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ if( sqlite3ExprIsVector(pX->pRight) ){ r1 = rTemp = sqlite3GetTempReg(pParse); codeExprOrVector(pParse, pX->pRight, r1, 1); testcase( pX->op==TK_GT ); testcase( pX->op==TK_GE ); testcase( pX->op==TK_LT ); testcase( pX->op==TK_LE ); op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1]; assert( pX->op!=TK_GT || op==OP_SeekGE ); assert( pX->op!=TK_GE || op==OP_SeekGE ); assert( pX->op!=TK_LT || op==OP_SeekLE ); assert( pX->op!=TK_LE || op==OP_SeekLE ); }else{ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); disableTerm(pLevel, pStart); op = aMoveOp[(pX->op - TK_GT)]; } sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1); VdbeComment((v, "pk")); |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
872 873 874 875 876 877 878 879 880 881 882 883 884 885 | mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); if( ALWAYS(pSrc!=0) ){ int i; for(i=0; i<pSrc->nSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); } } pS = pS->pPrior; } return mask; } | > > > | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); if( ALWAYS(pSrc!=0) ){ int i; for(i=0; i<pSrc->nSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); if( pSrc->a[i].fg.isTabFunc ){ mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg); } } } pS = pS->pPrior; } return mask; } |
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 | pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); } pTerm = &pWC->a[idxTerm]; | | | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight); transferJoinMarkings(pNew, pExpr); idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC); exprAnalyze(pSrc, pWC, idxNew); } pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */ pTerm->eOperator = 0; } /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create ** a virtual term for each vector component. The expression object ** used by each such virtual term is pExpr (the full vector IN(...) ** expression). The WhereTerm.iField variable identifies the index within |
︙ | ︙ |
Changes to test/cast.test.
︙ | ︙ | |||
339 340 341 342 343 344 345 346 | } {abc 0 abc} do_test cast-4.4 { db eval { SELECT CAST(a AS integer), a, CAST(a AS real), a FROM t1; } } {0 abc 0.0 abc} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {abc 0 abc} do_test cast-4.4 { db eval { SELECT CAST(a AS integer), a, CAST(a AS real), a FROM t1; } } {0 abc 0.0 abc} # Added 2018-01-26 # # EVIDENCE-OF: R-48741-32454 If the prefix integer is greater than # +9223372036854775807 then the result of the cast is exactly # +9223372036854775807. do_execsql_test cast-5.1 { SELECT CAST('9223372036854775808' AS integer); SELECT CAST(' +000009223372036854775808' AS integer); SELECT CAST('12345678901234567890123' AS INTEGER); } {9223372036854775807 9223372036854775807 9223372036854775807} # EVIDENCE-OF: R-06028-16857 Similarly, if the prefix integer is less # than -9223372036854775808 then the result of the cast is exactly # -9223372036854775808. do_execsql_test cast-5.2 { SELECT CAST('-9223372036854775808' AS integer); SELECT CAST('-9223372036854775809' AS integer); SELECT CAST('-12345678901234567890123' AS INTEGER); } {-9223372036854775808 -9223372036854775808 -9223372036854775808} # EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks # like a floating point value with an exponent, the exponent will be # ignored because it is no part of the integer prefix. # EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)" # results in 123, not in 12300000. do_execsql_test case-5.3 { SELECT CAST('123e+5' AS INTEGER); SELECT CAST('123e+5' AS NUMERIC); } {123 12300000.0} # The following does not have anything to do with the CAST operator, # but it does deal with affinity transformations. # do_execsql_test case-6.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a NUMERIC); INSERT INTO t1 VALUES ('9000000000000000001'), ('9000000000000000001 '), (' 9000000000000000001'), (' 9000000000000000001 '); SELECT * FROM t1; } {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001} finish_test |
Changes to test/expr.test.
︙ | ︙ | |||
973 974 975 976 977 978 979 | do_execsql_test expr-13.8 { SELECT "" <= ''; } {1} do_execsql_test expr-13.9 { SELECT '' <= ""; } {1} | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test expr-13.8 { SELECT "" <= ''; } {1} do_execsql_test expr-13.9 { SELECT '' <= ""; } {1} # 2018-02-26. Ticket https://www.sqlite.org/src/tktview/36fae083b450e3af85 # do_execsql_test expr-14.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); INSERT INTO t1 VALUES(0),(1),(NULL),(0.5),('1x'),('0x'); SELECT count(*) FROM t1 WHERE (x OR (8==9)) != (CASE WHEN x THEN 1 ELSE 0 END); } {0} do_execsql_test expr-14.2 { SELECT count(*) FROM t1 WHERE (x OR (8==9)) != (NOT NOT x); } {0} do_execsql_test expr-14.3 { SELECT sum(NOT x) FROM t1 WHERE x } {0} do_execsql_test expr-14.4 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} foreach {tn val} [list 1 NaN 2 -NaN 3 NaN0 4 -NaN0 5 Inf 6 -Inf] { do_execsql_test expr-15.$tn.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); INSERT INTO t1 VALUES(0),(1),(NULL),(0.5),('1x'),('0x'); } do_test expr-15.$tn.2 { set ::STMT [sqlite3_prepare db "INSERT INTO t1 VALUES(?)" -1 TAIL] sqlite3_bind_double $::STMT 1 $val sqlite3_step $::STMT sqlite3_reset $::STMT sqlite3_finalize $::STMT } {SQLITE_OK} do_execsql_test expr-15.$tn.3 { SELECT count(*) FROM t1 WHERE (x OR (8==9)) != (CASE WHEN x THEN 1 ELSE 0 END); } {0} do_execsql_test expr-15.$tn.4 { SELECT count(*) FROM t1 WHERE (x OR (8==9)) != (NOT NOT x); } {0} do_execsql_test expr-15.$tn.5 { SELECT sum(NOT x) FROM t1 WHERE x } {0} do_execsql_test expr-15.$tn.6 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} } finish_test |
Changes to test/fts3aa.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 253 | do_execsql_test 9.1 { CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---'); } do_execsql_test 9.2 { CREATE VIRTUAL TABLE t10 USING fts3(<, b, c); } finish_test | > | 246 247 248 249 250 251 252 253 254 | do_execsql_test 9.1 { CREATE VIRTUAL TABLE t9 USING fts4(a, "", '---'); } do_execsql_test 9.2 { CREATE VIRTUAL TABLE t10 USING fts3(<, b, c); } expand_all_sql db finish_test |
Changes to test/fts4onepass.test.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 | do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content do_execsql_test 3.$tn.$tn2.c { INSERT INTO ft2(ft2) VALUES('integrity-check'); } } eval $tcl2 } finish_test | > > > > > > > > > > > > > > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | do_execsql_test 3.$tn.$tn2.b { SELECT rowid, content FROM ft2 } $content do_execsql_test 3.$tn.$tn2.c { INSERT INTO ft2(ft2) VALUES('integrity-check'); } } eval $tcl2 } do_execsql_test 4.0 { CREATE VIRTUAL TABLE zt USING fts4(a, b); INSERT INTO zt(rowid, a, b) VALUES(1, 'unus duo', NULL); INSERT INTO zt(rowid, a, b) VALUES(2, NULL, NULL); BEGIN; UPDATE zt SET b='septum' WHERE rowid = 1; UPDATE zt SET b='octo' WHERE rowid = 1; COMMIT; SELECT count(*) FROM zt_segdir; } {3} finish_test |
Changes to test/func.test.
︙ | ︙ | |||
503 504 505 506 507 508 509 510 511 512 513 514 515 516 | do_test func-9.12-utf8 { execsql {SELECT hex(replace('abcdefg','','12'))} } {61626364656667} do_test func-9.13-utf8 { execsql {SELECT hex(replace('aabcdefg','a','aaa'))} } {616161616161626364656667} } # Use the "sqlite_register_test_function" TCL command which is part of # the text fixture in order to verify correct operation of some of # the user-defined SQL function APIs that are not used by the built-in # functions. # set ::DB [sqlite3_connection_pointer db] | > > > > > > > > > > > | 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 | do_test func-9.12-utf8 { execsql {SELECT hex(replace('abcdefg','','12'))} } {61626364656667} do_test func-9.13-utf8 { execsql {SELECT hex(replace('aabcdefg','a','aaa'))} } {616161616161626364656667} } do_execsql_test func-9.14 { WITH RECURSIVE c(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1040 ) SELECT count(*), sum(length(replace(printf('abc%.*cxyz',x,'m'),'m','nnnn'))-(6+x*4)) FROM c; } {1040 0} # Use the "sqlite_register_test_function" TCL command which is part of # the text fixture in order to verify correct operation of some of # the user-defined SQL function APIs that are not used by the built-in # functions. # set ::DB [sqlite3_connection_pointer db] |
︙ | ︙ |
Changes to test/func6.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !offset_sql_func { finish_test return } do_execsql_test func6-100 { PRAGMA page_size=4096; PRAGMA auto_vacuum=NONE; CREATE TABLE t1(a,b,c,d); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c; CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b,c); CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID; INSERT INTO t2(x,y) SELECT a, b FROM t1; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > | > | > > > > | > > < | > | | < < | | | | < < | < | | > | < > < < | < | < | | | < | > < | | < < | 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 | # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !offset_sql_func { finish_test return } set bNullTrim 0 ifcapable null_trim { set bNullTrim 1 } do_execsql_test func6-100 { PRAGMA page_size=4096; PRAGMA auto_vacuum=NONE; CREATE TABLE t1(a,b,c,d); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c; CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b,c); CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID; INSERT INTO t2(x,y) SELECT a, b FROM t1; } # Load the contents of $file from disk and return it encoded as a hex # string. proc loadhex {file} { set fd [open $file] fconfigure $fd -translation binary -encoding binary set data [read $fd] close $fd binary encode hex $data } # Each argument is either an integer between 0 and 65535, a text value, or # an empty string representing an SQL NULL. This command builds an SQLite # record containing the values passed as arguments and returns it encoded # as a hex string. proc hexrecord {args} { set hdr "" set body "" if {$::bNullTrim} { while {[llength $args] && [lindex $args end]=={}} { set args [lrange $args 0 end-1] } } foreach x $args { if {$x==""} { append hdr 00 } elseif {[string is integer $x]==0} { set n [string length $x] append hdr [format %02x [expr $n*2 + 13]] append body [binary encode hex $x] } elseif {$x == 0} { append hdr 08 } elseif {$x == 1} { append hdr 09 } elseif {$x <= 127} { append hdr 01 append body [format %02x $x] } else { append hdr 02 append body [format %04x $x] } } set res [format %02x [expr 1 + [string length $hdr]/2]] append res $hdr append res $body } # Argument $off is an offset into the database image encoded as a hex string # in argument $hexdb. This command returns 0 if the offset contains the hex # $hexrec, or throws an exception otherwise. # proc offset_contains_record {off hexdb hexrec} { set n [string length $hexrec] set off [expr $off*2] if { [string compare $hexrec [string range $hexdb $off [expr $off+$n-1]]] } { error "record not found!" } return 0 } # This command is the implementation of SQL function "offrec()". The first # argument to this is an offset value. The remaining values are used to # formulate an SQLite record. If database file test.db does not contain # an equivalent record at the specified offset, an exception is thrown. # Otherwise, 0 is returned. # proc offrec {args} { set offset [lindex $args 0] set rec [hexrecord {*}[lrange $args 1 end]] offset_contains_record $offset $::F $rec } set F [loadhex test.db] db func offrec offrec # Test the sanity of the tests. if {$bNullTrim} { set offset 8180 } else { set offset 8179 } do_execsql_test func6-105 { SELECT sqlite_offset(d) FROM t1 ORDER BY rowid LIMIT 1; } $offset do_test func6-106 { set r [hexrecord abc001 1 999 {}] offset_contains_record $offset $F $r } 0 set z100 [string trim [string repeat "0 " 100]] # Test offsets within table b-tree t1. do_execsql_test func6-110 { SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY rowid } $z100 do_execsql_test func6-120 { SELECT a, typeof(sqlite_offset(+a)) FROM t1 ORDER BY rowid LIMIT 2; } {abc001 null abc002 null} # Test offsets within index b-tree t1a. do_execsql_test func6-130 { SELECT offrec(sqlite_offset(a), a, rowid) FROM t1 ORDER BY a } $z100 # Test offsets within table b-tree t1 with a temp b-tree ORDER BY. do_execsql_test func6-140 { SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a } $z100 # Test offsets from both index t1a and table t1 in the same query. do_execsql_test func6-150 { SELECT offrec(sqlite_offset(a), a, rowid), offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a } [concat $z100 $z100] # Test offsets from both index t1bc and table t1 in the same query. do_execsql_test func6-160 { SELECT offrec(sqlite_offset(b), b, c, rowid), offrec(sqlite_offset(c), b, c, rowid), offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY b } [concat $z100 $z100 $z100] # Test offsets in WITHOUT ROWID table t2. do_execsql_test func6-200 { SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x } $z100 finish_test |
Changes to test/indexexpr1.test.
︙ | ︙ | |||
420 421 422 423 424 425 426 427 428 | DROP TABLE IF EXISTS t1; CREATE TABLE t1(a PRIMARY KEY,b UNIQUE); REPLACE INTO t1 VALUES(2, 1); REPLACE INTO t1 SELECT 6,1; CREATE INDEX t1aa ON t1(a-a); REPLACE INTO t1 SELECT a, randomblob(a) FROM t1 } {} finish_test | > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE IF EXISTS t1; CREATE TABLE t1(a PRIMARY KEY,b UNIQUE); REPLACE INTO t1 VALUES(2, 1); REPLACE INTO t1 SELECT 6,1; CREATE INDEX t1aa ON t1(a-a); REPLACE INTO t1 SELECT a, randomblob(a) FROM t1 } {} # 2018-01-31 https://www.sqlite.org/src/tktview/343634942dd54ab57b702411 # When an index on an expression depends on the string representation of # a numeric table column, trouble can arise since there are multiple # string that can map to the same numeric value. (Ex: 123, 0123, 000123). # do_execsql_test indexexpr-1600 { DROP TABLE IF EXISTS t1; CREATE TABLE t1 (a INTEGER, b); CREATE INDEX idx1 ON t1 (lower(a)); INSERT INTO t1 VALUES('0001234',3); PRAGMA integrity_check; } {ok} do_execsql_test indexexpr-1610 { INSERT INTO t1 VALUES('1234',0),('001234',2),('01234',1); SELECT b FROM t1 WHERE lower(a)='1234' ORDER BY +b; } {0 1 2 3} do_execsql_test indexexpr-1620 { SELECT b FROM t1 WHERE lower(a)='01234' ORDER BY +b; } {} finish_test |
Added test/istrue.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 | # 2018-02-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 expressions of the form # # x IS TRUE # x IS FALSE # x IS NOT TRUE # x IS NOT FALSE # # Tests are also included for the use of TRUE and FALSE as # literal values. set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test istrue-100 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y BOOLEAN); INSERT INTO t1 VALUES(1, true),(2, false),(3, null); SELECT x FROM t1 WHERE y IS TRUE; } {1} do_execsql_test istrue-110 { SELECT x FROM t1 WHERE y IS FALSE; } {2} do_execsql_test istrue-120 { SELECT x FROM t1 WHERE y IS NULL; } {3} do_execsql_test istrue-130 { SELECT x FROM t1 WHERE y IS NOT TRUE; } {2 3} do_execsql_test istrue-140 { SELECT x FROM t1 WHERE y IS NOT FALSE; } {1 3} do_execsql_test istrue-150 { SELECT x FROM t1 WHERE y IS NOT NULL; } {1 2} unset -nocomplain X set X 9 do_execsql_test istrue-160 { SELECT x FROM t1 WHERE y IS TRUE OR (8==$X) } {1} do_execsql_test istrue-170 { SELECT x FROM t1 WHERE y IS FALSE OR (8==$X) } {2} do_execsql_test istrue-180 { SELECT x FROM t1 WHERE y IS NULL OR (8==$X); } {3} do_execsql_test istrue-190 { SELECT x FROM t1 WHERE y IS NOT TRUE OR (8==$X); } {2 3} do_execsql_test istrue-200 { SELECT x FROM t1 WHERE y IS NOT FALSE OR (8==$X); } {1 3} do_execsql_test istrue-210 { SELECT x FROM t1 WHERE y IS NOT NULL OR (8==$X); } {1 2} do_execsql_test istrue-300 { SELECT x, y IS TRUE, y IS FALSE, y is NULL, y IS NOT TRUE, y IS NOT FALSE, y IS NOT NULL, '|' FROM t1 ORDER BY x; } {1 1 0 0 0 1 1 | 2 0 1 0 1 0 1 | 3 0 0 1 1 1 0 |} do_execsql_test istrue-400 { SELECT x FROM t1 WHERE true; } {1 2 3} do_execsql_test istrue-410 { SELECT x FROM t1 WHERE false; } {} do_execsql_test istrue-500 { CREATE TABLE t2( a INTEGER PRIMARY KEY, b BOOLEAN DEFAULT true, c BOOLEAN DEFAULT(true), d BOOLEAN DEFAULT false, e BOOLEAN DEFAULT(false) ); INSERT INTO t2 DEFAULT VALUES; SELECT * FROM t2; } {1 1 1 0 0} do_execsql_test istrue-510 { DROP TABLE t2; CREATE TABLE t2( a INTEGER PRIMARY KEY, b BOOLEAN DEFAULT(not true), c BOOLEAN DEFAULT(not false) ); INSERT INTO t2(a) VALUES(99); SELECT * FROM t2; } {99 0 1} do_execsql_test istrue-520 { DROP TABLE t2; CREATE TABLE t2( a INTEGER PRIMARY KEY, b BOOLEAN CHECK(b IS TRUE), c BOOLEAN CHECK(c IS FALSE), d BOOLEAN CHECK(d IS NOT TRUE), e BOOLEAN CHECK(e IS NOT FALSE) ); INSERT INTO t2 VALUES(1,true,false,null,null); SELECT * FROM t2; } {1 1 0 {} {}} do_catchsql_test istrue-521 { INSERT INTO t2 VALUES(2,false,false,null,null); } {1 {CHECK constraint failed: t2}} do_catchsql_test istrue-522 { INSERT INTO t2 VALUES(2,true,true,null,null); } {1 {CHECK constraint failed: t2}} do_catchsql_test istrue-523 { INSERT INTO t2 VALUES(2,true,false,true,null); } {1 {CHECK constraint failed: t2}} do_catchsql_test istrue-524 { INSERT INTO t2 VALUES(2,true,false,null,false); } {1 {CHECK constraint failed: t2}} finish_test |
Changes to test/join2.test.
︙ | ︙ | |||
151 152 153 154 155 156 157 | SELECT DISTINCT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 1112 {}} do_execsql_test 4.1.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | SELECT DISTINCT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 1112 {}} do_execsql_test 4.1.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { 0 0 0 {SCAN TABLE c1} 0 1 1 {SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)} 0 2 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test 4.1.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { 0 0 0 {SCAN TABLE c1} 0 1 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test 4.2.0 { DROP TABLE c1; DROP TABLE c2; DROP TABLE c3; CREATE TABLE c1(k UNIQUE, v1); CREATE TABLE c2(k UNIQUE, v2); CREATE TABLE c3(k UNIQUE, v3); INSERT INTO c1 VALUES(1, 2); INSERT INTO c2 VALUES(2, 3); INSERT INTO c3 VALUES(3, 'v3'); INSERT INTO c1 VALUES(111, 1112); INSERT INTO c2 VALUES(112, 1113); INSERT INTO c3 VALUES(113, 'v1113'); } do_execsql_test 4.2.1 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } {2 v3 1112 {}} do_execsql_test 4.2.2 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 1112 {}} do_execsql_test 4.2.3 { SELECT DISTINCT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 1112 {}} do_execsql_test 4.2.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { 0 0 0 {SCAN TABLE c1} 0 1 1 {SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?)} 0 2 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)} } do_eqp_test 4.2.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { 0 0 0 {SCAN TABLE c1} 0 1 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)} } # 2017-11-23 (Thanksgiving day) # OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code. # do_execsql_test 4.3.0 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; |
︙ | ︙ | |||
187 188 189 190 191 192 193 194 195 | INSERT INTO t1(x) SELECT x FROM c; INSERT INTO t2(x) SELECT x+9 FROM t1; SELECT a.x, c.x FROM t1 AS a LEFT JOIN t1 AS b ON (a.x=b.x) LEFT JOIN t2 AS c ON (a.x=c.x); } {1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {} 8 {} 9 {} 10 10} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t1(x) SELECT x FROM c; INSERT INTO t2(x) SELECT x+9 FROM t1; SELECT a.x, c.x FROM t1 AS a LEFT JOIN t1 AS b ON (a.x=b.x) LEFT JOIN t2 AS c ON (a.x=c.x); } {1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {} 8 {} 9 {} 10 10} do_execsql_test 5.0 { CREATE TABLE s1 (a INTEGER PRIMARY KEY); CREATE TABLE s2 (a INTEGER PRIMARY KEY); CREATE TABLE s3 (a INTEGER); CREATE UNIQUE INDEX ndx on s3(a); } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); } { 0 0 0 {SCAN TABLE s1} } do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); } { 0 0 0 {SCAN TABLE s1} } do_execsql_test 6.0 { CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX u1ab ON u1(b, c); } do_eqp_test 6.1 { SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c ); } { 0 0 0 {SCAN TABLE u2} } finish_test |
Changes to test/json101.test.
︙ | ︙ | |||
755 756 757 758 759 760 761 | FROM t12; } {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}} do_execsql_test json-12.120 { SELECT json_extract(x, '$.settings.layer2."tris.legomenon"."summary.report"') FROM t12; } {0} | > > > | > > > > > > > > > > > > > > > > > > > > | 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 | FROM t12; } {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}} do_execsql_test json-12.120 { SELECT json_extract(x, '$.settings.layer2."tris.legomenon"."summary.report"') FROM t12; } {0} # 2018-01-26 # ticket https://www.sqlite.org/src/tktview/80177f0c226ff54f6ddd41 # Make sure the query planner knows about the arguments to table-valued functions. # do_execsql_test json-13.100 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(id, json); INSERT INTO t1(id,json) VALUES(1,'{"items":[3,5]}'); CREATE TABLE t2(id, json); INSERT INTO t2(id,json) VALUES(2,'{"value":2}'); INSERT INTO t2(id,json) VALUES(3,'{"value":3}'); INSERT INTO t2(id,json) VALUES(4,'{"value":4}'); INSERT INTO t2(id,json) VALUES(5,'{"value":5}'); INSERT INTO t2(id,json) VALUES(6,'{"value":6}'); SELECT * FROM t1 CROSS JOIN t2 WHERE EXISTS(SELECT 1 FROM json_each(t1.json,'$.items') AS Z WHERE Z.value==t2.id); } {1 {{"items":[3,5]}} 3 {{"value":3}} 1 {{"items":[3,5]}} 5 {{"value":5}}} do_execsql_test json-13.110 { SELECT * FROM t2 CROSS JOIN t1 WHERE EXISTS(SELECT 1 FROM json_each(t1.json,'$.items') AS Z WHERE Z.value==t2.id); } {3 {{"value":3}} 1 {{"items":[3,5]}} 5 {{"value":5}} 1 {{"items":[3,5]}}} finish_test |
Changes to test/nockpt.test.
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 | } {1 2 3 4 5 6 7 8 9} do_execsql_test 1.13 { PRAGMA main.journal_mode } {wal} do_test 1.14 { sqlite3_db_config db NO_CKPT_ON_CLOSE 1 } {1} do_execsql_test 1.14 { PRAGMA main.journal_mode = delete } {delete} do_test 1.15 { file exists test.db-wal } {0} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 2 3 4 5 6 7 8 9} do_execsql_test 1.13 { PRAGMA main.journal_mode } {wal} do_test 1.14 { sqlite3_db_config db NO_CKPT_ON_CLOSE 1 } {1} do_execsql_test 1.14 { PRAGMA main.journal_mode = delete } {delete} do_test 1.15 { file exists test.db-wal } {0} if {$::tcl_platform(platform)!="windows"} { #------------------------------------------------------------------------- # Test an unusual scenario: # # 1. A wal mode db is opened and written. Then sqlite3_close_v2() used # to close the db handle while there is still an unfinalized # statement (so the db handle stays open). # # 2. The db, wal and *-shm files are deleted from the file system. # # 3. Another connection creates a new wal mode db at the same file-system # location as the previous one. # # 4. The statement left unfinalized in (1) is finalized. # # The test is to ensure that the connection left open in step (1) does # not try to delete the wal file from the file-system as part of step # 4. # reset_db db close # Open a connection on a wal database. Write to it a bit. Then prepare # a statement and call sqlite3_close_v2() (so that the statement handle # holds the db connection open). # set ::db1 [sqlite3_open_v2 test.db SQLITE_OPEN_READWRITE ""] do_test 2.0 { lindex [ sqlite3_exec $::db1 { PRAGMA journal_mode = wal; CREATE TABLE t1(x PRIMARY KEY, y UNIQUE, z); INSERT INTO t1 VALUES(1, 2, 3); PRAGMA wal_checkpoint; }] 0 } {0} set ::stmt [sqlite3_prepare $::db1 "SELECT * FROM t1" -1 dummy] sqlite3_close_v2 $::db1 # Delete the database, wal and shm files. # forcedelete test.db test.db-wal test.db-shm # Open and populate a new database file at the same file-system location # as the one just deleted. Contrive a partial checkpoint on it. # sqlite3 db test.db sqlite3 db2 test.db do_execsql_test 2.1 { PRAGMA journal_mode = wal; CREATE TABLE y1(a PRIMARY KEY, b UNIQUE, c); INSERT INTO y1 VALUES('a', 'b', 'c'); INSERT INTO y1 VALUES('d', 'e', 'f'); } {wal} do_execsql_test -db db2 2.2 { BEGIN; SELECT * FROM y1; } {a b c d e f} do_execsql_test 2.3 { UPDATE y1 SET c='g' WHERE a='d'; PRAGMA wal_checkpoint; } {0 11 10} do_execsql_test -db db2 2.4 { COMMIT } # Finalize the statement handle, causing the first connection to be # closed. Test that this has not corrupted the database file by # deleting the new wal file from the file-system. If it has, this # test should fail with an IO or corruption error. # do_test 2.5 { sqlite3_finalize $::stmt sqlite3 db3 test.db execsql { PRAGMA integrity_check; SELECT * FROM y1; } db3 } {ok a b c d e g} } finish_test |
Added test/normalize.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-01-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. # #*********************************************************************** # # Tests for the sqlite3_normalize() extension function. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix normalize foreach {tnum sql norm} { 100 {SELECT * FROM t1 WHERE a IN (1) AND b=51.42} {select*from t1 where a in(?,?,?)and b=?;} 110 {SELECT a, b+15, c FROM t1 WHERE d NOT IN (SELECT x FROM t2);} {select a,b+?,c from t1 where d not in(select x from t2);} 120 { SELECT NULL, b FROM t1 -- comment text WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */ SELECT a FROM t) OR e='hello'; } {select?,b from t1 where d in(with t(a)as(values(?))select a from t)or e=?;} 121 {/*Initial comment*/ -- another comment line SELECT NULL /* comment */ , b FROM t1 -- comment text WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */ SELECT a FROM t) OR e='hello'; } {select?,b from t1 where d in(with t(a)as(values(?))select a from t)or e=?;} 130 {/* Query containing parameters */ SELECT x,$::abc(15),y,@abc,z,?99,w FROM t1 /* Trailing comment */} {select x,?,y,?,z,?,w from t1;} 140 {/* Long list on the RHS of IN */ SELECT 15 IN (1,2,3,(SELECT * FROM t1),'xyz',x'abcd',22*(x+5),null);} {select?in(?,?,?);} 150 {SELECT x'abc'; -- illegal token} {} 160 {SELECT a,NULL,b FROM t1 WHERE c IS NOT NULL or D is null or e=5} {select a,?,b from t1 where c is not null or d is null or e=?;} 170 {/* IN list exactly 5 bytes long */ SELECT * FROM t1 WHERE x IN (1,2,3);} {select*from t1 where x in(?,?,?);} } { do_test $tnum [list sqlite3_normalize $sql] $norm } finish_test |
Changes to test/notnull.test.
︙ | ︙ | |||
557 558 559 560 561 562 563 564 | } } {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-5.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-5.5 { execsql { SELECT * FROM t1 } } {1 2} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } {1 {NOT NULL constraint failed: t1.b}} verify_ex_errcode notnull-5.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-5.5 { execsql { SELECT * FROM t1 } } {1 2} #------------------------------------------------------------------------- # Check that UNIQUE NOT NULL indexes are always recognized as such. # proc uses_op_next {sql} { db eval "EXPLAIN $sql" a { if {$a(opcode)=="Next"} { return 1 } } return 0 } proc do_uses_op_next_test {tn sql res} { uplevel [list do_test $tn [list uses_op_next $sql] $res] } reset_db do_execsql_test notnull-6.0 { CREATE TABLE t1(a UNIQUE); CREATE TABLE t2(a NOT NULL UNIQUE); CREATE TABLE t3(a UNIQUE NOT NULL); CREATE TABLE t4(a NOT NULL); CREATE UNIQUE INDEX t4a ON t4(a); CREATE TABLE t5(a PRIMARY KEY); CREATE TABLE t6(a PRIMARY KEY NOT NULL); CREATE TABLE t7(a NOT NULL PRIMARY KEY); CREATE TABLE t8(a PRIMARY KEY) WITHOUT ROWID; CREATE TABLE t9(a PRIMARY KEY UNIQUE NOT NULL); CREATE TABLE t10(a UNIQUE PRIMARY KEY NOT NULL); } do_uses_op_next_test notnull-6.1 "SELECT * FROM t1 WHERE a IS ?" 1 do_uses_op_next_test notnull-6.2 "SELECT * FROM t2 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.3 "SELECT * FROM t3 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.4 "SELECT * FROM t4 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.5 "SELECT * FROM t5 WHERE a IS ?" 1 do_uses_op_next_test notnull-6.6 "SELECT * FROM t6 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.7 "SELECT * FROM t7 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.8 "SELECT * FROM t8 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.9 "SELECT * FROM t8 WHERE a IS ?" 0 do_uses_op_next_test notnull-6.10 "SELECT * FROM t8 WHERE a IS ?" 0 finish_test |
Changes to test/printf2.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 151 152 153 | do_execsql_test printf2-4.9 { SELECT printf('|%,d|%,d|',123456789,-123456789); } {|123,456,789|-123,456,789|} do_execsql_test printf2-4.10 { SELECT printf('|%,d|%,d|',1234567890,-1234567890); } {|1,234,567,890|-1,234,567,890|} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test printf2-4.9 { SELECT printf('|%,d|%,d|',123456789,-123456789); } {|123,456,789|-123,456,789|} do_execsql_test printf2-4.10 { SELECT printf('|%,d|%,d|',1234567890,-1234567890); } {|1,234,567,890|-1,234,567,890|} # 2018-02-19. Unicode characters with %c do_execsql_test printf2-5.100 { SELECT printf('(%8c)',char(11106)); } {{( ⭢)}} do_execsql_test printf2-5.101 { SELECT printf('(%-8c)',char(11106)); } {{(⭢ )}} do_execsql_test printf2-5.102 { SELECT printf('(%5.3c)',char(1492)); } {{( ההה)}} do_execsql_test printf2-5.103 { SELECT printf('(%-5.3c)',char(1492)); } {{(ההה )}} do_execsql_test printf2-5.104 { SELECT printf('(%3.3c)',char(1492)); } {{(ההה)}} do_execsql_test printf2-5.105 { SELECT printf('(%-3.3c)',char(1492)); } {{(ההה)}} do_execsql_test printf2-5.104 { SELECT printf('(%2c)',char(1513)); } {{( ש)}} do_execsql_test printf2-5.106 { SELECT printf('(%-2c)',char(1513)); } {{(ש )}} # 2018-02-19. Unicode characters with the "!" flag in %s and friends. do_execsql_test printf2-6.100 { SELECT printf('(%!.3s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {(הנה)} do_execsql_test printf2-6.101 { SELECT printf('(%.6s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {(הנה)} do_execsql_test printf2-6.102 { SELECT printf('(%!5.3s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{( הנה)}} do_execsql_test printf2-6.103 { SELECT printf('(%8.6s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{( הנה)}} do_execsql_test printf2-6.104 { SELECT printf('(%!-5.3s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{(הנה )}} do_execsql_test printf2-6.105 { SELECT printf('(%-8.6s)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{(הנה )}} do_execsql_test printf2-6.106 { SELECT printf('(%!.3Q)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {('הנה')} do_execsql_test printf2-6.107 { SELECT printf('(%.6Q)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {('הנה')} do_execsql_test printf2-6.108 { SELECT printf('(%!7.3Q)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{( 'הנה')}} do_execsql_test printf2-6.109 { SELECT printf('(%10.6Q)','הנה מה־טוב ומה־נעים שבת אחים גם־יחד'); } {{( 'הנה')}} finish_test |
Changes to test/rowvalue.test.
︙ | ︙ | |||
433 434 435 436 437 438 439 | } {1 1 1 1 2 1} do_execsql_test 18.6 { SELECT * FROM b3 JOIN b4 ON b4.a = b3.a WHERE (b3.a, b3.b) IN ( SELECT a, b FROM b5 ); } {1 1 1 1 2 1} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | 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 | } {1 1 1 1 2 1} do_execsql_test 18.6 { SELECT * FROM b3 JOIN b4 ON b4.a = b3.a WHERE (b3.a, b3.b) IN ( SELECT a, b FROM b5 ); } {1 1 1 1 2 1} # 2018-02-13 Ticket https://www.sqlite.org/src/tktview/f484b65f3d6230593c3 # Incorrect result from a row-value comparison in the WHERE clause. # do_execsql_test 19.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY,b); INSERT INTO t1(a,b) VALUES(1,11),(2,22),(3,33),(4,44); SELECT * FROM t1 WHERE (a,b)>(0,0) ORDER BY a; } {1 11 2 22 3 33 4 44} do_execsql_test 19.2 { SELECT * FROM t1 WHERE (a,b)>=(0,0) ORDER BY a; } {1 11 2 22 3 33 4 44} do_execsql_test 19.3 { SELECT * FROM t1 WHERE (a,b)<(5,0) ORDER BY a DESC; } {4 44 3 33 2 22 1 11} do_execsql_test 19.4 { SELECT * FROM t1 WHERE (a,b)<=(5,0) ORDER BY a DESC; } {4 44 3 33 2 22 1 11} do_execsql_test 19.5 { SELECT * FROM t1 WHERE (a,b)>(3,0) ORDER BY a; } {3 33 4 44} do_execsql_test 19.6 { SELECT * FROM t1 WHERE (a,b)>=(3,0) ORDER BY a; } {3 33 4 44} do_execsql_test 19.7 { SELECT * FROM t1 WHERE (a,b)<(3,0) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.8 { SELECT * FROM t1 WHERE (a,b)<=(3,0) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.9 { SELECT * FROM t1 WHERE (a,b)>(3,32) ORDER BY a; } {3 33 4 44} do_execsql_test 19.10 { SELECT * FROM t1 WHERE (a,b)>(3,33) ORDER BY a; } {4 44} do_execsql_test 19.11 { SELECT * FROM t1 WHERE (a,b)>=(3,33) ORDER BY a; } {3 33 4 44} do_execsql_test 19.12 { SELECT * FROM t1 WHERE (a,b)>=(3,34) ORDER BY a; } {4 44} do_execsql_test 19.13 { SELECT * FROM t1 WHERE (a,b)<(3,34) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.14 { SELECT * FROM t1 WHERE (a,b)<(3,33) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.15 { SELECT * FROM t1 WHERE (a,b)<=(3,33) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.16 { SELECT * FROM t1 WHERE (a,b)<=(3,32) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.21 { SELECT * FROM t1 WHERE (0,0)<(a,b) ORDER BY a; } {1 11 2 22 3 33 4 44} do_execsql_test 19.22 { SELECT * FROM t1 WHERE (0,0)<=(a,b) ORDER BY a; } {1 11 2 22 3 33 4 44} do_execsql_test 19.23 { SELECT * FROM t1 WHERE (5,0)>(a,b) ORDER BY a DESC; } {4 44 3 33 2 22 1 11} do_execsql_test 19.24 { SELECT * FROM t1 WHERE (5,0)>=(a,b) ORDER BY a DESC; } {4 44 3 33 2 22 1 11} do_execsql_test 19.25 { SELECT * FROM t1 WHERE (3,0)<(a,b) ORDER BY a; } {3 33 4 44} do_execsql_test 19.26 { SELECT * FROM t1 WHERE (3,0)<=(a,b) ORDER BY a; } {3 33 4 44} do_execsql_test 19.27 { SELECT * FROM t1 WHERE (3,0)>(a,b) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.28 { SELECT * FROM t1 WHERE (3,0)>=(a,b) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.29 { SELECT * FROM t1 WHERE (3,32)<(a,b) ORDER BY a; } {3 33 4 44} do_execsql_test 19.30 { SELECT * FROM t1 WHERE (3,33)<(a,b) ORDER BY a; } {4 44} do_execsql_test 19.31 { SELECT * FROM t1 WHERE (3,33)<=(a,b) ORDER BY a; } {3 33 4 44} do_execsql_test 19.32 { SELECT * FROM t1 WHERE (3,34)<=(a,b) ORDER BY a; } {4 44} do_execsql_test 19.33 { SELECT * FROM t1 WHERE (3,34)>(a,b) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.34 { SELECT * FROM t1 WHERE (3,33)>(a,b) ORDER BY a DESC; } {2 22 1 11} do_execsql_test 19.35 { SELECT * FROM t1 WHERE (3,33)>=(a,b) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.36 { SELECT * FROM t1 WHERE (3,32)>=(a,b) ORDER BY a DESC; } {2 22 1 11} # 2018-02-18: Memory leak nexted row-value. Detected by OSSFuzz. # do_catchsql_test 20.1 { SELECT 1 WHERE (2,(2,0)) IS (2,(2,0)); } {0 1} finish_test |
Changes to test/spellfix.test.
︙ | ︙ | |||
275 276 277 278 279 280 281 | SELECT word, distance FROM t3 WHERE rowid = 10; } {keener {} {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?} } do_tracesql_test 6.2.3 { SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner'; } {keener 300 | | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | SELECT word, distance FROM t3 WHERE rowid = 10; } {keener {} {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?} } do_tracesql_test 6.2.3 { SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner'; } {keener 300 {SELECT id, word, rank, coalesce(k1,word) FROM "main"."t3_vocab" WHERE langid=0 AND k2>=?1 AND k2<?2} } } #------------------------------------------------------------------------- # Test that the spellfix1 table supports conflict handling (OR REPLACE # and so on). # |
︙ | ︙ |
Added test/spellfix4.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 | # 2018-02-14 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Test cases for the editdist3() function in the spellfix extension. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix spellfix4 ifcapable !vtab { finish_test ; return } load_static_extension db spellfix do_execsql_test 100 { CREATE TABLE cost1(iLang, cFrom, cTo, iCost); INSERT INTO cost1 VALUES (0, '', '?', 97), (0, '?', '', 98), (0, '?', '?', 99), (0, 'm', 'n', 50), (0, 'n', 'm', 50) ; SELECT editdist3('cost1'); SELECT editdist3('anchor','amchor'); } {{} 50} do_execsql_test 110 { SELECT editdist3('anchor','anchoxr'); } {97} do_execsql_test 111 { SELECT editdist3('anchor','xanchor'); } {97} do_execsql_test 112 { SELECT editdist3('anchor','anchorx'); } {97} do_execsql_test 120 { SELECT editdist3('anchor','anchr'); } {98} do_execsql_test 121 { SELECT editdist3('anchor','ancho'); } {98} do_execsql_test 122 { SELECT editdist3('anchor','nchor'); } {98} do_execsql_test 130 { SELECT editdist3('anchor','anchur'); } {99} do_execsql_test 131 { SELECT editdist3('anchor','onchor'); } {99} do_execsql_test 132 { SELECT editdist3('anchor','anchot'); } {99} do_execsql_test 140 { SELECT editdist3('anchor','omchor'); } {149} do_execsql_test 200 { INSERT INTO cost1 VALUES (0, 'a', 'ä', 5), (0, 'ss', 'ß', 8) ; SELECT editdist3('cost1'); SELECT editdist3('strasse','straße'); SELECT editdist3('straße','strasse'); } {{} 8 196} do_execsql_test 210 { SELECT editdist3('baume','bäume'); } {5} do_execsql_test 220 { SELECT editdist3('baum','bäume'); } {102} do_execsql_test 230 { INSERT INTO cost1 VALUES (0, 'ä', 'a', 5), (0, 'ß', 'ss', 8) ; SELECT editdist3('cost1'); SELECT editdist3('strasse','straße'); SELECT editdist3('straße','strasse'); } {{} 8 8} do_execsql_test 300 { DELETE FROM cost1; INSERT INTO cost1 VALUES (0, '', '?', 97), (0, '?', '', 98), (0, '?', '?', 99), (0, 'a', 'e', 50), (0, 'a', 'i', 70), (0, 'a', 'o', 75), (0, 'a', 'u', 81), (0, 'e', 'a', 50), (0, 'e', 'i', 52), (0, 'e', 'o', 72), (0, 'e', 'u', 82), (0, 'i', 'a', 70), (0, 'i', 'e', 52), (0, 'i', 'o', 75), (0, 'i', 'u', 83), (0, 'o', 'a', 75), (0, 'o', 'e', 72), (0, 'o', 'i', 75), (0, 'o', 'u', 40), (0, 'u', 'a', 81), (0, 'u', 'e', 82), (0, 'u', 'i', 83), (0, 'u', 'o', 40), (0, 'm', 'n', 45), (0, 'n', 'm', 45) ; CREATE TABLE words(x TEXT); INSERT INTO words VALUES ('abraham'), ('action'), ('africa'), ('aladdin'), ('alert'), ('alien'), ('amazon'), ('analog'), ('animal'), ('apollo'), ('archive'), ('arnold'), ('aspirin'), ('august'), ('average'), ('bahama'), ('bambino'), ('barcode'), ('bazooka'), ('belgium'), ('between'), ('biology'), ('blonde'), ('border'), ('brave'), ('british'), ('bucket'), ('button'), ('caesar'), ('camilla'), ('cannon'), ('caramel'), ('carpet'), ('catalog'), ('century'), ('chaos'), ('chef'), ('china'), ('circus'), ('classic'), ('clinic'), ('coconut'), ('combine'), ('complex'), ('congo'), ('convert'), ('cosmos'), ('crack'), ('crown'), ('cyclone'), ('deal'), ('delete'), ('denver'), ('detail'), ('diana'), ('direct'), ('dolby'), ('double'), ('dublin'), ('echo'), ('edition'), ('electra'), ('emotion'), ('enjoy'), ('escape'), ('everest'), ('exile'), ('express'), ('family'), ('ferrari'), ('filter'), ('fish'), ('florida'), ('ford'), ('forum'), ('frank'), ('frozen'), ('gallery'), ('garlic'), ('geneva'), ('gibson'), ('gloria'), ('gordon'), ('gravity'), ('ground'), ('habitat'), ('harlem'), ('hazard'), ('herbert'), ('hobby'), ('house'), ('icon'), ('immune'), ('india'), ('inside'), ('isotope'), ('jamaica'), ('jazz'), ('joker'), ('juliet'), ('jupiter'), ('kevin'), ('korea'), ('latin'), ('legal'), ('lexicon'), ('limbo'), ('lithium'), ('logo'), ('lucas'), ('madrid'), ('major'), ('manual'), ('mars'), ('maximum'), ('medical'), ('mental'), ('meter'), ('miguel'), ('mimosa'), ('miranda'), ('modern'), ('money'), ('morgan'), ('motor'), ('mystic'), ('nebula'), ('network'), ('nice'), ('nitro'), ('norway'), ('nurse'), ('octavia'), ('olympic'), ('opus'), ('orient'), ('othello'), ('pacific'), ('panama'), ('paper'), ('parking'), ('pasta'), ('paul'), ('people'), ('permit'), ('phrase'), ('pilgrim'), ('planet'), ('pocket'), ('police'), ('popular'), ('prefer'), ('presto'), ('private'), ('project'), ('proxy'), ('python'), ('quota'), ('rainbow'), ('raymond'), ('region'), ('report'), ('reward'), ('risk'), ('robot'), ('rose'), ('russian'), ('sailor'), ('salt'), ('saturn'), ('scorpio'), ('second'), ('seminar'), ('shadow'), ('shave'), ('shock'), ('silence'), ('sinatra'), ('sleep'), ('social'), ('sonata'), ('spain'), ('sphere'), ('spray'), ('state'), ('stone'), ('strong'), ('sugar'), ('supreme'), ('swing'), ('talent'), ('telecom'), ('thermos'), ('tina'), ('tommy'), ('torso'), ('trade'), ('trick'), ('tropic'), ('turtle'), ('uniform'), ('user'), ('vega'), ('vertigo'), ('village'), ('visible'), ('vocal'), ('voyage'), ('weekend'), ('winter'), ('year'), ('zipper') ; SELECT editdist3('cost1'); } {{}} do_execsql_test 310 { SELECT editdist3(a.x,b.x), a.x, b.x FROM words a, words b WHERE a.x<b.x ORDER BY 1, 2 LIMIT 20 } {139 bucket pocket 144 meter motor 149 manual mental 169 crack trick 173 sinatra sonata 174 edition emotion 174 major motor 174 risk rose 174 state stone 194 deal detail 196 alert talent 196 analog catalog 196 deal legal 196 ford forum 196 risk trick 196 stone strong 197 china tina 197 congo logo 197 diana tina 197 florida gloria} do_execsql_test 320 { SELECT md5sum(ed||'/'||sx||'/'||sy||',') FROM ( SELECT editdist3(a.x,b.x) AS ed, a.x AS sx, b.x AS sy FROM words a, words b WHERE a.x<b.x ORDER BY 1, 2 ) } {69d0a31872203a775e19325ea98cd053} finish_test |
Changes to test/tester.tcl.
︙ | ︙ | |||
2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 | # [finish_test ; return] in the callers context. # proc test_find_sqldiff {} { set prog [test_find_binary sqldiff] if {$prog==""} { return -code return } return $prog } # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set # to non-zero, then set the global variable $AUTOVACUUM to 1. set AUTOVACUUM $sqlite_options(default_autovacuum) # Make sure the FTS enhanced query syntax is disabled. | > > > > > > > > > > | 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 | # [finish_test ; return] in the callers context. # proc test_find_sqldiff {} { set prog [test_find_binary sqldiff] if {$prog==""} { return -code return } return $prog } # Call sqlite3_expanded_sql() on all statements associated with database # connection $db. This sometimes finds use-after-free bugs if run with # valgrind or address-sanitizer. proc expand_all_sql {db} { set stmt "" while {[set stmt [sqlite3_next_stmt $db $stmt]]!=""} { sqlite3_expanded_sql $stmt } } # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set # to non-zero, then set the global variable $AUTOVACUUM to 1. set AUTOVACUUM $sqlite_options(default_autovacuum) # Make sure the FTS enhanced query syntax is disabled. |
︙ | ︙ |
Changes to test/walro2.test.
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | puts -nonewline $fd "\0" close $fd } else { forcecopy test.db-shm test.db2-shm } } foreach bZeroShm {0 1} { set TN [expr $bZeroShm+1] do_multiclient_test tn { # Close all connections and delete the database. # code1 { db close } | > > > > > > > > > > > > | 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 | puts -nonewline $fd "\0" close $fd } else { forcecopy test.db-shm test.db2-shm } } # Most systems allocate the *-shm file in 32KB trunks. But on UNIX systems # for which the getpagesize() call returns greater than 32K, the *-shm # file is allocated in page-sized units (since you cannot mmap part of # a page). The following code sets variable $MINSHMSZ to the smallest # possible *-shm file (i.e. the greater of 32KB and the system page-size). # do_execsql_test 0.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); } {wal} set MINSHMSZ [file size test.db-shm] foreach bZeroShm {0 1} { set TN [expr $bZeroShm+1] do_multiclient_test tn { # Close all connections and delete the database. # code1 { db close } |
︙ | ︙ | |||
165 166 167 168 169 170 171 | code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } code2 { db2 close } sql1 { SELECT * FROM t1 } } {a b c d e f g h 1 2} do_test $TN.3.2.2 { list [file size test.db-wal] [file size test.db-shm] | | | | | 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 | code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } code2 { db2 close } sql1 { SELECT * FROM t1 } } {a b c d e f g h 1 2} do_test $TN.3.2.2 { list [file size test.db-wal] [file size test.db-shm] } [list 0 $MINSHMSZ] do_test $TN.3.3.0 { code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); INSERT INTO t1 VALUES(9, 10); } code2 { db2 close } code1 { db close } list [file size test.db-wal] [file size test.db-shm] } [list [wal_file_size 4 1024] $MINSHMSZ] do_test $TN.3.3.1 { code1 { sqlite3 db file:test.db?readonly_shm=1 } sql1 { SELECT * FROM t1 } } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} do_test $TN.3.3.2 { code2 { sqlite3 db2 test.db } sql2 { PRAGMA wal_checkpoint; DELETE FROM t1; INSERT INTO t1 VALUES('i', 'ii'); } code2 { db2 close } list [file size test.db-wal] [file size test.db-shm] } [list [wal_file_size 4 1024] $MINSHMSZ] do_test $TN.3.3.3 { sql1 { SELECT * FROM t1 } } {i ii} #----------------------------------------------------------------------- # # |
︙ | ︙ |
Changes to test/whereF.test.
︙ | ︙ | |||
211 212 213 214 215 216 217 218 | INSERT INTO t VALUES('{"foo":"bingo","alt":5.25}'); SELECT * FROM t WHERE(EXISTS(SELECT 1 FROM json_each(t.json,"$.foo") j WHERE j.value = 'meep')); } {{{"foo":"meep","other":12345}}} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | INSERT INTO t VALUES('{"foo":"bingo","alt":5.25}'); SELECT * FROM t WHERE(EXISTS(SELECT 1 FROM json_each(t.json,"$.foo") j WHERE j.value = 'meep')); } {{{"foo":"meep","other":12345}}} } # 2018-01-27 # Ticket https://sqlite.org/src/tktview/ec32177c99ccac2b180fd3ea2083 # Incorrect result when using the new OR clause factoring optimization # # This is the original test case as reported on the sqlite-users mailing # list # do_execsql_test 7.1 { DROP TABLE IF EXISTS cd; CREATE TABLE cd ( cdid INTEGER PRIMARY KEY NOT NULL, genreid integer ); CREATE INDEX cd_idx_genreid ON cd (genreid); INSERT INTO cd ( cdid, genreid ) VALUES ( 1, 1 ), ( 2, NULL ), ( 3, NULL ), ( 4, NULL ), ( 5, NULL ); SELECT cdid FROM cd me WHERE 2 > ( SELECT COUNT( * ) FROM cd rownum__emulation WHERE ( me.genreid IS NOT NULL AND rownum__emulation.genreid IS NULL ) OR ( me.genreid IS NOT NULL AND rownum__emulation.genreid IS NOT NULL AND rownum__emulation.genreid < me.genreid ) OR ( ( me.genreid = rownum__emulation.genreid OR ( me.genreid IS NULL AND rownum__emulation.genreid IS NULL ) ) AND rownum__emulation.cdid > me.cdid ) ); } {4 5} # Simplified test cases from the ticket # do_execsql_test 7.2 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER PRIMARY KEY, b); INSERT INTO t1(a,b) VALUES(1,1); CREATE TABLE t2(aa INTEGER PRIMARY KEY, bb); INSERT INTO t2(aa,bb) VALUES(1,1),(2,NULL),(3,NULL); SELECT ( SELECT COUNT(*) FROM t2 WHERE ( t1.b IS NOT NULL AND t2.bb IS NULL ) OR ( t2.bb < t1.b ) OR ( t1.b IS t2.bb AND t2.aa > t1.a ) ) FROM t1; } {2} # The fix for ticket ec32177c99ccac2b180fd3ea2083 only makes a difference # in the output when there is a TERM_VNULL entry in the WhereClause array. # And TERM_VNULL entries are only generated when compiling with # SQLITE_ENABLE_STAT4. Nevertheless, it is correct that TERM_VIRTUAL terms # should not participate in the factoring optimization. In all cases other # than TERM_VNULL, participation is harmless, but it does consume a few # extra CPU cycles. # # The following test verifies that the TERM_VIRTUAL terms resulting from # a GLOB operator do not appear anywhere in the generated code. This # confirms that the problem is fixed, even on builds that omit STAT4. # do_execsql_test 7.3 { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); INSERT INTO t1(a,b) VALUES(1,'abcxyz'); CREATE TABLE t2(aa INTEGER PRIMARY KEY, bb TEXT); INSERT INTO t2(aa,bb) VALUES(1,'abc'),(2,'wxyz'),(3,'xyz'); CREATE INDEX t2bb ON t2(bb); EXPLAIN SELECT ( SELECT COUNT(*) FROM t2 WHERE ( t1.b GLOB 'a*z' AND t2.bb='xyz' ) OR ( t2.bb = t1.b ) OR ( t2.aa = t1.a ) ) FROM t1; } {~/ (Lt|Ge) /} finish_test |
Added test/with4.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 | # 2018-02-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 the WITH clause in TRIGGERs and VIEWs. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix with4 ifcapable {!cte} { finish_test return } do_execsql_test 100 { ATTACH ':memory:' AS aux; CREATE TABLE main.t1(a,b); CREATE TABLE aux.t2(x,y); INSERT INTO t1 VALUES(1,2); INSERT INTO t2 VALUES(3,4); } {} do_catchsql_test 110 { CREATE VIEW v1 AS SELECT * FROM t1, aux.t2; } {1 {view v1 cannot reference objects in database aux}} do_catchsql_test 120 { CREATE VIEW v2 AS WITH v(m,n) AS (SELECT x,y FROM aux.t2) SELECT * FROM t1, v; } {1 {view v2 cannot reference objects in database aux}} do_catchsql_test 130 { CREATE VIEW v2 AS WITH v(m,n) AS (SELECT 5,?2) SELECT * FROM t1, v; } {1 {parameters are not allowed in views}} do_catchsql_test 200 { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN WITH v(m,n) AS (SELECT x,y FROM aux.t2) SELECT * FROM t1, v; END; } {1 {trigger r1 cannot reference objects in database aux}} do_catchsql_test 210 { CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN WITH v(m,n) AS (SELECT 5,?2) SELECT * FROM t1, v; END; } {1 {trigger cannot use variables}} finish_test |
Changes to test/zipfile.test.
︙ | ︙ | |||
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 | ifcapable !vtab { finish_test; return } if {[catch {load_static_extension db zipfile} error]} { puts "Skipping zipfile tests, hit load error: $error" finish_test; return } forcedelete test.zip do_execsql_test 1.0 { CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip'); PRAGMA table_info(zz); } { 0 name {} 1 {} 1 1 mode {} 0 {} 0 2 mtime {} 0 {} 0 3 sz {} 0 {} 0 4 rawdata {} 0 {} 0 5 data {} 0 {} 0 6 method {} 0 {} 0 } do_catchsql_test 1.1.0.1 { INSERT INTO zz(name, mode, mtime, sz, rawdata, method) VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0); } {1 {constraint failed}} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > | 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 | ifcapable !vtab { finish_test; return } if {[catch {load_static_extension db zipfile} error]} { puts "Skipping zipfile tests, hit load error: $error" finish_test; return } proc readfile {f} { set fd [open $f] fconfigure $fd -translation binary -encoding binary set data [read $fd] close $fd set data } if {$::tcl_platform(platform)=="unix" && [catch {exec unzip}]==0} { set ::UNZIP 1 load_static_extension db fileio proc do_unzip {file} { forcedelete test_unzip file mkdir test_unzip exec unzip -d test_unzip $file set res [db eval { SELECT replace(name,'test_unzip/',''),mode,mtime,data FROM fsdir('test_unzip') WHERE name!='test_unzip' ORDER BY name }] set res } } # The argument is a blob (not a hex string) containing a zip archive. # This proc removes the extended timestamp fields from the archive # and returns the result. # proc remove_timestamps {blob} { set hex [binary encode hex $blob] set hex [string map {55540500 00000500} $hex] binary decode hex $hex } # Argument $file is the name of a zip archive on disk. This function # executes test cases to check that the results of each of the following # are the same: # # SELECT * FROM zipfile($file) # SELECT * FROM zipfile( readfile($file) ) # SELECT * FROM zipfile( # (SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file)) # ) # proc do_zipfile_blob_test {tn file} { db func r readfile set q1 {SELECT name,mode,mtime,method,quote(data) FROM zipfile($file)} set q2 {SELECT name,mode,mtime,method,quote(data) FROM zipfile( r($file) )} set q3 {SELECT name,mode,mtime,method,quote(data) FROM zipfile( ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) ) )} set r1 [db eval $q1] set r2 [db eval $q2] set r3 [db eval $q3] #puts $r1 #puts $r2 #puts $r3 uplevel [list do_test $tn.1 [list set {} $r2] $r1] uplevel [list do_test $tn.2 [list set {} $r3] $r1] } # Argument $file is a zip file on disk. This command runs tests to: # # 1. Unpack the archive with unix command [unzip] and compare the # results to reading the same archive using the zipfile() table # valued function. # # 2. Creates a new archive with the same contents using the zipfile() # aggregate function as follows: # # SELECT writefile('test_unzip.zip', # ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) ) # ); # # Then tests that unpacking the new archive using [unzip] produces # the same results as in (1). # proc do_unzip_test {tn file} { if {[info vars ::UNZIP]==""} { return } db func sss strip_slash db eval { SELECT writefile('test_unzip.zip', ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) ) ); } set r1 [db eval { SELECT sss(name),mode,mtime,data FROM zipfile($file) ORDER BY name }] set r2 [do_unzip $file] set r3 [do_unzip test_unzip.zip] uplevel [list do_test $tn.1 [list set {} $r2] $r1] uplevel [list do_test $tn.2 [list set {} $r3] $r1] } proc strip_slash {in} { regsub {/$} $in {} } proc do_zip_tests {tn file} { uplevel do_zipfile_blob_test $tn.1 $file uplevel do_unzip_test $tn.2 $file } forcedelete test.zip do_execsql_test 1.0 { CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip'); PRAGMA table_info(zz); } { 0 name {} 1 {} 1 1 mode {} 0 {} 0 2 mtime {} 0 {} 0 3 sz {} 0 {} 0 4 rawdata {} 0 {} 0 5 data {} 0 {} 0 6 method {} 0 {} 0 } do_catchsql_test 1.1.0.1 { INSERT INTO zz(name, mode, mtime, sz, rawdata, method) VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0); } {1 {constraint failed}} do_catchsql_test 1.1.0.2 { INSERT INTO zz(name, mtime, sz, data, method) VALUES('g.txt', 1000000002, 5, '12345', 0); } {1 {constraint failed}} do_catchsql_test 1.1.0.3 { INSERT INTO zz(name, mtime, rawdata, method) VALUES('g.txt', 1000000002, '12345', 0); } {1 {constraint failed}} do_catchsql_test 1.1.0.4 { INSERT INTO zz(name, data, method) VALUES('g.txt', '12345', 7); } {1 {constraint failed}} do_execsql_test 1.1.1 { INSERT INTO zz(name, mode, mtime, data, method) VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0); } do_execsql_test 1.1.2 { INSERT INTO zz(name, mode, mtime, data, method) VALUES('g.txt', NULL, 1000000002, '12345', 0); } do_execsql_test 1.2 { SELECT name, mtime, data FROM zipfile('test.zip') } { f.txt 1000000000 abcde g.txt 1000000002 12345 } do_zip_tests 1.2a test.zip do_execsql_test 1.3 { INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt', '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb' ); } do_zip_tests 1.3a test.zip do_execsql_test 1.4 { SELECT name, mtime, data, method FROM zipfile('test.zip'); } { f.txt 1000000000 abcde 0 g.txt 1000000002 12345 0 h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8 } ifcapable json1 { do_execsql_test 1.4.1 { SELECT name, json_extract( zipfile_cds(z) , '$.crc32')!=0 FROM zipfile('test.zip'); } { f.txt 1 g.txt 1 h.txt 1 } } do_catchsql_test 1.4.2 { SELECT zipfile_cds(mode) FROM zipfile('test.zip'); } {0 {{} {} {}}} do_execsql_test 1.5.1 { BEGIN; INSERT INTO zz(name, mode, mtime, data, method) VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0); SELECT name FROM zz; COMMIT; |
︙ | ︙ | |||
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 | do_execsql_test 1.6.1 { SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 1000000006 zxcvb 0 } do_execsql_test 1.6.2 { UPDATE zz SET mtime=4 WHERE name='i.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_execsql_test 1.6.3 { UPDATE zz SET mode='-rw-r--r-x' WHERE name='h.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_execsql_test 1.6.4 { UPDATE zz SET name = 'blue.txt' WHERE name='f.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt 33188 1000000000 abcde 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_execsql_test 1.6.5 { UPDATE zz SET data = 'edcba' WHERE name='blue.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt 33188 1000000000 edcba 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 | > > > | 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 | do_execsql_test 1.6.1 { SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 1000000006 zxcvb 0 } do_zip_tests 1.6.1a test.zip do_execsql_test 1.6.2 { UPDATE zz SET mtime=4 WHERE name='i.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_execsql_test 1.6.3 { UPDATE zz SET mode='-rw-r--r-x' WHERE name='h.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { f.txt 33188 1000000000 abcde 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_zip_tests 1.6.3a test.zip do_execsql_test 1.6.4 { UPDATE zz SET name = 'blue.txt' WHERE name='f.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt 33188 1000000000 abcde 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_zip_tests 1.6.4a test.zip do_execsql_test 1.6.5 { UPDATE zz SET data = 'edcba' WHERE name='blue.txt'; SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt 33188 1000000000 edcba 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 |
︙ | ︙ | |||
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | do_execsql_test 1.6.8 { SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt/ 16877 1000000000 {} 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } #------------------------------------------------------------------------- db close forcedelete test.zip reset_db load_static_extension db zipfile do_execsql_test 2.1 { CREATE VIRTUAL TABLE zzz USING zipfile('test.zip'); INSERT INTO zzz(name, mode) VALUES('dirname', 'drwxr-xr-x'); SELECT name, mode, data FROM zzz; } {dirname/ 16877 {}} do_execsql_test 2.2 { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_execsql_test 1.6.8 { SELECT name, mode, mtime, data, method FROM zipfile('test.zip'); } { blue.txt/ 16877 1000000000 {} 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 zxcvb 0 } do_execsql_test 1.6.8 { UPDATE zz SET data = '' WHERE name='i.txt'; SELECT name,mode,mtime,data,method from zipfile('test.zip'); } { blue.txt/ 16877 1000000000 {} 0 h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8 i.txt 33188 4 {} 0 } do_execsql_test 1.6.9 { SELECT a.name, a.data FROM zz AS a, zz AS b WHERE a.name=+b.name AND +a.mode=b.mode } { blue.txt/ {} h.txt aaaaaaaaaabbbbbbbbbb i.txt {} } do_execsql_test 1.6.10 { SELECT name, data FROM zz WHERE name LIKE '%txt' } { h.txt aaaaaaaaaabbbbbbbbbb i.txt {} } do_execsql_test 1.7 { DELETE FROM zz; SELECT * FROM zz; } {} #------------------------------------------------------------------------- db close forcedelete test.zip reset_db load_static_extension db fileio load_static_extension db zipfile do_execsql_test 2.1 { CREATE VIRTUAL TABLE zzz USING zipfile('test.zip'); INSERT INTO zzz(name, mode) VALUES('dirname', 'drwxr-xr-x'); SELECT name, mode, data FROM zzz; } {dirname/ 16877 {}} do_execsql_test 2.2 { |
︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 206 207 208 | do_execsql_test 2.4 { SELECT name, mode, data FROM zzz; } { dirname3/ 16877 {} dirname2/ 16877 {} dirname2/file1.txt 33188 abcdefghijklmnop } # If on unix, check that the [unzip] utility can unpack our archive. # if {$::tcl_platform(platform)=="unix"} { do_test 2.5.1 { forcedelete dirname forcedelete dirname2 | > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | do_execsql_test 2.4 { SELECT name, mode, data FROM zzz; } { dirname3/ 16877 {} dirname2/ 16877 {} dirname2/file1.txt 33188 abcdefghijklmnop } do_zip_tests 2.4a test.zip # If on unix, check that the [unzip] utility can unpack our archive. # if {$::tcl_platform(platform)=="unix"} { do_test 2.5.1 { forcedelete dirname forcedelete dirname2 |
︙ | ︙ | |||
247 248 249 250 251 252 253 | } {1 {constraint failed}} } do_catchsql_test 3.2 { SELECT rowid FROM x1 } {1 {no such column: rowid}} | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 {constraint failed}} } do_catchsql_test 3.2 { SELECT rowid FROM x1 } {1 {no such column: rowid}} #------------------------------------------------------------------------- # Test some error conditions. # do_catchsql_test 4.1 { CREATE VIRTUAL TABLE yyy USING zipfile(); } {1 {zipfile constructor requires one argument}} do_catchsql_test 4.2 { CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip'); } {1 {zipfile constructor requires one argument}} do_catchsql_test 4.3 { SELECT * FROM zipfile() } {1 {zipfile() function requires an argument}} do_catchsql_test 4.4 { SELECT * FROM zipfile('/path/that/does/not/exist') } {1 {cannot open file: /path/that/does/not/exist}} foreach {tn mode} { 1 abcd 2 brwxrwxrwx 3 lrwxrrxrwx } { do_catchsql_test 4.5.$tn { WITH m(m) AS ( SELECT $mode) SELECT zipfile('a.txt', m, 1000, 'xyz') FROM m } [list 1 "zipfile: parse error in mode: $mode"] } do_catchsql_test 4.6 { WITH c(name,data) AS ( SELECT 'a.txt', 'abc') SELECT zipfile(name) FROM c } {1 {wrong number of arguments to function zipfile()}} do_catchsql_test 4.7 { WITH c(name,data) AS ( SELECT 'a.txt', 'abc' UNION ALL SELECT NULL, 'def' ) SELECT zipfile(name,data) FROM c } {1 {first argument to zipfile() must be non-NULL}} do_catchsql_test 4.7 { WITH c(name,data,method) AS ( SELECT 'a.txt', 'abc', 0 UNION SELECT 'b.txt', 'def', 8 UNION SELECT 'c.txt', 'ghi', 16 ) SELECT zipfile(name,NULL,NULL,data,method) FROM c } {1 {illegal method value: 16}} do_catchsql_test 4.8 { WITH c(name,data) AS ( SELECT 'a.txt', 'abc' UNION SELECT 'b.txt', 'def' UNION SELECT 'c.txt/', 'ghi' ) SELECT zipfile(name,NULL,NULL,data) FROM c } {1 {non-directory name must not end with /}} #-------------------------------------------------------------------------- db func rt remove_timestamps do_execsql_test 5.0 { WITH c(name,mtime,data) AS ( SELECT 'a.txt', 946684800, 'abc' ) SELECT name,mtime,data FROM zipfile( ( SELECT rt( zipfile(name,NULL,mtime,data,NULL) ) FROM c ) ) } { a.txt 946684800 abc } if {[info vars ::UNZIP]!=""} { ifcapable datetime { load_static_extension db fileio forcedelete test1.zip test2.zip do_test 6.0 { execsql { WITH c(name,mtime,data) AS ( SELECT 'a.txt', 946684800, 'abc' UNION ALL SELECT 'b.txt', 1000000000, 'abc' UNION ALL SELECT 'c.txt', 1111111000, 'abc' ) SELECT writefile('test1.zip', rt( zipfile(name, NULL, mtime, data) ) ), writefile('test2.zip', ( zipfile(name, NULL, mtime, data) ) ) FROM c; } forcedelete test_unzip file mkdir test_unzip exec unzip -d test_unzip test1.zip db eval { SELECT name, strftime('%s', mtime, 'unixepoch', 'localtime') FROM fsdir('test_unzip') WHERE name!='test_unzip' ORDER BY name } } [list {*}{ test_unzip/a.txt 946684800 test_unzip/b.txt 1000000000 test_unzip/c.txt 1111111000 }] do_execsql_test 6.1 { SELECT name, mtime, data FROM zipfile('test1.zip') } { a.txt 946684800 abc b.txt 1000000000 abc c.txt 1111111000 abc } do_test 6.2 { forcedelete test_unzip file mkdir test_unzip exec unzip -d test_unzip test2.zip db eval { SELECT name, mtime FROM fsdir('test_unzip') WHERE name!='test_unzip' ORDER BY name } } [list {*}{ test_unzip/a.txt 946684800 test_unzip/b.txt 1000000000 test_unzip/c.txt 1111111000 }] do_execsql_test 6.3 { SELECT name, mtime, sz, rawdata, data FROM zipfile('test2.zip') } { a.txt 946684800 3 abc abc b.txt 1000000000 3 abc abc c.txt 1111111000 3 abc abc } } } #------------------------------------------------------------------------- # Force an IO error by truncating the zip archive to zero bytes in size # while it is being read. forcedelete test.zip do_test 7.0 { execsql { WITH c(name,data) AS ( SELECT '1', randomblob(1000000) UNION ALL SELECT '2', randomblob(1000000) UNION ALL SELECT '3', randomblob(1000000) ) SELECT writefile('test.zip', zipfile(name, data) ) FROM c; } list [catch { db eval { SELECT name, data FROM zipfile('test.zip') } { if {$name==2} { close [open test.zip w+] } } } msg] $msg } {1 {error in fread()}} forcedelete test.zip do_execsql_test 8.0.1 { CREATE VIRTUAL TABLE zz USING zipfile('test.zip'); BEGIN; INSERT INTO zz(name, data) VALUES('a.txt', '1'); INSERT INTO zz(name, data) VALUES('b.txt', '2'); INSERT INTO zz(name, data) VALUES('c.txt', '1'); INSERT INTO zz(name, data) VALUES('d.txt', '2'); SELECT name, data FROM zz; } { a.txt 1 b.txt 2 c.txt 1 d.txt 2 } do_test 8.0.2 { db eval { SELECT name, data FROM zz } { if { $data=="2" } { db eval { DELETE FROM zz WHERE name=$name } } } execsql { SELECT name, data FROM zz } } {a.txt 1 c.txt 1} do_test 8.0.3 { db eval { SELECT name, data FROM zz } { db eval { DELETE FROM zz WHERE name=$name } } execsql { SELECT name, data FROM zz } } {} execsql COMMIT do_execsql_test 8.1.1 { CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip'); } do_catchsql_test 8.1.2 { INSERT INTO nogood(name, data) VALUES('abc', 'def'); } {1 {zipfile: failed to open file test_unzip for writing}} do_execsql_test 8.2.1 { DROP TABLE nogood; BEGIN; CREATE VIRTUAL TABLE nogood USING zipfile('test_unzip'); } do_catchsql_test 8.2.2 { INSERT INTO nogood(name, data) VALUES('abc', 'def'); } {1 {zipfile: failed to open file test_unzip for writing}} do_execsql_test 8.2.3 { COMMIT; } forcedelete test.zip do_execsql_test 8.3.1 { BEGIN; CREATE VIRTUAL TABLE ok USING zipfile('test.zip'); INSERT INTO ok(name, data) VALUES ('sqlite3', 'elf'); COMMIT; } #------------------------------------------------------------------------- # Test that the zipfile aggregate correctly adds and removes "/" from # the ends of directory file names. do_execsql_test 9.0 { WITH src(nm) AS ( VALUES('dir1') UNION ALL VALUES('dir2/') UNION ALL VALUES('dir3//') UNION ALL VALUES('dir4///') UNION ALL VALUES('/') ) SELECT name FROM zipfile((SELECT zipfile(nm, NULL) FROM src)) } {dir1/ dir2/ dir3/ dir4/ /} finish_test |
Added test/zipfile2.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 | # 2018 January 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 zipfile2 ifcapable !vtab { finish_test; return } if {[catch {load_static_extension db zipfile} error]} { puts "Skipping zipfile2 tests, hit load error: $error" finish_test; return } proc blobliteral {str} { set concat [string map {" " "" "\n" ""} $str] return "X'$concat'" } proc blob {str} { binary decode hex $str } proc findall {needle haystack} { set L [list] set start 0 while { [set idx [string first $needle $haystack $start]]>=0 } { lappend L $idx set start [expr $idx+1] } set L } do_execsql_test 1.0 { CREATE VIRTUAL TABLE aaa USING zipfile('testzip'); CREATE VIRTUAL TABLE bbb USING zipfile("testzip"); CREATE VIRTUAL TABLE ccc USING zipfile(`testzip`); CREATE VIRTUAL TABLE ddd USING zipfile([testzip]); CREATE VIRTUAL TABLE eee USING zipfile(testzip); CREATE VIRTUAL TABLE fff USING zipfile('test''zip'); } do_test 2.0 { forcedelete testdir file mkdir testdir execsql { CREATE VIRTUAL TABLE hhh USING zipfile('testdir') } catchsql { SELECT * FROM hhh } } {1 {error in fread()}} set archive { 504B0304140000080000D4A52BEC09F3B6E0110000001100000005000900612E 747874555405000140420F00636F6E74656E7473206F6620612E747874504B03 04140000080000D4A52BECD98916A7110000001100000005000900622E747874 555405000140420F00636F6E74656E7473206F6620622E747874504B01021E03 140000080000D4A52BEC09F3B6E0110000001100000005000900000000000000 0000A48100000000612E747874555405000140420F00504B01021E0314000008 0000D4A52BECD98916A71100000011000000050009000000000000000000A481 3D000000622E747874555405000140420F00504B050600000000020002007800 00007A0000000000 } if 0 { # This test is broken - the archive generated is slightly different # depending on the zlib version used. do_execsql_test 3.1 { WITH contents(name,mtime,data) AS ( VALUES('a.txt', 1000000, 'contents of a.txt') UNION ALL VALUES('b.txt', 1000000, 'contents of b.txt') ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents; } [blobliteral $archive] } set blob [blob $archive] do_execsql_test 3.2 { SELECT name,mtime,data FROM zipfile($blob) } { a.txt 1000000 {contents of a.txt} b.txt 1000000 {contents of b.txt} } # Corrupt each of the 0x50 0x4B (ascii "PK") headers in the file # Test that in each case this causes an error. # set L [findall 504B $archive] for {set i 0} {$i < [llength $L]} {incr i} { set idx [lindex $L $i] set a [string replace $archive $idx [expr $idx+3] 0000] set blob [blob $a] do_catchsql_test 3.3.$i { SELECT name,mtime,data FROM zipfile($blob) } {/1 .*/} } # Change the "extra info id" for all extended-timestamp fields. set L [findall 5554 $archive] for {set i 0} {$i < [llength $L]} {incr i} { set idx [lindex $L $i] set a [string replace $archive $idx [expr $idx+3] 1234] set blob [blob $a] do_execsql_test 3.4.$i { SELECT name,data FROM zipfile($blob) } { a.txt {contents of a.txt} b.txt {contents of b.txt} } } for {set i 0} {$i < [llength $L]} {incr i} { set idx [lindex $L $i] set a [string replace $archive [expr $idx+8] [expr $idx+9] 00] set blob [blob $a] do_execsql_test 3.5.$i { SELECT name,data FROM zipfile($blob) } { a.txt {contents of a.txt} b.txt {contents of b.txt} } } # set blob [db one { # WITH contents(name,mtime,data) AS ( # VALUES('a.txt', 1000000, 'aaaaaaaaaaaaaaaaaaaaaaa') # ) SELECT quote( zipfile(name,NULL,mtime,data) ) FROM contents; # }] # set blob [string range $blob 2 end] # set blob [string range $blob 0 end-1] # while {[string length $blob]>0} { # puts [string range $blob 0 63] # set blob [string range $blob 64 end] # } # exit set archive2 { 504B0304140000080800D4A52BEC08F54C6E050000001700000005000900612E 747874555405000140420F004B4CC40A00504B01021E03140000080800D4A52B EC08F54C6E0500000017000000050009000000000000000000A4810000000061 2E747874555405000140420F00504B050600000000010001003C000000310000 000000 } set blob [blob $archive2] do_execsql_test 4.0 { SELECT name,mtime,data,method FROM zipfile($blob) } { a.txt 1000000 aaaaaaaaaaaaaaaaaaaaaaa 8 } set L [findall 17000000 $archive2] set a $archive2 foreach i $L { set a [string replace $a $i [expr $i+7] 16000000] } set blob [blob $a] do_catchsql_test 4.1 { SELECT name,mtime,data,method FROM zipfile($blob) } {1 {inflate() failed (0)}} # Check the response to an unknown compression method (set data to NULL). set blob [blob [string map {0800 0900} $archive2]] do_execsql_test 4.2 { SELECT name,mtime,data IS NULL,method FROM zipfile($blob) } {a.txt 1000000 1 9} # Corrupt the EOCDS signature bytes in various ways. foreach {tn sub} { 1 {504B0500} 2 {504B0006} 3 {50000506} 4 {004B0506} } { set blob [blob [string map [list 504B0506 $sub] $archive2]] do_catchsql_test 4.3.$tn { SELECT * FROM zipfile($blob) } {1 {cannot find end of central directory record}} } #------------------------------------------------------------------------- # Test that a zero-length file with a '/' at the end is treated as # a directory (data IS NULL). Even if the mode doesn't indicate # that it is a directory. do_test 5.0 { set blob [db one { WITH c(n, d) AS ( SELECT 'notadir', '' ) SELECT zipfile(n, d) FROM c }] set hex [binary encode hex $blob] set hex [string map {6e6f7461646972 6e6f746164692f} $hex] set blob2 [binary decode hex $hex] execsql { SELECT name, data IS NULL FROM zipfile($blob2) } } {notadi/ 1} finish_test |
Added test/zipfilefault.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 | # 2018 January 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 source $testdir/malloc_common.tcl set testprefix zipfilefault ifcapable !vtab { finish_test; return } if {[catch {load_static_extension db zipfile} error]} { puts "Skipping zipfile2 tests, hit load error: $error" finish_test; return } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen load_static_extension db zipfile execsql { DROP TABLE IF EXISTS aaa } } -body { execsql { CREATE VIRTUAL TABLE aaa USING zipfile('test.zip') } } -test { faultsim_test_result {0 {}} } forcedelete test.zip sqlite3 db test.db load_static_extension db zipfile do_execsql_test 2.0 { CREATE VIRTUAL TABLE setup USING zipfile('test.zip'); INSERT INTO setup(name, data) VALUES('a.txt', '1234567890'); } do_faultsim_test 2.1 -faults oom* -body { execsql { SELECT name,data FROM zipfile('test.zip') } } -test { faultsim_test_result {0 {a.txt 1234567890}} } do_faultsim_test 2.2 -faults oom* -body { execsql { SELECT json_extract( zipfile_cds(z), '$.version-made-by' ) FROM zipfile('test.zip') } } -test { faultsim_test_result {0 798} } forcedelete test.zip reset_db load_static_extension db zipfile do_execsql_test 3.0 { CREATE VIRTUAL TABLE setup USING zipfile('test.zip'); INSERT INTO setup(name, data) VALUES('a.txt', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa'); } do_faultsim_test 3 -faults oom* -body { execsql { SELECT name,data FROM zipfile('test.zip') } } -test { faultsim_test_result {0 {a.txt aaaaaaaaaaaaaaaaaaaaaaaaaaaa}} } do_faultsim_test 4 -faults oom* -body { execsql { WITH c(n, d) AS ( SELECT 1, 'aaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb' ) SELECT name, data FROM zipfile( (SELECT zipfile(n, d) FROM c) ); } } -test { faultsim_test_result {0 {1 aaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb}} } reset_db sqlite3_db_config_lookaside db 0 0 0 load_static_extension db zipfile do_execsql_test 5.0 { CREATE VIRTUAL TABLE setup USING zipfile('test.zip') } do_faultsim_test 5.1 -faults oom* -prep { forcedelete test.zip } -body { execsql { INSERT INTO setup(name, data) VALUES('a.txt', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa'); } } -test { faultsim_test_result {0 {}} } do_faultsim_test 5.2 -faults oom* -prep { forcedelete test.zip } -body { execsql { INSERT INTO setup(name, data) VALUES('dir', NULL) } } -test { faultsim_test_result {0 {}} } do_faultsim_test 5.3 -faults oom* -prep { forcedelete test.zip execsql { DROP TABLE IF EXISTS setup; BEGIN; CREATE VIRTUAL TABLE setup USING zipfile('test.zip') } } -body { execsql { INSERT INTO setup(name, data) VALUES('dir', NULL) } } -test { catchsql { COMMIT } faultsim_test_result {0 {}} } do_faultsim_test 6.1 -faults oom* -body { execsql { WITH c(n, d) AS ( VALUES('a.txt', '1234567890') UNION ALL VALUES('dir', NULL) ) SELECT zipfile(n, d) IS NULL FROM c; } } -test { faultsim_test_result {0 0} } set big [string repeat 0123456789 1000] do_faultsim_test 6.2 -faults oom* -body { execsql { WITH c(n, d) AS ( VALUES('a.txt', $big) ) SELECT zipfile(n, NULL, NULL, d, 0) IS NULL FROM c; } } -test { faultsim_test_result {0 0} } do_faultsim_test 7.0 -faults oom* -prep { catch { db close } sqlite3 db "" } -body { load_static_extension db zipfile } -test { } finish_test |
Changes to tool/addopcodes.tcl.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | } close $in # The following are the extra token codes to be added. SPACE and # ILLEGAL *must* be the last two token codes and they must be in that order. # set extras { ISNOT FUNCTION COLUMN AGG_FUNCTION AGG_COLUMN UMINUS UPLUS REGISTER VECTOR SELECT_COLUMN IF_NULL_ROW ASTERISK SPAN END_OF_FILE | > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | } close $in # The following are the extra token codes to be added. SPACE and # ILLEGAL *must* be the last two token codes and they must be in that order. # set extras { TRUEFALSE ISNOT FUNCTION COLUMN AGG_FUNCTION AGG_COLUMN UMINUS UPLUS TRUTH REGISTER VECTOR SELECT_COLUMN IF_NULL_ROW ASTERISK SPAN END_OF_FILE |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
507 508 509 510 511 512 513 | if( stateno>YY_MAX_SHIFT ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; | > | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | if( stateno>YY_MAX_SHIFT ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); assert( i+YYNTOKEN<=(int)sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) ); assert( iLookAhead!=YYNOCODE ); assert( iLookAhead < YYNTOKEN ); i += iLookAhead; if( yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) |
︙ | ︙ |
Changes to tool/speed-check.sh.
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED" LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK" LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE" LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA" BASELINE="trunk" doExplain=0 doCachegrind=1 while test "$1" != ""; do case $1 in --reprepare) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --autovacuum) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" | > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED" LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK" LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE" LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA" BASELINE="trunk" doExplain=0 doCachegrind=1 doVdbeProfile=0 doWal=1 while test "$1" != ""; do case $1 in --reprepare) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --autovacuum) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" |
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 | SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --nomemstat) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --temp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --temp 6" ;; --wal) | > > > < > > | 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 | SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --nomemstat) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --temp) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --temp 6" ;; --legacy) doWal=0 ;; --wal) doWal=1 ;; --size) shift; SIZE=$1 ;; --cachesize) shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --cachesize $1" ;; --explain) doExplain=1 ;; --vdbeprofile) rm -f vdbe_profile.out CC_OPTS="$CC_OPTS -DVDBE_PROFILE" doCachegrind=0 doVdbeProfile=1 ;; --lean) CC_OPTS="$CC_OPTS $LEAN_OPTS" ;; --clang) CC=clang ;; |
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | ;; *) BASELINE=$1 ;; esac shift done SPEEDTEST_OPTS="$SPEEDTEST_OPTS --size $SIZE" echo "NAME = $NAME" | tee summary-$NAME.txt echo "SPEEDTEST_OPTS = $SPEEDTEST_OPTS" | tee -a summary-$NAME.txt echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt rm -f cachegrind.out.* speedtest1 speedtest1.db sqlite3.o $CC -g -Os -Wall -I. $CC_OPTS -c sqlite3.c size sqlite3.o | tee -a summary-$NAME.txt if test $doExplain -eq 1; then $CC -g -Os -Wall -I. $CC_OPTS \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ ./shell.c ./sqlite3.c -o sqlite3 -ldl -lpthread fi | > > > > > > | 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 | ;; *) BASELINE=$1 ;; esac shift done if test $doWal -eq 1; then SPEEDTEST_OPTS="$SPEEDTEST_OPTS --journal wal" fi SPEEDTEST_OPTS="$SPEEDTEST_OPTS --size $SIZE" echo "NAME = $NAME" | tee summary-$NAME.txt echo "SPEEDTEST_OPTS = $SPEEDTEST_OPTS" | tee -a summary-$NAME.txt echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt rm -f cachegrind.out.* speedtest1 speedtest1.db sqlite3.o if test $doVdbeProfile -eq 1; then rm -f vdbe_profile.out fi $CC -g -Os -Wall -I. $CC_OPTS -c sqlite3.c size sqlite3.o | tee -a summary-$NAME.txt if test $doExplain -eq 1; then $CC -g -Os -Wall -I. $CC_OPTS \ -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ ./shell.c ./sqlite3.c -o sqlite3 -ldl -lpthread fi |
︙ | ︙ | |||
159 160 161 162 163 164 165 | cg_anno.tcl cachegrind.out.* >cout-$NAME.txt echo '*****************************************************' >>cout-$NAME.txt sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>cout-$NAME.txt fi if test $doExplain -eq 1; then ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt fi | > > > > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | cg_anno.tcl cachegrind.out.* >cout-$NAME.txt echo '*****************************************************' >>cout-$NAME.txt sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>cout-$NAME.txt fi if test $doExplain -eq 1; then ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt fi if test $doVdbeProfile -eq 1; then tclsh ../sqlite/tool/vdbe_profile.tcl >vdbeprofile-$NAME.txt open vdbeprofile-$NAME.txt fi if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1; then fossil test-diff --tk -c 20 cout-$BASELINE.txt cout-$NAME.txt fi |