aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--Makefile.msc1
-rw-r--r--ext/fts5/fts5_aux.c16
-rw-r--r--ext/fts5/test/fts5af.test10
-rw-r--r--ext/misc/memvfs.c161
-rw-r--r--main.mk2
-rw-r--r--manifest85
-rw-r--r--manifest.uuid2
-rw-r--r--src/btree.c14
-rw-r--r--src/btree.h3
-rw-r--r--src/build.c21
-rw-r--r--src/expr.c25
-rw-r--r--src/func.c4
-rw-r--r--src/insert.c2
-rw-r--r--src/main.c16
-rw-r--r--src/malloc.c13
-rw-r--r--src/pager.c2
-rw-r--r--src/parse.y426
-rw-r--r--src/shell.c.in214
-rw-r--r--src/sqlite.h.in11
-rw-r--r--src/sqliteInt.h33
-rw-r--r--src/test_config.c6
-rw-r--r--src/trigger.c59
-rw-r--r--src/util.c26
-rw-r--r--src/vdbe.c44
-rw-r--r--src/where.c6
-rw-r--r--test/capi2.test2
-rw-r--r--test/colname.test19
-rw-r--r--test/fkey1.test14
-rw-r--r--test/func6.test86
-rw-r--r--test/indexexpr1.test23
-rw-r--r--test/misc1.test20
-rw-r--r--test/pragma5.test2
-rw-r--r--test/shell1.test6
-rw-r--r--test/speedtest1.c76
-rw-r--r--test/trace.test2
-rw-r--r--tool/lemon.c166
-rw-r--r--tool/lempar.c133
-rw-r--r--tool/speed-check.sh6
39 files changed, 1205 insertions, 554 deletions
diff --git a/Makefile.in b/Makefile.in
index 009ab2e06..e3dfb01ba 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -582,6 +582,8 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
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
diff --git a/Makefile.msc b/Makefile.msc
index 8e9e26d5a..5a479efb1 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -1597,6 +1597,7 @@ FUZZDATA = \
!IF $(DYNAMIC_SHELL)==0 && $(FOR_WIN10)==0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_STMTVTAB
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_DBSTAT_VTAB
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC -DSQLITE_INTROSPECTION_PRAGMAS
!ENDIF
# <<mark>>
diff --git a/ext/fts5/fts5_aux.c b/ext/fts5/fts5_aux.c
index 219ea6fff..594b981dd 100644
--- a/ext/fts5/fts5_aux.c
+++ b/ext/fts5/fts5_aux.c
@@ -359,6 +359,16 @@ static int fts5SnippetScore(
}
/*
+** Return the value in pVal interpreted as utf-8 text. Except, if pVal
+** contains a NULL value, return a pointer to a static string zero
+** bytes in length instead of a NULL pointer.
+*/
+static const char *fts5ValueToText(sqlite3_value *pVal){
+ const char *zRet = (const char*)sqlite3_value_text(pVal);
+ return zRet ? zRet : "";
+}
+
+/*
** Implementation of snippet() function.
*/
static void fts5SnippetFunction(
@@ -393,9 +403,9 @@ static void fts5SnippetFunction(
nCol = pApi->xColumnCount(pFts);
memset(&ctx, 0, sizeof(HighlightContext));
iCol = sqlite3_value_int(apVal[0]);
- ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
- ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
- zEllips = (const char*)sqlite3_value_text(apVal[3]);
+ ctx.zOpen = fts5ValueToText(apVal[1]);
+ ctx.zClose = fts5ValueToText(apVal[2]);
+ zEllips = fts5ValueToText(apVal[3]);
nToken = sqlite3_value_int(apVal[4]);
iBestCol = (iCol>=0 ? iCol : 0);
diff --git a/ext/fts5/test/fts5af.test b/ext/fts5/test/fts5af.test
index fa4ebd295..86c8f753f 100644
--- a/ext/fts5/test/fts5af.test
+++ b/ext/fts5/test/fts5af.test
@@ -175,6 +175,16 @@ do_execsql_test 5.1 {
SELECT snippet(p1, 0, '[', ']', '...', 6) FROM p1('x');
} {{[x] a a a a a...}}
+do_execsql_test 5.2 {
+ SELECT snippet(p1, 0, '[', ']', NULL, 6) FROM p1('x');
+} {{[x] a a a a a}}
+do_execsql_test 5.3 {
+ SELECT snippet(p1, 0, NULL, ']', '...', 6) FROM p1('x');
+} {{x] a a a a a...}}
+do_execsql_test 5.4 {
+ SELECT snippet(p1, 0, '[', NULL, '...', 6) FROM p1('x');
+} {{[x a a a a a...}}
+
} ;# foreach_detail_mode
finish_test
diff --git a/ext/misc/memvfs.c b/ext/misc/memvfs.c
index 62a8a033d..27a61c35e 100644
--- a/ext/misc/memvfs.c
+++ b/ext/misc/memvfs.c
@@ -10,23 +10,33 @@
**
******************************************************************************
**
-** This is an in-memory read-only VFS implementation. The application
-** supplies a block of memory which is the database file, and this VFS
-** uses that block of memory.
+** This is an in-memory VFS implementation. The application supplies
+** a chunk of memory to hold the database file.
**
-** Because there is no place to store journals and no good way to lock
-** the "file", this VFS is read-only.
+** Because there is place to store a rollback or wal journal, the database
+** must use one of journal_mode=MEMORY or journal_mode=NONE.
**
** USAGE:
**
-** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336", &db,
-** SQLITE_OPEN_READONLY | SQLITE_OPEN_URI,
+** sqlite3_open_v2("file:/whatever?ptr=0xf05538&sz=14336&max=65536", &db,
+** SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI,
** "memvfs");
**
-** The ptr= and sz= query parameters are required or the open will fail.
-** The ptr= parameter gives the memory address of the buffer holding the
-** read-only database and sz= gives the size of the database. The parameter
-** values may be in hexadecimal or decimal. The filename is ignored.
+** These are the query parameters:
+**
+** ptr= The address of the memory buffer that holds the database.
+**
+** sz= The current size the database file
+**
+** maxsz= The maximum size of the database. In other words, the
+** amount of space allocated for the ptr= buffer.
+**
+** freeonclose= If true, then sqlite3_free() is called on the ptr=
+** value when the connection closes.
+**
+** The ptr= and sz= query parameters are required. If maxsz= is omitted,
+** then it defaults to the sz= value. Parameter values can be in either
+** decimal or hexadecimal. The filename in the URI is ignored.
*/
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
@@ -49,7 +59,9 @@ typedef struct MemFile MemFile;
struct MemFile {
sqlite3_file base; /* IO methods */
sqlite3_int64 sz; /* Size of the file */
+ sqlite3_int64 szMax; /* Space allocated to aData */
unsigned char *aData; /* content of the file */
+ int bFreeOnClose; /* Invoke sqlite3_free() on aData at close */
};
/*
@@ -144,6 +156,8 @@ static const sqlite3_io_methods mem_io_methods = {
** to free.
*/
static int memClose(sqlite3_file *pFile){
+ MemFile *p = (MemFile *)pFile;
+ if( p->bFreeOnClose ) sqlite3_free(p->aData);
return SQLITE_OK;
}
@@ -170,21 +184,34 @@ static int memWrite(
int iAmt,
sqlite_int64 iOfst
){
- return SQLITE_READONLY;
+ MemFile *p = (MemFile *)pFile;
+ if( iOfst+iAmt>p->sz ){
+ if( iOfst+iAmt>p->szMax ) return SQLITE_FULL;
+ if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
+ p->sz = iOfst+iAmt;
+ }
+ memcpy(p->aData+iOfst, z, iAmt);
+ return SQLITE_OK;
}
/*
** Truncate an mem-file.
*/
static int memTruncate(sqlite3_file *pFile, sqlite_int64 size){
- return SQLITE_READONLY;
+ MemFile *p = (MemFile *)pFile;
+ if( size>p->sz ){
+ if( size>p->szMax ) return SQLITE_FULL;
+ memset(p->aData+p->sz, 0, size-p->sz);
+ }
+ p->sz = size;
+ return SQLITE_OK;
}
/*
** Sync an mem-file.
*/
static int memSync(sqlite3_file *pFile, int flags){
- return SQLITE_READONLY;
+ return SQLITE_OK;
}
/*
@@ -200,7 +227,7 @@ static int memFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
** Lock an mem-file.
*/
static int memLock(sqlite3_file *pFile, int eLock){
- return SQLITE_READONLY;
+ return SQLITE_OK;
}
/*
@@ -242,7 +269,10 @@ static int memSectorSize(sqlite3_file *pFile){
** Return the device characteristic flags supported by an mem-file.
*/
static int memDeviceCharacteristics(sqlite3_file *pFile){
- return SQLITE_IOCAP_IMMUTABLE;
+ return SQLITE_IOCAP_ATOMIC |
+ SQLITE_IOCAP_POWERSAFE_OVERWRITE |
+ SQLITE_IOCAP_SAFE_APPEND |
+ SQLITE_IOCAP_SEQUENTIAL;
}
/* Create a shared memory file mapping */
@@ -253,12 +283,12 @@ static int memShmMap(
int bExtend,
void volatile **pp
){
- return SQLITE_READONLY;
+ return SQLITE_IOERR_SHMMAP;
}
/* Perform locking on a shared-memory segment */
static int memShmLock(sqlite3_file *pFile, int offset, int n, int flags){
- return SQLITE_READONLY;
+ return SQLITE_IOERR_SHMLOCK;
}
/* Memory barrier operation on shared memory */
@@ -305,6 +335,9 @@ static int memOpen(
if( p->aData==0 ) return SQLITE_CANTOPEN;
p->sz = sqlite3_uri_int64(zName,"sz",0);
if( p->sz<0 ) return SQLITE_CANTOPEN;
+ p->szMax = sqlite3_uri_int64(zName,"max",p->sz);
+ if( p->szMax<p->sz ) return SQLITE_CANTOPEN;
+ p->bFreeOnClose = sqlite3_uri_boolean(zName,"freeonclose",0);
pFile->pMethods = &mem_io_methods;
return SQLITE_OK;
}
@@ -315,7 +348,7 @@ static int memOpen(
** returning.
*/
static int memDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
- return SQLITE_READONLY;
+ return SQLITE_IOERR_DELETE;
}
/*
@@ -328,14 +361,7 @@ static int memAccess(
int flags,
int *pResOut
){
- /* The spec says there are three possible values for flags. But only
- ** two of them are actually used */
- assert( flags==SQLITE_ACCESS_EXISTS || flags==SQLITE_ACCESS_READWRITE );
- if( flags==SQLITE_ACCESS_READWRITE ){
- *pResOut = 0;
- }else{
- *pResOut = 1;
- }
+ *pResOut = 0;
return SQLITE_OK;
}
@@ -416,31 +442,43 @@ static int memCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
#ifdef MEMVFS_TEST
/*
-** memload(FILENAME)
+** memvfs_from_file(FILENAME, MAXSIZE)
**
** This an SQL function used to help in testing the memvfs VFS. The
** function reads the content of a file into memory and then returns
-** a string that gives the locate and size of the in-memory buffer.
+** a URI that can be handed to ATTACH to attach the memory buffer as
+** a database. Example:
+**
+** ATTACH memvfs_from_file('test.db',1048576) AS inmem;
+**
+** The optional MAXSIZE argument gives the size of the memory allocation
+** used to hold the database. If omitted, it defaults to the size of the
+** file on disk.
*/
#include <stdio.h>
-static void memvfsMemloadFunc(
+static void memvfsFromFileFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
unsigned char *p;
sqlite3_int64 sz;
+ sqlite3_int64 szMax;
FILE *in;
const char *zFilename = (const char*)sqlite3_value_text(argv[0]);
- char zReturn[100];
+ char *zUri;
if( zFilename==0 ) return;
in = fopen(zFilename, "rb");
if( in==0 ) return;
fseek(in, 0, SEEK_END);
- sz = ftell(in);
+ szMax = sz = ftell(in);
rewind(in);
- p = sqlite3_malloc( sz );
+ if( argc>=2 ){
+ szMax = sqlite3_value_int64(argv[1]);
+ if( szMax<sz ) szMax = sz;
+ }
+ p = sqlite3_malloc64( szMax );
if( p==0 ){
fclose(in);
sqlite3_result_error_nomem(context);
@@ -448,18 +486,60 @@ static void memvfsMemloadFunc(
}
fread(p, sz, 1, in);
fclose(in);
- sqlite3_snprintf(sizeof(zReturn),zReturn,"ptr=%lld&sz=%lld",
- (sqlite3_int64)p, sz);
- sqlite3_result_text(context, zReturn, -1, SQLITE_TRANSIENT);
+ zUri = sqlite3_mprintf(
+ "file:/mem?vfs=memvfs&ptr=%lld&sz=%lld&max=%lld&freeonclose=1",
+ (sqlite3_int64)p, sz, szMax);
+ sqlite3_result_text(context, zUri, -1, sqlite3_free);
}
+#endif /* MEMVFS_TEST */
+
+#ifdef MEMVFS_TEST
+/*
+** memvfs_to_file(SCHEMA, FILENAME)
+**
+** The schema identified by SCHEMA must be a memvfs database. Write
+** the content of this database into FILENAME.
+*/
+static void memvfsToFileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ MemFile *p = 0;
+ FILE *out;
+ int rc;
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ sqlite3_vfs *pVfs = 0;
+ const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
+ const char *zFilename = (const char*)sqlite3_value_text(argv[1]);
+
+ if( zFilename==0 ) return;
+ out = fopen(zFilename, "wb");
+ if( out==0 ) return;
+ rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_VFS_POINTER, &pVfs);
+ if( rc || pVfs==0 ) return;
+ if( strcmp(pVfs->zName,"memvfs")!=0 ) return;
+ rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
+ if( rc ) return;
+ fwrite(p->aData, 1, (size_t)p->sz, out);
+ fclose(out);
+}
+#endif /* MEMVFS_TEST */
+
+#ifdef MEMVFS_TEST
/* Called for each new database connection */
static int memvfsRegister(
sqlite3 *db,
- const char **pzErrMsg,
+ char **pzErrMsg,
const struct sqlite3_api_routines *pThunk
){
- return sqlite3_create_function(db, "memload", 1, SQLITE_UTF8, 0,
- memvfsMemloadFunc, 0, 0);
+ sqlite3_create_function(db, "memvfs_from_file", 1, SQLITE_UTF8, 0,
+ memvfsFromFileFunc, 0, 0);
+ sqlite3_create_function(db, "memvfs_from_file", 2, SQLITE_UTF8, 0,
+ memvfsFromFileFunc, 0, 0);
+ sqlite3_create_function(db, "memvfs_to_file", 2, SQLITE_UTF8, 0,
+ memvfsToFileFunc, 0, 0);
+ return SQLITE_OK;
}
#endif /* MEMVFS_TEST */
@@ -485,6 +565,9 @@ int sqlite3_memvfs_init(
if( rc==SQLITE_OK ){
rc = sqlite3_auto_extension((void(*)(void))memvfsRegister);
}
+ if( rc==SQLITE_OK ){
+ rc = memvfsRegister(db, pzErrMsg, pApi);
+ }
#endif
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
return rc;
diff --git a/main.mk b/main.mk
index 9cdcc051e..a6a7dbf1c 100644
--- a/main.mk
+++ b/main.mk
@@ -510,6 +510,8 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
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
diff --git a/manifest b/manifest
index 6a47f6372..eb4d9552d 100644
--- a/manifest
+++ b/manifest
@@ -1,10 +1,10 @@
-C Have\szipfile\ssupport\sDELETE\scommands.
-D 2017-12-30T18:32:27.545
+C Merge\sin\sall\srecent\strunk\senhancements.
+D 2018-01-04T19:54:55.108
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
-F Makefile.in ceb40bfcb30ebba8e1202b34c56ff7e13e112f9809e2381d99be32c2726058f5
+F Makefile.in 1b11037c5ed3399a79433cc82c59b5e36a7b3a3e4e195bb27640d0d2145e03e1
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
-F Makefile.msc 5a740138ce23a88c33a02a65ffea45d129edf458afdc7547a2bdfd54f1ad6801
+F Makefile.msc 8723bebdec08013054d1ade8f65a13cad34bf8dd015f09649754be2b5f6edc59
F README.md eeae1e552f93ef72ef7c5b8f6647b368a001c28820ad1df179d3dae602bef681
F VERSION 0c10cdfed866fdd2d80434f64f042c3330f1daaed12e54287beb104f04b3faaf
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -108,7 +108,7 @@ F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
F ext/fts5/fts5Int.h eda28e3a0a5d87c412e8355fe35da875b04cb389908c8eb0d867ad662adbc491
-F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
+F ext/fts5/fts5_aux.c ca666a3bbe07c5a3bbe9fffaea19c935a1efaf337333e28bad7bdd1971ffd093
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
F ext/fts5/fts5_expr.c 01048018d21524e2c302b063ff5c3cdcf546e03297215e577205d85b47499deb
@@ -131,7 +131,7 @@ F ext/fts5/test/fts5ab.test 9205c839332c908aaad2b01ab8670ece8b161e8f2ec8a9fabf18
F ext/fts5/test/fts5ac.test a7aa7e1fefc6e1918aa4d3111d5c44a09177168e962c5fd2cca9620de8a7ed6d
F ext/fts5/test/fts5ad.test e8cf959dfcd57c8e46d6f5f25665686f3b6627130a9a981371dafdf6482790de
F ext/fts5/test/fts5ae.test 1142d16d9cc193894dc13cc8f9c7a8a21411ac61b5567a878514df6f9f0d7bb7
-F ext/fts5/test/fts5af.test aa635947bda31ac87fbe99483eef4d9a8571f58ad89c75dfb63312a35688eceb
+F ext/fts5/test/fts5af.test 724247405b13f8f06cc6ce464dc4f152dc5dd4e86b12c2099685d8f19747bf7b
F ext/fts5/test/fts5ag.test 7816f25a0707578f08145ab539fc0ca025f8951e788b28a6a18a06b2099469dd
F ext/fts5/test/fts5ah.test 27b5a33bfd0363ca8a4dc659e6e2a5df3dea1c3c5b04bc51ca6aeb1277bd9b21
F ext/fts5/test/fts5ai.test d837c42249c0d8ad1a2912270e22cf2f303790a611f85c0be3a58e42a3696e3d
@@ -280,7 +280,7 @@ F ext/misc/fileio.c 014152d4133e7b29eab8eb39d0c640659c23a6d23d882b4778f487ae7d1a
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
-F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
+F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
@@ -405,7 +405,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 9109d5786263a20fcf321a77c463d39c9ac84c871ea3774b0d213d8311dda105
+F main.mk 739f832da37d29e252dd9f609c3864f3ecfa42136132eab9b11acb5162b7d02d
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -424,10 +424,10 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
-F src/btree.c b83a6b03f160528020bb965f0c3a40af5286cd4923c3870fd218177f03a120a7
-F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
+F src/btree.c 0a1f63b50ab1ac5d4b1637c30cb1ae123fbc162ec8cb6336ddb9491a0bc1e363
+F src/btree.h 0866c0a08255142ea0e754aabd211c843cab32045c978a592a43152405ed0c84
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
-F src/build.c ed567f088edbc305dad33a6b14e08f8216a3860f6bad1d180450d5a5414bf346
+F src/build.c a03eb5a1cfff74784c24a4478ba5455711571936f1ac9d43f94fa7df57509977
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
@@ -435,20 +435,20 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
F src/delete.c 74667ad914ac143731a444a1bacf29ceb18f6eded8a0dd17aafae80baa07f8bb
-F src/expr.c fe11b91bb65b869143bd42023427c4429778ae42c0a0db7762f68f75b347a958
+F src/expr.c ad6e7a9c34a4bab9d10cc857d647ae7ce370a633b5c0bfa71f1c29b81ae364b8
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
-F src/func.c 0fb9a2d678d3c8aba89b46468b309cd7e8fa9806a369a30aa89024660845bb13
+F src/func.c bd528d5ed68ce5cbf78a762e3b735fa75009f7197ff07fab07fd771f35ebaa1b
F src/global.c ac3094f1dc59fbeb919aef7cc0cc827a8459d1fb1adb7972ef75bd9e0c10b75b
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
+F src/insert.c 14686083cedc198540b15a79586cdd4be2acf6d5fa97627e355f817ab07e9fee
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 55bcc3c741059a1056859e8adaf133aa179e22be12215c0936b2f354ef71209b
-F src/main.c 7ce55fa3c0bf669944de309ebab1655ed06ec67869adb0372c7a1062e461c448
-F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
+F src/main.c 690c4134f944cbd5b71d59dd6e61ce4131f6a50ab774f38108e57d07d79cf876
+F src/malloc.c 6f684fd039f53bf9195193eb0cde731a2954970fabc6ef054ba379b6052dc296
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
@@ -469,9 +469,9 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c 7fc2735390a7809d5d893ed735d994ff12521224b89738226fff6f1a0aa1c932
F src/os_win.c 0a4afa35cc8e812000df3ea2f64b476131b39e29e75d8007d0504726e4761de4
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
+F src/pager.c 9b9cb4e06c03d43d62480a7a685a012d645fcf3a39e7767ccb505fb41ee083ec
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
-F src/parse.y d79001da275bfe344b409006b85e81e486a0f6afc3762fdf0944f000f4aa0111
+F src/parse.y 44cbbc3e132ea128258eff7be7f6d5c5dfa25522f89ec8b5501276966511bd50
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
@@ -483,11 +483,11 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74
-F src/shell.c.in 9177b6cc706b1dd1ed81b05344641597d7ed8bba97a8fc31192309189846fab7
-F src/sqlite.h.in 2126192945019d4cdce335cb236b440a05ec75c93e4cd94c9c6d6e7fcc654cc4
+F src/shell.c.in 3e2db269982c4a6f7e8e32ef5620eda718a21a71bb2b5cd73c3ea9b87c6d21bc
+F src/sqlite.h.in 1f1a2da222ec57465794e8984d77f32d0bd0da80cdc136beadda461a0be9d80c
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
-F src/sqliteInt.h 003b78433baae4e5c997f99f2f9cf98d90754f256baeacb32f8189569a48251f
+F src/sqliteInt.h fd8702c65994d7de3e2d8f7d85d958731da1ed29476571fdfa2290fd8ec0bf80
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -507,7 +507,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
-F src/test_config.c 3904a8682aac58b77d20ca236face2b11e50781be4116004ba1ba79f69896ec9
+F src/test_config.c cc8a1d44648d9392a14f4ecfc841d027daaf61f952b9f70792edf11373aaa3dd
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
@@ -546,12 +546,12 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
F src/treeview.c eae35972ff44f67064de2eaf35f04afe94e7aea3271a8b3bcebb3f954880fec3
-F src/trigger.c 775053eecf6b73062e243404b56f5064446254d5cce17d8704d5cdffd72a546a
+F src/trigger.c a34539c69433276d37b0da9a89c117726ff2d292c0902895af1f393a983cd3a1
F src/update.c 961bd1265d4d1e5cd65c9a54fa5122fb7aefcb003fcf2de0c092fceb7e58972c
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
-F src/util.c d01fa6f45bfad3b65fb2490513aa2e0676412c61b4b094340b513cf72c3704a4
+F src/util.c 7315e97a8dc2c8e19ca64196c652cf0a65d13fd0a211b2cec082062372dc6261
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
-F src/vdbe.c 3393b508d9ad084ffce232a7c53e375ef5ac99b50b685c5131fcdfce97a9d534
+F src/vdbe.c c70267613df80345ed9bbd9c249c365b53bb9cbbe9d3e78e6d5c049d00ef5501
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
@@ -565,7 +565,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 5a3f464edd64596f601683ed321d12e6fd93c5fb9afdfb3653d6ffd0fee9c48f
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
-F src/where.c 5876c9100b622f7b9e5ee7f579b8b6a71ae5ba627724cea4546d9114c32b3cb5
+F src/where.c 36b92103f726609cc3dbe07c619426bd6886bede455de56ccff54c8e567f5582
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
F src/wherecode.c af1e79154aaa88cd802d6f2e5b945f67eaca7c958d1525fbf8ee19d5bd7b9020
F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46
@@ -662,7 +662,7 @@ F test/busy.test 510dc6daaad18bcbbc085bcc6217d6dc418def5e73f72ce1475eea0cb783472
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/cacheflush.test af25bb1509df04c1da10e38d8f322d66eceedf61
F test/cachespill.test 895997f84a25b323b166aecb69baab2d6380ea98f9e0bcc688c4493c535cfab9
-F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
+F test/capi2.test d3267a146df2251e7ad09a672d59e33e836d74c6fbeb843c18e87835ef646c12
F test/capi3.test 986e57cea8ab423b3fc8c2e3b69330394252d3d2a4496122ff3749e258305695
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
F test/capi3c.test 7ebed1d8fa2f3190149d556fe8cff5a006be62af437c5c4640db614470126098
@@ -686,7 +686,7 @@ F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
F test/collateB.test 1e68906951b846570f29f20102ed91d29e634854ee47454d725f2151ecac0b95
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
-F test/colname.test a7ecb8f1d6d8b30a6cf8fa84a2cd6f6e91cad8296376fabe485cf93cd5eb6229
+F test/colname.test 101aa39392a1f6883278f588836a3ab99178f8103f78032433400475cc05109f
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c
F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9
@@ -792,7 +792,7 @@ F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 87b5e43c872b7e69cd80b7b8813eb102b571a75d45dda24e38b65537bcc85733
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test f393e80c4b8d493b7a7f8f3809a8425bbf4292af1f5140f01cb1427798a2bbd4
-F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
+F test/fkey1.test 9d7e3a0d409e7f64ab077af3b4fc5e5ce1a4e8d8f1272b65b9d93480aeb1fa2b
F test/fkey2.test 155809016fad6b2a1491facf2ac53a551bc57c2c
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
@@ -921,6 +921,7 @@ F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test d202a7606d23f90988a664e88e268aed1087c11c
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4
+F test/func6.test a4281c8fcd42b56f7a60f28e8e4d444e8b2256f9e82658b7ab87699f8318f564
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
@@ -972,7 +973,7 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/index9.test 0aa3e509dddf81f93380396e40e9bb386904c1054924ba8fa9bcdfe85a8e7721
F test/indexedby.test faa585e315e868f09bce0eb39c41d6134649b13d2801638294d3ae616edf1609
-F test/indexexpr1.test 84100e880154a4b645db9f4fc7642756d9a2b6011b68f73c8efda4d244816de9
+F test/indexexpr1.test ace1ad489adc25325ad298434f13b1a515b36bf5dca9fe2a4b66cdf17aea3fa0
F test/indexexpr2.test 13247bac49143196556eb3f65e97ef301bd3e993f4511558b5db322ddc370ea6
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
@@ -1065,7 +1066,7 @@ F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
F test/minmax2.test dae92964ac87c1d2ef978c582e81a95e11c00f1cbef68980bfb2abaf10315063
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
-F test/misc1.test 76737c259537586355f45e2a1e121b6e91b5476c4604ad5c53d1abfcb3acf786
+F test/misc1.test 704ea2cc7e7b9deb622b37953f0e77d0879826e8c3bfc1d7a691528035405061
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3
@@ -1130,7 +1131,7 @@ F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
-F test/pragma5.test fd517f42ee847e126afbbbd9fd0fb9e5a4a61a962496a350adb8a22583fbdc37
+F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
@@ -1216,7 +1217,7 @@ F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test f78ea0e2637ae9f497cb41206f6346f983052ffc7a359e664aaf6847fc704ea7
+F test/shell1.test 6d69e08039aea13f2c42749f162fe05eab7b5c93729f31d49d7d27cf36226e5a
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
@@ -1253,7 +1254,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
-F test/speedtest1.c e44c5fccddcfe916c3bf7fe2f87dcc4b4fd66a0d923eb83515f311212670f267
+F test/speedtest1.c a5faf4cbe5769eee4b721b3875cb3f12520a9b99d9026b1063b47c39603375b8
F test/spellfix.test f9c1f431e2c096c8775fec032952320c0e4700db
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1448,7 +1449,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
F test/tkt4018.test 18dbc6617f7a4b90e938d1bd6d26ad18daafaf08
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
-F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
+F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
F test/trace3.test 56ab944fddacf628b118cc298503fc45c2e50ab0
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
@@ -1614,8 +1615,8 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c e6056373044d55296d21f81467dba7632bbb81dc49af072b3f0e76338771497e
-F tool/lempar.c 967ebf585cd09b11b89d255d213865109a9c4ff075680d22580a2826de288c89
+F tool/lemon.c 7f7735326ca9c3b48327b241063cee52d35d44e20ebe1b3624a81658052a4d39
+F tool/lempar.c dddd4f592b8bad36aec4500d456c5db5fe42fefc4ee384913880439d8917f87a
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
@@ -1653,7 +1654,7 @@ F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/spaceanal.tcl 4bfd19aad7eb3ce0372ef0255f58035e0bba4ff5e9acfd763a10c6fb365c8dec
-F tool/speed-check.sh a97ae367e9172a706101901e7caef48f1a14fc8a49053b25e79f6a67296b3412
+F tool/speed-check.sh 9ae425da8819e54e780cf494fc6d8175dfb16e109ae3214a45a5c9bb2b74e2c4
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
@@ -1693,7 +1694,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f69e8194bfa7de436c96028730ebd57f186d2e6207792e172e1aa38c7f4211c9
-R 145246df93a24ee9820cce32c6b5afb4
-U dan
-Z 640cac8c8ac89e53412f930b0b057c7a
+P 01d4e866fb7b01aeada537d41c4a47747c7810e2028f51077ee5b8b78c348954 a6eee0fcd89d3958f8720ebdb5f0a8558b4795d747128091dae283eb81c4f74f
+R d4f5940088399233b1f4f56f19294263
+U drh
+Z c1193b259bc575590a62665cc9281689
diff --git a/manifest.uuid b/manifest.uuid
index bc6078e24..0fefe4597 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-01d4e866fb7b01aeada537d41c4a47747c7810e2028f51077ee5b8b78c348954 \ No newline at end of file
+406f79183736b6ad360169b837172afef2c82a4312f5787db08c54167a44b15e \ No newline at end of file
diff --git a/src/btree.c b/src/btree.c
index 0fa00a2e1..8cd5ee673 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -4432,6 +4432,20 @@ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
return pCur->info.nKey;
}
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/*
+** Return the offset into the database file for the start of the
+** payload to which the cursor is pointing.
+*/
+i64 sqlite3BtreeOffset(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ assert( pCur->eState==CURSOR_VALID );
+ getCellInfo(pCur);
+ return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
+ (i64)(pCur->info.pPayload - pCur->pPage->aData);
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
/*
** Return the number of bytes of payload for the entry that pCur is
** currently pointing to. For table btrees, this will be the amount
diff --git a/src/btree.h b/src/btree.h
index e2c271cdc..e8e114bd2 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -291,6 +291,9 @@ int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+i64 sqlite3BtreeOffset(BtCursor*);
+#endif
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
diff --git a/src/build.c b/src/build.c
index 01d897241..26eb0579e 100644
--- a/src/build.c
+++ b/src/build.c
@@ -1221,34 +1221,37 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
** This routine is called by the parser while in the middle of
** parsing a CREATE TABLE statement.
*/
-void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
+void sqlite3AddDefaultValue(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The parsed expression of the default value */
+ const char *zStart, /* Start of the default value text */
+ const char *zEnd /* First character past end of defaut value text */
+){
Table *p;
Column *pCol;
sqlite3 *db = pParse->db;
p = pParse->pNewTable;
if( p!=0 ){
pCol = &(p->aCol[p->nCol-1]);
- if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
+ if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
/* A copy of pExpr is used instead of the original, as pExpr contains
- ** tokens that point to volatile memory. The 'span' of the expression
- ** is required by pragma table_info.
+ ** tokens that point to volatile memory.
*/
Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
memset(&x, 0, sizeof(x));
x.op = TK_SPAN;
- x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
- x.pLeft = pSpan->pExpr;
+ x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
+ x.pLeft = pExpr;
x.flags = EP_Skip;
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
sqlite3DbFree(db, x.u.zToken);
}
}
- sqlite3ExprDelete(db, pSpan->pExpr);
+ sqlite3ExprDelete(db, pExpr);
}
/*
@@ -1965,6 +1968,7 @@ void sqlite3EndTable(
pParse->nTab = 2;
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
+ if( pParse->nErr ) return;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
if( pSelTab==0 ) return;
assert( p->aCol==0 );
@@ -1975,6 +1979,7 @@ void sqlite3EndTable(
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
sqlite3Select(pParse, pSelect, &dest);
+ if( pParse->nErr ) return;
sqlite3VdbeEndCoroutine(v, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1);
addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
diff --git a/src/expr.c b/src/expr.c
index 524e53934..32cc4423f 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1654,17 +1654,16 @@ void sqlite3ExprListSetName(
void sqlite3ExprListSetSpan(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List to which to add the span. */
- ExprSpan *pSpan /* The span to be added */
+ const char *zStart, /* Start of the span */
+ const char *zEnd /* End of the span */
){
sqlite3 *db = pParse->db;
assert( pList!=0 || db->mallocFailed!=0 );
if( pList ){
struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
assert( pList->nExpr>0 );
- assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr );
sqlite3DbFree(db, pItem->zSpan);
- pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
+ pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);
}
}
@@ -3871,9 +3870,21 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
- constMask, r1, target, (char*)pDef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nFarg);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
+ Expr *pArg = pFarg->a[0].pExpr;
+ if( pArg->op==TK_COLUMN ){
+ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ }
+ }else
+#endif
+ {
+ sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
+ constMask, r1, target, (char*)pDef, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nFarg);
+ }
if( nFarg && constMask==0 ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
diff --git a/src/func.c b/src/func.c
index 7528fa8b4..1076b9716 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1799,6 +1799,10 @@ void sqlite3RegisterBuiltinFunctions(void){
#ifdef SQLITE_DEBUG
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
#endif
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
+ SQLITE_FUNC_TYPEOF),
+#endif
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
diff --git a/src/insert.c b/src/insert.c
index f0af0fbd1..e1514692c 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1571,6 +1571,7 @@ void sqlite3GenerateConstraintChecks(
}
/* Check to see if the new index entry will be unique */
+ sqlite3ExprCachePush(pParse);
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
@@ -1659,6 +1660,7 @@ void sqlite3GenerateConstraintChecks(
}
}
sqlite3VdbeResolveLabel(v, addrUniqueOk);
+ sqlite3ExprCachePop(pParse);
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
if( ipkTop ){
diff --git a/src/main.c b/src/main.c
index 32ce1889f..3c8035c12 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3911,6 +3911,22 @@ int sqlite3_test_control(int op, ...){
sqlite3_mutex_leave(db->mutex);
break;
}
+
+#if defined(YYCOVERAGE)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
+ **
+ ** This test control (only available when SQLite is compiled with
+ ** -DYYCOVERAGE) writes a report onto "out" that shows all
+ ** state/lookahead combinations in the parser state machine
+ ** which are never exercised. If any state is missed, make the
+ ** return code SQLITE_ERROR.
+ */
+ case SQLITE_TESTCTRL_PARSER_COVERAGE: {
+ FILE *out = va_arg(ap, FILE*);
+ if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
+ break;
+ }
+#endif /* defined(YYCOVERAGE) */
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
diff --git a/src/malloc.c b/src/malloc.c
index b750f6e72..ec2d93ac8 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -628,6 +628,19 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
}
/*
+** The text between zStart and zEnd represents a phrase within a larger
+** SQL statement. Make a copy of this phrase in space obtained form
+** sqlite3DbMalloc(). Omit leading and trailing whitespace.
+*/
+char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ int n;
+ while( sqlite3Isspace(zStart[0]) ) zStart++;
+ n = (int)(zEnd - zStart);
+ while( n>0 && sqlite3Isspace(zStart[n-1]) ) n--;
+ return sqlite3DbStrNDup(db, zStart, n);
+}
+
+/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
diff --git a/src/pager.c b/src/pager.c
index dbb7636ca..295cbe04c 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -5579,7 +5579,7 @@ static int getPageMMap(
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
- }else{
+ }else{
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
}
if( pPg ){
diff --git a/src/parse.y b/src/parse.y
index 0867d1e0c..e780f8c3a 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -273,26 +273,44 @@ typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);}
signed ::= plus_num.
signed ::= minus_num.
+// The scanpt non-terminal takes a value which is a pointer to the
+// input text just past the last token that has been shifted into
+// the parser. By surrounding some phrase in the grammar with two
+// scanpt non-terminals, we can capture the input text for that phrase.
+// For example:
+//
+// something ::= .... scanpt(A) phrase scanpt(Z).
+//
+// The text that is parsed as "phrase" is a string starting at A
+// and containing (int)(Z-A) characters. There might be some extra
+// whitespace on either end of the text, but that can be removed in
+// post-processing, if needed.
+//
+%type scanpt {const char*}
+scanpt(A) ::= . {
+ assert( yyLookahead!=YYNOCODE );
+ A = yyLookaheadToken.z;
+}
+
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
//
carglist ::= carglist ccons.
carglist ::= .
ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
-ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT MINUS(A) term(X). {
- ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, X.pExpr, 0);
- v.zStart = A.z;
- v.zEnd = X.zEnd;
- sqlite3AddDefaultValue(pParse,&v);
-}
-ccons ::= DEFAULT id(X). {
- ExprSpan v;
- spanExpr(&v, pParse, TK_STRING, X);
- sqlite3AddDefaultValue(pParse,&v);
+ccons ::= DEFAULT scanpt(A) term(X) scanpt(Z).
+ {sqlite3AddDefaultValue(pParse,X,A,Z);}
+ccons ::= DEFAULT LP(A) expr(X) RP(Z).
+ {sqlite3AddDefaultValue(pParse,X,A.z+1,Z.z);}
+ccons ::= DEFAULT PLUS(A) term(X) scanpt(Z).
+ {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
@@ -304,7 +322,7 @@ ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
-ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
+ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
@@ -355,7 +373,7 @@ tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
tcons ::= CHECK LP expr(E) RP onconf.
- {sqlite3AddCheckConstraint(pParse,E.pExpr);}
+ {sqlite3AddCheckConstraint(pParse,E);}
tcons ::= FOREIGN KEY LP eidlist(FA) RP
REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
@@ -549,16 +567,16 @@ distinct(A) ::= . {A = 0;}
%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);}
sclp(A) ::= selcollist(A) COMMA.
sclp(A) ::= . {A = 0;}
-selcollist(A) ::= sclp(A) expr(X) as(Y). {
- A = sqlite3ExprListAppend(pParse, A, X.pExpr);
+selcollist(A) ::= sclp(A) scanpt(B) expr(X) scanpt(Z) as(Y). {
+ A = sqlite3ExprListAppend(pParse, A, X);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
- sqlite3ExprListSetSpan(pParse,A,&X);
+ sqlite3ExprListSetSpan(pParse,A,B,Z);
}
-selcollist(A) ::= sclp(A) STAR. {
+selcollist(A) ::= sclp(A) scanpt STAR. {
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
A = sqlite3ExprListAppend(pParse, A, p);
}
-selcollist(A) ::= sclp(A) nm(X) DOT STAR. {
+selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR. {
Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
@@ -656,7 +674,7 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
-on_opt(N) ::= ON expr(E). {N = E.pExpr;}
+on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= . {N = 0;}
// Note that this block abuses the Token type just a little. If there is
@@ -693,11 +711,11 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,A,Y.pExpr);
+ A = sqlite3ExprListAppend(pParse,A,Y);
sqlite3ExprListSetSortOrder(A,Z);
}
sortlist(A) ::= expr(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/
+ A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/
sqlite3ExprListSetSortOrder(A,Z);
}
@@ -715,7 +733,7 @@ groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);}
having_opt(A) ::= . {A = 0;}
-having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
+having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {Expr*}
@@ -729,11 +747,11 @@ having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
//%destructor limit_opt {sqlite3ExprDelete(pParse->db, $$);}
limit_opt(A) ::= . {A = 0;}
limit_opt(A) ::= LIMIT expr(X).
- {A = sqlite3PExpr(pParse,TK_LIMIT,X.pExpr,0);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,X,0);}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
- {A = sqlite3PExpr(pParse,TK_LIMIT,X.pExpr,Y.pExpr);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,X,Y);}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
- {A = sqlite3PExpr(pParse,TK_LIMIT,Y.pExpr,X.pExpr);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,Y,X);}
/////////////////////////// The DELETE statement /////////////////////////////
//
@@ -757,7 +775,7 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
-where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
+where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
@@ -784,18 +802,18 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). {
- A = sqlite3ExprListAppend(pParse, A, Y.pExpr);
+ A = sqlite3ExprListAppend(pParse, A, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= setlist(A) COMMA LP idlist(X) RP EQ expr(Y). {
- A = sqlite3ExprListAppendVector(pParse, A, X, Y.pExpr);
+ A = sqlite3ExprListAppendVector(pParse, A, X, Y);
}
setlist(A) ::= nm(X) EQ expr(Y). {
- A = sqlite3ExprListAppend(pParse, 0, Y.pExpr);
+ A = sqlite3ExprListAppend(pParse, 0, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= LP idlist(X) RP EQ expr(Y). {
- A = sqlite3ExprListAppendVector(pParse, 0, X, Y.pExpr);
+ A = sqlite3ExprListAppendVector(pParse, 0, X, Y);
}
////////////////////////// The INSERT command /////////////////////////////////
@@ -829,26 +847,18 @@ idlist(A) ::= nm(Y).
/////////////////////////// Expression Processing /////////////////////////////
//
-%type expr {ExprSpan}
-%destructor expr {sqlite3ExprDelete(pParse->db, $$.pExpr);}
-%type term {ExprSpan}
-%destructor term {sqlite3ExprDelete(pParse->db, $$.pExpr);}
+%type expr {Expr*}
+%destructor expr {sqlite3ExprDelete(pParse->db, $$);}
+%type term {Expr*}
+%destructor term {sqlite3ExprDelete(pParse->db, $$);}
%include {
- /* This is a utility routine used to set the ExprSpan.zStart and
- ** ExprSpan.zEnd values of pOut so that the span covers the complete
- ** range of text beginning with pStart and going to the end of pEnd.
- */
- static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
- pOut->zStart = pStart->z;
- pOut->zEnd = &pEnd->z[pEnd->n];
- }
/* Construct a new Expr object from a single identifier. Use the
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
- static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
+ static Expr *tokenExpr(Parse *pParse, int op, Token t){
Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
if( p ){
memset(p, 0, sizeof(Expr));
@@ -866,136 +876,98 @@ idlist(A) ::= nm(Y).
p->nHeight = 1;
#endif
}
- pOut->pExpr = p;
- pOut->zStart = t.z;
- pOut->zEnd = &t.z[t.n];
+ return p;
}
}
expr(A) ::= term(A).
-expr(A) ::= LP(B) expr(X) RP(E).
- {spanSet(&A,&B,&E); /*A-overwrites-B*/ A.pExpr = X.pExpr;}
-expr(A) ::= id(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
-expr(A) ::= JOIN_KW(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
+expr(A) ::= LP expr(X) RP. {A = X;}
+expr(A) ::= id(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
+expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
- spanSet(&A,&X,&Z); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
-term(A) ::= NULL|FLOAT|BLOB(X). {spanExpr(&A,pParse,@X,X); /*A-overwrites-X*/}
-term(A) ::= STRING(X). {spanExpr(&A,pParse,@X,X); /*A-overwrites-X*/}
+term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
+term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
term(A) ::= INTEGER(X). {
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
- A.zStart = X.z;
- A.zEnd = X.z + X.n;
+ A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
}
expr(A) ::= VARIABLE(X). {
if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){
u32 n = X.n;
- spanExpr(&A, pParse, TK_VARIABLE, X);
- sqlite3ExprAssignVarNumber(pParse, A.pExpr, n);
+ A = tokenExpr(pParse, TK_VARIABLE, X);
+ sqlite3ExprAssignVarNumber(pParse, A, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
Token t = X; /*A-overwrites-X*/
assert( t.n>=2 );
- spanSet(&A, &t, &t);
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- A.pExpr = 0;
+ A = 0;
}else{
- A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( A.pExpr ) sqlite3GetInt32(&t.z[1], &A.pExpr->iTable);
+ A = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( A ) sqlite3GetInt32(&t.z[1], &A->iTable);
}
}
}
expr(A) ::= expr(A) COLLATE ids(C). {
- A.pExpr = sqlite3ExprAddCollateToken(pParse, A.pExpr, &C, 1);
- A.zEnd = &C.z[C.n];
+ A = sqlite3ExprAddCollateToken(pParse, A, &C, 1);
}
%ifndef SQLITE_OMIT_CAST
-expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1);
- sqlite3ExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0);
+expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. {
+ A = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, A, E, 0);
}
%endif SQLITE_OMIT_CAST
-expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). {
+expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP. {
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
- A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
- spanSet(&A,&X,&E);
- if( D==SF_Distinct && A.pExpr ){
- A.pExpr->flags |= EP_Distinct;
+ A = sqlite3ExprFunction(pParse, Y, &X);
+ if( D==SF_Distinct && A ){
+ A->flags |= EP_Distinct;
}
}
-expr(A) ::= id(X) LP STAR RP(E). {
- A.pExpr = sqlite3ExprFunction(pParse, 0, &X);
- spanSet(&A,&X,&E);
+expr(A) ::= id(X) LP STAR RP. {
+ A = sqlite3ExprFunction(pParse, 0, &X);
}
term(A) ::= CTIME_KW(OP). {
- A.pExpr = sqlite3ExprFunction(pParse, 0, &OP);
- spanSet(&A, &OP, &OP);
+ A = sqlite3ExprFunction(pParse, 0, &OP);
}
-%include {
- /* This routine constructs a binary expression node out of two ExprSpan
- ** objects and uses the result to populate a new ExprSpan object.
- */
- static void spanBinaryExpr(
- Parse *pParse, /* The parsing context. Errors accumulate here */
- int op, /* The binary operation */
- ExprSpan *pLeft, /* The left operand, and output */
- ExprSpan *pRight /* The right operand */
- ){
- pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr);
- pLeft->zEnd = pRight->zEnd;
- }
-
- /* If doNot is true, then add a TK_NOT Expr-node wrapper around the
- ** outside of *ppExpr.
- */
- static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
- if( doNot ){
- pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0);
- }
- }
-}
-
-expr(A) ::= LP(L) nexprlist(X) COMMA expr(Y) RP(R). {
- ExprList *pList = sqlite3ExprListAppend(pParse, X, Y.pExpr);
- A.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = pList;
- spanSet(&A, &L, &R);
+expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. {
+ ExprList *pList = sqlite3ExprListAppend(pParse, X, Y);
+ A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( A ){
+ A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
}
-expr(A) ::= expr(A) AND(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) OR(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+expr(A) ::= expr(A) AND(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) OR(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) LT|GT|GE|LE(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) PLUS|MINUS(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) STAR|SLASH|REM(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) CONCAT(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) CONCAT(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
%type likeop {Token}
likeop(A) ::= LIKE_KW|MATCH(A).
likeop(A) ::= NOT LIKE_KW|MATCH(X). {A=X; A.n|=0x80000000; /*A-overwrite-X*/}
@@ -1003,42 +975,26 @@ expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] {
ExprList *pList;
int bNot = OP.n & 0x80000000;
OP.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
- A.pExpr = sqlite3ExprFunction(pParse, pList, &OP);
- exprNot(pParse, bNot, &A);
- A.zEnd = Y.zEnd;
- if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, Y);
+ pList = sqlite3ExprListAppend(pParse,pList, A);
+ A = sqlite3ExprFunction(pParse, pList, &OP);
+ if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
+ if( A ) A->flags |= EP_InfixFunc;
}
expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
ExprList *pList;
int bNot = OP.n & 0x80000000;
OP.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
- A.pExpr = sqlite3ExprFunction(pParse, pList, &OP);
- exprNot(pParse, bNot, &A);
- A.zEnd = E.zEnd;
- if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
-}
-
-%include {
- /* Construct an expression node for a unary postfix operator
- */
- static void spanUnaryPostfix(
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand, and output */
- Token *pPostOp /* The operand token for setting the span */
- ){
- pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
- pOperand->zEnd = &pPostOp->z[pPostOp->n];
- }
+ pList = sqlite3ExprListAppend(pParse,0, Y);
+ pList = sqlite3ExprListAppend(pParse,pList, A);
+ pList = sqlite3ExprListAppend(pParse,pList, E);
+ A = sqlite3ExprFunction(pParse, pList, &OP);
+ if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
+ if( A ) A->flags |= EP_InfixFunc;
}
-expr(A) ::= expr(A) ISNULL|NOTNULL(E). {spanUnaryPostfix(pParse,@E,&A,&E);}
-expr(A) ::= expr(A) NOT NULL(E). {spanUnaryPostfix(pParse,TK_NOTNULL,&A,&E);}
+expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);}
+expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);}
%include {
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
@@ -1060,61 +1016,42 @@ expr(A) ::= expr(A) NOT NULL(E). {spanUnaryPostfix(pParse,TK_NOTNULL,&A,&E);}
// is any other expression, code as TK_IS or TK_ISNOT.
//
expr(A) ::= expr(A) IS expr(Y). {
- spanBinaryExpr(pParse,TK_IS,&A,&Y);
- binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL);
+ A = sqlite3PExpr(pParse,TK_IS,A,Y);
+ binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
- spanBinaryExpr(pParse,TK_ISNOT,&A,&Y);
- binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
-}
-
-%include {
- /* Construct an expression node for a unary prefix operator
- */
- static void spanUnaryPrefix(
- ExprSpan *pOut, /* Write the new expression node here */
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand */
- Token *pPreOp /* The operand token for setting the span */
- ){
- pOut->zStart = pPreOp->z;
- pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
- pOut->zEnd = pOperand->zEnd;
- }
+ A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
+ binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
}
-
-
expr(A) ::= NOT(B) expr(X).
- {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
+ {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= BITNOT(B) expr(X).
- {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
-expr(A) ::= MINUS(B) expr(X). [BITNOT]
- {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);/*A-overwrites-B*/}
-expr(A) ::= PLUS(B) expr(X). [BITNOT]
- {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);/*A-overwrites-B*/}
+ {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
+expr(A) ::= MINUS expr(X). [BITNOT]
+ {A = sqlite3PExpr(pParse, TK_UMINUS, X, 0);}
+expr(A) ::= PLUS expr(X). [BITNOT]
+ {A = sqlite3PExpr(pParse, TK_UPLUS, X, 0);}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
- ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr);
- A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, A.pExpr, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, X);
+ pList = sqlite3ExprListAppend(pParse,pList, Y);
+ A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0);
+ if( A ){
+ A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- exprNot(pParse, N, &A);
- A.zEnd = Y.zEnd;
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
%ifndef SQLITE_OMIT_SUBQUERY
%type in_op {int}
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
- expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] {
+ expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP. [IN] {
if( Y==0 ){
/* Expressions of the form
**
@@ -1124,8 +1061,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprDelete(pParse->db, A.pExpr);
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1);
+ sqlite3ExprDelete(pParse->db, A);
+ A = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1);
}else if( Y->nExpr==1 ){
/* Expressions of the form:
**
@@ -1152,54 +1089,48 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
- A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A.pExpr, pRHS);
+ A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS);
}else{
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = Y;
- sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ if( A ){
+ A->x.pList = Y;
+ sqlite3ExprSetHeightAndFlags(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
}
- exprNot(pParse, N, &A);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
- A.zEnd = &E.z[E.n];
}
- expr(A) ::= LP(B) select(X) RP(E). {
- spanSet(&A,&B,&E); /*A-overwrites-B*/
- A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, X);
+ expr(A) ::= LP select(X) RP. {
+ A = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, A, X);
}
- expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] {
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, Y);
- exprNot(pParse, N, &A);
- A.zEnd = &E.z[E.n];
+ expr(A) ::= expr(A) in_op(N) LP select(Y) RP. [IN] {
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ sqlite3PExprAddSelect(pParse, A, Y);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E);
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, pSelect);
- exprNot(pParse, N, &A);
- A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ sqlite3PExprAddSelect(pParse, A, pSelect);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
- expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
+ expr(A) ::= EXISTS LP select(Y) RP. {
Expr *p;
- spanSet(&A,&B,&E); /*A-overwrites-B*/
- p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
sqlite3PExprAddSelect(pParse, p, Y);
}
%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
-expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
- spanSet(&A,&C,&E); /*A-overwrites-C*/
- A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
- sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
+expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. {
+ A = sqlite3PExpr(pParse, TK_CASE, X, 0);
+ if( A ){
+ A->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
+ sqlite3ExprSetHeightAndFlags(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
sqlite3ExprDelete(pParse->db, Z);
@@ -1208,20 +1139,20 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(A) WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,A, Y.pExpr);
- A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
+ A = sqlite3ExprListAppend(pParse,A, Y);
+ A = sqlite3ExprListAppend(pParse,A, Z);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
+ A = sqlite3ExprListAppend(pParse,0, Y);
+ A = sqlite3ExprListAppend(pParse,A, Z);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete(pParse->db, $$);}
-case_else(A) ::= ELSE expr(X). {A = X.pExpr;}
+case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
-case_operand(A) ::= expr(X). {A = X.pExpr; /*A-overwrites-X*/}
+case_operand(A) ::= expr(X). {A = X; /*A-overwrites-X*/}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
@@ -1232,9 +1163,9 @@ case_operand(A) ::= . {A = 0;}
exprlist(A) ::= nexprlist(A).
exprlist(A) ::= . {A = 0;}
nexprlist(A) ::= nexprlist(A) COMMA expr(Y).
- {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);}
+ {A = sqlite3ExprListAppend(pParse,A,Y);}
nexprlist(A) ::= expr(Y).
- {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/}
+ {A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/}
%ifndef SQLITE_OMIT_SUBQUERY
/* A paren_exprlist is an optional expression list contained inside
@@ -1388,7 +1319,7 @@ foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete(pParse->db, $$);}
when_clause(A) ::= . { A = 0; }
-when_clause(A) ::= WHEN expr(X). { A = X.pExpr; }
+when_clause(A) ::= WHEN expr(X). { A = X; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
@@ -1437,34 +1368,33 @@ tridxby ::= NOT INDEXED. {
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
// UPDATE
trigger_cmd(A) ::=
- UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z).
- {A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R);}
+ UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E).
+ {A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R, B.z, E);}
// INSERT
-trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S).
- {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);/*A-overwrites-R*/}
+trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
+ trnm(X) idlist_opt(F) select(S) scanpt(Z).
+ {A = sqlite3TriggerInsertStep(pParse->db,&X,F,S,R,B,Z);/*A-overwrites-R*/}
// DELETE
-trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
- {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
+trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E).
+ {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y, B.z, E);}
// SELECT
-trigger_cmd(A) ::= select(X).
- {A = sqlite3TriggerSelectStep(pParse->db, X); /*A-overwrites-X*/}
+trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E).
+ {A = sqlite3TriggerSelectStep(pParse->db, X, B, E); /*A-overwrites-X*/}
// The special RAISE expression that may occur in trigger programs
-expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( A.pExpr ){
- A.pExpr->affinity = OE_Ignore;
+expr(A) ::= RAISE LP IGNORE RP. {
+ A = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( A ){
+ A->affinity = OE_Ignore;
}
}
-expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
- if( A.pExpr ) {
- A.pExpr->affinity = (char)T;
+expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. {
+ A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
+ if( A ) {
+ A->affinity = (char)T;
}
}
%endif !SQLITE_OMIT_TRIGGER
@@ -1485,16 +1415,16 @@ cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
%ifndef SQLITE_OMIT_ATTACH
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
- sqlite3Attach(pParse, F.pExpr, D.pExpr, K);
+ sqlite3Attach(pParse, F, D, K);
}
cmd ::= DETACH database_kw_opt expr(D). {
- sqlite3Detach(pParse, D.pExpr);
+ sqlite3Detach(pParse, D);
}
%type key_opt {Expr*}
%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
key_opt(A) ::= . { A = 0; }
-key_opt(A) ::= KEY expr(X). { A = X.pExpr; }
+key_opt(A) ::= KEY expr(X). { A = X; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
diff --git a/src/shell.c.in b/src/shell.c.in
index f7edb53f0..6f1c92e00 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -730,6 +730,71 @@ static char quoteChar(const char *zName){
}
/*
+** Construct a fake object name and column list to describe the structure
+** of the view, virtual table, or table valued function zSchema.zName.
+*/
+static char *shellFakeSchema(
+ sqlite3 *db, /* The database connection containing the vtab */
+ const char *zSchema, /* Schema of the database holding the vtab */
+ const char *zName /* The name of the virtual table */
+){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ ShellText s;
+ char cQuote;
+ char *zDiv = "(";
+ int nRow = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
+ zSchema ? zSchema : "main", zName);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ initText(&s);
+ if( zSchema ){
+ cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
+ appendText(&s, zSchema, cQuote);
+ appendText(&s, ".", 0);
+ }
+ cQuote = quoteChar(zName);
+ appendText(&s, zName, cQuote);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
+ nRow++;
+ appendText(&s, zDiv, 0);
+ zDiv = ",";
+ cQuote = quoteChar(zCol);
+ appendText(&s, zCol, cQuote);
+ }
+ appendText(&s, ")", 0);
+ sqlite3_finalize(pStmt);
+ if( nRow==0 ){
+ freeText(&s);
+ s.z = 0;
+ }
+ return s.z;
+}
+
+/*
+** SQL function: shell_module_schema(X)
+**
+** Return a fake schema for the table-valued function or eponymous virtual
+** table X.
+*/
+static void shellModuleSchema(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ const char *zName = (const char*)sqlite3_value_text(apVal[0]);
+ char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
+ if( zFake ){
+ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %z */", zFake),
+ -1, sqlite3_free);
+ }
+}
+
+/*
** SQL function: shell_add_schema(S,X)
**
** Add the schema name X to the CREATE statement in S and return the result.
@@ -764,20 +829,36 @@ static void shellAddSchemaName(
int i = 0;
const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
- assert( nVal==2 );
+ const char *zName = (const char*)sqlite3_value_text(apVal[2]);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
int n = strlen30(aPrefix[i]);
if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
- char cQuote = quoteChar(zSchema);
- char *z;
- if( cQuote ){
- z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
- }else{
- z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ char *z = 0;
+ char *zFake = 0;
+ if( zSchema ){
+ char cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
+ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
+ }else{
+ z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ }
+ }
+ if( zName
+ && aPrefix[i][0]=='V'
+ && (zFake = shellFakeSchema(db, zSchema, zName))!=0
+ ){
+ if( z==0 ){
+ z = sqlite3_mprintf("%s\n/* %z */", zIn, zFake);
+ }else{
+ z = sqlite3_mprintf("%z\n/* %z */", z, zFake);
+ }
+ }
+ if( z ){
+ sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ return;
}
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
- return;
}
}
}
@@ -3006,8 +3087,10 @@ static void open_db(ShellState *p, int keepAlive){
sqlite3_zipfile_init(p->db, 0, 0);
sqlite3_sqlar_init(p->db, 0, 0);
#endif
- sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
+ 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);
}
}
@@ -6073,59 +6156,48 @@ static int do_meta_command(char *zLine, ShellState *p){
ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
- const char *zDiv = 0;
+ const char *zDiv = "(";
+ const char *zName = 0;
int iSchema = 0;
+ int bDebug = 0;
+ int ii;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
initText(&sSelect);
- if( nArg>=2 && optionMatch(azArg[1], "indent") ){
- data.cMode = data.mode = MODE_Pretty;
- nArg--;
- if( nArg==2 ) azArg[1] = azArg[2];
+ for(ii=1; ii<nArg; ii++){
+ if( optionMatch(azArg[ii],"indent") ){
+ data.cMode = data.mode = MODE_Pretty;
+ }else if( optionMatch(azArg[ii],"debug") ){
+ bDebug = 1;
+ }else if( zName==0 ){
+ zName = azArg[ii];
+ }else{
+ raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
}
- if( nArg==2 && azArg[1][0]!='-' ){
- int i;
- for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
- if( strcmp(azArg[1],"sqlite_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TABLE sqlite_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+ if( zName!=0 ){
+ int isMaster = sqlite3_strlike(zName, "sqlite_master", 0)==0;
+ if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master",0)==0 ){
char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+ new_argv[0] = sqlite3_mprintf(
+ "CREATE TABLE %s (\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
- ")";
+ ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else{
- zDiv = "(";
+ sqlite3_free(new_argv[0]);
}
- }else if( nArg==1 ){
- zDiv = "(";
- }else{
- raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
}
if( zDiv ){
sqlite3_stmt *pStmt = 0;
@@ -6145,39 +6217,48 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
appendText(&sSelect, zDiv, 0);
zDiv = " UNION ALL ";
- if( strcmp(zDb, "main")!=0 ){
- appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
- appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, ", 0);
- appendText(&sSelect, zDb, '\'');
- appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ if( sqlite3_stricmp(zDb, "main")!=0 ){
appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ".sqlite_master", 0);
}else{
- appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
+ appendText(&sSelect, "NULL", 0);
}
+ appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ".sqlite_master", 0);
}
sqlite3_finalize(pStmt);
+#ifdef SQLITE_INTROSPECTION_PRAGMAS
+ if( zName ){
+ appendText(&sSelect,
+ " UNION ALL SELECT shell_module_schema(name),"
+ " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0);
+ }
+#endif
appendText(&sSelect, ") WHERE ", 0);
- if( nArg>1 ){
- char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
- if( strchr(azArg[1], '.') ){
+ if( zName ){
+ char *zQarg = sqlite3_mprintf("%Q", zName);
+ if( strchr(zName, '.') ){
appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
}else{
appendText(&sSelect, "lower(tbl_name)", 0);
}
- appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, strchr(zName, '*') ? " GLOB " : " LIKE ", 0);
appendText(&sSelect, zQarg, 0);
appendText(&sSelect, " AND ", 0);
sqlite3_free(zQarg);
}
appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
- rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ if( bDebug ){
+ utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
+ }else{
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ }
freeText(&sSelect);
}
if( zErrMsg ){
@@ -6863,6 +6944,9 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
+#ifdef YYCOVERAGE
+ { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" },
+#endif
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET, "" },
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
@@ -6988,6 +7072,14 @@ static int do_meta_command(char *zLine, ShellState *p){
isOk = 3;
}
break;
+
+#ifdef YYCOVERAGE
+ case SQLITE_TESTCTRL_PARSER_COVERAGE:
+ if( nArg==2 ){
+ sqlite3_test_control(testctrl, p->out);
+ isOk = 3;
+ }
+#endif
}
}
if( isOk==0 && iCtrl>=0 ){
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f161eea6f..f63b02931 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -6971,9 +6971,9 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
** a pointer to the underlying [sqlite3_file] object to be written into
-** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
+** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
** case is a short-circuit path which does not actually invoke the
** underlying sqlite3_io_methods.xFileControl method.
**
@@ -6985,7 +6985,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** an incorrect zDbName and an SQLITE_ERROR return from the underlying
** xFileControl method.
**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
+** See also: [file control opcodes]
*/
int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
@@ -7042,7 +7042,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
-#define SQLITE_TESTCTRL_LAST 25 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
+#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
/*
** CAPI3REF: SQLite Runtime Status
@@ -8300,7 +8301,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
-** method of a [virtual table implementation].
+** method of a [virtual table].
**
** The first argument must be the sqlite3_index_info object that is the
** first parameter to the xBestIndex() method. The second argument must be
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b0c4711b0..8e7913320 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1063,7 +1063,6 @@ typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
-typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
@@ -1630,6 +1629,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
+#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -2505,17 +2505,6 @@ struct ExprList {
};
/*
-** An instance of this structure is used by the parser to record both
-** the parse tree for an expression and the span of input text for an
-** expression.
-*/
-struct ExprSpan {
- Expr *pExpr; /* The expression parse tree */
- const char *zStart; /* First character of input text */
- const char *zEnd; /* One character past the end of input text */
-};
-
-/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
**
@@ -3215,6 +3204,7 @@ struct TriggerStep {
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
ExprList *pExprList; /* SET clause for UPDATE. */
IdList *pIdList; /* Column names for INSERT */
+ char *zSpan; /* Original SQL text of this command */
TriggerStep *pNext; /* Next in the link-list */
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
@@ -3525,6 +3515,7 @@ void *sqlite3DbMallocRaw(sqlite3*, u64);
void *sqlite3DbMallocRawNN(sqlite3*, u64);
char *sqlite3DbStrDup(sqlite3*,const char*);
char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
+char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
void *sqlite3Realloc(void*, u64);
void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
void *sqlite3DbRealloc(sqlite3 *, void *, u64);
@@ -3663,7 +3654,7 @@ ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
void sqlite3ExprListSetSortOrder(ExprList*,int);
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
-void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
+void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
u32 sqlite3ExprListFlags(const ExprList*);
int sqlite3Init(sqlite3*, char**);
@@ -3693,7 +3684,7 @@ void sqlite3AddColumn(Parse*,Token*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
-void sqlite3AddDefaultValue(Parse*,ExprSpan*);
+void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*,
@@ -3914,11 +3905,14 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
- TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
+ TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
+ const char*,const char*);
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
- Select*,u8);
- TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
- TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
+ Select*,u8,const char*,const char*);
+ TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
+ const char*,const char*);
+ TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
+ const char*,const char*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
@@ -4348,6 +4342,9 @@ void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_DEBUG
void sqlite3ParserTrace(FILE*, char *);
#endif
+#if defined(YYCOVERAGE)
+ int sqlite3ParserCoverage(FILE*);
+#endif
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
diff --git a/src/test_config.c b/src/test_config.c
index 24a7287da..ad63016ba 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -160,6 +160,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mem5", "0", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","1",TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","0",TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "1", TCL_GLOBAL_ONLY);
#else
diff --git a/src/trigger.c b/src/trigger.c
index d8aac2cc2..9f7bff505 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -25,6 +25,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
+ sqlite3DbFree(db, pTmp->zSpan);
sqlite3DbFree(db, pTmp);
}
@@ -340,13 +341,29 @@ triggerfinish_cleanup:
}
/*
+** Duplicate a range of text from an SQL statement, then convert all
+** whitespace characters into ordinary space characters.
+*/
+static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ char *z = sqlite3DbSpanDup(db, zStart, zEnd);
+ int i;
+ if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
+ return z;
+}
+
+/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
**
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
-TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
+TriggerStep *sqlite3TriggerSelectStep(
+ sqlite3 *db, /* Database connection */
+ Select *pSelect, /* The SELECT statement */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
+){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(db, pSelect);
@@ -355,6 +372,7 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
return pTriggerStep;
}
@@ -367,7 +385,9 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
static TriggerStep *triggerStepAllocate(
sqlite3 *db, /* Database connection */
u8 op, /* Trigger opcode */
- Token *pName /* The target name */
+ Token *pName, /* The target name */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
@@ -378,6 +398,7 @@ static TriggerStep *triggerStepAllocate(
sqlite3Dequote(z);
pTriggerStep->zTarget = z;
pTriggerStep->op = op;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
}
return pTriggerStep;
}
@@ -394,13 +415,15 @@ TriggerStep *sqlite3TriggerInsertStep(
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
Select *pSelect, /* A SELECT statement that supplies values */
- u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
assert(pSelect != 0 || db->mallocFailed);
- pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
pTriggerStep->pIdList = pColumn;
@@ -423,11 +446,13 @@ TriggerStep *sqlite3TriggerUpdateStep(
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
- u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
@@ -446,11 +471,13 @@ TriggerStep *sqlite3TriggerUpdateStep(
TriggerStep *sqlite3TriggerDeleteStep(
sqlite3 *db, /* Database connection */
Token *pTableName, /* The table from which rows are deleted */
- Expr *pWhere /* The WHERE clause */
+ Expr *pWhere, /* The WHERE clause */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pTriggerStep->orconf = OE_Default;
@@ -705,6 +732,14 @@ static int codeTriggerProgram(
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
assert( pParse->okConstFactor==0 );
+#ifndef SQLITE_OMIT_TRACE
+ if( pStep->zSpan ){
+ sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
+ sqlite3MPrintf(db, "-- %s", pStep->zSpan),
+ P4_DYNAMIC);
+ }
+#endif
+
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
@@ -845,9 +880,11 @@ static TriggerPrg *codeRowTrigger(
pTab->zName
));
#ifndef SQLITE_OMIT_TRACE
- sqlite3VdbeChangeP4(v, -1,
- sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
- );
+ if( pTrigger->zName ){
+ sqlite3VdbeChangeP4(v, -1,
+ sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
+ );
+ }
#endif
/* If one was specified, code the WHEN clause. If it evaluates to false
diff --git a/src/util.c b/src/util.c
index a4dbe8fda..75de4b3b3 100644
--- a/src/util.c
+++ b/src/util.c
@@ -321,6 +321,24 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
}
/*
+** Compute 10 to the E-th power. Examples: E==1 results in 10.
+** E==2 results in 100. E==50 results in 1.0e50.
+**
+** This routine only works for values of E between 1 and 341.
+*/
+static LONGDOUBLE_TYPE sqlite3Pow10(int E){
+ LONGDOUBLE_TYPE x = 10.0;
+ LONGDOUBLE_TYPE r = 1.0;
+ while(1){
+ if( E & 1 ) r *= x;
+ E >>= 1;
+ if( E==0 ) break;
+ x *= x;
+ }
+ return r;
+}
+
+/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
**
@@ -475,11 +493,10 @@ do_atof_calc:
if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
result = (double)s;
}else{
- LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
if( esign<0 ){
result = s / scale;
result /= 1.0e+308;
@@ -499,10 +516,7 @@ do_atof_calc:
}
}
}else{
- /* 1.0e+22 is the largest power of 10 than can be
- ** represented exactly. */
- while( e%22 ) { scale *= 1.0e+1; e -= 1; }
- while( e>0 ) { scale *= 1.0e+22; e -= 22; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
if( esign<0 ){
result = s / scale;
}else{
diff --git a/src/vdbe.c b/src/vdbe.c
index cfe18a9d1..4d643d726 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2349,6 +2349,36 @@ case OP_IfNullRow: { /* jump */
break;
}
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/* Opcode: Offset P1 P2 P3 * *
+** Synopsis: r[P3] = sqlite_offset(P1)
+**
+** Store in register r[P3] the byte offset into the database file that is the
+** start of the payload for the record at which that cursor P1 is currently
+** pointing.
+**
+** P2 is the column number for the argument to the sqlite_offset() function.
+** This opcode does not use P2 itself, but the P2 value is used by the
+** code generator. The P1, P2, and P3 operands to this opcode are the
+** as as for OP_Column.
+**
+** This opcode is only available if SQLite is compiled with the
+** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option.
+*/
+case OP_Offset: { /* out3 */
+ VdbeCursor *pC; /* The VDBE cursor */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ pOut = &p->aMem[pOp->p3];
+ if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
+ sqlite3VdbeMemSetNull(pOut);
+ }else{
+ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
+ }
+ break;
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX
**
@@ -7016,7 +7046,13 @@ case OP_Function: {
break;
}
-
+/* Opcode: Trace P1 P2 * P4 *
+**
+** Write P4 on the statement trace output if statement tracing is
+** enabled.
+**
+** Operand P1 must be 0x7fffffff and P2 must positive.
+*/
/* Opcode: Init P1 P2 P3 P4 *
** Synopsis: Start at P2
**
@@ -7035,6 +7071,7 @@ case OP_Function: {
** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
** error is encountered.
*/
+case OP_Trace:
case OP_Init: { /* jump */
char *zTrace;
int i;
@@ -7049,7 +7086,9 @@ case OP_Init: { /* jump */
** sqlite3_expanded_sql(P) otherwise.
*/
assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
- assert( pOp==p->aOp ); /* Always instruction 0 */
+
+ /* OP_Init is always instruction 0 */
+ assert( pOp==p->aOp || pOp->opcode==OP_Trace );
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
@@ -7092,6 +7131,7 @@ case OP_Init: { /* jump */
#endif /* SQLITE_OMIT_TRACE */
assert( pOp->p2>0 );
if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
+ if( pOp->opcode==OP_Trace ) break;
for(i=1; i<p->nOp; i++){
if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
}
diff --git a/src/where.c b/src/where.c
index d3aec354b..ec5352794 100644
--- a/src/where.c
+++ b/src/where.c
@@ -5146,7 +5146,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
- if( pOp->opcode==OP_Column ){
+ if( pOp->opcode==OP_Column
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ || pOp->opcode==OP_Offset
+#endif
+ ){
int x = pOp->p2;
assert( pIdx->pTable==pTab );
if( !HasRowid(pTab) ){
diff --git a/test/capi2.test b/test/capi2.test
index 39f50dd07..5e5187181 100644
--- a/test/capi2.test
+++ b/test/capi2.test
@@ -184,7 +184,7 @@ do_test capi2-3.5 {
} {1 {(1) no such column: bogus} {;;x;}}
do_test capi2-3.6 {
set rc [catch {
- sqlite3_prepare $DB {select 5/0} -1 TAIL
+ sqlite3_prepare $DB {select 5/0;} -1 TAIL
} VM]
lappend rc $TAIL
} {0 {}}
diff --git a/test/colname.test b/test/colname.test
index 5a4028677..358ea77e0 100644
--- a/test/colname.test
+++ b/test/colname.test
@@ -398,6 +398,25 @@ do_execsql_test colname-9.320 {
SELECT name FROM pragma_table_info('t2');
} {Bbb}
+# Issue detected by OSSFuzz on 2017-12-24 (Christmas Eve)
+# caused by check-in https://sqlite.org/src/info/6b2ff26c25
+#
+# Prior to being fixed, the following CREATE TABLE was dereferencing
+# a NULL pointer and segfaulting.
+#
+do_catchsql_test colname-9.400 {
+ CREATE TABLE t4 AS SELECT #0;
+} {1 {near "#0": syntax error}}
+
+# Issue detected by OSSFuzz on 2017-12-25 (Christmas Day)
+# also caused by check-in https://sqlite.org/src/info/6b2ff26c25
+#
+# Prior to being fixed, the following CREATE TABLE caused an
+# assertion fault.
+#
+do_catchsql_test colname-9.410 {
+ CREATE TABLE t5 AS SELECT RAISE(abort,a);
+} {1 {RAISE() may only be used within a trigger-program}}
# Make sure the quotation marks get removed from the column names
# when constructing a new table from an aggregate SELECT.
diff --git a/test/fkey1.test b/test/fkey1.test
index d9b038a02..2530327fc 100644
--- a/test/fkey1.test
+++ b/test/fkey1.test
@@ -171,6 +171,20 @@ do_catchsql_test fkey1-5.2 {
INSERT OR REPLACE INTO t11 VALUES (2, 3);
} {1 {FOREIGN KEY constraint failed}}
+# Make sure sqlite3_trace() output works with triggers used to implement
+# FK constraints
+#
+proc sqltrace {txt} {
+ global traceoutput
+ lappend traceoutput $txt
+}
+do_test fkey1-5.2.1 {
+ unset -nocomplain traceoutput
+ db trace sqltrace
+ catch {db eval {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
+ set traceoutput
+} {{INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);} {INSERT OR REPLACE INTO t11 VALUES(2,3);}}
+
# A similar test to the above.
do_execsql_test fkey1-5.3 {
CREATE TABLE Foo (
diff --git a/test/func6.test b/test/func6.test
new file mode 100644
index 000000000..02e1998cd
--- /dev/null
+++ b/test/func6.test
@@ -0,0 +1,86 @@
+# 2017-12-16
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+#
+# Test cases for the sqlite_offset() function.
+#
+# Some of the tests in this file depend on the exact placement of content
+# within b-tree pages. Such placement is at the implementations discretion,
+# and so it is possible for results to change from one release to the next.
+#
+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;
+}
+do_execsql_test func6-110 {
+ SELECT a, sqlite_offset(d)/4096 + 1,
+ sqlite_offset(d)%4096 FROM t1
+ ORDER BY rowid LIMIT 2;
+} {abc001 2 4084 abc002 2 4069}
+do_execsql_test func6-120 {
+ SELECT a, typeof(sqlite_offset(+a)) FROM t1
+ ORDER BY rowid LIMIT 2;
+} {abc001 null abc002 null}
+do_execsql_test func6-130 {
+ SELECT a, sqlite_offset(a)/4096+1,
+ sqlite_offset(a)%4096
+ FROM t1
+ ORDER BY a LIMIT 2;
+} {abc001 3 4087 abc002 3 4076}
+do_execsql_test func6-140 {
+ SELECT a, sqlite_offset(d)/4096+1,
+ sqlite_offset(d)%4096
+ FROM t1
+ ORDER BY a LIMIT 2;
+} {abc001 2 4084 abc002 2 4069}
+do_execsql_test func6-150 {
+ SELECT a,
+ sqlite_offset(a)/4096+1,
+ sqlite_offset(a)%4096,
+ sqlite_offset(d)/4096+1,
+ sqlite_offset(d)%4096
+ FROM t1
+ ORDER BY a LIMIT 2;
+} {abc001 3 4087 2 4084 abc002 3 4076 2 4069}
+do_execsql_test func6-160 {
+ SELECT b,
+ sqlite_offset(b)/4096+1,
+ sqlite_offset(b)%4096,
+ sqlite_offset(c)/4096+1,
+ sqlite_offset(c)%4096,
+ sqlite_offset(d)/4096+1,
+ sqlite_offset(d)%4096
+ FROM t1
+ ORDER BY b LIMIT 2;
+} {1 4 4090 4 4090 2 4084 2 4 4081 4 4081 2 4069}
+
+
+do_execsql_test func6-200 {
+ SELECT y, sqlite_offset(y)/4096+1,
+ sqlite_offset(y)%4096
+ FROM t2
+ ORDER BY x LIMIT 2;
+} {1 5 4087 2 5 4076}
+
+finish_test
diff --git a/test/indexexpr1.test b/test/indexexpr1.test
index 0e24c8066..28c23b908 100644
--- a/test/indexexpr1.test
+++ b/test/indexexpr1.test
@@ -401,5 +401,28 @@ do_execsql_test indexexpr1-1430 {
SELECT abs(15+3) IN (SELECT 17 UNION ALL SELECT 18) FROM t1;
} {1 1}
+# 2018-01-02 ticket https://sqlite.org/src/info/dc3f932f5a147771
+# A REPLACE into a table that uses an index on an expression causes
+# an assertion fault. Problem discovered by OSSFuzz.
+#
+do_execsql_test indexexpr1-1500 {
+ CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
+ CREATE INDEX t1500ab ON t1500(a*b);
+ INSERT INTO t1500(a,b) VALUES(1,2);
+ REPLACE INTO t1500(a,b) VALUES(1,3); -- formerly caused assertion fault
+ SELECT * FROM t1500;
+} {1 3}
+
+# 2018-01-03 OSSFuzz discovers another test case for the same problem
+# above.
+#
+do_execsql_test indexexpr-1510 {
+ 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
diff --git a/test/misc1.test b/test/misc1.test
index 2acfa5c2d..05b1b1980 100644
--- a/test/misc1.test
+++ b/test/misc1.test
@@ -722,4 +722,24 @@ do_execsql_test misc1-26.0 {
SELECT randomblob(min(max(coalesce(EXISTS (SELECT 1 FROM ( SELECT (SELECT 2147483647) NOT IN (SELECT 2147483649 UNION ALL SELECT DISTINCT -1) IN (SELECT 2147483649), 'fault', (SELECT ALL -1 INTERSECT SELECT 'experiments') IN (SELECT ALL 56.1 ORDER BY 'experiments' DESC) FROM (SELECT DISTINCT 2147483648, 'hardware' UNION ALL SELECT -2147483648, 'experiments' ORDER BY 2147483648 LIMIT 1 OFFSET 123456789.1234567899) GROUP BY (SELECT ALL 0 INTERSECT SELECT 'in') IN (SELECT DISTINCT 'experiments' ORDER BY zeroblob(1000) LIMIT 56.1 OFFSET -456) HAVING EXISTS (SELECT 'fault' EXCEPT SELECT DISTINCT 56.1) UNION SELECT 'The', 'The', 2147483649 UNION ALL SELECT DISTINCT 'hardware', 'first', 'experiments' ORDER BY 'hardware' LIMIT 123456789.1234567899 OFFSET -2147483647)) NOT IN (SELECT (SELECT DISTINCT (SELECT 'The') FROM abc ORDER BY EXISTS (SELECT -1 INTERSECT SELECT ALL NULL) ASC) IN (SELECT DISTINCT EXISTS (SELECT ALL 123456789.1234567899 ORDER BY 1 ASC, NULL DESC) FROM sqlite_master INTERSECT SELECT 456)), (SELECT ALL 'injection' UNION ALL SELECT ALL (SELECT DISTINCT 'first' UNION SELECT DISTINCT 'The') FROM (SELECT 456, 'in', 2147483649))),1), 500)), 'first', EXISTS (SELECT DISTINCT 456 FROM abc ORDER BY 'experiments' DESC) FROM abc;
} {}
+# 2017-12-29
+#
+# The following behaviors (duplicate column names on an INSERT or UPDATE)
+# are undocumented. These tests are added to ensure that historical behavior
+# does not change accidentally.
+#
+# For duplication columns on an INSERT, the first value is used.
+# For duplication columns on an UPDATE, the last value is used.
+#
+do_execsql_test misc1-27.0 {
+ CREATE TABLE dup1(a,b,c);
+ INSERT INTO dup1(a,b,c,a,b,c) VALUES(1,2,3,4,5,6);
+ SELECT a,b,c FROM dup1;
+} {1 2 3}
+do_execsql_test misc1-27.1 {
+ UPDATE dup1 SET a=7, b=8, c=9, a=10, b=11, c=12;
+ SELECT a,b,c FROM dup1;
+} {10 11 12}
+
+
finish_test
diff --git a/test/pragma5.test b/test/pragma5.test
index 625ab9201..d2c58000c 100644
--- a/test/pragma5.test
+++ b/test/pragma5.test
@@ -34,7 +34,7 @@ do_execsql_test 1.0 {
1 builtin {} 0 {} 0
}
do_execsql_test 1.1 {
- SELECT * FROM pragma_function_list WHERE name='upper'
+ SELECT * FROM pragma_function_list WHERE name='upper' AND builtin
} {upper 1}
do_execsql_test 1.2 {
SELECT * FROM pragma_function_list WHERE name LIKE 'exter%';
diff --git a/test/shell1.test b/test/shell1.test
index ddd72c718..0d03c64f7 100644
--- a/test/shell1.test
+++ b/test/shell1.test
@@ -581,8 +581,10 @@ do_test shell1-3.21.4 {
}
catchcmd "test.db" ".schema"
} {0 {CREATE TABLE t1(x);
-CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
-CREATE VIEW v1 AS SELECT y+1 FROM v2;}}
+CREATE VIEW v2 AS SELECT x+1 AS y FROM t1
+/* v2(y) */;
+CREATE VIEW v1 AS SELECT y+1 FROM v2
+/* v1("y+1") */;}}
db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}
}
diff --git a/test/speedtest1.c b/test/speedtest1.c
index b92801a20..9342da79b 100644
--- a/test/speedtest1.c
+++ b/test/speedtest1.c
@@ -32,7 +32,7 @@ static const char zHelp[] =
" --size N Relative test size. Default=100\n"
" --stats Show statistics at the end\n"
" --temp N N from 0 to 9. 0: no temp table. 9: all temp tables\n"
- " --testset T Run test-set T (main, cte, rtree, orm, debug)\n"
+ " --testset T Run test-set T (main, cte, rtree, orm, fp, debug)\n"
" --trace Turn on SQL tracing\n"
" --threads N Use up to N threads for sorting\n"
" --utf16be Set text encoding to UTF-16BE\n"
@@ -1120,7 +1120,77 @@ void testset_cte(void){
);
speedtest1_run();
speedtest1_end_test();
+}
+
+/*
+** Compute a pseudo-random floating point ascii number.
+*/
+void speedtest1_random_ascii_fp(char *zFP){
+ int x = speedtest1_random();
+ int y = speedtest1_random();
+ int z;
+ z = y%10;
+ if( z<0 ) z = -z;
+ y /= 10;
+ sqlite3_snprintf(100,zFP,"%d.%de%d",y,z,x%200);
+}
+
+/*
+** A testset for floating-point numbers.
+*/
+void testset_fp(void){
+ int n;
+ int i;
+ char zFP1[100];
+ char zFP2[100];
+
+ n = g.szTest*5000;
+ speedtest1_begin_test(100, "Fill a table with %d FP values", n*2);
+ speedtest1_exec("BEGIN");
+ speedtest1_exec("CREATE%s TABLE t1(a REAL %s, b REAL %s);",
+ isTemp(1), g.zNN, g.zNN);
+ speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2); -- %d times", n);
+ for(i=1; i<=n; i++){
+ speedtest1_random_ascii_fp(zFP1);
+ speedtest1_random_ascii_fp(zFP2);
+ sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC);
+ sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_exec("COMMIT");
+ speedtest1_end_test();
+
+ n = g.szTest/25 + 2;
+ speedtest1_begin_test(110, "%d range queries", n);
+ speedtest1_prepare("SELECT sum(b) FROM t1 WHERE a BETWEEN ?1 AND ?2");
+ for(i=1; i<=n; i++){
+ speedtest1_random_ascii_fp(zFP1);
+ speedtest1_random_ascii_fp(zFP2);
+ sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC);
+ sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_end_test();
+ speedtest1_begin_test(120, "CREATE INDEX three times");
+ speedtest1_exec("BEGIN;");
+ speedtest1_exec("CREATE INDEX t1a ON t1(a);");
+ speedtest1_exec("CREATE INDEX t1b ON t1(b);");
+ speedtest1_exec("CREATE INDEX t1ab ON t1(a,b);");
+ speedtest1_exec("COMMIT;");
+ speedtest1_end_test();
+
+ n = g.szTest/3 + 2;
+ speedtest1_begin_test(130, "%d indexed range queries", n);
+ speedtest1_prepare("SELECT sum(b) FROM t1 WHERE a BETWEEN ?1 AND ?2");
+ for(i=1; i<=n; i++){
+ speedtest1_random_ascii_fp(zFP1);
+ speedtest1_random_ascii_fp(zFP2);
+ sqlite3_bind_text(g.pStmt, 1, zFP1, -1, SQLITE_STATIC);
+ sqlite3_bind_text(g.pStmt, 2, zFP2, -1, SQLITE_STATIC);
+ speedtest1_run();
+ }
+ speedtest1_end_test();
}
#ifdef SQLITE_ENABLE_RTREE
@@ -1873,6 +1943,8 @@ int main(int argc, char **argv){
testset_orm();
}else if( strcmp(zTSet,"cte")==0 ){
testset_cte();
+ }else if( strcmp(zTSet,"fp")==0 ){
+ testset_fp();
}else if( strcmp(zTSet,"rtree")==0 ){
#ifdef SQLITE_ENABLE_RTREE
testset_rtree(6, 147);
@@ -1881,7 +1953,7 @@ int main(int argc, char **argv){
"the R-Tree tests\n");
#endif
}else{
- fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
+ fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree fp\n",
zTSet);
}
speedtest1_final();
diff --git a/test/trace.test b/test/trace.test
index fd51d7ab6..37914857f 100644
--- a/test/trace.test
+++ b/test/trace.test
@@ -197,7 +197,7 @@ ifcapable trigger {
UPDATE t1 SET a=a+1;
}
set TRACE_OUT
- } {{UPDATE t1 SET a=a+1;} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2} {-- TRIGGER r1t1} {-- TRIGGER r1t2}}
+ } {{UPDATE t1 SET a=a+1;} {-- TRIGGER r1t1} {-- UPDATE t2 SET a=new.a WHERE rowid=new.rowid} {-- TRIGGER r1t2} {-- SELECT 'hello'} {-- TRIGGER r1t1} {-- UPDATE t2 SET a=new.a WHERE rowid=new.rowid} {-- TRIGGER r1t2} {-- SELECT 'hello'} {-- TRIGGER r1t1} {-- UPDATE t2 SET a=new.a WHERE rowid=new.rowid} {-- TRIGGER r1t2} {-- SELECT 'hello'}}
}
# With 3.6.21, we add the ability to expand host parameters in the trace
diff --git a/tool/lemon.c b/tool/lemon.c
index acc5450c9..96bbed747 100644
--- a/tool/lemon.c
+++ b/tool/lemon.c
@@ -384,6 +384,12 @@ struct lemon {
int nrule; /* Number of rules */
int nsymbol; /* Number of terminal and nonterminal symbols */
int nterminal; /* Number of terminal symbols */
+ int minShiftReduce; /* Minimum shift-reduce action value */
+ int errAction; /* Error action value */
+ int accAction; /* Accept action value */
+ int noAction; /* No-op action value */
+ int minReduce; /* Minimum reduce action */
+ int maxAction; /* Maximum action value of any kind */
struct symbol **symbols; /* Sorted array of pointers to symbols */
int errorcnt; /* Number of errors */
struct symbol *errsym; /* The error symbol */
@@ -407,6 +413,7 @@ struct lemon {
char *tokenprefix; /* A prefix added to token names in the .h file */
int nconflict; /* Number of parsing conflicts */
int nactiontab; /* Number of entries in the yy_action[] table */
+ int nlookaheadtab; /* Number of entries in yy_lookahead[] */
int tablesize; /* Total table size of all tables in bytes */
int basisflag; /* Print only basis configurations */
int has_fallback; /* True if any %fallback is seen in the grammar */
@@ -583,10 +590,12 @@ struct acttab {
int mxLookahead; /* Maximum aLookahead[].lookahead */
int nLookahead; /* Used slots in aLookahead[] */
int nLookaheadAlloc; /* Slots allocated in aLookahead[] */
+ int nterminal; /* Number of terminal symbols */
+ int nsymbol; /* total number of symbols */
};
/* Return the number of entries in the yy_action table */
-#define acttab_size(X) ((X)->nAction)
+#define acttab_lookahead_size(X) ((X)->nAction)
/* The value for the N-th entry in yy_action */
#define acttab_yyaction(X,N) ((X)->aAction[N].action)
@@ -602,13 +611,15 @@ void acttab_free(acttab *p){
}
/* Allocate a new acttab structure */
-acttab *acttab_alloc(void){
+acttab *acttab_alloc(int nsymbol, int nterminal){
acttab *p = (acttab *) calloc( 1, sizeof(*p) );
if( p==0 ){
fprintf(stderr,"Unable to allocate memory for a new acttab.");
exit(1);
}
memset(p, 0, sizeof(*p));
+ p->nsymbol = nsymbol;
+ p->nterminal = nterminal;
return p;
}
@@ -649,16 +660,24 @@ void acttab_action(acttab *p, int lookahead, int action){
** to an empty set in preparation for a new round of acttab_action() calls.
**
** Return the offset into the action table of the new transaction.
+**
+** If the makeItSafe parameter is true, then the offset is chosen so that
+** it is impossible to overread the yy_lookaside[] table regardless of
+** the lookaside token. This is done for the terminal symbols, as they
+** come from external inputs and can contain syntax errors. When makeItSafe
+** is false, there is more flexibility in selecting offsets, resulting in
+** a smaller table. For non-terminal symbols, which are never syntax errors,
+** makeItSafe can be false.
*/
-int acttab_insert(acttab *p){
- int i, j, k, n;
+int acttab_insert(acttab *p, int makeItSafe){
+ int i, j, k, n, end;
assert( p->nLookahead>0 );
/* Make sure we have enough space to hold the expanded action table
** in the worst case. The worst case occurs if the transaction set
** must be appended to the current action table
*/
- n = p->mxLookahead + 1;
+ n = p->nsymbol + 1;
if( p->nAction + n >= p->nActionAlloc ){
int oldAlloc = p->nActionAlloc;
p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
@@ -680,7 +699,8 @@ int acttab_insert(acttab *p){
**
** i is the index in p->aAction[] where p->mnLookahead is inserted.
*/
- for(i=p->nAction-1; i>=0; i--){
+ end = makeItSafe ? p->mnLookahead : 0;
+ for(i=p->nAction-1; i>=end; i--){
if( p->aAction[i].lookahead==p->mnLookahead ){
/* All lookaheads and actions in the aLookahead[] transaction
** must match against the candidate aAction[i] entry. */
@@ -710,12 +730,13 @@ int acttab_insert(acttab *p){
** an empty offset in the aAction[] table in which we can add the
** aLookahead[] transaction.
*/
- if( i<0 ){
+ if( i<end ){
/* Look for holes in the aAction[] table that fit the current
** aLookahead[] transaction. Leave i set to the offset of the hole.
** If no holes are found, i is left at p->nAction, which means the
** transaction will be appended. */
- for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){
+ i = makeItSafe ? p->mnLookahead : 0;
+ for(; i<p->nActionAlloc - p->mxLookahead; i++){
if( p->aAction[i].lookahead<0 ){
for(j=0; j<p->nLookahead; j++){
k = p->aLookahead[j].lookahead - p->mnLookahead + i;
@@ -733,11 +754,19 @@ int acttab_insert(acttab *p){
}
}
/* Insert transaction set at index i. */
+#if 0
+ printf("Acttab:");
+ for(j=0; j<p->nLookahead; j++){
+ printf(" %d", p->aLookahead[j].lookahead);
+ }
+ printf(" inserted at %d\n", i);
+#endif
for(j=0; j<p->nLookahead; j++){
k = p->aLookahead[j].lookahead - p->mnLookahead + i;
p->aAction[k] = p->aLookahead[j];
if( k>=p->nAction ) p->nAction = k+1;
}
+ if( makeItSafe && i+p->nterminal>=p->nAction ) p->nAction = i+p->nterminal+1;
p->nLookahead = 0;
/* Return the offset that is added to the lookahead in order to get the
@@ -745,6 +774,16 @@ int acttab_insert(acttab *p){
return i - p->mnLookahead;
}
+/*
+** Return the size of the action table without the trailing syntax error
+** entries.
+*/
+int acttab_action_size(acttab *p){
+ int n = p->nAction;
+ while( n>0 && p->aAction[n-1].lookahead<0 ){ n--; }
+ return n;
+}
+
/********************** From the file "build.c" *****************************/
/*
** Routines to construction the finite state machine for the LEMON
@@ -1718,6 +1757,7 @@ int main(int argc, char **argv)
stats_line("states", lem.nxstate);
stats_line("conflicts", lem.nconflict);
stats_line("action table entries", lem.nactiontab);
+ stats_line("lookahead table entries", lem.nlookaheadtab);
stats_line("total table size (bytes)", lem.tablesize);
}
if( lem.nconflict > 0 ){
@@ -3020,6 +3060,27 @@ PRIVATE FILE *file_open(
return fp;
}
+/* Print the text of a rule
+*/
+void rule_print(FILE *out, struct rule *rp){
+ int i, j;
+ fprintf(out, "%s",rp->lhs->name);
+ /* if( rp->lhsalias ) fprintf(out,"(%s)",rp->lhsalias); */
+ fprintf(out," ::=");
+ for(i=0; i<rp->nrhs; i++){
+ struct symbol *sp = rp->rhs[i];
+ if( sp->type==MULTITERMINAL ){
+ fprintf(out," %s", sp->subsym[0]->name);
+ for(j=1; j<sp->nsubsym; j++){
+ fprintf(out,"|%s", sp->subsym[j]->name);
+ }
+ }else{
+ fprintf(out," %s", sp->name);
+ }
+ /* if( rp->rhsalias[i] ) fprintf(out,"(%s)",rp->rhsalias[i]); */
+ }
+}
+
/* Duplicate the input file without comments and without actions
** on rules */
void Reprint(struct lemon *lemp)
@@ -3047,21 +3108,7 @@ void Reprint(struct lemon *lemp)
printf("\n");
}
for(rp=lemp->rule; rp; rp=rp->next){
- printf("%s",rp->lhs->name);
- /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
- printf(" ::=");
- for(i=0; i<rp->nrhs; i++){
- sp = rp->rhs[i];
- if( sp->type==MULTITERMINAL ){
- printf(" %s", sp->subsym[0]->name);
- for(j=1; j<sp->nsubsym; j++){
- printf("|%s", sp->subsym[j]->name);
- }
- }else{
- printf(" %s", sp->name);
- }
- /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
- }
+ rule_print(stdout, rp);
printf(".");
if( rp->precsym ) printf(" [%s]",rp->precsym->name);
/* if( rp->code ) printf("\n %s",rp->code); */
@@ -3321,16 +3368,19 @@ PRIVATE int compute_action(struct lemon *lemp, struct action *ap)
switch( ap->type ){
case SHIFT: act = ap->x.stp->statenum; break;
case SHIFTREDUCE: {
- act = ap->x.rp->iRule + lemp->nstate;
/* Since a SHIFT is inherient after a prior REDUCE, convert any
** SHIFTREDUCE action with a nonterminal on the LHS into a simple
** REDUCE action: */
- if( ap->sp->index>=lemp->nterminal ) act += lemp->nrule;
+ if( ap->sp->index>=lemp->nterminal ){
+ act = lemp->minReduce + ap->x.rp->iRule;
+ }else{
+ act = lemp->minShiftReduce + ap->x.rp->iRule;
+ }
break;
}
- case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break;
- case ERROR: act = lemp->nstate + lemp->nrule*2; break;
- case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break;
+ case REDUCE: act = lemp->minReduce + ap->x.rp->iRule; break;
+ case ERROR: act = lemp->errAction; break;
+ case ACCEPT: act = lemp->accAction; break;
default: act = -1; break;
}
return act;
@@ -4038,6 +4088,13 @@ void ReportTable(
int mnNtOfst, mxNtOfst;
struct axset *ax;
+ lemp->minShiftReduce = lemp->nstate;
+ lemp->errAction = lemp->minShiftReduce + lemp->nrule;
+ lemp->accAction = lemp->errAction + 1;
+ lemp->noAction = lemp->accAction + 1;
+ lemp->minReduce = lemp->noAction + 1;
+ lemp->maxAction = lemp->minReduce + lemp->nrule;
+
in = tplt_open(lemp);
if( in==0 ) return;
out = file_open(lemp,".c","wb");
@@ -4076,7 +4133,7 @@ void ReportTable(
minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++;
fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++;
fprintf(out,"#define YYACTIONTYPE %s\n",
- minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++;
+ minimum_size_type(0,lemp->maxAction,&szActionType)); lineno++;
if( lemp->wildcard ){
fprintf(out,"#define YYWILDCARD %d\n",
lemp->wildcard->index); lineno++;
@@ -4144,7 +4201,7 @@ void ReportTable(
** of placing the largest action sets first */
for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i;
qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare);
- pActtab = acttab_alloc();
+ pActtab = acttab_alloc(lemp->nsymbol, lemp->nterminal);
for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){
stp = ax[i].stp;
if( ax[i].isTkn ){
@@ -4155,7 +4212,7 @@ void ReportTable(
if( action<0 ) continue;
acttab_action(pActtab, ap->sp->index, action);
}
- stp->iTknOfst = acttab_insert(pActtab);
+ stp->iTknOfst = acttab_insert(pActtab, 1);
if( stp->iTknOfst<mnTknOfst ) mnTknOfst = stp->iTknOfst;
if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst;
}else{
@@ -4167,7 +4224,7 @@ void ReportTable(
if( action<0 ) continue;
acttab_action(pActtab, ap->sp->index, action);
}
- stp->iNtOfst = acttab_insert(pActtab);
+ stp->iNtOfst = acttab_insert(pActtab, 0);
if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst;
if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
}
@@ -4200,16 +4257,18 @@ void ReportTable(
** been computed */
fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++;
fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
+ fprintf(out,"#define YYNTOKEN %d\n",lemp->nterminal); lineno++;
fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++;
- fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++;
- i = lemp->nstate + lemp->nrule;
+ i = lemp->minShiftReduce;
+ fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",i); lineno++;
+ i += lemp->nrule;
fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++;
- fprintf(out,"#define YY_MIN_REDUCE %d\n", i); lineno++;
- i = lemp->nstate + lemp->nrule*2;
+ fprintf(out,"#define YY_ERROR_ACTION %d\n", lemp->errAction); lineno++;
+ fprintf(out,"#define YY_ACCEPT_ACTION %d\n", lemp->accAction); lineno++;
+ fprintf(out,"#define YY_NO_ACTION %d\n", lemp->noAction); lineno++;
+ fprintf(out,"#define YY_MIN_REDUCE %d\n", lemp->minReduce); lineno++;
+ i = lemp->minReduce + lemp->nrule;
fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++;
- fprintf(out,"#define YY_ERROR_ACTION %d\n", i); lineno++;
- fprintf(out,"#define YY_ACCEPT_ACTION %d\n", i+1); lineno++;
- fprintf(out,"#define YY_NO_ACTION %d\n", i+2); lineno++;
tplt_xfer(lemp->name,in,out,&lineno);
/* Now output the action table and its associates:
@@ -4225,13 +4284,13 @@ void ReportTable(
*/
/* Output the yy_action table */
- lemp->nactiontab = n = acttab_size(pActtab);
+ lemp->nactiontab = n = acttab_action_size(pActtab);
lemp->tablesize += n*szActionType;
fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++;
fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
for(i=j=0; i<n; i++){
int action = acttab_yyaction(pActtab, i);
- if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
+ if( action<0 ) action = lemp->noAction;
if( j==0 ) fprintf(out," /* %5d */ ", i);
fprintf(out, " %4d,", action);
if( j==9 || i==n-1 ){
@@ -4244,6 +4303,7 @@ void ReportTable(
fprintf(out, "};\n"); lineno++;
/* Output the yy_lookahead table */
+ lemp->nlookaheadtab = n = acttab_lookahead_size(pActtab);
lemp->tablesize += n*szCodeType;
fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
for(i=j=0; i<n; i++){
@@ -4263,7 +4323,6 @@ void ReportTable(
/* Output the yy_shift_ofst[] table */
n = lemp->nxstate;
while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
- fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++;
fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
@@ -4288,7 +4347,6 @@ void ReportTable(
fprintf(out, "};\n"); lineno++;
/* Output the yy_reduce_ofst[] table */
- fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
n = lemp->nxstate;
while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++;
@@ -4320,7 +4378,11 @@ void ReportTable(
for(i=j=0; i<n; i++){
stp = lemp->sorted[i];
if( j==0 ) fprintf(out," /* %5d */ ", i);
- fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule);
+ if( stp->iDfltReduce<0 ){
+ fprintf(out, " %4d,", lemp->errAction);
+ }else{
+ fprintf(out, " %4d,", stp->iDfltReduce + lemp->minReduce);
+ }
if( j==9 || i==n-1 ){
fprintf(out, "\n"); lineno++;
j = 0;
@@ -4354,10 +4416,8 @@ void ReportTable(
*/
for(i=0; i<lemp->nsymbol; i++){
lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name);
- fprintf(out," %-15s",line);
- if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
+ fprintf(out," /* %4d */ \"%s\",\n",i, lemp->symbols[i]->name); lineno++;
}
- if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
tplt_xfer(lemp->name,in,out,&lineno);
/* Generate a table containing a text string that describes every
@@ -4401,7 +4461,7 @@ void ReportTable(
if( sp==0 || sp->type==TERMINAL ||
sp->index<=0 || sp->destructor!=0 ) continue;
if( once ){
- fprintf(out, " /* Default NON-TERMINAL Destructor */\n"); lineno++;
+ fprintf(out, " /* Default NON-TERMINAL Destructor */\n");lineno++;
once = 0;
}
fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++;
@@ -4444,8 +4504,10 @@ void ReportTable(
** Note: This code depends on the fact that rules are number
** sequentually beginning with 0.
*/
- for(rp=lemp->rule; rp; rp=rp->next){
- fprintf(out," { %d, %d },\n",rp->lhs->index,-rp->nrhs); lineno++;
+ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
+ fprintf(out," { %4d, %4d }, /* (%d) ",rp->lhs->index,-rp->nrhs,i);
+ rule_print(out, rp);
+ fprintf(out," */\n"); lineno++;
}
tplt_xfer(lemp->name,in,out,&lineno);
@@ -4711,7 +4773,7 @@ void ResortStates(struct lemon *lemp)
for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i];
stp->nTknAct = stp->nNtAct = 0;
- stp->iDfltReduce = lemp->nrule; /* Init dflt action to "syntax error" */
+ stp->iDfltReduce = -1; /* Init dflt action to "syntax error" */
stp->iTknOfst = NO_OFFSET;
stp->iNtOfst = NO_OFFSET;
for(ap=stp->ap; ap; ap=ap->next){
@@ -4723,7 +4785,7 @@ void ResortStates(struct lemon *lemp)
stp->nNtAct++;
}else{
assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp );
- stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule;
+ stp->iDfltReduce = iAction;
}
}
}
diff --git a/tool/lempar.c b/tool/lempar.c
index da81ddd4b..9164eb0c1 100644
--- a/tool/lempar.c
+++ b/tool/lempar.c
@@ -72,14 +72,15 @@
** defined, then do no error processing.
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
+** YYNTOKEN Number of terminal symbols
** YY_MAX_SHIFT Maximum value for shift actions
** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** YY_MIN_REDUCE Minimum value for reduce actions
-** YY_MAX_REDUCE Maximum value for reduce actions
** YY_ERROR_ACTION The yy_action[] code for syntax error
** YY_ACCEPT_ACTION The yy_action[] code for accept
** YY_NO_ACTION The yy_action[] code for no-op
+** YY_MIN_REDUCE Minimum value for reduce actions
+** YY_MAX_REDUCE Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
@@ -115,9 +116,6 @@
** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE.
**
-** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
-** and YY_MAX_REDUCE
-**
** N == YY_ERROR_ACTION A syntax error has occurred.
**
** N == YY_ACCEPT_ACTION The parser accepts its input.
@@ -125,25 +123,22 @@
** N == YY_NO_ACTION No such action. Denotes unused
** slots in the yy_action[] table.
**
+** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
+** and YY_MAX_REDUCE
+**
** The action table is constructed as a single large table named yy_action[].
** Given state S and lookahead X, the action is computed as either:
**
** (A) N = yy_action[ yy_shift_ofst[S] + X ]
** (B) N = yy_default[S]
**
-** The (A) formula is preferred. The B formula is used instead if:
-** (1) The yy_shift_ofst[S]+X value is out of range, or
-** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
-** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
-** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
-** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
-** Hence only tests (1) and (2) need to be evaluated.)
+** The (A) formula is preferred. The B formula is used instead if
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
**
** The formulas above are for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
-** YY_SHIFT_USE_DFLT.
+** the yy_shift_ofst[] array.
**
** The following are the tables generated in this section:
**
@@ -259,13 +254,13 @@ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
}
#endif /* NDEBUG */
-#ifndef NDEBUG
+#if defined(YYCOVERAGE) || !defined(NDEBUG)
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
static const char *const yyTokenName[] = {
%%
};
-#endif /* NDEBUG */
+#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
@@ -461,6 +456,43 @@ int ParseStackPeak(void *p){
}
#endif
+/* This array of booleans keeps track of the parser statement
+** coverage. The element yycoverage[X][Y] is set when the parser
+** is in state X and has a lookahead token Y. In a well-tested
+** systems, every element of this matrix should end up being set.
+*/
+#if defined(YYCOVERAGE)
+static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
+#endif
+
+/*
+** Write into out a description of every state/lookahead combination that
+**
+** (1) has not been used by the parser, and
+** (2) is not a syntax error.
+**
+** Return the number of missed state/lookahead combinations.
+*/
+#if defined(YYCOVERAGE)
+int ParseCoverage(FILE *out){
+ int stateno, iLookAhead, i;
+ int nMissed = 0;
+ for(stateno=0; stateno<YYNSTATE; stateno++){
+ i = yy_shift_ofst[stateno];
+ for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
+ if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
+ if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
+ if( out ){
+ fprintf(out,"State %d lookahead %s %s\n", stateno,
+ yyTokenName[iLookAhead],
+ yycoverage[stateno][iLookAhead] ? "ok" : "missed");
+ }
+ }
+ }
+ return nMissed;
+}
+#endif
+
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
@@ -472,13 +504,18 @@ static unsigned int yy_find_shift_action(
int i;
int stateno = pParser->yytos->stateno;
- if( stateno>=YY_MIN_REDUCE ) return stateno;
+ 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 && i+YYNTOKEN<=sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) );
assert( iLookAhead!=YYNOCODE );
+ assert( iLookAhead < YYNTOKEN );
i += iLookAhead;
- if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ if( yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
YYCODETYPE iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
@@ -541,7 +578,6 @@ static int yy_find_reduce_action(
assert( stateno<=YY_REDUCE_COUNT );
#endif
i = yy_reduce_ofst[stateno];
- assert( i!=YY_REDUCE_USE_DFLT );
assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
#ifdef YYERRORSYMBOL
@@ -578,20 +614,21 @@ static void yyStackOverflow(yyParser *yypParser){
** Print tracing information for a SHIFT action
*/
#ifndef NDEBUG
-static void yyTraceShift(yyParser *yypParser, int yyNewState){
+static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
if( yyTraceFILE ){
if( yyNewState<YYNSTATE ){
- fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
- yyTracePrompt,yyTokenName[yypParser->yytos->major],
+ fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
+ yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
yyNewState);
}else{
- fprintf(yyTraceFILE,"%sShift '%s'\n",
- yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+ fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
+ yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
+ yyNewState - YY_MIN_REDUCE);
}
}
}
#else
-# define yyTraceShift(X,Y)
+# define yyTraceShift(X,Y,Z)
#endif
/*
@@ -633,7 +670,7 @@ static void yy_shift(
yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor;
yytos->minor.yy0 = yyMinor;
- yyTraceShift(yypParser, yyNewState);
+ yyTraceShift(yypParser, yyNewState, "Shift");
}
/* The following table contains information about every rule that
@@ -673,8 +710,14 @@ static void yy_reduce(
#ifndef NDEBUG
if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
yysize = yyRuleInfo[yyruleno].nrhs;
- fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
- yyRuleName[yyruleno], yymsp[yysize].stateno);
+ if( yysize ){
+ fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
+ yyTracePrompt,
+ yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);
+ }else{
+ fprintf(yyTraceFILE, "%sReduce %d [%s].\n",
+ yyTracePrompt, yyruleno, yyRuleName[yyruleno]);
+ }
}
#endif /* NDEBUG */
@@ -729,16 +772,11 @@ static void yy_reduce(
/* It is not possible for a REDUCE to be followed by an error */
assert( yyact!=YY_ERROR_ACTION );
- if( yyact==YY_ACCEPT_ACTION ){
- yypParser->yytos += yysize;
- yy_accept(yypParser);
- }else{
- yymsp += yysize+1;
- yypParser->yytos = yymsp;
- yymsp->stateno = (YYACTIONTYPE)yyact;
- yymsp->major = (YYCODETYPE)yygoto;
- yyTraceShift(yypParser, yyact);
- }
+ yymsp += yysize+1;
+ yypParser->yytos = yymsp;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yyTraceShift(yypParser, yyact, "... then shift");
}
/*
@@ -848,20 +886,31 @@ void Parse(
#ifndef NDEBUG
if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+ int stateno = yypParser->yytos->stateno;
+ if( stateno < YY_MIN_REDUCE ){
+ fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
+ yyTracePrompt,yyTokenName[yymajor],stateno);
+ }else{
+ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
+ yyTracePrompt,yyTokenName[yymajor],stateno-YY_MIN_REDUCE);
+ }
}
#endif
do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
- if( yyact <= YY_MAX_SHIFTREDUCE ){
+ if( yyact >= YY_MIN_REDUCE ){
+ yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor);
+ }else if( yyact <= YY_MAX_SHIFTREDUCE ){
yy_shift(yypParser,yyact,yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt--;
#endif
yymajor = YYNOCODE;
- }else if( yyact <= YY_MAX_REDUCE ){
- yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor);
+ }else if( yyact==YY_ACCEPT_ACTION ){
+ yypParser->yytos--;
+ yy_accept(yypParser);
+ return;
}else{
assert( yyact == YY_ERROR_ACTION );
yyminorunion.yy0 = yyminor;
diff --git a/tool/speed-check.sh b/tool/speed-check.sh
index 2cda5c807..6cc301898 100644
--- a/tool/speed-check.sh
+++ b/tool/speed-check.sh
@@ -117,6 +117,12 @@ while test "$1" != ""; do
--orm)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset orm"
;;
+ --cte)
+ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset cte"
+ ;;
+ --fp)
+ SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset fp"
+ ;;
-*)
CC_OPTS="$CC_OPTS $1"
;;