Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8477f7f79c | |||
| ee9d4d7fed | |||
| 53872e7259 | |||
| 3d6bedf14f | |||
| 12b0fabde2 | |||
| 3b3c86ade2 | |||
| 110e3afd11 | |||
| 35284b6c48 |
+18
-38
@@ -22,7 +22,7 @@ TOP = @abs_srcdir@
|
||||
#
|
||||
BCC = @BUILD_CC@ @BUILD_CFLAGS@
|
||||
|
||||
# TCC is the C Compile and options for use in building executables that
|
||||
# TCC is the C Compile and options for use in building executables that
|
||||
# will run on the target platform. (BCC and TCC are usually the
|
||||
# same unless your are cross-compiling.) Separate CC and CFLAGS macros
|
||||
# are provide so that these aspects of the build process can be changed
|
||||
@@ -35,7 +35,7 @@ TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session
|
||||
|
||||
# Define this for the autoconf-based build, so that the code knows it can
|
||||
# include the generated config.h
|
||||
#
|
||||
#
|
||||
TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
|
||||
|
||||
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
|
||||
@@ -66,7 +66,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
|
||||
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
|
||||
|
||||
# Any target libraries which libsqlite must be linked against
|
||||
#
|
||||
#
|
||||
TLIBS = @LIBS@ $(LIBS)
|
||||
|
||||
# Flags controlling use of the in memory btree implementation
|
||||
@@ -78,8 +78,8 @@ TLIBS = @LIBS@ $(LIBS)
|
||||
TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
|
||||
|
||||
# Enable/disable loadable extensions, and other optional features
|
||||
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
|
||||
# The same set of OMIT and ENABLE flags should be passed to the
|
||||
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
|
||||
# The same set of OMIT and ENABLE flags should be passed to the
|
||||
# LEMON parser generator and the mkkeywordhash tool as well.
|
||||
OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
|
||||
|
||||
@@ -126,8 +126,8 @@ SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
|
||||
# If gcov support was enabled by the configure script, add the appropriate
|
||||
# flags here. It's not always as easy as just having the user add the right
|
||||
# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
|
||||
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
|
||||
# Supposedly GCC does the right thing if you use --coverage, but in
|
||||
# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
|
||||
# Supposedly GCC does the right thing if you use --coverage, but in
|
||||
# practice it still fails. See:
|
||||
#
|
||||
# http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html
|
||||
@@ -425,7 +425,7 @@ TESTSRC = \
|
||||
$(TOP)/ext/fts3/fts3_term.c \
|
||||
$(TOP)/ext/fts3/fts3_test.c \
|
||||
$(TOP)/ext/session/test_session.c \
|
||||
$(TOP)/ext/rbu/test_rbu.c
|
||||
$(TOP)/ext/rbu/test_rbu.c
|
||||
|
||||
# Statically linked extensions
|
||||
#
|
||||
@@ -507,7 +507,7 @@ TESTSRC2 = \
|
||||
$(TOP)/ext/fts3/fts3_write.c \
|
||||
$(TOP)/ext/async/sqlite3async.c \
|
||||
$(TOP)/ext/session/sqlite3session.c \
|
||||
$(TOP)/ext/misc/stmt.c
|
||||
$(TOP)/ext/misc/stmt.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
#
|
||||
@@ -602,7 +602,7 @@ FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ
|
||||
FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000
|
||||
FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000
|
||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
DBFUZZ_OPT =
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
@@ -664,22 +664,6 @@ sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
|
||||
dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
|
||||
|
||||
DBFUZZ2_OPTS = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_EANBLE_FTS5
|
||||
|
||||
dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
|
||||
clang-6.0 -I. -g -O0 -fsanitize=fuzzer,undefined -o dbfuzz2 \
|
||||
$(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c
|
||||
mkdir -p dbfuzz2-dir
|
||||
cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
|
||||
|
||||
mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c
|
||||
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \
|
||||
$(TLIBS) -rpath "$(libdir)"
|
||||
@@ -1143,7 +1127,7 @@ FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon$(BEXE) $(OPTS) fts5parse.y
|
||||
@@ -1170,7 +1154,7 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DBUILD_sqlite
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
@@ -1186,10 +1170,6 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC)
|
||||
$(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
|
||||
-o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
|
||||
|
||||
coretestprogs: $(TESTPROGS)
|
||||
|
||||
testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)
|
||||
|
||||
# A very detailed test running most or all test cases
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
|
||||
@@ -1249,7 +1229,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
|
||||
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
|
||||
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in
|
||||
$(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(TEXE): sqltclsh.c
|
||||
@@ -1316,7 +1296,7 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
|
||||
@@ -1344,7 +1324,7 @@ snapshot-tarball: sqlite3.c
|
||||
# The next two rules are used to support the "threadtest" target. Building
|
||||
# threadtest runs a few thread-safety tests that are implemented in C. This
|
||||
# target is invoked by the releasetest.tcl script.
|
||||
#
|
||||
#
|
||||
THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
|
||||
$(TOP)/test/tt3_checkpoint.c \
|
||||
$(TOP)/test/tt3_index.c \
|
||||
@@ -1358,7 +1338,7 @@ threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC)
|
||||
threadtest: threadtest3$(TEXE)
|
||||
./threadtest3$(TEXE)
|
||||
|
||||
releasetest:
|
||||
releasetest:
|
||||
$(TCLSH_CMD) $(TOP)/test/releasetest.tcl
|
||||
|
||||
# Standard install and cleanup targets
|
||||
@@ -1366,7 +1346,7 @@ releasetest:
|
||||
lib_install: libsqlite3.la
|
||||
$(INSTALL) -d $(DESTDIR)$(libdir)
|
||||
$(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir)
|
||||
|
||||
|
||||
install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install}
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir)
|
||||
@@ -1384,7 +1364,7 @@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
|
||||
rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
|
||||
$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)
|
||||
|
||||
clean:
|
||||
clean:
|
||||
rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
|
||||
rm -f sqlite3.h opcodes.*
|
||||
rm -rf .libs .deps
|
||||
|
||||
@@ -2335,10 +2335,6 @@ extensiontest: testfixture.exe testloadext.dll
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
|
||||
|
||||
coretestprogs: $(TESTPROGS)
|
||||
|
||||
testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
|
||||
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
@set PATH=$(LIBTCLPATH);$(PATH)
|
||||
.\testfixture.exe $(TOP)\test\all.test $(TESTOPTS)
|
||||
|
||||
@@ -1,427 +0,0 @@
|
||||
/*
|
||||
** 2018-09-27
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file demonstrates an eponymous virtual table that returns information
|
||||
** from sqlite3_status64() and sqlite3_db_status().
|
||||
**
|
||||
** Usage example:
|
||||
**
|
||||
** .load ./memstat
|
||||
** .mode quote
|
||||
** .header on
|
||||
** SELECT * FROM memstat;
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB)
|
||||
#if !defined(SQLITEINT_H)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/* memstat_vtab is a subclass of sqlite3_vtab which will
|
||||
** serve as the underlying representation of a memstat virtual table
|
||||
*/
|
||||
typedef struct memstat_vtab memstat_vtab;
|
||||
struct memstat_vtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this memstat vtab */
|
||||
};
|
||||
|
||||
/* memstat_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct memstat_cursor memstat_cursor;
|
||||
struct memstat_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection for this cursor */
|
||||
int iRowid; /* Current row in aMemstatColumn[] */
|
||||
int iDb; /* Which schema we are looking at */
|
||||
int nDb; /* Number of schemas */
|
||||
char **azDb; /* Names of all schemas */
|
||||
sqlite3_int64 aVal[2]; /* Result values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The memstatConnect() method is invoked to create a new
|
||||
** memstat_vtab that describes the memstat virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for memstat_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the memstat_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against memstat will look like.
|
||||
*/
|
||||
static int memstatConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
memstat_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define MSV_COLUMN_NAME 0 /* Name of quantity being measured */
|
||||
#define MSV_COLUMN_SCHEMA 1 /* schema name */
|
||||
#define MSV_COLUMN_VALUE 2 /* Current value */
|
||||
#define MSV_COLUMN_HIWTR 3 /* Highwater mark */
|
||||
|
||||
rc = sqlite3_declare_vtab(db,"CREATE TABLE x(name,schema,value,hiwtr)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for memstat_cursor objects.
|
||||
*/
|
||||
static int memstatDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new memstat_cursor object.
|
||||
*/
|
||||
static int memstatOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
memstat_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->db = ((memstat_vtab*)p)->db;
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear all the schema names from a cursor
|
||||
*/
|
||||
static void memstatClearSchema(memstat_cursor *pCur){
|
||||
int i;
|
||||
if( pCur->azDb==0 ) return;
|
||||
for(i=0; i<pCur->nDb; i++){
|
||||
sqlite3_free(pCur->azDb[i]);
|
||||
}
|
||||
sqlite3_free(pCur->azDb);
|
||||
pCur->azDb = 0;
|
||||
pCur->nDb = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Fill in the azDb[] array for the cursor.
|
||||
*/
|
||||
static int memstatFindSchemas(memstat_cursor *pCur){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
if( pCur->nDb ) return SQLITE_OK;
|
||||
rc = sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char **az, *z;
|
||||
az = sqlite3_realloc(pCur->azDb, sizeof(char*)*(pCur->nDb+1));
|
||||
if( az==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCur->azDb = az;
|
||||
z = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
|
||||
if( z==0 ){
|
||||
memstatClearSchema(pCur);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pCur->azDb[pCur->nDb] = z;
|
||||
pCur->nDb++;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Destructor for a memstat_cursor.
|
||||
*/
|
||||
static int memstatClose(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
memstatClearSchema(pCur);
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Allowed values for aMemstatColumn[].eType
|
||||
*/
|
||||
#define MSV_GSTAT 0 /* sqlite3_status64() information */
|
||||
#define MSV_DB 1 /* sqlite3_db_status() information */
|
||||
#define MSV_ZIPVFS 2 /* ZIPVFS file-control with 64-bit return */
|
||||
|
||||
/*
|
||||
** An array of quantities that can be measured and reported by
|
||||
** this virtual table
|
||||
*/
|
||||
static const struct MemstatColumns {
|
||||
const char *zName; /* Symbolic name */
|
||||
unsigned char eType; /* Type of interface */
|
||||
unsigned char mNull; /* Bitmask of which columns are NULL */
|
||||
/* 2: dbname, 4: current, 8: hiwtr */
|
||||
int eOp; /* Opcode */
|
||||
} aMemstatColumn[] = {
|
||||
{"MEMORY_USED", MSV_GSTAT, 2, SQLITE_STATUS_MEMORY_USED },
|
||||
{"MALLOC_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_MALLOC_SIZE },
|
||||
{"MALLOC_COUNT", MSV_GSTAT, 2, SQLITE_STATUS_MALLOC_COUNT },
|
||||
{"PAGECACHE_USED", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_USED },
|
||||
{"PAGECACHE_OVERFLOW", MSV_GSTAT, 2, SQLITE_STATUS_PAGECACHE_OVERFLOW },
|
||||
{"PAGECACHE_SIZE", MSV_GSTAT, 6, SQLITE_STATUS_PAGECACHE_SIZE },
|
||||
{"PARSER_STACK", MSV_GSTAT, 6, SQLITE_STATUS_PARSER_STACK },
|
||||
{"DB_LOOKASIDE_USED", MSV_DB, 2, SQLITE_DBSTATUS_LOOKASIDE_USED },
|
||||
{"DB_LOOKASIDE_HIT", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_HIT },
|
||||
{"DB_LOOKASIDE_MISS_SIZE", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
|
||||
{"DB_LOOKASIDE_MISS_FULL", MSV_DB, 6, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
|
||||
{"DB_CACHE_USED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED },
|
||||
#if SQLITE_VERSION_NUMBER >= 3140000
|
||||
{"DB_CACHE_USED_SHARED", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_USED_SHARED },
|
||||
#endif
|
||||
{"DB_SCHEMA_USED", MSV_DB, 10, SQLITE_DBSTATUS_SCHEMA_USED },
|
||||
{"DB_STMT_USED", MSV_DB, 10, SQLITE_DBSTATUS_STMT_USED },
|
||||
{"DB_CACHE_HIT", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_HIT },
|
||||
{"DB_CACHE_MISS", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_MISS },
|
||||
{"DB_CACHE_WRITE", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_WRITE },
|
||||
#if SQLITE_VERSION_NUMBER >= 3230000
|
||||
{"DB_CACHE_SPILL", MSV_DB, 10, SQLITE_DBSTATUS_CACHE_SPILL },
|
||||
#endif
|
||||
{"DB_DEFERRED_FKS", MSV_DB, 10, SQLITE_DBSTATUS_DEFERRED_FKS },
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
{"ZIPVFS_CACHE_USED", MSV_ZIPVFS, 8, 231454 },
|
||||
{"ZIPVFS_CACHE_HIT", MSV_ZIPVFS, 8, 231455 },
|
||||
{"ZIPVFS_CACHE_MISS", MSV_ZIPVFS, 8, 231456 },
|
||||
{"ZIPVFS_CACHE_WRITE", MSV_ZIPVFS, 8, 231457 },
|
||||
{"ZIPVFS_DIRECT_READ", MSV_ZIPVFS, 8, 231458 },
|
||||
{"ZIPVFS_DIRECT_BYTES", MSV_ZIPVFS, 8, 231459 },
|
||||
#endif /* SQLITE_ENABLE_ZIPVFS */
|
||||
};
|
||||
#define MSV_NROW (sizeof(aMemstatColumn)/sizeof(aMemstatColumn[0]))
|
||||
|
||||
/*
|
||||
** Advance a memstat_cursor to its next row of output.
|
||||
*/
|
||||
static int memstatNext(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
int i;
|
||||
assert( pCur->iRowid<=MSV_NROW );
|
||||
while(1){
|
||||
i = (int)pCur->iRowid - 1;
|
||||
if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){
|
||||
pCur->iRowid++;
|
||||
if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */
|
||||
pCur->iDb = 0;
|
||||
i++;
|
||||
}
|
||||
pCur->aVal[0] = 0;
|
||||
pCur->aVal[1] = 0;
|
||||
switch( aMemstatColumn[i].eType ){
|
||||
case MSV_GSTAT: {
|
||||
if( sqlite3_libversion_number()>=3010000 ){
|
||||
sqlite3_status64(aMemstatColumn[i].eOp,
|
||||
&pCur->aVal[0], &pCur->aVal[1],0);
|
||||
}else{
|
||||
int xCur, xHiwtr;
|
||||
sqlite3_status(aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
|
||||
pCur->aVal[0] = xCur;
|
||||
pCur->aVal[1] = xHiwtr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSV_DB: {
|
||||
int xCur, xHiwtr;
|
||||
sqlite3_db_status(pCur->db, aMemstatColumn[i].eOp, &xCur, &xHiwtr, 0);
|
||||
pCur->aVal[0] = xCur;
|
||||
pCur->aVal[1] = xHiwtr;
|
||||
break;
|
||||
}
|
||||
case MSV_ZIPVFS: {
|
||||
int rc;
|
||||
rc = sqlite3_file_control(pCur->db, pCur->azDb[pCur->iDb],
|
||||
aMemstatColumn[i].eOp, (void*)&pCur->aVal[0]);
|
||||
if( rc!=SQLITE_OK ) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the memstat_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int memstatColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int iCol /* Which column to return */
|
||||
){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
int i;
|
||||
assert( pCur->iRowid>0 && pCur->iRowid<=MSV_NROW );
|
||||
i = (int)pCur->iRowid - 1;
|
||||
if( (aMemstatColumn[i].mNull & (1<<iCol))!=0 ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
switch( iCol ){
|
||||
case MSV_COLUMN_NAME: {
|
||||
sqlite3_result_text(ctx, aMemstatColumn[i].zName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_SCHEMA: {
|
||||
sqlite3_result_text(ctx, pCur->azDb[pCur->iDb], -1, 0);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_VALUE: {
|
||||
sqlite3_result_int64(ctx, pCur->aVal[0]);
|
||||
break;
|
||||
}
|
||||
case MSV_COLUMN_HIWTR: {
|
||||
sqlite3_result_int64(ctx, pCur->aVal[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int memstatRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
*pRowid = pCur->iRowid*1000 + pCur->iDb;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int memstatEof(sqlite3_vtab_cursor *cur){
|
||||
memstat_cursor *pCur = (memstat_cursor*)cur;
|
||||
return pCur->iRowid>MSV_NROW;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the memstat_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
** once prior to any call to memstatColumn() or memstatRowid() or
|
||||
** memstatEof().
|
||||
*/
|
||||
static int memstatFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
memstat_cursor *pCur = (memstat_cursor *)pVtabCursor;
|
||||
int rc = memstatFindSchemas(pCur);
|
||||
if( rc ) return rc;
|
||||
pCur->iRowid = 0;
|
||||
pCur->iDb = 0;
|
||||
return memstatNext(pVtabCursor);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the memstat virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
*/
|
||||
static int memstatBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
pIdxInfo->estimatedCost = (double)500;
|
||||
pIdxInfo->estimatedRows = 500;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** memstat virtual table.
|
||||
*/
|
||||
static sqlite3_module memstatModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
memstatConnect, /* xConnect */
|
||||
memstatBestIndex, /* xBestIndex */
|
||||
memstatDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
memstatOpen, /* xOpen - open a cursor */
|
||||
memstatClose, /* xClose - close a cursor */
|
||||
memstatFilter, /* xFilter - configure scan constraints */
|
||||
memstatNext, /* xNext - advance a cursor */
|
||||
memstatEof, /* xEof - check for end of scan */
|
||||
memstatColumn, /* xColumn - read data */
|
||||
memstatRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
int sqlite3MemstatVtabInit(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "sqlite_memstat", &memstatModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_CORE
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_memstat_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3MemstatVtabInit(db);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_CORE */
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_MEMSTATVTAB) */
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements functions that compute SHA1 hashes.
|
||||
** This SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha1(X)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements functions that compute SHA3 hashes.
|
||||
** This SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
|
||||
@@ -1295,9 +1295,6 @@ typedef struct Transliteration Transliteration;
|
||||
struct Transliteration {
|
||||
unsigned short int cFrom;
|
||||
unsigned char cTo0, cTo1, cTo2, cTo3;
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
unsigned char cTo4;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1711,11 +1708,7 @@ static const Transliteration *spellfixFindTranslit(int c, int *pxTop){
|
||||
** should be freed by the caller.
|
||||
*/
|
||||
static unsigned char *transliterate(const unsigned char *zIn, int nIn){
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
unsigned char *zOut = sqlite3_malloc64( nIn*5 + 1 );
|
||||
#else
|
||||
unsigned char *zOut = sqlite3_malloc64( nIn*4 + 1 );
|
||||
#endif
|
||||
int c, sz, nOut;
|
||||
if( zOut==0 ) return 0;
|
||||
nOut = 0;
|
||||
@@ -1739,11 +1732,6 @@ static unsigned char *transliterate(const unsigned char *zIn, int nIn){
|
||||
zOut[nOut++] = tbl[x].cTo2;
|
||||
if( tbl[x].cTo3 ){
|
||||
zOut[nOut++] = tbl[x].cTo3;
|
||||
#ifdef SQLITE_SPELLFIX_5BYTE_MAPPINGS
|
||||
if( tbl[x].cTo4 ){
|
||||
zOut[nOut++] = tbl[x].cTo4;
|
||||
}
|
||||
#endif /* SQLITE_SPELLFIX_5BYTE_MAPPINGS */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-74
@@ -405,8 +405,7 @@ struct rbu_vfs {
|
||||
sqlite3_vfs *pRealVfs; /* Underlying VFS */
|
||||
sqlite3_mutex *mutex; /* Mutex to protect pMain */
|
||||
sqlite3rbu *pRbu; /* Owner RBU object */
|
||||
rbu_file *pMain; /* List of main db files */
|
||||
rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */
|
||||
rbu_file *pMain; /* Linked list of main db files */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -435,7 +434,6 @@ struct rbu_file {
|
||||
const char *zWal; /* Wal filename for this main db file */
|
||||
rbu_file *pWalFd; /* Wal file descriptor for this main db */
|
||||
rbu_file *pMainNext; /* Next MAIN_DB file */
|
||||
rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -4032,69 +4030,6 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an item to the main-db lists, if it is not already present.
|
||||
**
|
||||
** There are two main-db lists. One for all file descriptors, and one
|
||||
** for all file descriptors with rbu_file.pDb!=0. If the argument has
|
||||
** rbu_file.pDb!=0, then it is assumed to already be present on the
|
||||
** main list and is only added to the pDb!=0 list.
|
||||
*/
|
||||
static void rbuMainlistAdd(rbu_file *p){
|
||||
rbu_vfs *pRbuVfs = p->pRbuVfs;
|
||||
rbu_file *pIter;
|
||||
assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
if( p->pRbu==0 ){
|
||||
for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
|
||||
p->pMainNext = pRbuVfs->pMain;
|
||||
pRbuVfs->pMain = p;
|
||||
}else{
|
||||
for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
|
||||
if( pIter==0 ){
|
||||
p->pMainRbuNext = pRbuVfs->pMainRbu;
|
||||
pRbuVfs->pMainRbu = p;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove an item from the main-db lists.
|
||||
*/
|
||||
static void rbuMainlistRemove(rbu_file *p){
|
||||
rbu_file **pp;
|
||||
sqlite3_mutex_enter(p->pRbuVfs->mutex);
|
||||
for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
|
||||
if( *pp ) *pp = p->pMainNext;
|
||||
p->pMainNext = 0;
|
||||
for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
|
||||
if( *pp ) *pp = p->pMainRbuNext;
|
||||
p->pMainRbuNext = 0;
|
||||
sqlite3_mutex_leave(p->pRbuVfs->mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
** Given that zWal points to a buffer containing a wal file name passed to
|
||||
** either the xOpen() or xAccess() VFS method, search the main-db list for
|
||||
** a file-handle opened by the same database connection on the corresponding
|
||||
** database file.
|
||||
**
|
||||
** If parameter bRbu is true, only search for file-descriptors with
|
||||
** rbu_file.pDb!=0.
|
||||
*/
|
||||
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
|
||||
rbu_file *pDb;
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
if( bRbu ){
|
||||
for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
|
||||
}else{
|
||||
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
|
||||
}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
return pDb;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an rbu file.
|
||||
*/
|
||||
@@ -4112,14 +4047,17 @@ static int rbuVfsClose(sqlite3_file *pFile){
|
||||
sqlite3_free(p->zDel);
|
||||
|
||||
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
||||
rbuMainlistRemove(p);
|
||||
rbu_file **pp;
|
||||
sqlite3_mutex_enter(p->pRbuVfs->mutex);
|
||||
for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
|
||||
*pp = p->pMainNext;
|
||||
sqlite3_mutex_leave(p->pRbuVfs->mutex);
|
||||
rbuUnlockShm(p);
|
||||
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
|
||||
}
|
||||
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
|
||||
rbuUpdateTempSize(p, 0);
|
||||
}
|
||||
assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
|
||||
|
||||
/* Close the underlying file handle */
|
||||
rc = p->pReal->pMethods->xClose(p->pReal);
|
||||
@@ -4378,9 +4316,6 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
}else if( rc==SQLITE_NOTFOUND ){
|
||||
pRbu->pTargetFd = p;
|
||||
p->pRbu = pRbu;
|
||||
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
||||
rbuMainlistAdd(p);
|
||||
}
|
||||
if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
@@ -4542,6 +4477,20 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given that zWal points to a buffer containing a wal file name passed to
|
||||
** either the xOpen() or xAccess() VFS method, return a pointer to the
|
||||
** file-handle opened by the same database connection on the corresponding
|
||||
** database file.
|
||||
*/
|
||||
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
|
||||
rbu_file *pDb;
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
return pDb;
|
||||
}
|
||||
|
||||
/*
|
||||
** A main database named zName has just been opened. The following
|
||||
** function returns a pointer to a buffer owned by SQLite that contains
|
||||
@@ -4620,7 +4569,7 @@ static int rbuVfsOpen(
|
||||
pFd->zWal = rbuMainToWal(zName, flags);
|
||||
}
|
||||
else if( flags & SQLITE_OPEN_WAL ){
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
|
||||
if( pDb ){
|
||||
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
||||
/* This call is to open a *-wal file. Intead, open the *-oal. This
|
||||
@@ -4672,7 +4621,10 @@ static int rbuVfsOpen(
|
||||
** mutex protected linked list of all such files. */
|
||||
pFile->pMethods = &rbuvfs_io_methods;
|
||||
if( flags & SQLITE_OPEN_MAIN_DB ){
|
||||
rbuMainlistAdd(pFd);
|
||||
sqlite3_mutex_enter(pRbuVfs->mutex);
|
||||
pFd->pMainNext = pRbuVfs->pMain;
|
||||
pRbuVfs->pMain = pFd;
|
||||
sqlite3_mutex_leave(pRbuVfs->mutex);
|
||||
}
|
||||
}else{
|
||||
sqlite3_free(pFd->zDel);
|
||||
@@ -4720,7 +4672,7 @@ static int rbuVfsAccess(
|
||||
** file opened instead.
|
||||
*/
|
||||
if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
|
||||
if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
||||
if( *pResOut ){
|
||||
rc = SQLITE_CANTOPEN;
|
||||
|
||||
+31
-168
@@ -106,24 +106,14 @@ typedef float GeoCoord;
|
||||
**
|
||||
** encoding (1 byte) 0=big-endian, 1=little-endian
|
||||
** nvertex (3 bytes) Number of vertexes as a big-endian integer
|
||||
**
|
||||
** Enough space is allocated for 4 coordinates, to work around over-zealous
|
||||
** warnings coming from some compiler (notably, clang). In reality, the size
|
||||
** of each GeoPoly memory allocate is adjusted as necessary so that the
|
||||
** GeoPoly.a[] array at the end is the appropriate size.
|
||||
*/
|
||||
typedef struct GeoPoly GeoPoly;
|
||||
struct GeoPoly {
|
||||
int nVertex; /* Number of vertexes */
|
||||
unsigned char hdr[4]; /* Header for on-disk representation */
|
||||
GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */
|
||||
GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */
|
||||
};
|
||||
|
||||
/* The size of a memory allocation needed for a GeoPoly object sufficient
|
||||
** to hold N coordinate pairs.
|
||||
*/
|
||||
#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
|
||||
|
||||
/*
|
||||
** State of a parse of a GeoJSON input.
|
||||
*/
|
||||
@@ -148,7 +138,7 @@ static void geopolySwab32(unsigned char *a){
|
||||
|
||||
/* Skip whitespace. Return the next non-whitespace character. */
|
||||
static char geopolySkipSpace(GeoParse *p){
|
||||
while( safe_isspace(p->z[0]) ) p->z++;
|
||||
while( p->z[0] && safe_isspace(p->z[0]) ) p->z++;
|
||||
return p->z[0];
|
||||
}
|
||||
|
||||
@@ -168,7 +158,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
|
||||
if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
|
||||
for(;; j++){
|
||||
c = z[j];
|
||||
if( safe_isdigit(c) ) continue;
|
||||
if( c>='0' && c<='9' ) continue;
|
||||
if( c=='.' ){
|
||||
if( z[j-1]=='-' ) return 0;
|
||||
if( seenDP ) return 0;
|
||||
@@ -190,17 +180,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
|
||||
break;
|
||||
}
|
||||
if( z[j-1]<'0' ) return 0;
|
||||
if( pVal ){
|
||||
#ifdef SQLITE_AMALGAMATION
|
||||
/* The sqlite3AtoF() routine is much much faster than atof(), if it
|
||||
** is available */
|
||||
double r;
|
||||
(void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8);
|
||||
*pVal = r;
|
||||
#else
|
||||
*pVal = (GeoCoord)atof((const char*)p->z);
|
||||
#endif
|
||||
}
|
||||
if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z);
|
||||
p->z += j;
|
||||
return 1;
|
||||
}
|
||||
@@ -258,10 +238,12 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
|
||||
&& s.a[1]==s.a[s.nVertex*2-1]
|
||||
&& (s.z++, geopolySkipSpace(&s)==0)
|
||||
){
|
||||
int nByte;
|
||||
GeoPoly *pOut;
|
||||
int x = 1;
|
||||
s.nVertex--; /* Remove the redundant vertex at the end */
|
||||
pOut = sqlite3_malloc64( GEOPOLY_SZ(s.nVertex) );
|
||||
nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord);
|
||||
pOut = sqlite3_malloc64( nByte );
|
||||
x = 1;
|
||||
if( pOut==0 ) goto parse_json_err;
|
||||
pOut->nVertex = s.nVertex;
|
||||
@@ -464,27 +446,6 @@ static void geopolyXformFunc(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the area enclosed by the polygon.
|
||||
**
|
||||
** This routine can also be used to detect polygons that rotate in
|
||||
** the wrong direction. Polygons are suppose to be counter-clockwise (CCW).
|
||||
** This routine returns a negative value for clockwise (CW) polygons.
|
||||
*/
|
||||
static double geopolyArea(GeoPoly *p){
|
||||
double rArea = 0.0;
|
||||
int ii;
|
||||
for(ii=0; ii<p->nVertex-1; ii++){
|
||||
rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */
|
||||
* (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */
|
||||
* 0.5;
|
||||
}
|
||||
rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */
|
||||
* (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */
|
||||
* 0.5;
|
||||
return rArea;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the geopoly_area(X) function.
|
||||
**
|
||||
@@ -500,106 +461,21 @@ static void geopolyAreaFunc(
|
||||
){
|
||||
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
||||
if( p ){
|
||||
sqlite3_result_double(context, geopolyArea(p));
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the geopoly_ccw(X) function.
|
||||
**
|
||||
** If the rotation of polygon X is clockwise (incorrect) instead of
|
||||
** counter-clockwise (the correct winding order according to RFC7946)
|
||||
** then reverse the order of the vertexes in polygon X.
|
||||
**
|
||||
** In other words, this routine returns a CCW polygon regardless of the
|
||||
** winding order of its input.
|
||||
**
|
||||
** Use this routine to sanitize historical inputs that that sometimes
|
||||
** contain polygons that wind in the wrong direction.
|
||||
*/
|
||||
static void geopolyCcwFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
||||
if( p ){
|
||||
if( geopolyArea(p)<0.0 ){
|
||||
int ii, jj;
|
||||
for(ii=2, jj=p->nVertex*2 - 4; ii<jj; ii+=2, jj-=2){
|
||||
GeoCoord t = p->a[ii];
|
||||
p->a[ii] = p->a[jj];
|
||||
p->a[jj] = t;
|
||||
t = p->a[ii+1];
|
||||
p->a[ii+1] = p->a[jj+1];
|
||||
p->a[jj+1] = t;
|
||||
}
|
||||
double rArea = 0.0;
|
||||
int ii;
|
||||
for(ii=0; ii<p->nVertex-1; ii++){
|
||||
rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */
|
||||
* (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */
|
||||
* 0.5;
|
||||
}
|
||||
sqlite3_result_blob(context, p->hdr,
|
||||
4+8*p->nVertex, SQLITE_TRANSIENT);
|
||||
rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */
|
||||
* (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */
|
||||
* 0.5;
|
||||
sqlite3_result_double(context, rArea);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
#define GEOPOLY_PI 3.1415926535897932385
|
||||
|
||||
/* Fast approximation for cosine(X) for X between -0.5*pi and 2*pi
|
||||
*/
|
||||
static double geopolyCosine(double r){
|
||||
assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI );
|
||||
if( r>=1.5*GEOPOLY_PI ){
|
||||
r -= 2.0*GEOPOLY_PI;
|
||||
}
|
||||
if( r>=0.5*GEOPOLY_PI ){
|
||||
return -geopolyCosine(r-GEOPOLY_PI);
|
||||
}else{
|
||||
double r2 = r*r;
|
||||
double r3 = r2*r;
|
||||
double r5 = r3*r2;
|
||||
return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Function: geopoly_regular(X,Y,R,N)
|
||||
**
|
||||
** Construct a simple, convex, regular polygon centered at X, Y
|
||||
** with circumradius R and with N sides.
|
||||
*/
|
||||
static void geopolyRegularFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
double x = sqlite3_value_double(argv[0]);
|
||||
double y = sqlite3_value_double(argv[1]);
|
||||
double r = sqlite3_value_double(argv[2]);
|
||||
int n = sqlite3_value_int(argv[3]);
|
||||
int i;
|
||||
GeoPoly *p;
|
||||
|
||||
if( n<3 || r<=0.0 ) return;
|
||||
if( n>1000 ) n = 1000;
|
||||
p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
|
||||
if( p==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
p->hdr[0] = *(unsigned char*)&i;
|
||||
p->hdr[1] = 0;
|
||||
p->hdr[2] = (n>>8)&0xff;
|
||||
p->hdr[3] = n&0xff;
|
||||
for(i=0; i<n; i++){
|
||||
double rAngle = 2.0*GEOPOLY_PI*i/n;
|
||||
p->a[i*2] = x - r*geopolyCosine(rAngle-0.5*GEOPOLY_PI);
|
||||
p->a[i*2+1] = y + r*geopolyCosine(rAngle);
|
||||
}
|
||||
sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** If pPoly is a polygon, compute its bounding box. Then:
|
||||
**
|
||||
@@ -644,7 +520,7 @@ static GeoPoly *geopolyBBox(
|
||||
if( pRc ) *pRc = SQLITE_OK;
|
||||
if( aCoord==0 ){
|
||||
geopolyBboxFill:
|
||||
pOut = sqlite3_realloc(p, GEOPOLY_SZ(4));
|
||||
pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
|
||||
if( pOut==0 ){
|
||||
sqlite3_free(p);
|
||||
if( context ) sqlite3_result_error_nomem(context);
|
||||
@@ -1672,16 +1548,7 @@ static int geopolyUpdate(
|
||||
if( sqlite3_value_nochange(aData[2]) ){
|
||||
sqlite3_bind_null(pUp, 2);
|
||||
}else{
|
||||
GeoPoly *p = 0;
|
||||
if( sqlite3_value_type(aData[2])==SQLITE_TEXT
|
||||
&& (p = geopolyFuncParam(0, aData[2], &rc))!=0
|
||||
&& rc==SQLITE_OK
|
||||
){
|
||||
sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
sqlite3_bind_value(pUp, 2, aData[2]);
|
||||
}
|
||||
sqlite3_free(p);
|
||||
sqlite3_bind_value(pUp, 2, aData[2]);
|
||||
nChange = 1;
|
||||
}
|
||||
for(jj=1; jj<pRtree->nAux; jj++){
|
||||
@@ -1754,22 +1621,19 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
static const struct {
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
signed char nArg;
|
||||
unsigned char bPure;
|
||||
int nArg;
|
||||
const char *zName;
|
||||
} aFunc[] = {
|
||||
{ geopolyAreaFunc, 1, 1, "geopoly_area" },
|
||||
{ geopolyBlobFunc, 1, 1, "geopoly_blob" },
|
||||
{ geopolyJsonFunc, 1, 1, "geopoly_json" },
|
||||
{ geopolySvgFunc, -1, 1, "geopoly_svg" },
|
||||
{ geopolyWithinFunc, 2, 1, "geopoly_within" },
|
||||
{ geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" },
|
||||
{ geopolyOverlapFunc, 2, 1, "geopoly_overlap" },
|
||||
{ geopolyDebugFunc, 1, 0, "geopoly_debug" },
|
||||
{ geopolyBBoxFunc, 1, 1, "geopoly_bbox" },
|
||||
{ geopolyXformFunc, 7, 1, "geopoly_xform" },
|
||||
{ geopolyRegularFunc, 4, 1, "geopoly_regular" },
|
||||
{ geopolyCcwFunc, 1, 1, "geopoly_ccw" },
|
||||
{ geopolyAreaFunc, 1, "geopoly_area" },
|
||||
{ geopolyBlobFunc, 1, "geopoly_blob" },
|
||||
{ geopolyJsonFunc, 1, "geopoly_json" },
|
||||
{ geopolySvgFunc, -1, "geopoly_svg" },
|
||||
{ geopolyWithinFunc, 2, "geopoly_within" },
|
||||
{ geopolyContainsPointFunc, 3, "geopoly_contains_point" },
|
||||
{ geopolyOverlapFunc, 2, "geopoly_overlap" },
|
||||
{ geopolyDebugFunc, 1, "geopoly_debug" },
|
||||
{ geopolyBBoxFunc, 1, "geopoly_bbox" },
|
||||
{ geopolyXformFunc, 7, "geopoly_xform" },
|
||||
};
|
||||
static const struct {
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
|
||||
@@ -1780,9 +1644,8 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
int enc = aFunc[i].bPure ? SQLITE_UTF8|SQLITE_DETERMINISTIC : SQLITE_UTF8;
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
|
||||
enc, 0,
|
||||
SQLITE_UTF8, 0,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||
|
||||
@@ -586,17 +586,4 @@ SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"')
|
||||
ROLLBACK;
|
||||
.print '</svg>'
|
||||
|
||||
.print '<h1>Regular Polygons</h1>'
|
||||
.print '<svg width="1000" height="200" style="border:1px solid black">'
|
||||
SELECT geopoly_svg(geopoly_regular(100,100,40,3),'style="fill:none;stroke:red;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(200,100,40,4),'style="fill:none;stroke:orange;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(300,100,40,5),'style="fill:none;stroke:green;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(400,100,40,6),'style="fill:none;stroke:blue;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(500,100,40,7),'style="fill:none;stroke:purple;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(600,100,40,8),'style="fill:none;stroke:red;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(700,100,40,10),'style="fill:none;stroke:orange;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(800,100,40,20),'style="fill:none;stroke:green;stroke-width:1"');
|
||||
SELECT geopoly_svg(geopoly_regular(900,100,40,30),'style="fill:none;stroke:blue;stroke-width:1"');
|
||||
.print '</svg>'
|
||||
|
||||
.print '</html>'
|
||||
|
||||
@@ -655,13 +655,6 @@ do_test $tn.13.3 {
|
||||
} {1 one 2 two 3 iii}
|
||||
execsql ROLLBACK
|
||||
|
||||
do_test $tn.14.1 { sqlite3session_config strm_size -1 } 64
|
||||
do_test $tn.14.2 { sqlite3session_config strm_size 65536 } 65536
|
||||
do_test $tn.14.3 { sqlite3session_config strm_size 64 } 64
|
||||
do_test $tn.14.4 {
|
||||
list [catch {sqlite3session_config invalid 123} msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -95,23 +95,6 @@ proc changeset_from_sql {sql {dbname main}} {
|
||||
return $changeset
|
||||
}
|
||||
|
||||
proc patchset_from_sql {sql {dbname main}} {
|
||||
set rc [catch {
|
||||
sqlite3session S db $dbname
|
||||
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
|
||||
S attach $name
|
||||
}
|
||||
db eval $sql
|
||||
S patchset
|
||||
} patchset]
|
||||
catch { S delete }
|
||||
|
||||
if {$rc} {
|
||||
error $patchset
|
||||
}
|
||||
return $patchset
|
||||
}
|
||||
|
||||
proc do_then_apply_sql {sql {dbname main}} {
|
||||
proc xConflict args { return "OMIT" }
|
||||
set rc [catch {
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
# 2018 October 18
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix sessioninvert
|
||||
|
||||
proc iter_invert {C} {
|
||||
set x [list]
|
||||
sqlite3session_foreach -invert c $C { lappend x $c }
|
||||
set x
|
||||
}
|
||||
|
||||
proc do_invert_test {tn sql {iter {}}} {
|
||||
|
||||
forcecopy test.db test.db2
|
||||
sqlite3 db2 test.db2
|
||||
|
||||
set C [changeset_from_sql $sql]
|
||||
|
||||
forcecopy test.db test.db3
|
||||
sqlite3 db3 test.db3
|
||||
uplevel [list do_test $tn.1 [list compare_db db db3] {}]
|
||||
|
||||
set I [sqlite3changeset_invert $C]
|
||||
sqlite3changeset_apply db $I {}
|
||||
uplevel [list do_test $tn.2 [list compare_db db db2] {}]
|
||||
|
||||
sqlite3changeset_apply_v2 -invert db3 $C {}
|
||||
uplevel [list do_test $tn.3 [list compare_db db db3] {}]
|
||||
|
||||
if {$iter!=""} {
|
||||
uplevel [list do_test $tn.4 [list iter_invert $C] [list {*}$iter]]
|
||||
}
|
||||
|
||||
catch { db2 close }
|
||||
catch { db3 close }
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b, c);
|
||||
CREATE TABLE t2(d, e, f, PRIMARY KEY(e, f));
|
||||
|
||||
INSERT INTO t1 VALUES(1, 'one', 'i');
|
||||
INSERT INTO t1 VALUES(2, 'two', 'ii');
|
||||
INSERT INTO t1 VALUES(3, 'three', 'iii');
|
||||
INSERT INTO t1 VALUES(4, 'four', 'iv');
|
||||
INSERT INTO t1 VALUES(5, 'five', 'v');
|
||||
INSERT INTO t1 VALUES(6, 'six', 'vi');
|
||||
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
}
|
||||
|
||||
do_invert_test 1.1 {
|
||||
INSERT INTO t1 VALUES(7, 'seven', 'vii');
|
||||
} {
|
||||
{DELETE t1 0 X.. {i 7 t seven t vii} {}}
|
||||
}
|
||||
|
||||
do_invert_test 1.2 {
|
||||
DELETE FROM t1 WHERE a<4;
|
||||
} {
|
||||
{INSERT t1 0 X.. {} {i 1 t one t i}}
|
||||
{INSERT t1 0 X.. {} {i 2 t two t ii}}
|
||||
{INSERT t1 0 X.. {} {i 3 t three t iii}}
|
||||
}
|
||||
|
||||
do_invert_test 1.3 {
|
||||
UPDATE t1 SET c=5;
|
||||
} {
|
||||
{UPDATE t1 0 X.. {i 1 {} {} i 5} {{} {} {} {} t i}}
|
||||
{UPDATE t1 0 X.. {i 2 {} {} i 5} {{} {} {} {} t ii}}
|
||||
{UPDATE t1 0 X.. {i 3 {} {} i 5} {{} {} {} {} t iii}}
|
||||
{UPDATE t1 0 X.. {i 4 {} {} i 5} {{} {} {} {} t iv}}
|
||||
{UPDATE t1 0 X.. {i 5 {} {} i 5} {{} {} {} {} t v}}
|
||||
{UPDATE t1 0 X.. {i 6 {} {} i 5} {{} {} {} {} t vi}}
|
||||
}
|
||||
|
||||
do_invert_test 1.4 {
|
||||
UPDATE t1 SET b = a+1 WHERE a%2;
|
||||
DELETE FROM t2;
|
||||
INSERT INTO t1 VALUES(10, 'ten', NULL);
|
||||
}
|
||||
|
||||
do_invert_test 1.5 {
|
||||
UPDATE t2 SET d = d-1;
|
||||
} {
|
||||
{UPDATE t2 0 .XX {i 2 t three t iii} {i 3 {} {} {} {}}}
|
||||
{UPDATE t2 0 .XX {i 1 t two t ii} {i 2 {} {} {} {}}}
|
||||
{UPDATE t2 0 .XX {i 5 t six t vi} {i 6 {} {} {} {}}}
|
||||
{UPDATE t2 0 .XX {i 3 t four t iv} {i 4 {} {} {} {}}}
|
||||
{UPDATE t2 0 .XX {i 0 t one t i} {i 1 {} {} {} {}}}
|
||||
{UPDATE t2 0 .XX {i 4 t five t v} {i 5 {} {} {} {}}}
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
ANALYZE;
|
||||
PRAGMA writable_schema = 1;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
SELECT * FROM sqlite_stat1;
|
||||
} {
|
||||
t2 sqlite_autoindex_t2_1 {6 1 1}
|
||||
t1 sqlite_autoindex_t1_1 {6 1}
|
||||
}
|
||||
|
||||
do_invert_test 2.1 {
|
||||
INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3');
|
||||
} {
|
||||
{DELETE sqlite_stat1 0 XX. {t t3 t idx2 t {1 2 3}} {}}
|
||||
}
|
||||
|
||||
do_invert_test 2.2 {
|
||||
DELETE FROM sqlite_stat1;
|
||||
} {
|
||||
{INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {6 1}}}
|
||||
{INSERT sqlite_stat1 0 XX. {} {t t2 t sqlite_autoindex_t2_1 t {6 1 1}}}
|
||||
}
|
||||
|
||||
do_invert_test 2.3 {
|
||||
UPDATE sqlite_stat1 SET stat = 'hello world';
|
||||
}
|
||||
|
||||
do_test 3.0 {
|
||||
forcecopy test.db test.db2
|
||||
sqlite3 db2 test.db2
|
||||
set P [patchset_from_sql {
|
||||
INSERT INTO t2 VALUES(1, 2, 3);
|
||||
DELETE FROM t2 WHERE d = 3;
|
||||
}]
|
||||
|
||||
list [catch { sqlite3changeset_apply_v2 -invert db2 $P {} } msg] $msg
|
||||
} {1 SQLITE_CORRUPT}
|
||||
|
||||
do_test 3.1 {
|
||||
list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg
|
||||
} {1 SQLITE_CORRUPT}
|
||||
|
||||
do_test 3.2 {
|
||||
sqlite3changeset_apply_v2 db2 $P {}
|
||||
compare_db db db2
|
||||
} {}
|
||||
|
||||
|
||||
finish_test
|
||||
+56
-111
@@ -25,8 +25,6 @@ typedef struct SessionInput SessionInput;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
|
||||
|
||||
typedef struct SessionHook SessionHook;
|
||||
struct SessionHook {
|
||||
void *pCtx;
|
||||
@@ -89,7 +87,6 @@ struct sqlite3_changeset_iter {
|
||||
SessionInput in; /* Input buffer or stream */
|
||||
SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
|
||||
int bPatchset; /* True if this is a patchset */
|
||||
int bInvert; /* True to invert changeset */
|
||||
int rc; /* Iterator error code */
|
||||
sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
|
||||
char *zTab; /* Current table */
|
||||
@@ -1796,12 +1793,12 @@ int sqlite3session_attach(
|
||||
static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
|
||||
if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
|
||||
u8 *aNew;
|
||||
i64 nNew = p->nAlloc ? p->nAlloc : 128;
|
||||
int nNew = p->nAlloc ? p->nAlloc : 128;
|
||||
do {
|
||||
nNew = nNew*2;
|
||||
}while( (nNew-p->nBuf)<nByte );
|
||||
}while( nNew<(p->nBuf+nByte) );
|
||||
|
||||
aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
|
||||
aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
|
||||
if( 0==aNew ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -2399,12 +2396,12 @@ static int sessionGenerateChangeset(
|
||||
rc = sqlite3_reset(pSel);
|
||||
}
|
||||
|
||||
/* If the buffer is now larger than sessions_strm_chunk_size, pass
|
||||
/* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
|
||||
** its contents to the xOutput() callback. */
|
||||
if( xOutput
|
||||
&& rc==SQLITE_OK
|
||||
&& buf.nBuf>nNoop
|
||||
&& buf.nBuf>sessions_strm_chunk_size
|
||||
&& buf.nBuf>SESSIONS_STRM_CHUNK_SIZE
|
||||
){
|
||||
rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
|
||||
nNoop = -1;
|
||||
@@ -2543,8 +2540,7 @@ static int sessionChangesetStart(
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn,
|
||||
int nChangeset, /* Size of buffer pChangeset in bytes */
|
||||
void *pChangeset, /* Pointer to buffer containing changeset */
|
||||
int bInvert /* True to invert changeset */
|
||||
void *pChangeset /* Pointer to buffer containing changeset */
|
||||
){
|
||||
sqlite3_changeset_iter *pRet; /* Iterator to return */
|
||||
int nByte; /* Number of bytes to allocate for iterator */
|
||||
@@ -2564,7 +2560,6 @@ static int sessionChangesetStart(
|
||||
pRet->in.xInput = xInput;
|
||||
pRet->in.pIn = pIn;
|
||||
pRet->in.bEof = (xInput ? 0 : 1);
|
||||
pRet->bInvert = bInvert;
|
||||
|
||||
/* Populate the output variable and return success. */
|
||||
*pp = pRet;
|
||||
@@ -2579,16 +2574,7 @@ int sqlite3changeset_start(
|
||||
int nChangeset, /* Size of buffer pChangeset in bytes */
|
||||
void *pChangeset /* Pointer to buffer containing changeset */
|
||||
){
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
|
||||
}
|
||||
int sqlite3changeset_start_v2(
|
||||
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
||||
int nChangeset, /* Size of buffer pChangeset in bytes */
|
||||
void *pChangeset, /* Pointer to buffer containing changeset */
|
||||
int flags
|
||||
){
|
||||
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
|
||||
return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2599,16 +2585,7 @@ int sqlite3changeset_start_strm(
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn
|
||||
){
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
|
||||
}
|
||||
int sqlite3changeset_start_v2_strm(
|
||||
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn,
|
||||
int flags
|
||||
){
|
||||
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
|
||||
return sessionChangesetStart(pp, xInput, pIn, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2616,7 +2593,7 @@ int sqlite3changeset_start_v2_strm(
|
||||
** object and the buffer is full, discard some data to free up space.
|
||||
*/
|
||||
static void sessionDiscardData(SessionInput *pIn){
|
||||
if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){
|
||||
if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
|
||||
int nMove = pIn->buf.nBuf - pIn->iNext;
|
||||
assert( nMove>=0 );
|
||||
if( nMove>0 ){
|
||||
@@ -2639,7 +2616,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){
|
||||
int rc = SQLITE_OK;
|
||||
if( pIn->xInput ){
|
||||
while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
|
||||
int nNew = sessions_strm_chunk_size;
|
||||
int nNew = SESSIONS_STRM_CHUNK_SIZE;
|
||||
|
||||
if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
|
||||
if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
|
||||
@@ -2987,10 +2964,10 @@ static int sessionChangesetNext(
|
||||
op = p->in.aData[p->in.iNext++];
|
||||
}
|
||||
|
||||
if( p->zTab==0 || (p->bPatchset && p->bInvert) ){
|
||||
if( p->zTab==0 ){
|
||||
/* The first record in the changeset is not a table header. Must be a
|
||||
** corrupt changeset. */
|
||||
assert( p->in.iNext==1 || p->zTab );
|
||||
assert( p->in.iNext==1 );
|
||||
return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||
}
|
||||
|
||||
@@ -3015,39 +2992,33 @@ static int sessionChangesetNext(
|
||||
*paRec = &p->in.aData[p->in.iNext];
|
||||
p->in.iNext += *pnRec;
|
||||
}else{
|
||||
sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue);
|
||||
sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]);
|
||||
|
||||
/* If this is an UPDATE or DELETE, read the old.* record. */
|
||||
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
|
||||
u8 *abPK = p->bPatchset ? p->abPK : 0;
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
}
|
||||
|
||||
/* If this is an INSERT or UPDATE, read the new.* record. */
|
||||
if( p->op!=SQLITE_DELETE ){
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
|
||||
p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
|
||||
if( p->rc!=SQLITE_OK ) return p->rc;
|
||||
}
|
||||
|
||||
if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){
|
||||
if( p->bPatchset && p->op==SQLITE_UPDATE ){
|
||||
/* If this is an UPDATE that is part of a patchset, then all PK and
|
||||
** modified fields are present in the new.* record. The old.* record
|
||||
** is currently completely empty. This block shifts the PK fields from
|
||||
** new.* to old.*, to accommodate the code that reads these arrays. */
|
||||
for(i=0; i<p->nCol; i++){
|
||||
assert( p->bPatchset==0 || p->apValue[i]==0 );
|
||||
assert( p->apValue[i]==0 );
|
||||
if( p->abPK[i] ){
|
||||
assert( p->apValue[i]==0 );
|
||||
p->apValue[i] = p->apValue[i+p->nCol];
|
||||
if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
|
||||
p->apValue[i+p->nCol] = 0;
|
||||
}
|
||||
}
|
||||
}else if( p->bInvert ){
|
||||
if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
|
||||
else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3364,7 +3335,7 @@ static int sessionChangesetInvert(
|
||||
}
|
||||
|
||||
assert( rc==SQLITE_OK );
|
||||
if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){
|
||||
if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
|
||||
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
||||
sOut.nBuf = 0;
|
||||
if( rc!=SQLITE_OK ) goto finished_invert;
|
||||
@@ -3443,8 +3414,7 @@ struct SessionApplyCtx {
|
||||
int bDeferConstraints; /* True to defer constraints */
|
||||
SessionBuffer constraints; /* Deferred constraints are stored here */
|
||||
SessionBuffer rebase; /* Rebase information (if any) here */
|
||||
u8 bRebaseStarted; /* If table header is already in rebase */
|
||||
u8 bRebase; /* True to collect rebase information */
|
||||
int bRebaseStarted; /* If table header is already in rebase */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3841,36 +3811,35 @@ static int sessionRebaseAdd(
|
||||
sqlite3_changeset_iter *pIter /* Iterator pointing at current change */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->bRebase ){
|
||||
int i;
|
||||
int eOp = pIter->op;
|
||||
if( p->bRebaseStarted==0 ){
|
||||
/* Append a table-header to the rebase buffer */
|
||||
const char *zTab = pIter->zTab;
|
||||
sessionAppendByte(&p->rebase, 'T', &rc);
|
||||
sessionAppendVarint(&p->rebase, p->nCol, &rc);
|
||||
sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
|
||||
sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
|
||||
p->bRebaseStarted = 1;
|
||||
}
|
||||
|
||||
assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
|
||||
assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
|
||||
|
||||
sessionAppendByte(&p->rebase,
|
||||
(eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
|
||||
);
|
||||
sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
sqlite3_value *pVal = 0;
|
||||
if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
|
||||
sqlite3changeset_old(pIter, i, &pVal);
|
||||
}else{
|
||||
sqlite3changeset_new(pIter, i, &pVal);
|
||||
}
|
||||
sessionAppendValue(&p->rebase, pVal, &rc);
|
||||
}
|
||||
int i;
|
||||
int eOp = pIter->op;
|
||||
if( p->bRebaseStarted==0 ){
|
||||
/* Append a table-header to the rebase buffer */
|
||||
const char *zTab = pIter->zTab;
|
||||
sessionAppendByte(&p->rebase, 'T', &rc);
|
||||
sessionAppendVarint(&p->rebase, p->nCol, &rc);
|
||||
sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
|
||||
sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
|
||||
p->bRebaseStarted = 1;
|
||||
}
|
||||
|
||||
assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
|
||||
assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
|
||||
|
||||
sessionAppendByte(&p->rebase,
|
||||
(eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
|
||||
);
|
||||
sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
sqlite3_value *pVal = 0;
|
||||
if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
|
||||
sqlite3changeset_old(pIter, i, &pVal);
|
||||
}else{
|
||||
sqlite3changeset_new(pIter, i, &pVal);
|
||||
}
|
||||
sessionAppendValue(&p->rebase, pVal, &rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4213,7 +4182,7 @@ static int sessionRetryConstraints(
|
||||
SessionBuffer cons = pApply->constraints;
|
||||
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
|
||||
|
||||
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
|
||||
rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
|
||||
if( rc==SQLITE_OK ){
|
||||
int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
|
||||
int rc2;
|
||||
@@ -4279,7 +4248,6 @@ static int sessionChangesetApply(
|
||||
|
||||
pIter->in.bNoDiscard = 1;
|
||||
memset(&sApply, 0, sizeof(sApply));
|
||||
sApply.bRebase = (ppRebase && pnRebase);
|
||||
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
||||
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
||||
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
||||
@@ -4430,8 +4398,7 @@ static int sessionChangesetApply(
|
||||
}
|
||||
}
|
||||
|
||||
assert( sApply.bRebase || sApply.rebase.nBuf==0 );
|
||||
if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){
|
||||
if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){
|
||||
*ppRebase = (void*)sApply.rebase.aBuf;
|
||||
*pnRebase = sApply.rebase.nBuf;
|
||||
sApply.rebase.aBuf = 0;
|
||||
@@ -4469,8 +4436,7 @@ int sqlite3changeset_apply_v2(
|
||||
int flags
|
||||
){
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
|
||||
int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionChangesetApply(
|
||||
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
||||
@@ -4527,8 +4493,7 @@ int sqlite3changeset_apply_v2_strm(
|
||||
int flags
|
||||
){
|
||||
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
||||
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
||||
int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
|
||||
int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sessionChangesetApply(
|
||||
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
||||
@@ -4901,12 +4866,13 @@ static int sessionChangegroupOutput(
|
||||
sessionAppendByte(&buf, p->op, &rc);
|
||||
sessionAppendByte(&buf, p->bIndirect, &rc);
|
||||
sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
|
||||
if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){
|
||||
rc = xOutput(pOut, buf.aBuf, buf.nBuf);
|
||||
buf.nBuf = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
|
||||
rc = xOutput(pOut, buf.aBuf, buf.nBuf);
|
||||
buf.nBuf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -5297,7 +5263,7 @@ static int sessionRebase(
|
||||
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
||||
sessionAppendBlob(&sOut, aRec, nRec, &rc);
|
||||
}
|
||||
if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){
|
||||
if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){
|
||||
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
||||
sOut.nBuf = 0;
|
||||
}
|
||||
@@ -5408,25 +5374,4 @@ void sqlite3rebaser_delete(sqlite3_rebaser *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Global configuration
|
||||
*/
|
||||
int sqlite3session_config(int op, void *pArg){
|
||||
int rc = SQLITE_OK;
|
||||
switch( op ){
|
||||
case SQLITE_SESSION_CONFIG_STRMSIZE: {
|
||||
int *pInt = (int*)pArg;
|
||||
if( *pInt>0 ){
|
||||
sessions_strm_chunk_size = *pInt;
|
||||
}
|
||||
*pInt = sessions_strm_chunk_size;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = SQLITE_MISUSE;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
@@ -473,38 +473,12 @@ int sqlite3session_isempty(sqlite3_session *pSession);
|
||||
** consecutively. There is no chance that the iterator will visit a change
|
||||
** the applies to table X, then one for table Y, and then later on visit
|
||||
** another change for table X.
|
||||
**
|
||||
** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
|
||||
** may be modified by passing a combination of
|
||||
** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter.
|
||||
**
|
||||
** Note that the sqlite3changeset_start_v2() API is still <b>experimental</b>
|
||||
** and therefore subject to change.
|
||||
*/
|
||||
int sqlite3changeset_start(
|
||||
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
|
||||
int nChangeset, /* Size of changeset blob in bytes */
|
||||
void *pChangeset /* Pointer to blob containing changeset */
|
||||
);
|
||||
int sqlite3changeset_start_v2(
|
||||
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
|
||||
int nChangeset, /* Size of changeset blob in bytes */
|
||||
void *pChangeset, /* Pointer to blob containing changeset */
|
||||
int flags /* SESSION_CHANGESETSTART_* flags */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags for sqlite3changeset_start_v2
|
||||
**
|
||||
** The following flags may passed via the 4th parameter to
|
||||
** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
|
||||
**
|
||||
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
||||
** Invert the changeset while iterating through it. This is equivalent to
|
||||
** inverting a changeset using sqlite3changeset_invert() before applying it.
|
||||
** It is an error to specify this flag with a patchset.
|
||||
*/
|
||||
#define SQLITE_CHANGESETSTART_INVERT 0x0002
|
||||
|
||||
|
||||
/*
|
||||
@@ -1159,7 +1133,7 @@ int sqlite3changeset_apply_v2(
|
||||
),
|
||||
void *pCtx, /* First argument passed to xConflict */
|
||||
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
|
||||
int flags /* SESSION_CHANGESETAPPLY_* flags */
|
||||
int flags /* Combination of SESSION_APPLY_* flags */
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -1177,14 +1151,8 @@ int sqlite3changeset_apply_v2(
|
||||
** causes the sessions module to omit this savepoint. In this case, if the
|
||||
** caller has an open transaction or savepoint when apply_v2() is called,
|
||||
** it may revert the partially applied changeset by rolling it back.
|
||||
**
|
||||
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
||||
** Invert the changeset before applying it. This is equivalent to inverting
|
||||
** a changeset using sqlite3changeset_invert() before applying it. It is
|
||||
** an error to specify this flag with a patchset.
|
||||
*/
|
||||
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
|
||||
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
|
||||
|
||||
/*
|
||||
** CAPI3REF: Constants Passed To The Conflict Handler
|
||||
@@ -1578,12 +1546,6 @@ int sqlite3changeset_start_strm(
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn
|
||||
);
|
||||
int sqlite3changeset_start_v2_strm(
|
||||
sqlite3_changeset_iter **pp,
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData),
|
||||
void *pIn,
|
||||
int flags
|
||||
);
|
||||
int sqlite3session_changeset_strm(
|
||||
sqlite3_session *pSession,
|
||||
int (*xOutput)(void *pOut, const void *pData, int nData),
|
||||
@@ -1610,45 +1572,6 @@ int sqlite3rebaser_rebase_strm(
|
||||
void *pOut
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure global parameters
|
||||
**
|
||||
** The sqlite3session_config() interface is used to make global configuration
|
||||
** changes to the sessions module in order to tune it to the specific needs
|
||||
** of the application.
|
||||
**
|
||||
** The sqlite3session_config() interface is not threadsafe. If it is invoked
|
||||
** while any other thread is inside any other sessions method then the
|
||||
** results are undefined. Furthermore, if it is invoked after any sessions
|
||||
** related objects have been created, the results are also undefined.
|
||||
**
|
||||
** The first argument to the sqlite3session_config() function must be one
|
||||
** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
|
||||
** interpretation of the (void*) value passed as the second parameter and
|
||||
** the effect of calling this function depends on the value of the first
|
||||
** parameter.
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_SESSION_CONFIG_STRMSIZE<dd>
|
||||
** By default, the sessions module streaming interfaces attempt to input
|
||||
** and output data in approximately 1 KiB chunks. This operand may be used
|
||||
** to set and query the value of this configuration setting. The pointer
|
||||
** passed as the second argument must point to a value of type (int).
|
||||
** If this value is greater than 0, it is used as the new streaming data
|
||||
** chunk size for both input and output. Before returning, the (int) value
|
||||
** pointed to by pArg is set to the final value of the streaming interface
|
||||
** chunk size.
|
||||
** </dl>
|
||||
**
|
||||
** This function returns SQLITE_OK if successful, or an SQLite error code
|
||||
** otherwise.
|
||||
*/
|
||||
int sqlite3session_config(int op, void *pArg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Values for sqlite3session_config().
|
||||
*/
|
||||
#define SQLITE_SESSION_CONFIG_STRMSIZE 1
|
||||
|
||||
/*
|
||||
** Make sure we can call this stuff from C++.
|
||||
|
||||
+20
-97
@@ -737,32 +737,20 @@ static int SQLITE_TCLAPI testSqlite3changesetApply(
|
||||
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
||||
|
||||
/* Check for the -nosavepoint flag */
|
||||
if( bV2 ){
|
||||
if( objc>1 ){
|
||||
const char *z1 = Tcl_GetString(objv[1]);
|
||||
int n = strlen(z1);
|
||||
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
|
||||
flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
|
||||
objc--;
|
||||
objv++;
|
||||
}
|
||||
}
|
||||
if( objc>1 ){
|
||||
const char *z1 = Tcl_GetString(objv[1]);
|
||||
int n = strlen(z1);
|
||||
if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){
|
||||
flags |= SQLITE_CHANGESETAPPLY_INVERT;
|
||||
objc--;
|
||||
objv++;
|
||||
}
|
||||
if( bV2 && objc>1 ){
|
||||
const char *z1 = Tcl_GetString(objv[1]);
|
||||
int n = strlen(z1);
|
||||
if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
|
||||
flags = SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
|
||||
objc--;
|
||||
objv++;
|
||||
}
|
||||
}
|
||||
|
||||
if( objc!=4 && objc!=5 ){
|
||||
const char *zMsg;
|
||||
if( bV2 ){
|
||||
zMsg = "?-nosavepoint? ?-inverse? "
|
||||
"DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
||||
zMsg = "?-nosavepoint? DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
||||
}else{
|
||||
zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
|
||||
}
|
||||
@@ -981,56 +969,31 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach(
|
||||
Tcl_Obj *pCS;
|
||||
Tcl_Obj *pScript;
|
||||
int isCheckNext = 0;
|
||||
int isInvert = 0;
|
||||
|
||||
TestStreamInput sStr;
|
||||
memset(&sStr, 0, sizeof(sStr));
|
||||
|
||||
while( objc>1 ){
|
||||
if( objc>1 ){
|
||||
char *zOpt = Tcl_GetString(objv[1]);
|
||||
int nOpt = strlen(zOpt);
|
||||
if( zOpt[0]!='-' ) break;
|
||||
if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){
|
||||
isInvert = 1;
|
||||
}else
|
||||
if( nOpt<=5 && 0==sqlite3_strnicmp(zOpt, "-next", nOpt) ){
|
||||
isCheckNext = 1;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
objv++;
|
||||
objc--;
|
||||
isCheckNext = (strcmp(zOpt, "-next")==0);
|
||||
}
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(
|
||||
interp, 1, objv, "?-next? ?-invert? VARNAME CHANGESET SCRIPT");
|
||||
if( objc!=4+isCheckNext ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?-next? VARNAME CHANGESET SCRIPT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pVarname = objv[1];
|
||||
pCS = objv[2];
|
||||
pScript = objv[3];
|
||||
pVarname = objv[1+isCheckNext];
|
||||
pCS = objv[2+isCheckNext];
|
||||
pScript = objv[3+isCheckNext];
|
||||
|
||||
pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
|
||||
sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
|
||||
if( isInvert ){
|
||||
int f = SQLITE_CHANGESETSTART_INVERT;
|
||||
if( sStr.nStream==0 ){
|
||||
rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f);
|
||||
}else{
|
||||
void *pCtx = (void*)&sStr;
|
||||
sStr.aData = (unsigned char*)pChangeset;
|
||||
sStr.nData = nChangeset;
|
||||
rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
|
||||
}
|
||||
if( sStr.nStream==0 ){
|
||||
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
||||
}else{
|
||||
if( sStr.nStream==0 ){
|
||||
rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
|
||||
}else{
|
||||
sStr.aData = (unsigned char*)pChangeset;
|
||||
sStr.nData = nChangeset;
|
||||
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
|
||||
}
|
||||
sStr.aData = (unsigned char*)pChangeset;
|
||||
sStr.nData = nChangeset;
|
||||
rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc, 0);
|
||||
@@ -1239,45 +1202,6 @@ static int SQLITE_TCLAPI test_sqlite3rebaser_create(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3rebaser_configure OP VALUE
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_sqlite3session_config(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
struct ConfigOpt {
|
||||
const char *zSub;
|
||||
int op;
|
||||
} aSub[] = {
|
||||
{ "strm_size", SQLITE_SESSION_CONFIG_STRMSIZE },
|
||||
{ "invalid", 0 },
|
||||
{ 0 }
|
||||
};
|
||||
int rc;
|
||||
int iSub;
|
||||
int iVal;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "OP VALUE");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
rc = Tcl_GetIndexFromObjStruct(interp,
|
||||
objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3session_config(aSub[iSub].op, (void*)&iVal);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return test_session_error(interp, rc, 0);
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
int TestSession_Init(Tcl_Interp *interp){
|
||||
struct Cmd {
|
||||
const char *zCmd;
|
||||
@@ -1293,7 +1217,6 @@ int TestSession_Init(Tcl_Interp *interp){
|
||||
test_sqlite3changeset_apply_replace_all },
|
||||
{ "sql_exec_changeset", test_sql_exec_changeset },
|
||||
{ "sqlite3rebaser_create", test_sqlite3rebaser_create },
|
||||
{ "sqlite3session_config", test_sqlite3session_config },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ int sqlite3_user_authenticate(
|
||||
db->auth.nAuthPW = nPW;
|
||||
rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
|
||||
db->auth.authLevel = authLevel;
|
||||
sqlite3ExpirePreparedStatements(db, 0);
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
if( rc ){
|
||||
return rc; /* OOM error, I/O error, etc. */
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# EXE The suffix to add to executable files. ".exe" for windows
|
||||
# and "" for Unix.
|
||||
#
|
||||
# TCC C Compiler and options for use in building executables that
|
||||
# TCC C Compiler and options for use in building executables that
|
||||
# will run on the target platform. This is usually the same
|
||||
# as BCC, unless you are cross-compiling.
|
||||
#
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
# This is how we compile
|
||||
#
|
||||
TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
|
||||
TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP)
|
||||
TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3
|
||||
TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth
|
||||
TCCX += -I$(TOP)/ext/session
|
||||
@@ -236,7 +236,7 @@ SRC += \
|
||||
$(TOP)/ext/session/sqlite3session.h
|
||||
SRC += \
|
||||
$(TOP)/ext/userauth/userauth.c \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
SRC += \
|
||||
$(TOP)/ext/rbu/sqlite3rbu.c \
|
||||
$(TOP)/ext/rbu/sqlite3rbu.h
|
||||
@@ -251,7 +251,7 @@ FTS5_HDR = \
|
||||
$(TOP)/ext/fts5/fts5.h \
|
||||
$(TOP)/ext/fts5/fts5Int.h \
|
||||
fts5parse.h
|
||||
|
||||
|
||||
FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_aux.c \
|
||||
$(TOP)/ext/fts5/fts5_buffer.c \
|
||||
@@ -431,7 +431,7 @@ TESTSRC2 = \
|
||||
$(TOP)/ext/async/sqlite3async.c \
|
||||
$(TOP)/ext/misc/stmt.c \
|
||||
$(TOP)/ext/session/sqlite3session.c \
|
||||
$(TOP)/ext/session/test_session.c
|
||||
$(TOP)/ext/session/test_session.c
|
||||
|
||||
# Header files used by all library source files.
|
||||
#
|
||||
@@ -484,7 +484,7 @@ EXTHDR += \
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/fts5/fts5Int.h \
|
||||
fts5parse.h \
|
||||
$(TOP)/ext/fts5/fts5.h
|
||||
$(TOP)/ext/fts5/fts5.h
|
||||
EXTHDR += \
|
||||
$(TOP)/ext/userauth/sqlite3userauth.h
|
||||
|
||||
@@ -800,7 +800,7 @@ rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
|
||||
|
||||
|
||||
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon $(OPTS) fts5parse.y
|
||||
@@ -834,13 +834,13 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
|
||||
tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
|
||||
|
||||
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
|
||||
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
|
||||
sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl
|
||||
tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
|
||||
|
||||
sqltclsh$(EXE): sqltclsh.c
|
||||
$(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
$(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB)
|
||||
|
||||
sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
|
||||
$(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB)
|
||||
@@ -893,10 +893,6 @@ fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \
|
||||
-o testfixture$(EXE) $(LIBTCL) $(THREADLIB)
|
||||
|
||||
coretestprogs: $(TESTPROGS)
|
||||
|
||||
testprogs: coretestprogs srcck1$(EXE) fuzzcheck$(EXE) sessionfuzz$(EXE)
|
||||
|
||||
fulltest: $(TESTPROGS) fuzztest
|
||||
./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS)
|
||||
|
||||
@@ -953,7 +949,7 @@ smoketest: $(TESTPROGS) fuzzcheck$(EXE)
|
||||
# The next two rules are used to support the "threadtest" target. Building
|
||||
# threadtest runs a few thread-safety tests that are implemented in C. This
|
||||
# target is invoked by the releasetest.tcl script.
|
||||
#
|
||||
#
|
||||
THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
|
||||
$(TOP)/test/tt3_checkpoint.c \
|
||||
$(TOP)/test/tt3_index.c \
|
||||
@@ -1017,12 +1013,12 @@ wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c
|
||||
$(TOP)/test/wordcount.c sqlite3.c
|
||||
|
||||
speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
$(TCCX) -I. $(ST_OPT) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.c $(THREADLIB)
|
||||
$(TCCX) -I. $(ST_OPT) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.c $(THREADLIB)
|
||||
|
||||
kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
$(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
$(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \
|
||||
$(THREADLIB)
|
||||
|
||||
@@ -1054,7 +1050,7 @@ install: sqlite3 libsqlite3.a sqlite3.h
|
||||
mv libsqlite3.a /usr/lib
|
||||
mv sqlite3.h /usr/include
|
||||
|
||||
clean:
|
||||
clean:
|
||||
rm -f *.o sqlite3 sqlite3.exe libsqlite3.a sqlite3.h opcodes.*
|
||||
rm -f lemon lemon.exe lempar.c parse.* sqlite*.tar.gz
|
||||
rm -f mkkeywordhash mkkeywordhash.exe keywordhash.h
|
||||
@@ -1082,7 +1078,7 @@ clean:
|
||||
rm -f sqlite3rc.h
|
||||
rm -f shell.c sqlite3ext.h
|
||||
rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
|
||||
rm -f sqlite3_expert sqlite3_expert.exe
|
||||
rm -f sqlite3_expert sqlite3_expert.exe
|
||||
rm -f sqlite-*-output.vsix
|
||||
rm -f mptester mptester.exe
|
||||
rm -f fuzzershell fuzzershell.exe
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
C Add\sthe\ssqlite3_normalized_sql()\sAPI.
|
||||
D 2018-10-29T17:53:23.938
|
||||
C Reduce\sthe\ssize\sof\sExpr\sto\s64-bytes.\s\sThis\sworks\ssomewhat,\sbut\sthere\sare\ntest\sfailures.\s\sMore\simportantly,\sthe\ssize\sreduction\sfrom\s80-\sto\s64-bytes\shas\nnot\slowered\sthe\sschema\smemory\susage,\sbut\sit\shas\smade\sthe\scode\sa\slittle\sbigger\nand\sa\slittle\sslower.\s\sSo\sthe\sinitial\sevidence\sis\sthat\sthis\sExpr\srefactoring\nexperiment\sis\snot\sworking...
|
||||
D 2018-09-19T20:14:48.730
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F Makefile.in 783093f97550d2fd61618ca76ada6fbbfc6ec26c242a66e8c25a4d9d54cde899
|
||||
F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc fd51f9eba2cc0da0c26344b7f08addc16a2094640bb60e481dcd6408b901a293
|
||||
F Makefile.msc b946f8806a5d401a299453f61de80dfd1a9df14fa4902b299e6465e3c3134872
|
||||
F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
|
||||
F VERSION 654da1d4053fb09ffc33a3910e6d427182a7dcdc67e934fa83de2849ac83fccb
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -286,7 +286,6 @@ F ext/misc/fileio.c 7317d825fab6a3c48f6e3822a00a6a22e08e55af31700ac96f16a523f830
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c 276f87dc8365b34b0fffb7ef32481dd07fac6fdb3224e2822396a48377ac8363
|
||||
F ext/misc/memstat.c 7542ff1dd1d926e63dab904070e689cd5b47e4dd19498ad31947c42b207f5363
|
||||
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
|
||||
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
@@ -297,10 +296,10 @@ F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6
|
||||
F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8db77
|
||||
F ext/misc/scrub.c db9fff56fed322ca587d73727c6021b11ae79ce3f31b389e1d82891d144f22ad
|
||||
F ext/misc/series.c c7197db304f7009b08d6459a9de02e7f51ad0e1a3fdacbc1ebf5252a9a346959
|
||||
F ext/misc/sha1.c df0a667211baa2c0612d8486acbf6331b9f8633fd4d605c17c7cccd26d59c6bd
|
||||
F ext/misc/shathree.c 22ba7ca84a433d6466a7d05dcc876910b435a715da8cc462517db9351412b8c8
|
||||
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
|
||||
F ext/misc/shathree.c 9e960ba50483214c6a7a4b1517f8d8cef799e9db381195178c3fd3ad207e10c0
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c f88ecb2c0294453ce8b7704b211f5350c41b085b38c8e056852e3a08b0f5e484
|
||||
F ext/misc/spellfix.c 54d650f44f3a69a851814791bd4d304575cdbbf78d96d4f0801b44a8f31a58c5
|
||||
F ext/misc/sqlar.c 57d5bc45cd5492208e451f697404be88f8612527d64c9d42f96b325b64983d74
|
||||
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
|
||||
F ext/misc/templatevtab.c 8251b31011dd00fc38e739c78c234c930be42b3b274bbe0493b79cd40db02a9e
|
||||
@@ -348,7 +347,7 @@ F ext/rbu/rbusplit.test 69271c790732b28bd465551d80b0a9a3f074e189896ee8490ce56d22
|
||||
F ext/rbu/rbutemplimit.test cd553a9288d515d0b5f87d277e76fd18c4aa740b761e7880fab11ce986ea18d1
|
||||
F ext/rbu/rbuvacuum.test ff357e9b556ca7ad4673da0ff7f244def919ff858e0f9f350d3e30fdd83a62a8
|
||||
F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
||||
F ext/rbu/sqlite3rbu.c 71f8c09948d09ec9c5a8dbe7127e8ef61ef0853e698b2650be2485ac7b9c75c8
|
||||
F ext/rbu/sqlite3rbu.c f438fea899d15d13ff3e3133242b9e378c37b5a3d76add8c342c68bdd65c6819
|
||||
F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2
|
||||
F ext/rbu/test_rbu.c baa23eb28457580673d2175e5f0c29ced0cd320ee819b13ad362398c53b96e90
|
||||
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||
@@ -361,7 +360,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
|
||||
F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
|
||||
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/geopoly.c 2464b3325fcc2878ed08458efeb995f830f4eef28bbf3da9757c4bd95e6f9549
|
||||
F ext/rtree/geopoly.c 415a8ca5dfab54eea779e0bf31a859afb0b869a5147a726df4aec4b57c1bad57
|
||||
F ext/rtree/rtree.c 6cc2e673cf1e9ea1619f13ab990f12389dfb951b131acbc2fbe164cee8992a20
|
||||
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
|
||||
F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
|
||||
@@ -389,9 +388,9 @@ F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c36c4bd0203b27dbff
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1d2f94ac66
|
||||
F ext/rtree/visual01.txt 17c3afefc208c375607aa82242e97fa79c316e539bcd0b7b3e59344c69445d05
|
||||
F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
|
||||
F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e
|
||||
F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc
|
||||
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
|
||||
F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479
|
||||
F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40
|
||||
@@ -407,26 +406,25 @@ F ext/session/sessionE.test 0a616c4ad8fd2c05f23217ebb6212ef80b7fef30f5f086a6633a
|
||||
F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce
|
||||
F ext/session/sessionG.test 3edde849c4071078d92bd682c836186f6e4e5a3fb6bcf3fc1de1a7caa5e4427d
|
||||
F ext/session/sessionH.test 332b60e4c2e0a680105e11936201cabe378216f307e2747803cea56fa7d9ebae
|
||||
F ext/session/session_common.tcl 29ec9910aca1e996ca1c8531b8cecabf96eb576aa53de65a8ff03d848b9a2a8b
|
||||
F ext/session/session_common.tcl ee925e0d233677e45e395fb1f559b84068ce7baa8aa1034441739d3e87ee249c
|
||||
F ext/session/session_speed_test.c edc1f96fd5e0e4b16eb03e2a73041013d59e8723
|
||||
F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec
|
||||
F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec
|
||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||
F ext/session/sessionfault2.test 555a8504de03d59b369ef20209585da5aeb2671dedabc4584e9ffe6269689185
|
||||
F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169
|
||||
F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8
|
||||
F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e
|
||||
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
||||
F ext/session/sqlite3session.c 8772d3cb9124a14f85c7c9ca2bc4931f1180ee99acf5386bdfdd6892455b2443
|
||||
F ext/session/sqlite3session.h 05351d2f50a1203fdffbeb590fdbbc796c9a6bfcd0c9b26cf6db3854e3eb4294
|
||||
F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec
|
||||
F ext/session/sqlite3session.c 2d29bbd888599b94b2c8b31ff433675e008273a4d225b336508b18e6187fec1d
|
||||
F ext/session/sqlite3session.h c01820d5b6e73e86d88008f4d1c1c7dfb83422963018292b864028a0400ceccf
|
||||
F ext/session/test_session.c dba36c6c0153b22501112d3e8882b5c946cf617c955153b6712bd2f8ba1428c0
|
||||
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e629edbe2648
|
||||
F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk ab2257d67e9db1fa9ef6159fadc32ef59ab24b9734cd567622d795392c3b2d83
|
||||
F main.mk ff82d38126f8f0668b7990e0f1f3dcd74fa2d477c19b2e3feaaba586051e9b48
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -438,36 +436,36 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c bcb67339d8551408bfc99aa78b597abdc9b880114bc4e42027f9a02615df4f43
|
||||
F src/alter.c 3a859149c15cc78a446e0d632a1a9d24786e230ed1de53d8b88ca2c96f90ace0
|
||||
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
|
||||
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
|
||||
F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
|
||||
F src/attach.c d06bf7ab9efceb7c679ba8beaeeb3082ce3defde482f54de50ac175469f7c4ca
|
||||
F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114
|
||||
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173
|
||||
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
|
||||
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
|
||||
F src/build.c 675799caa8bdd73bea8f8c268a735cb208133ce875bf5c4cbcf7280bebfb2227
|
||||
F src/callback.c 789bd33d188146f66c0dd8306472a72d1c05f71924b24a91caf6bd45cf9aba73
|
||||
F src/build.c 3bdd61d7ecba6f40e7efead3ffb61b2e3bad87de73f407c288035937c9b33687
|
||||
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b
|
||||
F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387
|
||||
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
|
||||
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
|
||||
F src/dbstat.c 5f96184b8a751b7c92b959b55679f56e409c3b3bbe98eaf5e43189c16d4df082
|
||||
F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2
|
||||
F src/expr.c 16dee9504d0c6a09de8aa188fb0989ec3fd48b9704abd4fc80539065f2b52adc
|
||||
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
|
||||
F src/delete.c 07a7ecf18a64478be7241cbb332bc26321586384c750e47fb566f678c5aee512
|
||||
F src/expr.c 5814b4b5d4b9e615faba427a554de5152c972cc0132f6968a13250c07b709372
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 972a4ba14296bef2303a0abbad1e3d82bc3c61f9e6ce4e8e9528bdee68748812
|
||||
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
|
||||
F src/fkey.c 234d4e9fb2a35a11d6ee831dbc19e74fb8bfaf5e09b310ce3cffbf37d6eb57e0
|
||||
F src/func.c 82aeef69505b67197a476836d44cc16c1a434ee53481f23cffb70a75a1bcbc7a
|
||||
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
|
||||
F src/hash.c 931ec82d7e070654a8facb42549bbb3a25720171d73ba94c3d3160580d01ef1f
|
||||
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 0a214201afec77880a31a59c33d86b473a160fc5cc31981eab2041ae03d8bf2f
|
||||
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
|
||||
F src/loadext.c 448eab53ecdb566a1259ee2d45ebff9c0bc4a2cf393774488775c33e4fbe89bf
|
||||
F src/loadext.c 30b140d0e5031924c56f802760506c0a235ced0dff9f3d95119aa86df12856e2
|
||||
F src/main.c 6275ece0699a957c4709a7ebe29476f132adbe459d18a6b497e234e4669abf91
|
||||
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
@@ -488,33 +486,33 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de
|
||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c f6e91b8fd82af7afbfd073c4974ad6cdb8e62d9f65ceddb45167835a0567fdc0
|
||||
F src/os_unix.c d8e37bc3af9b15a52c3fecd366c95416251aa8d89481dd56170bad538b421721
|
||||
F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c f803ffcd8440b5249549ea103158a1c659bf060961b2389f9fede66a3a352d0b
|
||||
F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b
|
||||
F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963
|
||||
F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179
|
||||
F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d
|
||||
F src/parse.y 96a86b76766af46ac9e64afc1576ea7cb0f7219d2f3a7b6c03bb07043017bdf5
|
||||
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c 35efa85894f1ae533c03c64591dfc82f916ad78250591082bbae72a2811bceab
|
||||
F src/pragma.h e50df79399da8c2efc6bd4b7034e242d0dc6ab2016564f08e94103367098b1e4
|
||||
F src/prepare.c bf148a889ed92589dd2e6b99b54107e8c7668ad2f69a41bb55b4bbc701fc6474
|
||||
F src/pragma.c 79abc65c08d2754048efee3ba99fe91863dfeab0ba699a4439fa5053ec87cf36
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097
|
||||
F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073
|
||||
F src/resolve.c adfb08e3e31243433ed60613bd244ba0bef63c80ca0f2fee754db02a831b5811
|
||||
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
|
||||
F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f
|
||||
F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d
|
||||
F src/sqlite.h.in 4f95d6f484ce247fa7cbb7382641d40919cfe9c3bf8091bc462638c7bac4efea
|
||||
F src/select.c 6bacf10a3a65b692586e80ffda8114ce485d47b0bc1fe18a001f39c5c054db81
|
||||
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
|
||||
F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
|
||||
F src/sqliteInt.h be74ca8df8831848718a9ddcd71af265807ca77ef25f1d3416a7b4378c4372fb
|
||||
F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63
|
||||
F src/sqliteInt.h 5cf4c8f1687b8a2042da2259ee8a5a14bf8aa7914a124afa2010afd2c759ccb2
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6
|
||||
F src/test1.c e89148fdb0b3aa92af609669078c219d7b26bf442418b547f0db79d82a7d82f9
|
||||
F src/tclsqlite.c e0bf71a6d24b8c23393c000abffab05979bbca2a72d0b0f79260e2cf1527fda5
|
||||
F src/test1.c 9bb042e4afedc570f78638993fc9cc1760d897d3b27dd72c20618044b2a8fa5e
|
||||
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
@@ -529,7 +527,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 5ebafbcd5c75ac1c16bb0c8fe926dc325cc03e780943a88ca50e0d9a4fc4d2f5
|
||||
F src/test_config.c 3bbc5e593f308cbff426bb88c9dbf75deab551e5ddcece1251b8d9a40e55aef5
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
|
||||
@@ -567,33 +565,33 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 9e781e1ca80eefe7b5d6a9e2cd5c678c847da55fd6f093781fad7950934d4c83
|
||||
F src/treeview.c 0ef7dc77d6fe03172ba65dddfd3b3c557b7b7e217ca1963b7665beb266a0e2c0
|
||||
F src/tokenize.c 9f55961518f77793edd56eee860ecf035d4370ebbb0726ad2f6cada6637fd16b
|
||||
F src/treeview.c 1bc9fc4ebd661bea19b4f39dd32f34b609faf2250112d83d7ffa40ab1c3b386b
|
||||
F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd
|
||||
F src/update.c 1816d56c1bca1ba4e0ef98cac2f49be62858e9df1dc08844c7067eb41cc44274
|
||||
F src/update.c 682f112c49247d2fe5950c9fe2226046c6bc497cf114f74d58766926914216ff
|
||||
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
|
||||
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
|
||||
F src/vdbe.c 005e691ea4c7d51e6c1a69d9389aeb34700884c85f51681817ddea3fdc2fc39b
|
||||
F src/vdbe.c 80603eb66708c2f27879912a4e9456900e66491c3409ca5e392109114e8f6337
|
||||
F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
|
||||
F src/vdbeInt.h 8a52b8db3d20f9755a965d864b8653052c7ef1ccadceb2e057047cd421f6336e
|
||||
F src/vdbeapi.c ecccfce6f614c33a95952efeec969d163e8349eac314ee2b7b163eda921b5eb0
|
||||
F src/vdbeaux.c f547901b1aa9e2d81c63f06893f633648e434180666a827aacb547d7d6c8a601
|
||||
F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827
|
||||
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
|
||||
F src/vdbeaux.c 43ee58196823e17093601388993bbea03456c6ffbbd83d516096af71346d93e3
|
||||
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
|
||||
F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641
|
||||
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
|
||||
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
|
||||
F src/vtab.c 70188a745dc4e57d26e942681ff4b2912b7c8249ad5de3f60f0677b4337bcfaa
|
||||
F src/vtab.c 0d613164d56f43aca041de072ceba541f35fc29eeb7085e69f84829249d7fc46
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
|
||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
||||
F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
|
||||
F src/where.c a54a3d639bcd751d1474deff58e239b2e475a96e1b8f9178aa7864df8782a4e3
|
||||
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
|
||||
F src/wherecode.c 3df0a541373d5f999684d761e4bd700d57adb46c7d39da4e77b767b5adcd5893
|
||||
F src/whereexpr.c 7660a5845113f05f60fa615aed40047a058587a36b70a7b0c28b74253a19ffa1
|
||||
F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc
|
||||
F src/walker.c 4ba292cadd145b8b77e8b2128a363beff0bd87c7f9abfe090c0948eb0330d727
|
||||
F src/where.c 33a546a918b0439e3e174351ca00c9158f26d73c5a8bb54c6c3cf5bae20b7499
|
||||
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
|
||||
F src/wherecode.c ab5992174e31e30f4624fbd57ddffce63db69c861c09811871e0cbab739a2a91
|
||||
F src/whereexpr.c c88f2047c493c36a11116b524c0c9b621253f512930386e81ea96309d7740fd6
|
||||
F src/window.c 4b503da928dace3e845b891381a4d98eeb8c5744313ae3643df8d8d21fdcca65
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||
@@ -605,14 +603,11 @@ F test/alter.test 99e72759d48d6531ac2a9f346b4a9b5fe8f89c67a0fa5e916a3990d3b1fe9d
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
||||
F test/alter4.test 7e93a21fe131e1dfeb317e90056856f96b10381fc7fe3a05e765569a23400433
|
||||
F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959
|
||||
F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499
|
||||
F test/alterauth.test dc50064e3d57d60cf8708decefed15cfa154242f6d44069858d4c6c9b1aea961
|
||||
F test/altercol.test 53fb5e218c9296afc160f2c4fcbeaf42bd0604815d9b3896a7d2eec583ad8704
|
||||
F test/alterlegacy.test e7c07d605c2a85e7d1696c89e6bf64dfc932fc6d9320fe8708c8f5fc0b524d41
|
||||
F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9
|
||||
F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b
|
||||
F test/altertab.test fb8a9a2ab6deb5f860d27675f6213d14ab79b705e0d6350eead4ef3a3f73bf3e
|
||||
F test/altertab2.test 159fd5f7b23ddc841fe678f579f9b1b8e69f44296f3ff75d1b4c155d37a59832
|
||||
F test/altermalloc2.test 0231398534c494401a70a1d06a63d7849cb5b317fcc14228cbdb53039eba7eae
|
||||
F test/altertab.test 3b830144c18ae00abd2a27e3d2851c8bb1ee8fe655fa16d8a5971066dc71b58a
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df
|
||||
F test/analyze3.test ff62d9029e6deb2c914490c6b00caf7fae47cc85cdc046e4a0d0a4d4b87c71d8
|
||||
@@ -643,7 +638,7 @@ F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3
|
||||
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 12c4f028e570acf9e0a4b0b7fe6f536e21f3d5ebddcece423603d0569beaf438
|
||||
F test/auth.test 3310d9c08e928beca42d3eadaaf53cef619d9d275f598565a3758a21ce63138e
|
||||
F test/auth.test f0c1a8fc7f07d94e3e26ba7f77eb4a5cedda67b10d9a49275b154ab03749b6c0
|
||||
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
|
||||
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
|
||||
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
|
||||
@@ -669,8 +664,8 @@ F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
|
||||
F test/bestindex1.test 852170bddbb21daa121fabcc274640ff83d7d8705912e8b5fe7ed2c5a9a9224a
|
||||
F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e76e5928
|
||||
F test/bestindex3.test 001788a114ad96d81d5154fe77c7f1e26e84b3a2b5635ca29e4f96f6decc534e
|
||||
F test/bestindex4.test 210eac9323ef88881212d6ae90c84dad86ec14d82c6f4fc9a9ee24c76a8f2014
|
||||
F test/bestindex5.test 412b42f8036b28d8b2f3534d89389ad946a4b1a65a12263f51936f7424296f1b
|
||||
F test/bestindex4.test 4cb5ff7dbaebadb87d366f51969271778423b455
|
||||
F test/bestindex5.test 0b61fc294997a6b5f869a9f7e111a64c0437b5cef2f6a3d1fb2bba4af6f7c1b0
|
||||
F test/bestindex6.test d856a9bb63d927493575823eed44053bc36251e241aa364e54d0f2a2d302e1d4
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
@@ -770,10 +765,8 @@ F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee
|
||||
F test/dbfuzz2.c fae8599108dbf6460f8862677a22ee517c9030cdd931df0ed3c66c09ab14e46a
|
||||
F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c
|
||||
F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e
|
||||
F test/dbstatus.test c15fa97f743dac7ce996814c84b56317e138895ee15ce27f15b608aa6924c90a
|
||||
F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0
|
||||
@@ -972,7 +965,7 @@ F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664
|
||||
F test/fuzzdata2.db 128b3feeb78918d075c9b14b48610145a0dd4c8d6f1ca7c2870c7e425f5bf31f
|
||||
F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba
|
||||
F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e42ed2
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata5.db 7a3467a24e7112c1f1041ae9ad1e7060c2074da82d420ce786953cc3d3dd20b5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
@@ -1059,7 +1052,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a6
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/like3.test 430691e6057e11a59e934be74c06b85605b80061d45af5714d52886a811efeb7
|
||||
F test/like3.test cf0ff2d06c9d8456283aeff405b911642298441206306aeaeaa93973233b1195
|
||||
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
|
||||
F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e
|
||||
F test/loadext.test d077450695ddb5c1ea3ad7d48e5f5850fe732ad9
|
||||
@@ -1135,7 +1128,7 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
|
||||
F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a
|
||||
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
||||
F test/normalize.test 6a80564d2000702b5919ed2c1069fef0f95762142bc96a71b4c124a845165713
|
||||
F test/normalize.test 1dedf653ca33b0b55fd0c7967d2861a51f1801a7aa899a02d4c0d7adfcd5acdc
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
|
||||
F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
|
||||
@@ -1178,7 +1171,7 @@ F test/permutations.test 8749e292c8f7e98072049543da8c0fe60e1625f0a9f490686230609
|
||||
F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
|
||||
F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
|
||||
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
|
||||
F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
|
||||
F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
|
||||
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
|
||||
@@ -1200,7 +1193,7 @@ F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl c5b474f9880073fc3b69729ee05d5284653a9ee101af572204917d9dcb1d9015 x
|
||||
F test/releasetest.tcl 7e90ec5d2854d80e2574f70df834ef9cae705d21fe43a19dc217a3ce33a3798c x
|
||||
F test/resetdb.test 684a6ffde5a5141bba79f3101981cc38dcfc3403f61e643b7b3aa68bef0b8408
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
@@ -1258,7 +1251,7 @@ F test/server1.test c2b00864514a68a0e6fd518659dc95d0050307a357a08969872bef027d78
|
||||
F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
|
||||
F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb
|
||||
F test/sessionfuzz.c b0fcdcf757451957e17396a3af5171f1fdf9b2babc81da9fa35675df46c4729a
|
||||
F test/shared.test 1826673eb5eb745fb91a3bdac99a7737057742ae38dcb0fe076a384d6727578b
|
||||
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
|
||||
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
|
||||
F test/shared3.test ab693f9b6e156b8bfb2a0ad94f29fe69602a5d38
|
||||
F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558
|
||||
@@ -1270,7 +1263,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test d2bf5daeb6f449f0169c9ef3094db17a16a02199c5dcf1a635a3e79b07eb0edd
|
||||
F test/shell1.test 707c03fbd07ac506cfb6fa09da4ee22e2b50453c3db2f404694116eb990168f3
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
|
||||
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
|
||||
@@ -1338,11 +1331,11 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309
|
||||
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
|
||||
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test 5ddfdcda81f362d54cf301a65678edea2a02a570760a4c88051fc2730aafcd81
|
||||
F test/tabfunc01.test c47171c36b3d411df2bd49719dcaa5d034f8d277477fd41d253940723b969a51
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test dca8aa30d84175e7d8c8fc43d3ffa11fa56e23fbdac2679d03833a0f326edf34
|
||||
F test/tclsqlite.test 5337e8890b96dad1ee541b15fbeec32e6bac2fe7fa096f91089057385aadba9b
|
||||
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
|
||||
F test/tempdb2.test 4749545409c6d7438b435c3f05cdd139cf4145a954a6908d19e3443ffd8724b3
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1563,7 +1556,7 @@ F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2
|
||||
F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test 71e1bf4c0e2e0d37c84d7db5b33cd47eb4a7662c19d93ede4112b350b186f61f
|
||||
F test/view.test 226fb71e37be61854f3a01929ae0a7e14584d6aef5c459bb0a22318f0b6dd210
|
||||
F test/vtab1.test 8f91b9538d1404c3932293a588c4344218a0c94792d4289bb55e41020e7b3fff
|
||||
F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
@@ -1591,7 +1584,7 @@ F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9
|
||||
F test/wal6.test b602704e4b066199bc89d91ca9000f335dcf4572
|
||||
F test/wal64k.test 2a525c0f45d709bae3765c71045ccec5df7d100ccbd3a7860fdba46c9addb965
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
F test/wal8.test d9df3fba4caad5854ed69ed673c68482514203c8
|
||||
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
|
||||
@@ -1638,7 +1631,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test b7769ee8dbefd987fb266715fee887f05f9ff180016b06fca7fa402df739193b
|
||||
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
|
||||
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||
F test/whereL.test 0a19fc44cd1122040f56c934f1b14d0ca85bde28f270268a428dd9796ea0634c
|
||||
F test/whereL.test 84de61afe4b8e5a3ff7d741c990d85cb44b3ce798cd8412d5603930f3f75014f
|
||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
|
||||
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
|
||||
@@ -1648,17 +1641,17 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 02e481ac48c445b43bab7b3cf1e4115165b5127a1aa29e14f5372922c836f1a4
|
||||
F test/window1.test 474bef1a6ac291755e51d1f9458dc11117c1870ac5e08b4d3938649b215f8334
|
||||
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
|
||||
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
|
||||
F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823
|
||||
F test/window3.test e274b7f8952ca4ed25996e0e45c047192b066e0aaff2a822d4293c8c4f1d8d98
|
||||
F test/window4.tcl 511425f6b0abf9b953df54cc9c7295cc7c25d78f4ed6f7a74b094eec0120eccb
|
||||
F test/window4.test c5d6bf3403e4ade2f19df2afe4c16f29fb817c392c6c1c8017edb7165c191a62
|
||||
F test/window4.tcl 871364059b7d320d556ec6ef804d604a4e8cc1547a3102c5d56067371bb200af
|
||||
F test/window4.test 323b118eb592932036388643ca6dcaead87f699bbea2984bbca49ba4ad6c2509
|
||||
F test/window5.test 8187f46597c90b73e8f96659e893353cbda337479cc582f7a488eab351ba08d3
|
||||
F test/window6.test 5eae4ae7a590ccf1e605880969ca0bad3955616ac91cad3031baea38748badb3
|
||||
F test/window6.test 7574778c79cae89f1781df237bf9ff5063886deca91a36efc53934315f0e7612
|
||||
F test/windowfault.test 23abad97b72c6f609002255ddd41ef5c8922408f918f9b98ad6005ab316e482f
|
||||
F test/with1.test 2465d98ffce80d00553ac7135697c18b0369275b6ecc750daa2af320b8c812ca
|
||||
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
|
||||
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
|
||||
@@ -1707,7 +1700,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
|
||||
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
|
||||
F tool/mkpragmatab.tcl 656e64fc4e8b5d91525bac1e81834de3217507657e846b1a08375ca195fa8479
|
||||
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
|
||||
F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
@@ -1774,10 +1767,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 de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f
|
||||
R 3a0379f1d958d505b0867531ec02f91e
|
||||
T *branch * normalized_sql
|
||||
T *sym-normalized_sql *
|
||||
T -sym-trunk *
|
||||
U mistachkin
|
||||
Z aed093f5ed17f4e7a3a3d3f732fe7b71
|
||||
P 8487f84af00a8afde4ae24c4925e0f8ac9f38e86ea8b453dccedb3ee10f7f667
|
||||
R dc50e2519bfa1235f8e5a29ec2577516
|
||||
U drh
|
||||
Z a9cd90cadb1b1e1e79d944ecc746eecf
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
592b66e8058dd03a056a036e2606247c9efdb06d15eebe9bcc455f7f55e30ae6
|
||||
24b0f66ac611e26f55ffeaff459b0d7ab53e6fa8d72765bea77c3b50634357e8
|
||||
+38
-51
@@ -169,6 +169,20 @@ void sqlite3AlterRenameTable(
|
||||
goto exit_rename_table;
|
||||
}
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pVTab ){
|
||||
int i = ++pParse->nMem;
|
||||
sqlite3VdbeLoadString(v, i, zName);
|
||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* figure out how many UTF-8 characters are in zName */
|
||||
zTabName = pTab->zName;
|
||||
nTabName = sqlite3Utf8CharLen(zTabName, -1);
|
||||
@@ -226,20 +240,6 @@ void sqlite3AlterRenameTable(
|
||||
, zDb, zTabName, zName, zTabName, zDb, zName);
|
||||
}
|
||||
|
||||
/* If this is a virtual table, invoke the xRename() function if
|
||||
** one is defined. The xRename() callback will modify the names
|
||||
** of any resources used by the v-table implementation (including other
|
||||
** SQLite tables) that are identified by the name of the virtual table.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pVTab ){
|
||||
int i = ++pParse->nMem;
|
||||
sqlite3VdbeLoadString(v, i, zName);
|
||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
#endif
|
||||
|
||||
renameReloadSchema(pParse, iDb);
|
||||
renameTestSchema(pParse, zDb, iDb==1);
|
||||
|
||||
@@ -803,7 +803,8 @@ static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
||||
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
||||
}else if( pExpr->op==TK_COLUMN
|
||||
&& pExpr->iColumn==p->iCol
|
||||
&& p->pTab==pExpr->y.pTab
|
||||
&& ALWAYS(pExpr->eX==EX_Tab)
|
||||
&& p->pTab==pExpr->x.pTab
|
||||
){
|
||||
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
||||
}
|
||||
@@ -1061,14 +1062,9 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
||||
db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
|
||||
);
|
||||
pParse->eTriggerOp = pNew->op;
|
||||
/* ALWAYS() because if the table of the trigger does not exist, the
|
||||
** error would have been hit before this point */
|
||||
if( ALWAYS(pParse->pTriggerTab) ){
|
||||
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
|
||||
}
|
||||
|
||||
/* Resolve symbols in WHEN clause */
|
||||
if( rc==SQLITE_OK && pNew->pWhen ){
|
||||
if( pNew->pWhen ){
|
||||
rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen);
|
||||
}
|
||||
|
||||
@@ -1346,8 +1342,11 @@ renameColumnFunc_done:
|
||||
*/
|
||||
static int renameTableExprCb(Walker *pWalker, Expr *pExpr){
|
||||
RenameCtx *p = pWalker->u.pRename;
|
||||
if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){
|
||||
renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab);
|
||||
if( pExpr->op==TK_COLUMN
|
||||
&& ALWAYS(pExpr->eX==EX_Tab)
|
||||
&& p->pTab==pExpr->x.pTab
|
||||
){
|
||||
renameTokenFind(pWalker->pParse, p, (void*)&pExpr->x.pTab);
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -1427,20 +1426,17 @@ static void renameTableFunc(
|
||||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
if( sParse.pNewTable ){
|
||||
Table *pTab = sParse.pNewTable;
|
||||
|
||||
if( pTab->pSelect ){
|
||||
if( isLegacy==0 ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
|
||||
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
||||
if( sParse.nErr ) rc = sParse.rc;
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
}
|
||||
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
||||
if( sParse.nErr ) rc = sParse.rc;
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
}else{
|
||||
/* Modify any FK definitions to point to the new table. */
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
@@ -1459,9 +1455,7 @@ static void renameTableFunc(
|
||||
** "CREATE [VIRTUAL] TABLE" bit. */
|
||||
if( sqlite3_stricmp(zOld, pTab->zName)==0 ){
|
||||
sCtx.pTab = pTab;
|
||||
if( isLegacy==0 ){
|
||||
sqlite3WalkExprList(&sWalker, pTab->pCheck);
|
||||
}
|
||||
sqlite3WalkExprList(&sWalker, pTab->pCheck);
|
||||
renameTokenFind(&sParse, &sCtx, pTab->zName);
|
||||
}
|
||||
}
|
||||
@@ -1469,9 +1463,7 @@ static void renameTableFunc(
|
||||
|
||||
else if( sParse.pNewIndex ){
|
||||
renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName);
|
||||
if( isLegacy==0 ){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
||||
}
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
@@ -1484,14 +1476,12 @@ static void renameTableFunc(
|
||||
renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
|
||||
}
|
||||
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
}
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
renameWalkTrigger(&sWalker, pTrigger);
|
||||
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
||||
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
||||
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1549,7 +1539,6 @@ static void renameTableTest(
|
||||
char const *zDb = (const char*)sqlite3_value_text(argv[0]);
|
||||
char const *zInput = (const char*)sqlite3_value_text(argv[1]);
|
||||
int bTemp = sqlite3_value_int(argv[4]);
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
sqlite3_xauth xAuth = db->xAuth;
|
||||
@@ -1562,7 +1551,7 @@ static void renameTableTest(
|
||||
Parse sParse;
|
||||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
if( sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
@@ -1571,9 +1560,7 @@ static void renameTableTest(
|
||||
}
|
||||
|
||||
else if( sParse.pNewTrigger ){
|
||||
if( isLegacy==0 ){
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
}
|
||||
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
|
||||
int i2 = sqlite3FindDbName(db, zDb);
|
||||
|
||||
+13
-7
@@ -564,13 +564,19 @@ int sqlite3FixExpr(
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
||||
}else{
|
||||
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
||||
}
|
||||
if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
||||
return 1;
|
||||
switch( pExpr->eX ){
|
||||
case EX_Select: {
|
||||
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
||||
break;
|
||||
}
|
||||
case EX_Right: {
|
||||
if( sqlite3FixExpr(pFix, pExpr->x.pRight) ) return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
|
||||
@@ -151,7 +151,6 @@ void sqlite3AuthRead(
|
||||
int iCol; /* Index of column in table */
|
||||
|
||||
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
|
||||
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
||||
if( db->xAuth==0 ) return;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
||||
if( iDb<0 ){
|
||||
@@ -208,7 +207,6 @@ int sqlite3AuthCheck(
|
||||
/* Don't do any authorization checks if the database is initialising
|
||||
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
||||
*/
|
||||
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
||||
if( db->init.busy || IN_SPECIAL_PARSE ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+4
-6
@@ -633,12 +633,6 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
||||
|
||||
/* Delete the Table structure itself.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
if( pTable->pColHash ){
|
||||
sqlite3HashClear(pTable->pColHash);
|
||||
sqlite3_free(pTable->pColHash);
|
||||
}
|
||||
#endif
|
||||
sqlite3DeleteColumnNames(db, pTable);
|
||||
sqlite3DbFree(db, pTable->zName);
|
||||
sqlite3DbFree(db, pTable->zColAff);
|
||||
@@ -1777,6 +1771,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
}
|
||||
}
|
||||
|
||||
/* The remaining transformations only apply to b-tree tables, not to
|
||||
** virtual tables */
|
||||
if( IN_DECLARE_VTAB ) return;
|
||||
|
||||
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
||||
** into BTREE_BLOBKEY.
|
||||
*/
|
||||
|
||||
+2
-17
@@ -295,21 +295,6 @@ static FuncDef *functionSearch(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
FuncDef *sqlite3FunctionSearchN(
|
||||
int h, /* Hash of the name */
|
||||
const char *zFunc, /* Name of function */
|
||||
int nFunc /* Length of the name */
|
||||
){
|
||||
FuncDef *p;
|
||||
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
|
||||
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 ){
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/*
|
||||
** Insert a new FuncDef into a FuncDefHash hash table.
|
||||
@@ -323,7 +308,7 @@ void sqlite3InsertBuiltinFuncs(
|
||||
FuncDef *pOther;
|
||||
const char *zName = aDef[i].zName;
|
||||
int nName = sqlite3Strlen30(zName);
|
||||
int h = SQLITE_FUNC_HASH(zName[0], nName);
|
||||
int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ;
|
||||
assert( zName[0]>='a' && zName[0]<='z' );
|
||||
pOther = functionSearch(h, zName);
|
||||
if( pOther ){
|
||||
@@ -402,7 +387,7 @@ FuncDef *sqlite3FindFunction(
|
||||
*/
|
||||
if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
|
||||
bestScore = 0;
|
||||
h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName);
|
||||
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
|
||||
p = functionSearch(h, zName);
|
||||
while( p ){
|
||||
int score = matchQuality(p, nArg, enc);
|
||||
|
||||
@@ -235,9 +235,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_FTS5
|
||||
"ENABLE_FTS5",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_GEOPOLY
|
||||
"ENABLE_GEOPOLY",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_HIDDEN_COLUMNS
|
||||
"ENABLE_HIDDEN_COLUMNS",
|
||||
#endif
|
||||
@@ -268,9 +265,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_MULTIPLEX
|
||||
"ENABLE_MULTIPLEX",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_NORMALIZE
|
||||
"ENABLE_NORMALIZE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_NULL_TRIM
|
||||
"ENABLE_NULL_TRIM",
|
||||
#endif
|
||||
|
||||
+6
-23
@@ -324,33 +324,22 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
|
||||
|
||||
p->flags = aHdr[0];
|
||||
if( p->flags==0x0A || p->flags==0x0D ){
|
||||
isLeaf = 1;
|
||||
nHdr = 8;
|
||||
}else if( p->flags==0x05 || p->flags==0x02 ){
|
||||
isLeaf = 0;
|
||||
nHdr = 12;
|
||||
}else{
|
||||
goto statPageIsCorrupt;
|
||||
}
|
||||
if( p->iPgno==1 ) nHdr += 100;
|
||||
p->nCell = get2byte(&aHdr[3]);
|
||||
p->nMxPayload = 0;
|
||||
szPage = sqlite3BtreeGetPageSize(pBt);
|
||||
|
||||
isLeaf = (p->flags==0x0A || p->flags==0x0D);
|
||||
nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
|
||||
|
||||
nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
|
||||
nUnused += (int)aHdr[7];
|
||||
iOff = get2byte(&aHdr[1]);
|
||||
while( iOff ){
|
||||
int iNext;
|
||||
if( iOff>=szPage ) goto statPageIsCorrupt;
|
||||
nUnused += get2byte(&aData[iOff+2]);
|
||||
iNext = get2byte(&aData[iOff]);
|
||||
if( iNext<iOff+4 && iNext>0 ) goto statPageIsCorrupt;
|
||||
iOff = iNext;
|
||||
iOff = get2byte(&aData[iOff]);
|
||||
}
|
||||
p->nUnused = nUnused;
|
||||
p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
|
||||
szPage = sqlite3BtreeGetPageSize(pBt);
|
||||
|
||||
if( p->nCell ){
|
||||
int i; /* Used to iterate through cells */
|
||||
@@ -367,7 +356,6 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
StatCell *pCell = &p->aCell[i];
|
||||
|
||||
iOff = get2byte(&aData[nHdr+i*2]);
|
||||
if( iOff<nHdr || iOff>=szPage ) goto statPageIsCorrupt;
|
||||
if( !isLeaf ){
|
||||
pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
|
||||
iOff += 4;
|
||||
@@ -384,8 +372,8 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
}
|
||||
if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
|
||||
getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
|
||||
if( nLocal<0 ) goto statPageIsCorrupt;
|
||||
pCell->nLocal = nLocal;
|
||||
assert( nLocal>=0 );
|
||||
assert( nPayload>=(u32)nLocal );
|
||||
assert( nLocal<=(nUsable-35) );
|
||||
if( nPayload>(u32)nLocal ){
|
||||
@@ -414,11 +402,6 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
|
||||
statPageIsCorrupt:
|
||||
p->flags = 0;
|
||||
p->nCell = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-3
@@ -185,9 +185,7 @@ Expr *sqlite3LimitWhere(
|
||||
pEList = sqlite3ExprListAppend(pParse, pEList, p);
|
||||
}
|
||||
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
|
||||
if( pLhs ){
|
||||
pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
|
||||
}
|
||||
sqlite3PExprAddExprList(pParse, pLhs, pEList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+279
-157
@@ -48,7 +48,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
if( pExpr->flags & EP_Generic ) return 0;
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
assert( pExpr->eX==EX_Select );
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
}
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
@@ -58,11 +58,12 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
return sqlite3AffinityType(pExpr->u.zToken, 0);
|
||||
}
|
||||
#endif
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){
|
||||
return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN)
|
||||
&& ALWAYS(pExpr->eX==EX_Tab) && pExpr->x.pTab ){
|
||||
return sqlite3TableColumnAffinity(pExpr->x.pTab, pExpr->iColumn);
|
||||
}
|
||||
if( op==TK_SELECT_COLUMN ){
|
||||
assert( pExpr->pLeft->flags&EP_xIsSelect );
|
||||
assert( pExpr->pLeft->eX==EX_Select );
|
||||
return sqlite3ExprAffinity(
|
||||
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
||||
);
|
||||
@@ -108,7 +109,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
|
||||
if( ExprHasProperty(pExpr, EP_Unlikely) ){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List );
|
||||
assert( pExpr->x.pList->nExpr>0 );
|
||||
assert( pExpr->op==TK_FUNCTION );
|
||||
pExpr = pExpr->x.pList->a[0].pExpr;
|
||||
@@ -143,13 +144,14 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|
||||
|| op==TK_REGISTER || op==TK_TRIGGER)
|
||||
&& p->y.pTab!=0
|
||||
&& p->eX==EX_Tab
|
||||
&& p->x.pTab!=0
|
||||
){
|
||||
/* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
|
||||
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
int j = p->iColumn;
|
||||
if( j>=0 ){
|
||||
const char *zColl = p->y.pTab->aCol[j].zColl;
|
||||
const char *zColl = p->x.pTab->aCol[j].zColl;
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
}
|
||||
break;
|
||||
@@ -166,13 +168,11 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
|
||||
p = p->pLeft;
|
||||
}else{
|
||||
Expr *pNext = p->pRight;
|
||||
/* The Expr.x union is never used at the same time as Expr.pRight */
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
Expr *pNext = 0;
|
||||
/* p->flags holds EP_Collate and p->pLeft->flags does not. And
|
||||
** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
|
||||
** least one EP_Collate. Thus the following two ALWAYS. */
|
||||
if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
|
||||
if( p->eX==EX_List ){
|
||||
int i;
|
||||
for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
|
||||
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
|
||||
@@ -180,6 +180,8 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( p->eX==EX_Right ){
|
||||
pNext = p->x.pRight;
|
||||
}
|
||||
p = pNext;
|
||||
}
|
||||
@@ -258,9 +260,9 @@ static char comparisonAffinity(Expr *pExpr){
|
||||
pExpr->op==TK_NE || pExpr->op==TK_IS || pExpr->op==TK_ISNOT );
|
||||
assert( pExpr->pLeft );
|
||||
aff = sqlite3ExprAffinity(pExpr->pLeft);
|
||||
if( pExpr->pRight ){
|
||||
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
|
||||
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( pExpr->eX==EX_Right ){
|
||||
aff = sqlite3CompareAffinity(pExpr->x.pRight, aff);
|
||||
}else if( pExpr->eX==EX_Select ){
|
||||
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
|
||||
}else if( aff==0 ){
|
||||
aff = SQLITE_AFF_BLOB;
|
||||
@@ -307,8 +309,12 @@ static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
||||
**
|
||||
** Argument pRight (but not pLeft) may be a null pointer. In this case,
|
||||
** it is not considered.
|
||||
**
|
||||
** The second form (sqlite3BinaryExprCollSeq()) uses the Expr.pLeft
|
||||
** and Expr.x.pRight pointer from the second argument instead of separate
|
||||
** pointers.
|
||||
*/
|
||||
CollSeq *sqlite3BinaryCompareCollSeq(
|
||||
CollSeq *sqlite3ComparisonCollSeq(
|
||||
Parse *pParse,
|
||||
Expr *pLeft,
|
||||
Expr *pRight
|
||||
@@ -327,6 +333,13 @@ CollSeq *sqlite3BinaryCompareCollSeq(
|
||||
}
|
||||
return pColl;
|
||||
}
|
||||
CollSeq *sqlite3ComparisonExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
if( pExpr->eX==EX_Right ){
|
||||
return sqlite3ComparisonCollSeq(pParse, pExpr->pLeft, pExpr->x.pRight);
|
||||
}else{
|
||||
return sqlite3ComparisonCollSeq(pParse, pExpr->pLeft, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for a comparison operator.
|
||||
@@ -344,7 +357,7 @@ static int codeCompare(
|
||||
int addr;
|
||||
CollSeq *p4;
|
||||
|
||||
p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
|
||||
p4 = sqlite3ComparisonCollSeq(pParse, pLeft, pRight);
|
||||
p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
|
||||
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
|
||||
(void*)p4, P4_COLLSEQ);
|
||||
@@ -439,7 +452,7 @@ Expr *sqlite3ExprForVectorField(
|
||||
){
|
||||
Expr *pRet;
|
||||
if( pVector->op==TK_SELECT ){
|
||||
assert( pVector->flags & EP_xIsSelect );
|
||||
assert( pVector->eX==EX_Select );
|
||||
/* The TK_SELECT_COLUMN Expr node:
|
||||
**
|
||||
** pLeft: pVector containing TK_SELECT. Not deleted.
|
||||
@@ -547,7 +560,7 @@ static void codeVectorCompare(
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
Expr *pRight = pExpr->x.pRight;
|
||||
int nLeft = sqlite3ExprVectorSize(pLeft);
|
||||
int i;
|
||||
int regLeft = 0;
|
||||
@@ -681,12 +694,20 @@ static void heightOfSelect(Select *pSelect, int *pnHeight){
|
||||
static void exprSetHeight(Expr *p){
|
||||
int nHeight = 0;
|
||||
heightOfExpr(p->pLeft, &nHeight);
|
||||
heightOfExpr(p->pRight, &nHeight);
|
||||
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
heightOfSelect(p->x.pSelect, &nHeight);
|
||||
}else if( p->x.pList ){
|
||||
heightOfExprList(p->x.pList, &nHeight);
|
||||
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
|
||||
switch( p->eX ){
|
||||
case EX_Select: {
|
||||
heightOfSelect(p->x.pSelect, &nHeight);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
heightOfExprList(p->x.pList, &nHeight);
|
||||
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
|
||||
break;
|
||||
}
|
||||
case EX_Right: {
|
||||
heightOfExpr(p->x.pRight, &nHeight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->nHeight = nHeight + 1;
|
||||
}
|
||||
@@ -700,7 +721,7 @@ static void exprSetHeight(Expr *p){
|
||||
** Expr.flags.
|
||||
*/
|
||||
void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
|
||||
if( pParse->nErr ) return;
|
||||
if( p==0 || pParse->nErr ) return;
|
||||
exprSetHeight(p);
|
||||
sqlite3ExprCheckHeight(pParse, p->nHeight);
|
||||
}
|
||||
@@ -720,7 +741,7 @@ int sqlite3SelectExprHeight(Select *p){
|
||||
** Expr.flags.
|
||||
*/
|
||||
void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
|
||||
if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
|
||||
if( p && p->eX==EX_List ){
|
||||
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
|
||||
}
|
||||
}
|
||||
@@ -825,7 +846,9 @@ void sqlite3ExprAttachSubtrees(
|
||||
sqlite3ExprDelete(db, pRight);
|
||||
}else{
|
||||
if( pRight ){
|
||||
pRoot->pRight = pRight;
|
||||
assert( pRoot->eX==EX_None );
|
||||
pRoot->x.pRight = pRight;
|
||||
pRoot->eX = EX_Right;
|
||||
pRoot->flags |= EP_Propagate & pRight->flags;
|
||||
}
|
||||
if( pLeft ){
|
||||
@@ -873,9 +896,11 @@ Expr *sqlite3PExpr(
|
||||
** do a memory allocation failure) then delete the pSelect object.
|
||||
*/
|
||||
void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
|
||||
if( pExpr ){
|
||||
if( pExpr && pSelect ){
|
||||
assert( pExpr->eX==EX_None );
|
||||
pExpr->eX = EX_Select;
|
||||
pExpr->x.pSelect = pSelect;
|
||||
ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
|
||||
ExprSetProperty(pExpr, EP_Subquery);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pExpr);
|
||||
}else{
|
||||
assert( pParse->db->mallocFailed );
|
||||
@@ -883,6 +908,22 @@ void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add ExprList to the Expr.x.pList field. Or, if pExpr is NULL (due
|
||||
** do a memory allocation failure) then delete the pSelect object.
|
||||
*/
|
||||
void sqlite3PExprAddExprList(Parse *pParse, Expr *pExpr, ExprList *pList){
|
||||
if( pExpr && pList ){
|
||||
assert( pExpr->eX==EX_None );
|
||||
pExpr->eX = EX_List;
|
||||
pExpr->x.pList = pList;
|
||||
/* sqlite3ExprSetHeightAndFlags(pParse, pExpr); // done by caller */
|
||||
}else{
|
||||
assert( pParse->db->mallocFailed );
|
||||
sqlite3ExprListDelete(pParse->db, pList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** If the expression is always either TRUE or FALSE (respectively),
|
||||
@@ -956,9 +997,12 @@ Expr *sqlite3ExprFunction(
|
||||
if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
|
||||
}
|
||||
pNew->x.pList = pList;
|
||||
assert( pNew->eX==EX_None );
|
||||
if( pList ){
|
||||
pNew->eX = EX_List;
|
||||
pNew->x.pList = pList;
|
||||
}
|
||||
ExprSetProperty(pNew, EP_HasFunc);
|
||||
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
||||
sqlite3ExprSetHeightAndFlags(pParse, pNew);
|
||||
if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
|
||||
return pNew;
|
||||
@@ -1052,31 +1096,39 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
assert( p!=0 );
|
||||
/* Sanity check: Assert that the IntValue is non-negative if it exists */
|
||||
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
|
||||
|
||||
assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed );
|
||||
assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced)
|
||||
|| p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) );
|
||||
assert( p->eX!=EX_Select || p->x.pSelect!=0 );
|
||||
assert( p->eX!=EX_List || p->x.pList!=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
assert( p->pLeft==0 );
|
||||
assert( p->pRight==0 );
|
||||
assert( p->x.pSelect==0 );
|
||||
assert( p->eX==EX_None || p->eX==EX_Tab );
|
||||
}
|
||||
if( !ExprHasProperty(p, EP_TokenOnly) ){
|
||||
assert( p->op!=TK_FUNCTION || p->pLeft==0 );
|
||||
}
|
||||
if( !ExprHasProperty(p, (EP_TokenOnly|EP_Reduced)) ){
|
||||
assert( p->pWin==0 || p->pLeft==0 );
|
||||
assert( p->pWin==0 || p->op==TK_FUNCTION );
|
||||
}
|
||||
#endif
|
||||
if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
|
||||
/* The Expr.x union is never used at the same time as Expr.pRight */
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
|
||||
if( p->pRight ){
|
||||
sqlite3ExprDeleteNN(db, p->pRight);
|
||||
}else if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, p->x.pList);
|
||||
switch( p->eX ){
|
||||
case EX_Select: {
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
sqlite3ExprListDelete(db, p->x.pList);
|
||||
break;
|
||||
}
|
||||
case EX_Right: {
|
||||
sqlite3ExprDelete(db, p->x.pRight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
assert( p->op==TK_FUNCTION );
|
||||
sqlite3WindowDelete(db, p->y.pWin);
|
||||
if( !ExprHasProperty(p, EP_Reduced) ){
|
||||
sqlite3WindowDelete(db, p->pWin);
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
@@ -1088,6 +1140,29 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p ) sqlite3ExprDeleteNN(db, p);
|
||||
}
|
||||
|
||||
void sqlite3ExprClearXUnion(sqlite3 *db, Expr *p){
|
||||
switch( p->eX ){
|
||||
case EX_Select: {
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
sqlite3ExprListDelete(db, p->x.pList);
|
||||
break;
|
||||
}
|
||||
case EX_Right: {
|
||||
sqlite3ExprDelete(db, p->x.pRight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->eX = EX_None;
|
||||
}
|
||||
void sqlite3ExprAddTab(sqlite3 *db, Expr *pExpr, Table *pTab){
|
||||
sqlite3ExprClearXUnion(db, pExpr);
|
||||
pExpr->eX = EX_Tab;
|
||||
pExpr->x.pTab = pTab;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes allocated for the expression structure
|
||||
** passed as the first argument. This is always one of EXPR_FULLSIZE,
|
||||
@@ -1140,7 +1215,7 @@ static int dupedExprStructSize(Expr *p, int flags){
|
||||
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
|
||||
if( 0==flags || p->op==TK_SELECT_COLUMN
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
|| ExprHasProperty(p, EP_WinFunc)
|
||||
|| p->pWin
|
||||
#endif
|
||||
){
|
||||
nSize = EXPR_FULLSIZE;
|
||||
@@ -1149,10 +1224,9 @@ static int dupedExprStructSize(Expr *p, int flags){
|
||||
assert( !ExprHasProperty(p, EP_FromJoin) );
|
||||
assert( !ExprHasProperty(p, EP_MemToken) );
|
||||
assert( !ExprHasProperty(p, EP_NoReduce) );
|
||||
if( p->pLeft || p->x.pList ){
|
||||
if( p->pLeft || p->eX!=EX_None ){
|
||||
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
|
||||
}else{
|
||||
assert( p->pRight==0 );
|
||||
nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
|
||||
}
|
||||
}
|
||||
@@ -1190,7 +1264,8 @@ static int dupedExprSize(Expr *p, int flags){
|
||||
if( p ){
|
||||
nByte = dupedExprNodeSize(p, flags);
|
||||
if( flags&EXPRDUP_REDUCE ){
|
||||
nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
|
||||
nByte += dupedExprSize(p->pLeft, flags);
|
||||
if( p->eX==EX_Right ) nByte += dupedExprSize(p->x.pRight, flags);
|
||||
}
|
||||
}
|
||||
return nByte;
|
||||
@@ -1200,7 +1275,7 @@ static int dupedExprSize(Expr *p, int flags){
|
||||
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
|
||||
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
|
||||
** to store the copy of expression p, the copies of p->u.zToken
|
||||
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
|
||||
** (if applicable), and the copies of the p->pLeft and p->x.pRight expressions,
|
||||
** if any. Before returning, *pzBuffer is set to the first byte past the
|
||||
** portion of the buffer copied into by this function.
|
||||
*/
|
||||
@@ -1253,6 +1328,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
||||
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
|
||||
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
|
||||
pNew->flags |= staticFlag;
|
||||
assert( pNew->eX==p->eX );
|
||||
assert( pNew->eV==p->eV );
|
||||
|
||||
/* Copy the p->u.zToken string, if any. */
|
||||
if( nToken ){
|
||||
@@ -1262,41 +1339,55 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
||||
|
||||
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
|
||||
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
|
||||
if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
|
||||
}else{
|
||||
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
|
||||
switch( p->eX ){
|
||||
case EX_Select: {
|
||||
assert( pNew->eX==EX_Select );
|
||||
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
|
||||
if( pNew->x.pSelect==0 ) pNew->eX = EX_None;
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
assert( pNew->eX==EX_List );
|
||||
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
|
||||
if( pNew->x.pList==0 ) pNew->eX = EX_None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in pNew->pLeft and pNew->pRight. */
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
|
||||
/* Fill in pNew->pLeft and pNew->x.pRight. */
|
||||
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
|
||||
zAlloc += dupedExprNodeSize(p, dupFlags);
|
||||
if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
|
||||
pNew->pLeft = p->pLeft ?
|
||||
exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
pNew->pRight = p->pRight ?
|
||||
exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
|
||||
if( p->eX==EX_Right ){
|
||||
pNew->x.pRight = exprDup(db, p->x.pRight, EXPRDUP_REDUCE, &zAlloc);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin);
|
||||
assert( ExprHasProperty(pNew, EP_WinFunc) );
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
if( pzBuffer ){
|
||||
*pzBuffer = zAlloc;
|
||||
}
|
||||
}else{
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){
|
||||
pNew->pWin = 0;
|
||||
}else{
|
||||
pNew->pWin = sqlite3WindowDup(db, pNew, p->pWin);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
|
||||
if( pNew->op==TK_SELECT_COLUMN ){
|
||||
pNew->pLeft = p->pLeft;
|
||||
assert( p->iColumn==0 || p->pRight==0 );
|
||||
assert( p->pRight==0 || p->pRight==p->pLeft );
|
||||
assert( p->iColumn==0 || p->eX!=EX_Right );
|
||||
/* OLD: assert( p->pRight==0 || p->x.pRight==p->pLeft ); */
|
||||
}else{
|
||||
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
||||
}
|
||||
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
|
||||
if( p->eX==EX_Right ){
|
||||
pNew->x.pRight = sqlite3ExprDup(db, p->x.pRight, 0);
|
||||
if( pNew->x.pRight==0 ) pNew->eX = EX_None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1373,8 +1464,8 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
){
|
||||
assert( pNewExpr->iColumn==0 || i>0 );
|
||||
if( pNewExpr->iColumn==0 ){
|
||||
assert( pOldExpr->pLeft==pOldExpr->pRight );
|
||||
pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
|
||||
assert( pOldExpr->pLeft==pOldExpr->x.pRight );
|
||||
pPriorSelectCol = pNewExpr->pLeft = pNewExpr->x.pRight;
|
||||
}else{
|
||||
assert( i>0 );
|
||||
assert( pItem[-1].pExpr!=0 );
|
||||
@@ -1620,7 +1711,9 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
|
||||
/* Store the SELECT statement in pRight so it will be deleted when
|
||||
** sqlite3ExprListDelete() is called */
|
||||
pFirst->pRight = pExpr;
|
||||
assert( pFirst->eX==EX_None );
|
||||
pFirst->x.pRight = pExpr;
|
||||
pFirst->eX = EX_Right;
|
||||
pExpr = 0;
|
||||
|
||||
/* Remember the size of the LHS in iTable so that we can check that
|
||||
@@ -1958,7 +2051,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
|
||||
/* Check if pExpr is a sub-select. If so, consider it variable. */
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( pExpr->eX==EX_Select ){
|
||||
pWalker->eCode = 0;
|
||||
return WRC_Abort;
|
||||
}
|
||||
@@ -2092,9 +2185,10 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
case TK_BLOB:
|
||||
return 0;
|
||||
case TK_COLUMN:
|
||||
assert( p->eX==EX_Tab );
|
||||
return ExprHasProperty(p, EP_CanBeNull) ||
|
||||
p->y.pTab==0 || /* Reference to column of index on expression */
|
||||
(p->iColumn>=0 && p->y.pTab->aCol[p->iColumn].notNull==0);
|
||||
p->x.pTab==0 || /* Reference to column of index on expression */
|
||||
(p->iColumn>=0 && p->x.pTab->aCol[p->iColumn].notNull==0);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@@ -2149,14 +2243,6 @@ int sqlite3IsRowid(const char *z){
|
||||
if( sqlite3StrICmp(z, "OID")==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
int sqlite3IsRowidN(const char *z, int n){
|
||||
if( sqlite3StrNICmp(z, "_ROWID_", n)==0 ) return 1;
|
||||
if( sqlite3StrNICmp(z, "ROWID", n)==0 ) return 1;
|
||||
if( sqlite3StrNICmp(z, "OID", n)==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** pX is the RHS of an IN operator. If pX is a SELECT statement
|
||||
@@ -2172,8 +2258,10 @@ static Select *isCandidateForInOpt(Expr *pX){
|
||||
ExprList *pEList;
|
||||
Table *pTab;
|
||||
int i;
|
||||
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
||||
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
||||
if( pX->eX!=EX_Select ) return 0; /* Not a subquery */
|
||||
if( ExprHasProperty(pX, EP_VarSelect) ){
|
||||
return 0; /* Correlated subq */
|
||||
}
|
||||
p = pX->x.pSelect;
|
||||
if( p->pPrior ) return 0; /* Not a compound SELECT */
|
||||
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
|
||||
@@ -2231,7 +2319,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
|
||||
static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
Expr *pLHS;
|
||||
int res;
|
||||
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
|
||||
assert( pIn->eX!=EX_Select );
|
||||
pLHS = pIn->pLeft;
|
||||
pIn->pLeft = 0;
|
||||
res = sqlite3ExprIsConstant(pIn);
|
||||
@@ -2342,7 +2430,7 @@ int sqlite3FindInIndex(
|
||||
** or not NULL is actually possible (it may not be, for example, due
|
||||
** to NOT NULL constraints in the schema). If no NULL values are possible,
|
||||
** set prRhsHasNull to 0 before continuing. */
|
||||
if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
|
||||
if( prRhsHasNull && pX->eX==EX_Select ){
|
||||
int i;
|
||||
ExprList *pEList = pX->x.pSelect->pEList;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
@@ -2438,7 +2526,7 @@ int sqlite3FindInIndex(
|
||||
for(i=0; i<nExpr; i++){
|
||||
Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
|
||||
Expr *pRhs = pEList->a[i].pExpr;
|
||||
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
||||
CollSeq *pReq = sqlite3ComparisonCollSeq(pParse, pLhs, pRhs);
|
||||
int j;
|
||||
|
||||
assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
|
||||
@@ -2495,8 +2583,8 @@ int sqlite3FindInIndex(
|
||||
** the IN operator so return IN_INDEX_NOOP.
|
||||
*/
|
||||
if( eType==0
|
||||
&& (inFlags & IN_INDEX_NOOP_OK)
|
||||
&& !ExprHasProperty(pX, EP_xIsSelect)
|
||||
&& (inFlags & IN_INDEX_NOOP_OK)!=0
|
||||
&& pX->eX==EX_List
|
||||
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
|
||||
){
|
||||
eType = IN_INDEX_NOOP;
|
||||
@@ -2511,7 +2599,7 @@ int sqlite3FindInIndex(
|
||||
eType = IN_INDEX_EPH;
|
||||
if( inFlags & IN_INDEX_LOOP ){
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
if( pX->pLeft->iColumn<0 && pX->eX==EX_List ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
}
|
||||
}else if( prRhsHasNull ){
|
||||
@@ -2544,7 +2632,7 @@ int sqlite3FindInIndex(
|
||||
static char *exprINAffinity(Parse *pParse, Expr *pExpr){
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
int nVal = sqlite3ExprVectorSize(pLeft);
|
||||
Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
|
||||
Select *pSelect = (pExpr->eX==EX_Select) ? pExpr->x.pSelect : 0;
|
||||
char *zRet;
|
||||
|
||||
assert( pExpr->op==TK_IN );
|
||||
@@ -2592,7 +2680,7 @@ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
|
||||
*/
|
||||
void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( pExpr->flags & EP_xIsSelect ){
|
||||
if( pExpr->eX==EX_Select ){
|
||||
sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
|
||||
}else
|
||||
#endif
|
||||
@@ -2684,7 +2772,8 @@ int sqlite3CodeSubselect(
|
||||
pExpr->iTable, (isRowid?0:nVal));
|
||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
assert( pExpr->eX==EX_Select || pExpr->eX==EX_List );
|
||||
if( pExpr->eX==EX_Select ){
|
||||
/* Case 1: expr IN (SELECT ...)
|
||||
**
|
||||
** Generate code to write the results of the select into the temporary
|
||||
@@ -2719,7 +2808,7 @@ int sqlite3CodeSubselect(
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
||||
for(i=0; i<nVal; i++){
|
||||
Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
|
||||
pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
|
||||
pKeyInfo->aColl[i] = sqlite3ComparisonCollSeq(
|
||||
pParse, p, pEList->a[i].pExpr
|
||||
);
|
||||
}
|
||||
@@ -2813,7 +2902,7 @@ int sqlite3CodeSubselect(
|
||||
testcase( pExpr->op==TK_EXISTS );
|
||||
testcase( pExpr->op==TK_SELECT );
|
||||
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
|
||||
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_Select );
|
||||
|
||||
pSel = pExpr->x.pSelect;
|
||||
ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY",
|
||||
@@ -2870,7 +2959,7 @@ int sqlite3CodeSubselect(
|
||||
*/
|
||||
int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
|
||||
int nVector = sqlite3ExprVectorSize(pIn->pLeft);
|
||||
if( (pIn->flags & EP_xIsSelect) ){
|
||||
if( pIn->eX==EX_Select ){
|
||||
if( nVector!=pIn->x.pSelect->pEList->nExpr ){
|
||||
sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
|
||||
return 1;
|
||||
@@ -3000,7 +3089,7 @@ static void sqlite3ExprCodeIN(
|
||||
int r2, regToFree;
|
||||
int regCkNull = 0;
|
||||
int ii;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List );
|
||||
if( destIfNull!=destIfFalse ){
|
||||
regCkNull = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
|
||||
@@ -3389,8 +3478,10 @@ expr_code_doover:
|
||||
** datatype by applying the Affinity of the table column to the
|
||||
** constant.
|
||||
*/
|
||||
int aff;
|
||||
int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
|
||||
int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
aff = sqlite3TableColumnAffinity(pExpr->x.pTab, pExpr->iColumn);
|
||||
if( aff!=SQLITE_AFF_BLOB ){
|
||||
static const char zAff[] = "B\000C\000D\000E";
|
||||
assert( SQLITE_AFF_BLOB=='A' );
|
||||
@@ -3414,7 +3505,8 @@ expr_code_doover:
|
||||
iTab = pParse->iSelfTab - 1;
|
||||
}
|
||||
}
|
||||
return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
return sqlite3ExprCodeGetColumn(pParse, pExpr->x.pTab,
|
||||
pExpr->iColumn, iTab, target,
|
||||
pExpr->op2);
|
||||
}
|
||||
@@ -3503,8 +3595,9 @@ expr_code_doover:
|
||||
codeVectorCompare(pParse, pExpr, target, op, p5);
|
||||
}else{
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pLeft, pExpr->pRight, op,
|
||||
assert( pExpr->eX==EX_Right );
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2);
|
||||
codeCompare(pParse, pLeft, pExpr->x.pRight, op,
|
||||
r1, r2, inReg, SQLITE_STOREP2 | p5);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
@@ -3541,7 +3634,8 @@ expr_code_doover:
|
||||
assert( TK_RSHIFT==OP_ShiftRight ); testcase( op==TK_RSHIFT );
|
||||
assert( TK_CONCAT==OP_Concat ); testcase( op==TK_CONCAT );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2);
|
||||
sqlite3VdbeAddOp3(v, op, r2, r1, target);
|
||||
testcase( regFree1==0 );
|
||||
testcase( regFree2==0 );
|
||||
@@ -3560,6 +3654,7 @@ expr_code_doover:
|
||||
return target;
|
||||
#endif
|
||||
}else{
|
||||
memset(&tempX, 0, sizeof(tempX));
|
||||
tempX.op = TK_INTEGER;
|
||||
tempX.flags = EP_IntValue|EP_TokenOnly;
|
||||
tempX.u.iValue = 0;
|
||||
@@ -3584,7 +3679,8 @@ expr_code_doover:
|
||||
int bNormal; /* IS TRUE or IS FALSE */
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
testcase( regFree1==0 );
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->x.pRight);
|
||||
bNormal = pExpr->op2==TK_IS;
|
||||
testcase( isTrue && bNormal);
|
||||
testcase( !isTrue && bNormal);
|
||||
@@ -3628,8 +3724,8 @@ expr_code_doover:
|
||||
CollSeq *pColl = 0; /* A collating sequence */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
return pExpr->y.pWin->regResult;
|
||||
if( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) && pExpr->pWin ){
|
||||
return pExpr->pWin->regResult;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3638,7 +3734,7 @@ expr_code_doover:
|
||||
** out of the inner loop, even if that means an extra OP_Copy. */
|
||||
return sqlite3ExprCodeAtInit(pParse, pExpr, -1);
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List || pExpr->eX==EX_None );
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
@@ -3872,7 +3968,9 @@ expr_code_doover:
|
||||
** p1==1 -> old.a p1==4 -> new.a
|
||||
** p1==2 -> old.b p1==5 -> new.b
|
||||
*/
|
||||
Table *pTab = pExpr->y.pTab;
|
||||
Table *pTab;
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
pTab = pExpr->x.pTab;
|
||||
int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;
|
||||
|
||||
assert( pExpr->iTable==0 || pExpr->iTable==1 );
|
||||
@@ -3881,9 +3979,10 @@ expr_code_doover:
|
||||
assert( p1>=0 && p1<(pTab->nCol*2+2) );
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Param, p1, target);
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
VdbeComment((v, "r[%d]=%s.%s", target,
|
||||
(pExpr->iTable ? "new" : "old"),
|
||||
(pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName)
|
||||
(pExpr->iColumn<0 ? "rowid" : pExpr->x.pTab->aCol[pExpr->iColumn].zName)
|
||||
));
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
@@ -3947,8 +4046,8 @@ expr_code_doover:
|
||||
Expr *pX; /* The X expression */
|
||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||
assert(pExpr->x.pList->nExpr > 0);
|
||||
assert( pExpr->eX==EX_List );
|
||||
assert( pExpr->x.pList->nExpr > 0);
|
||||
pEList = pExpr->x.pList;
|
||||
aListelem = pEList->a;
|
||||
nExpr = pEList->nExpr;
|
||||
@@ -3971,7 +4070,8 @@ expr_code_doover:
|
||||
for(i=0; i<nExpr-1; i=i+2){
|
||||
if( pX ){
|
||||
assert( pTest!=0 );
|
||||
opCompare.pRight = aListelem[i].pExpr;
|
||||
opCompare.x.pRight = aListelem[i].pExpr;
|
||||
opCompare.eX = EX_Right;
|
||||
}else{
|
||||
pTest = aListelem[i].pExpr;
|
||||
}
|
||||
@@ -4280,17 +4380,20 @@ static void exprCodeBetween(
|
||||
memset(&compRight, 0, sizeof(Expr));
|
||||
memset(&exprAnd, 0, sizeof(Expr));
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List );
|
||||
exprX = *pExpr->pLeft;
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
exprAnd.x.pRight = &compRight;
|
||||
exprAnd.eX = EX_Right;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = &exprX;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compLeft.x.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compLeft.eX = EX_Right;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = &exprX;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
compRight.x.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
compRight.eX = EX_Right;
|
||||
exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
@@ -4347,14 +4450,16 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
int d2 = sqlite3VdbeMakeLabel(v);
|
||||
testcase( jumpIfNull==0 );
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3ExprIfTrue(pParse, pExpr->x.pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
testcase( jumpIfNull==0 );
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3ExprIfTrue(pParse, pExpr->x.pRight, dest, jumpIfNull);
|
||||
break;
|
||||
}
|
||||
case TK_NOT: {
|
||||
@@ -4367,7 +4472,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
int isTrue; /* IS TRUE or IS NOT TRUE */
|
||||
testcase( jumpIfNull==0 );
|
||||
isNot = pExpr->op2==TK_ISNOT;
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->x.pRight);
|
||||
testcase( isTrue && isNot );
|
||||
testcase( !isTrue && isNot );
|
||||
if( isTrue ^ isNot ){
|
||||
@@ -4395,8 +4501,9 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
|
||||
testcase( jumpIfNull==0 );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
assert( pExpr->eX==EX_Right );
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
@@ -4513,14 +4620,16 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
case TK_AND: {
|
||||
testcase( jumpIfNull==0 );
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3ExprIfFalse(pParse, pExpr->x.pRight, dest, jumpIfNull);
|
||||
break;
|
||||
}
|
||||
case TK_OR: {
|
||||
int d2 = sqlite3VdbeMakeLabel(v);
|
||||
testcase( jumpIfNull==0 );
|
||||
sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
|
||||
sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3ExprIfFalse(pParse, pExpr->x.pRight, dest, jumpIfNull);
|
||||
sqlite3VdbeResolveLabel(v, d2);
|
||||
break;
|
||||
}
|
||||
@@ -4534,7 +4643,8 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
int isTrue; /* IS TRUE or IS NOT TRUE */
|
||||
testcase( jumpIfNull==0 );
|
||||
isNot = pExpr->op2==TK_ISNOT;
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
isTrue = sqlite3ExprTruthValue(pExpr->x.pRight);
|
||||
testcase( isTrue && isNot );
|
||||
testcase( !isTrue && isNot );
|
||||
if( isTrue ^ isNot ){
|
||||
@@ -4565,8 +4675,9 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
|
||||
testcase( jumpIfNull==0 );
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
|
||||
assert( pExpr->eX==EX_Right );
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pExpr->x.pRight, ®Free2);
|
||||
codeCompare(pParse, pExpr->pLeft, pExpr->x.pRight, op,
|
||||
r1, r2, dest, jumpIfNull);
|
||||
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
||||
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
||||
@@ -4734,20 +4845,6 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
|
||||
if( pA->op==TK_FUNCTION ){
|
||||
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* Justification for the assert():
|
||||
** window functions have p->op==TK_FUNCTION but aggregate functions
|
||||
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
|
||||
** function and a window function should have failed before reaching
|
||||
** this point. And, it is not possible to have a window function and
|
||||
** a scalar function with the same name and number of arguments. So
|
||||
** if we reach this point, either A and B both window functions or
|
||||
** neither are a window functions. */
|
||||
assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) );
|
||||
if( ExprHasProperty(pA,EP_WinFunc) ){
|
||||
if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2;
|
||||
}
|
||||
#endif
|
||||
}else if( pA->op==TK_COLLATE ){
|
||||
if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
||||
}else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
@@ -4756,17 +4853,36 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
}
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
|
||||
if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
|
||||
if( combinedFlags & EP_xIsSelect ) return 2;
|
||||
if( pA->eX==EX_Select || pA->eX!=pB->eX ) return 2;
|
||||
if( (combinedFlags & EP_FixedCol)==0
|
||||
&& sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
|
||||
if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
|
||||
if( pA->eX==EX_Right ){
|
||||
if( sqlite3ExprCompare(pParse,pA->x.pRight,pB->x.pRight,iTab) ) return 2;
|
||||
}
|
||||
if( pA->eX==EX_List ){
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
|
||||
}
|
||||
assert( (combinedFlags & EP_Reduced)==0 );
|
||||
if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE ){
|
||||
if( pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( pA->iTable!=pB->iTable
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* Justification for the assert():
|
||||
** window functions have p->op==TK_FUNCTION but aggregate functions
|
||||
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
|
||||
** function and a window function should have failed before reaching
|
||||
** this point. And, it is not possible to have a window function and
|
||||
** a scalar function with the same name and number of arguments. So
|
||||
** if we reach this point, either A and B both window functions or
|
||||
** neither are a window functions. */
|
||||
assert( (pA->pWin==0)==(pB->pWin==0) );
|
||||
|
||||
if( pA->pWin!=0 ){
|
||||
if( sqlite3WindowCompare(pParse,pA->pWin,pB->pWin)!=0 ) return 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -4840,9 +4956,10 @@ int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
|
||||
if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
|
||||
return 1;
|
||||
}
|
||||
assert( pE2->op!=TK_OR || pE2->eX==EX_Right );
|
||||
if( pE2->op==TK_OR
|
||||
&& (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
|
||||
|| sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
|
||||
|| sqlite3ExprImpliesExpr(pParse, pE1, pE2->x.pRight, iTab) )
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
@@ -4857,15 +4974,18 @@ int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
|
||||
/*
|
||||
** This is the Expr node callback for sqlite3ExprImpliesNotNullRow().
|
||||
** If the expression node requires that the table at pWalker->iCur
|
||||
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
|
||||
**
|
||||
** This routine controls an optimization. False positives (setting
|
||||
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
|
||||
** (never setting pWalker->eCode) is a harmless missed optimization.
|
||||
** have a non-NULL column, then set pWalker->eCode to 1 and abort.
|
||||
*/
|
||||
static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_AGG_COLUMN );
|
||||
/* This routine is only called for WHERE clause expressions and so it
|
||||
** cannot have any TK_AGG_COLUMN entries because those are only found
|
||||
** in HAVING clauses. We can get a TK_AGG_FUNCTION in a WHERE clause,
|
||||
** but that is an illegal construct and the query will be rejected at
|
||||
** a later stage of processing, so the TK_AGG_FUNCTION case does not
|
||||
** need to be considered here. */
|
||||
assert( pExpr->op!=TK_AGG_COLUMN );
|
||||
testcase( pExpr->op==TK_AGG_FUNCTION );
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
||||
switch( pExpr->op ){
|
||||
case TK_ISNOT:
|
||||
@@ -4907,8 +5027,9 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_LE );
|
||||
testcase( pExpr->op==TK_GT );
|
||||
testcase( pExpr->op==TK_GE );
|
||||
if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab))
|
||||
|| (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab))
|
||||
assert( pExpr->eX==EX_Right );
|
||||
if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->x.pTab))
|
||||
|| (pExpr->x.pRight->op==TK_COLUMN && IsVirtual(pExpr->x.pRight->x.pTab))
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
@@ -5139,7 +5260,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
&& (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
|
||||
){
|
||||
pCol = &pAggInfo->aCol[k];
|
||||
pCol->pTab = pExpr->y.pTab;
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
pCol->pTab = pExpr->x.pTab;
|
||||
pCol->iTable = pExpr->iTable;
|
||||
pCol->iColumn = pExpr->iColumn;
|
||||
pCol->iMem = ++pParse->nMem;
|
||||
@@ -5197,14 +5319,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
u8 enc = ENC(pParse->db);
|
||||
i = addAggInfoFunc(pParse->db, pAggInfo);
|
||||
if( i>=0 ){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List || pExpr->eX==EX_None );
|
||||
pItem = &pAggInfo->aFunc[i];
|
||||
pItem->pExpr = pExpr;
|
||||
pItem->iMem = ++pParse->nMem;
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
||||
pExpr->u.zToken,
|
||||
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
|
||||
pExpr->eX==EX_List ? pExpr->x.pList->nExpr : 0, enc, 0);
|
||||
if( pExpr->flags & EP_Distinct ){
|
||||
pItem->iDistinct = pParse->nTab++;
|
||||
}else{
|
||||
|
||||
+5
-1
@@ -502,7 +502,11 @@ static Expr *exprTableColumn(
|
||||
){
|
||||
Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
|
||||
if( pExpr ){
|
||||
pExpr->y.pTab = pTab;
|
||||
assert( pExpr->eX==EX_None );
|
||||
if( pTab ){
|
||||
pExpr->x.pTab = pTab;
|
||||
pExpr->eX = EX_Tab;
|
||||
}
|
||||
pExpr->iTable = iCursor;
|
||||
pExpr->iColumn = iCol;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1848,7 +1848,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
|
||||
return 0;
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List );
|
||||
nExpr = pExpr->x.pList->nExpr;
|
||||
pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
|
||||
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
|
||||
|
||||
-56
@@ -64,20 +64,6 @@ static unsigned int strHash(const char *z){
|
||||
}
|
||||
return h;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
static unsigned int strHashN(const char *z, int n){
|
||||
unsigned int h = 0;
|
||||
int i;
|
||||
for(i=0; i<n; i++){
|
||||
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
|
||||
** 0x9e3779b1 is 2654435761 which is the closest prime number to
|
||||
** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
|
||||
h += sqlite3UpperToLower[z[i]];
|
||||
h *= 0x9e3779b1;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
|
||||
/* Link pNew element into the hash table pH. If pEntry!=0 then also
|
||||
@@ -189,40 +175,6 @@ static HashElem *findElementWithHash(
|
||||
}
|
||||
return &nullElement;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
static HashElem *findElementWithHashN(
|
||||
const Hash *pH, /* The pH to be searched */
|
||||
const char *pKey, /* The key we are searching for */
|
||||
int nKey, /* Number of key bytes to use */
|
||||
unsigned int *pHash /* Write the hash value here */
|
||||
){
|
||||
HashElem *elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
unsigned int h; /* The computed hash */
|
||||
static HashElem nullElement = { 0, 0, 0, 0 };
|
||||
|
||||
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
|
||||
struct _ht *pEntry;
|
||||
h = strHashN(pKey, nKey) % pH->htsize;
|
||||
pEntry = &pH->ht[h];
|
||||
elem = pEntry->chain;
|
||||
count = pEntry->count;
|
||||
}else{
|
||||
h = 0;
|
||||
elem = pH->first;
|
||||
count = pH->count;
|
||||
}
|
||||
if( pHash ) *pHash = h;
|
||||
while( count-- ){
|
||||
assert( elem!=0 );
|
||||
if( sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){
|
||||
return elem;
|
||||
}
|
||||
elem = elem->next;
|
||||
}
|
||||
return &nullElement;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
@@ -267,14 +219,6 @@ void *sqlite3HashFind(const Hash *pH, const char *pKey){
|
||||
assert( pKey!=0 );
|
||||
return findElementWithHash(pH, pKey, 0)->data;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
void *sqlite3HashFindN(const Hash *pH, const char *pKey, int nKey){
|
||||
assert( pH!=0 );
|
||||
assert( pKey!=0 );
|
||||
assert( nKey>=0 );
|
||||
return findElementWithHashN(pH, pKey, nKey, 0)->data;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey
|
||||
** and the data is "data".
|
||||
|
||||
+1
-7
@@ -451,13 +451,7 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
sqlite3_str_length,
|
||||
sqlite3_str_value,
|
||||
/* Version 3.25.0 and later */
|
||||
sqlite3_create_window_function,
|
||||
/* Version 3.26.0 and later */
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
sqlite3_normalized_sql
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
sqlite3_create_window_function
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+59
-70
@@ -136,10 +136,12 @@
|
||||
#define SQLITE_FSFLAGS_IS_MSDOS 0x1
|
||||
|
||||
/*
|
||||
** If we are to be thread-safe, include the pthreads header.
|
||||
** If we are to be thread-safe, include the pthreads header and define
|
||||
** the SQLITE_UNIX_THREADS macro.
|
||||
*/
|
||||
#if SQLITE_THREADSAFE
|
||||
# include <pthread.h>
|
||||
# define SQLITE_UNIX_THREADS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -519,11 +521,7 @@ static struct unix_syscall {
|
||||
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
|
||||
|
||||
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
||||
# ifdef __ANDROID__
|
||||
{ "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 },
|
||||
# else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
|
||||
# endif
|
||||
#else
|
||||
{ "ioctl", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
@@ -1117,7 +1115,8 @@ struct unixFileId {
|
||||
|
||||
/*
|
||||
** An instance of the following structure is allocated for each open
|
||||
** inode.
|
||||
** inode. Or, on LinuxThreads, there is one of these structures for
|
||||
** each inode opened by each thread.
|
||||
**
|
||||
** A single inode can have multiple file descriptors, so each unixFile
|
||||
** structure contains a pointer to an instance of this object and this
|
||||
@@ -1163,16 +1162,13 @@ struct unixInodeInfo {
|
||||
|
||||
/*
|
||||
** A lists of all unixInodeInfo objects.
|
||||
**
|
||||
** Must hold unixBigLock in order to read or write this variable.
|
||||
*/
|
||||
static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not.
|
||||
** This routine is used only within assert() to help verify correct mutex
|
||||
** usage.
|
||||
** True if the inode mutex is held, or not. Used only within assert()
|
||||
** to help verify correct mutex usage.
|
||||
*/
|
||||
int unixFileMutexHeld(unixFile *pFile){
|
||||
assert( pFile->pInode );
|
||||
@@ -1300,8 +1296,8 @@ static void closePendingFds(unixFile *pFile){
|
||||
/*
|
||||
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
|
||||
**
|
||||
** The global mutex must be held when this routine is called, but the mutex
|
||||
** on the inode being deleted must NOT be held.
|
||||
** The mutex entered using the unixEnterMutex() function must be held
|
||||
** when this function is called.
|
||||
*/
|
||||
static void releaseInodeInfo(unixFile *pFile){
|
||||
unixInodeInfo *pInode = pFile->pInode;
|
||||
@@ -1336,7 +1332,8 @@ static void releaseInodeInfo(unixFile *pFile){
|
||||
** describes that file descriptor. Create a new one if necessary. The
|
||||
** return value might be uninitialized if an error occurs.
|
||||
**
|
||||
** The global mutex must held when calling this routine.
|
||||
** The mutex entered using the unixEnterMutex() function must be held
|
||||
** when this function is called.
|
||||
**
|
||||
** Return an appropriate error code.
|
||||
*/
|
||||
@@ -1397,7 +1394,6 @@ static int findInodeInfo(
|
||||
#else
|
||||
fileId.ino = (u64)statbuf.st_ino;
|
||||
#endif
|
||||
assert( unixMutexHeld() );
|
||||
pInode = inodeList;
|
||||
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
|
||||
pInode = pInode->pNext;
|
||||
@@ -1417,7 +1413,6 @@ static int findInodeInfo(
|
||||
}
|
||||
}
|
||||
pInode->nRef = 1;
|
||||
assert( unixMutexHeld() );
|
||||
pInode->pNext = inodeList;
|
||||
pInode->pPrev = 0;
|
||||
if( inodeList ) inodeList->pPrev = pInode;
|
||||
@@ -4215,18 +4210,18 @@ static int unixGetpagesize(void){
|
||||
**
|
||||
** The following fields are read-only after the object is created:
|
||||
**
|
||||
** hShm
|
||||
** fid
|
||||
** zFilename
|
||||
**
|
||||
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
|
||||
** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
|
||||
** unixMutexHeld() is true when reading or writing any other field
|
||||
** in this structure.
|
||||
*/
|
||||
struct unixShmNode {
|
||||
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
|
||||
sqlite3_mutex *pShmMutex; /* Mutex to access this object */
|
||||
sqlite3_mutex *mutex; /* Mutex to access this object */
|
||||
char *zFilename; /* Name of the mmapped file */
|
||||
int hShm; /* Open file descriptor */
|
||||
int h; /* Open file descriptor */
|
||||
int szRegion; /* Size of shared-memory regions */
|
||||
u16 nRegion; /* Size of array apRegion */
|
||||
u8 isReadonly; /* True if read-only */
|
||||
@@ -4248,16 +4243,16 @@ struct unixShmNode {
|
||||
** The following fields are initialized when this object is created and
|
||||
** are read-only thereafter:
|
||||
**
|
||||
** unixShm.pShmNode
|
||||
** unixShm.pFile
|
||||
** unixShm.id
|
||||
**
|
||||
** All other fields are read/write. The unixShm.pShmNode->pShmMutex must
|
||||
** be held while accessing any read/write fields.
|
||||
** All other fields are read/write. The unixShm.pFile->mutex must be held
|
||||
** while accessing any read/write fields.
|
||||
*/
|
||||
struct unixShm {
|
||||
unixShmNode *pShmNode; /* The underlying unixShmNode object */
|
||||
unixShm *pNext; /* Next unixShm with the same unixShmNode */
|
||||
u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */
|
||||
u8 hasMutex; /* True if holding the unixShmNode mutex */
|
||||
u8 id; /* Id of this connection within its unixShmNode */
|
||||
u16 sharedMask; /* Mask of shared locks held */
|
||||
u16 exclMask; /* Mask of exclusive locks held */
|
||||
@@ -4287,8 +4282,7 @@ static int unixShmSystemLock(
|
||||
|
||||
/* Access to the unixShmNode object is serialized by the caller */
|
||||
pShmNode = pFile->pInode->pShmNode;
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
|
||||
assert( pShmNode->nRef>0 || unixMutexHeld() );
|
||||
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) );
|
||||
|
||||
/* Shared locks never span more than one byte */
|
||||
assert( n==1 || lockType!=F_RDLCK );
|
||||
@@ -4296,13 +4290,13 @@ static int unixShmSystemLock(
|
||||
/* Locks are within range */
|
||||
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
||||
|
||||
if( pShmNode->hShm>=0 ){
|
||||
if( pShmNode->h>=0 ){
|
||||
/* Initialize the locking parameters */
|
||||
f.l_type = lockType;
|
||||
f.l_whence = SEEK_SET;
|
||||
f.l_start = ofst;
|
||||
f.l_len = n;
|
||||
rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
||||
rc = osSetPosixAdvisoryLock(pShmNode->h, &f, pFile);
|
||||
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
|
||||
}
|
||||
|
||||
@@ -4374,18 +4368,18 @@ static void unixShmPurge(unixFile *pFd){
|
||||
int nShmPerMap = unixShmRegionPerMap();
|
||||
int i;
|
||||
assert( p->pInode==pFd->pInode );
|
||||
sqlite3_mutex_free(p->pShmMutex);
|
||||
sqlite3_mutex_free(p->mutex);
|
||||
for(i=0; i<p->nRegion; i+=nShmPerMap){
|
||||
if( p->hShm>=0 ){
|
||||
if( p->h>=0 ){
|
||||
osMunmap(p->apRegion[i], p->szRegion);
|
||||
}else{
|
||||
sqlite3_free(p->apRegion[i]);
|
||||
}
|
||||
}
|
||||
sqlite3_free(p->apRegion);
|
||||
if( p->hShm>=0 ){
|
||||
robust_close(pFd, p->hShm, __LINE__);
|
||||
p->hShm = -1;
|
||||
if( p->h>=0 ){
|
||||
robust_close(pFd, p->h, __LINE__);
|
||||
p->h = -1;
|
||||
}
|
||||
p->pInode->pShmNode = 0;
|
||||
sqlite3_free(p);
|
||||
@@ -4427,7 +4421,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
|
||||
lock.l_start = UNIX_SHM_DMS;
|
||||
lock.l_len = 1;
|
||||
lock.l_type = F_WRLCK;
|
||||
if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) {
|
||||
if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) {
|
||||
rc = SQLITE_IOERR_LOCK;
|
||||
}else if( lock.l_type==F_UNLCK ){
|
||||
if( pShmNode->isReadonly ){
|
||||
@@ -4435,12 +4429,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
|
||||
rc = SQLITE_READONLY_CANTINIT;
|
||||
}else{
|
||||
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
|
||||
/* The first connection to attach must truncate the -shm file. We
|
||||
** truncate to 3 bytes (an arbitrary small number, less than the
|
||||
** -shm header size) rather than 0 as a system debugging aid, to
|
||||
** help detect if a -shm file truncation is legitimate or is the work
|
||||
** or a rogue process. */
|
||||
if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){
|
||||
if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename);
|
||||
}
|
||||
}
|
||||
@@ -4546,12 +4535,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath);
|
||||
sqlite3FileSuffix3(pDbFd->zPath, zShm);
|
||||
#endif
|
||||
pShmNode->hShm = -1;
|
||||
pShmNode->h = -1;
|
||||
pDbFd->pInode->pShmNode = pShmNode;
|
||||
pShmNode->pInode = pDbFd->pInode;
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pShmNode->pShmMutex==0 ){
|
||||
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||
if( pShmNode->mutex==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto shm_open_err;
|
||||
}
|
||||
@@ -4559,11 +4548,11 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
|
||||
pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777));
|
||||
pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777));
|
||||
}
|
||||
if( pShmNode->hShm<0 ){
|
||||
pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));
|
||||
if( pShmNode->hShm<0 ){
|
||||
if( pShmNode->h<0 ){
|
||||
pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777));
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
|
||||
goto shm_open_err;
|
||||
}
|
||||
@@ -4574,7 +4563,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
** is owned by the same user that owns the original database. Otherwise,
|
||||
** the original owner will not be able to connect.
|
||||
*/
|
||||
robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid);
|
||||
robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
|
||||
|
||||
rc = unixLockSharedMemory(pDbFd, pShmNode);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
|
||||
@@ -4594,13 +4583,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
** the cover of the unixEnterMutex() mutex and the pointer from the
|
||||
** new (struct unixShm) object to the pShmNode has been set. All that is
|
||||
** left to do is to link the new object into the linked list starting
|
||||
** at pShmNode->pFirst. This must be done while holding the
|
||||
** pShmNode->pShmMutex.
|
||||
** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
|
||||
** mutex.
|
||||
*/
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
p->pNext = pShmNode->pFirst;
|
||||
pShmNode->pFirst = p;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
return rc;
|
||||
|
||||
/* Jump here on any error */
|
||||
@@ -4652,7 +4641,7 @@ static int unixShmMap(
|
||||
|
||||
p = pDbFd->pShm;
|
||||
pShmNode = p->pShmNode;
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
if( pShmNode->isUnlocked ){
|
||||
rc = unixLockSharedMemory(pDbFd, pShmNode);
|
||||
if( rc!=SQLITE_OK ) goto shmpage_out;
|
||||
@@ -4660,8 +4649,8 @@ static int unixShmMap(
|
||||
}
|
||||
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
|
||||
assert( pShmNode->pInode==pDbFd->pInode );
|
||||
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
|
||||
/* Minimum number of regions required to be mapped. */
|
||||
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
|
||||
@@ -4673,12 +4662,12 @@ static int unixShmMap(
|
||||
|
||||
pShmNode->szRegion = szRegion;
|
||||
|
||||
if( pShmNode->hShm>=0 ){
|
||||
if( pShmNode->h>=0 ){
|
||||
/* The requested region is not mapped into this processes address space.
|
||||
** Check to see if it has been allocated (i.e. if the wal-index file is
|
||||
** large enough to contain the requested region).
|
||||
*/
|
||||
if( osFstat(pShmNode->hShm, &sStat) ){
|
||||
if( osFstat(pShmNode->h, &sStat) ){
|
||||
rc = SQLITE_IOERR_SHMSIZE;
|
||||
goto shmpage_out;
|
||||
}
|
||||
@@ -4706,7 +4695,7 @@ static int unixShmMap(
|
||||
assert( (nByte % pgsz)==0 );
|
||||
for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
|
||||
int x = 0;
|
||||
if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){
|
||||
if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){
|
||||
const char *zFile = pShmNode->zFilename;
|
||||
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
|
||||
goto shmpage_out;
|
||||
@@ -4729,22 +4718,22 @@ static int unixShmMap(
|
||||
int nMap = szRegion*nShmPerMap;
|
||||
int i;
|
||||
void *pMem;
|
||||
if( pShmNode->hShm>=0 ){
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = osMmap(0, nMap,
|
||||
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion
|
||||
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
|
||||
);
|
||||
if( pMem==MAP_FAILED ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
|
||||
goto shmpage_out;
|
||||
}
|
||||
}else{
|
||||
pMem = sqlite3_malloc64(nMap);
|
||||
pMem = sqlite3_malloc64(szRegion);
|
||||
if( pMem==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto shmpage_out;
|
||||
}
|
||||
memset(pMem, 0, nMap);
|
||||
memset(pMem, 0, szRegion);
|
||||
}
|
||||
|
||||
for(i=0; i<nShmPerMap; i++){
|
||||
@@ -4761,7 +4750,7 @@ shmpage_out:
|
||||
*pp = 0;
|
||||
}
|
||||
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -4795,12 +4784,12 @@ static int unixShmLock(
|
||||
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
|
||||
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
|
||||
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
|
||||
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
|
||||
|
||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||
assert( n>1 || mask==(1<<ofst) );
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
if( flags & SQLITE_SHM_UNLOCK ){
|
||||
u16 allMask = 0; /* Mask of locks held by siblings */
|
||||
|
||||
@@ -4873,7 +4862,7 @@ static int unixShmLock(
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
|
||||
p->id, osGetpid(0), p->sharedMask, p->exclMask));
|
||||
return rc;
|
||||
@@ -4923,14 +4912,14 @@ static int unixShmUnmap(
|
||||
|
||||
/* Remove connection p from the set of connections associated
|
||||
** with pShmNode */
|
||||
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_enter(pShmNode->mutex);
|
||||
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
|
||||
*pp = p->pNext;
|
||||
|
||||
/* Free the connection p */
|
||||
sqlite3_free(p);
|
||||
pDbFd->pShm = 0;
|
||||
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
|
||||
/* If pShmNode->nRef has reached 0, then close the underlying
|
||||
** shared-memory file, too */
|
||||
@@ -4939,7 +4928,7 @@ static int unixShmUnmap(
|
||||
assert( pShmNode->nRef>0 );
|
||||
pShmNode->nRef--;
|
||||
if( pShmNode->nRef==0 ){
|
||||
if( deleteFlag && pShmNode->hShm>=0 ){
|
||||
if( deleteFlag && pShmNode->h>=0 ){
|
||||
osUnlink(pShmNode->zFilename);
|
||||
}
|
||||
unixShmPurge(pDbFd);
|
||||
|
||||
@@ -7021,7 +7021,6 @@ void sqlite3PagerSetCodec(
|
||||
void (*xCodecFree)(void*),
|
||||
void *pCodec
|
||||
){
|
||||
pager_reset(pPager);
|
||||
if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
|
||||
pPager->xCodec = pPager->memDb ? 0 : xCodec;
|
||||
pPager->xCodecSizeChng = xCodecSizeChng;
|
||||
|
||||
+15
-29
@@ -936,15 +936,17 @@ idlist(A) ::= nm(Y).
|
||||
/* memset(p, 0, sizeof(Expr)); */
|
||||
p->op = (u8)op;
|
||||
p->affinity = 0;
|
||||
p->eX = EX_None;
|
||||
p->flags = EP_Leaf;
|
||||
p->iAgg = -1;
|
||||
p->pLeft = p->pRight = 0;
|
||||
p->x.pList = 0;
|
||||
p->pLeft = 0;
|
||||
p->pAggInfo = 0;
|
||||
p->y.pTab = 0;
|
||||
p->op2 = 0;
|
||||
p->iTable = 0;
|
||||
p->iColumn = 0;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
p->pWin = 0;
|
||||
#endif
|
||||
p->u.zToken = (char*)&p[1];
|
||||
memcpy(p->u.zToken, t.z, t.n);
|
||||
p->u.zToken[t.n] = 0;
|
||||
@@ -1049,11 +1051,7 @@ term(A) ::= CTIME_KW(OP). {
|
||||
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);
|
||||
}
|
||||
sqlite3PExprAddExprList(pParse, A, pList);
|
||||
}
|
||||
|
||||
expr(A) ::= expr(A) AND(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
|
||||
@@ -1101,10 +1099,11 @@ expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);}
|
||||
** unary TK_ISNULL or TK_NOTNULL expression. */
|
||||
static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){
|
||||
if( pA && pY && pY->op==TK_NULL && pA->eX==EX_Right && !IN_RENAME_OBJECT ){
|
||||
pA->op = (u8)op;
|
||||
sqlite3ExprDelete(db, pA->pRight);
|
||||
pA->pRight = 0;
|
||||
sqlite3ExprDelete(db, pA->x.pRight);
|
||||
pA->x.pRight = 0;
|
||||
pA->eX = EX_None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1140,11 +1139,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
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);
|
||||
}
|
||||
sqlite3PExprAddExprList(pParse, A, pList);
|
||||
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
|
||||
}
|
||||
%ifndef SQLITE_OMIT_SUBQUERY
|
||||
@@ -1192,12 +1187,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS);
|
||||
}else{
|
||||
A = sqlite3PExpr(pParse, TK_IN, A, 0);
|
||||
if( A ){
|
||||
A->x.pList = Y;
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A);
|
||||
}else{
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
}
|
||||
sqlite3PExprAddExprList(pParse, A, Y);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A);
|
||||
if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
|
||||
}
|
||||
}
|
||||
@@ -1228,13 +1219,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
/* CASE expressions */
|
||||
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);
|
||||
}
|
||||
sqlite3PExprAddExprList(pParse,A,Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y);
|
||||
sqlite3ExprSetHeightAndFlags(pParse, A);
|
||||
}
|
||||
%type case_exprlist {ExprList*}
|
||||
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@
|
||||
** The PCache.pSynced variable is used to optimize searching for a dirty
|
||||
** page to eject from the cache mid-transaction. It is better to eject
|
||||
** a page that does not require a journal sync than one that does.
|
||||
** Therefore, pSynced is maintained so that it *almost* always points
|
||||
** Therefore, pSynced is maintained to that it *almost* always points
|
||||
** to either the oldest page in the pDirty/pDirtyTail list that has a
|
||||
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
|
||||
** (so that the right page to eject can be found by following pDirtyPrev
|
||||
|
||||
+10
-24
@@ -1090,12 +1090,11 @@ void sqlite3Pragma(
|
||||
int nHidden = 0;
|
||||
Column *pCol;
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
pParse->nMem = 7;
|
||||
pParse->nMem = 6;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
int isHidden = IsHiddenColumn(pCol);
|
||||
if( isHidden && pPragma->iArg==0 ){
|
||||
if( IsHiddenColumn(pCol) ){
|
||||
nHidden++;
|
||||
continue;
|
||||
}
|
||||
@@ -1107,14 +1106,13 @@ void sqlite3Pragma(
|
||||
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
||||
}
|
||||
assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
|
||||
sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi",
|
||||
sqlite3VdbeMultiLoad(v, 1, "issisi",
|
||||
i-nHidden,
|
||||
pCol->zName,
|
||||
sqlite3ColumnType(pCol,""),
|
||||
pCol->notNull ? 1 : 0,
|
||||
pCol->pDflt ? pCol->pDflt->u.zToken : 0,
|
||||
k,
|
||||
isHidden);
|
||||
k);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2118,24 +2116,12 @@ void sqlite3Pragma(
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* Pragma iArg
|
||||
** ---------- ------
|
||||
** key 0
|
||||
** rekey 1
|
||||
** hexkey 2
|
||||
** hexrekey 3
|
||||
** textkey 4
|
||||
** textrekey 5
|
||||
*/
|
||||
case PragTyp_KEY: {
|
||||
if( zRight ){
|
||||
int n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1;
|
||||
if( (pPragma->iArg & 1)==0 ){
|
||||
sqlite3_key_v2(db, zDb, zRight, n);
|
||||
}else{
|
||||
sqlite3_rekey_v2(db, zDb, zRight, n);
|
||||
}
|
||||
}
|
||||
if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
|
||||
break;
|
||||
}
|
||||
case PragTyp_REKEY: {
|
||||
if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
|
||||
break;
|
||||
}
|
||||
case PragTyp_HEXKEY: {
|
||||
@@ -2147,7 +2133,7 @@ void sqlite3Pragma(
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
|
||||
if( (i&1)!=0 ) zKey[i/2] = iByte;
|
||||
}
|
||||
if( (pPragma->iArg & 1)==0 ){
|
||||
if( (zLeft[3] & 0xf)==0xb ){
|
||||
sqlite3_key_v2(db, zDb, zKey, i/2);
|
||||
}else{
|
||||
sqlite3_rekey_v2(db, zDb, zKey, i/2);
|
||||
|
||||
+69
-89
@@ -48,9 +48,10 @@
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 40
|
||||
#define PragTyp_HEXKEY 41
|
||||
#define PragTyp_KEY 42
|
||||
#define PragTyp_LOCK_STATUS 43
|
||||
#define PragTyp_PARSER_TRACE 44
|
||||
#define PragTyp_STATS 45
|
||||
#define PragTyp_REKEY 43
|
||||
#define PragTyp_LOCK_STATUS 44
|
||||
#define PragTyp_PARSER_TRACE 45
|
||||
#define PragTyp_STATS 46
|
||||
|
||||
/* Property flags associated with various pragma. */
|
||||
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
|
||||
@@ -67,57 +68,58 @@
|
||||
** result column is different from the name of the pragma
|
||||
*/
|
||||
static const char *const pragCName[] = {
|
||||
/* 0 */ "id", /* Used by: foreign_key_list */
|
||||
/* 1 */ "seq",
|
||||
/* 2 */ "table",
|
||||
/* 3 */ "from",
|
||||
/* 4 */ "to",
|
||||
/* 5 */ "on_update",
|
||||
/* 6 */ "on_delete",
|
||||
/* 7 */ "match",
|
||||
/* 8 */ "cid", /* Used by: table_xinfo */
|
||||
/* 9 */ "name",
|
||||
/* 10 */ "type",
|
||||
/* 11 */ "notnull",
|
||||
/* 12 */ "dflt_value",
|
||||
/* 13 */ "pk",
|
||||
/* 14 */ "hidden",
|
||||
/* table_info reuses 8 */
|
||||
/* 0 */ "cache_size", /* Used by: default_cache_size */
|
||||
/* 1 */ "cid", /* Used by: table_info */
|
||||
/* 2 */ "name",
|
||||
/* 3 */ "type",
|
||||
/* 4 */ "notnull",
|
||||
/* 5 */ "dflt_value",
|
||||
/* 6 */ "pk",
|
||||
/* 7 */ "tbl", /* Used by: stats */
|
||||
/* 8 */ "idx",
|
||||
/* 9 */ "wdth",
|
||||
/* 10 */ "hght",
|
||||
/* 11 */ "flgs",
|
||||
/* 12 */ "seqno", /* Used by: index_info */
|
||||
/* 13 */ "cid",
|
||||
/* 14 */ "name",
|
||||
/* 15 */ "seqno", /* Used by: index_xinfo */
|
||||
/* 16 */ "cid",
|
||||
/* 17 */ "name",
|
||||
/* 18 */ "desc",
|
||||
/* 19 */ "coll",
|
||||
/* 20 */ "key",
|
||||
/* 21 */ "tbl", /* Used by: stats */
|
||||
/* 22 */ "idx",
|
||||
/* 23 */ "wdth",
|
||||
/* 24 */ "hght",
|
||||
/* 25 */ "flgs",
|
||||
/* 26 */ "seq", /* Used by: index_list */
|
||||
/* 21 */ "seq", /* Used by: index_list */
|
||||
/* 22 */ "name",
|
||||
/* 23 */ "unique",
|
||||
/* 24 */ "origin",
|
||||
/* 25 */ "partial",
|
||||
/* 26 */ "seq", /* Used by: database_list */
|
||||
/* 27 */ "name",
|
||||
/* 28 */ "unique",
|
||||
/* 29 */ "origin",
|
||||
/* 30 */ "partial",
|
||||
/* 31 */ "table", /* Used by: foreign_key_check */
|
||||
/* 32 */ "rowid",
|
||||
/* 33 */ "parent",
|
||||
/* 34 */ "fkid",
|
||||
/* index_info reuses 15 */
|
||||
/* 35 */ "seq", /* Used by: database_list */
|
||||
/* 36 */ "name",
|
||||
/* 37 */ "file",
|
||||
/* 38 */ "busy", /* Used by: wal_checkpoint */
|
||||
/* 39 */ "log",
|
||||
/* 40 */ "checkpointed",
|
||||
/* 41 */ "name", /* Used by: function_list */
|
||||
/* 42 */ "builtin",
|
||||
/* collation_list reuses 26 */
|
||||
/* 43 */ "database", /* Used by: lock_status */
|
||||
/* 44 */ "status",
|
||||
/* 45 */ "cache_size", /* Used by: default_cache_size */
|
||||
/* module_list pragma_list reuses 9 */
|
||||
/* 46 */ "timeout", /* Used by: busy_timeout */
|
||||
/* 28 */ "file",
|
||||
/* 29 */ "name", /* Used by: function_list */
|
||||
/* 30 */ "builtin",
|
||||
/* 31 */ "name", /* Used by: module_list pragma_list */
|
||||
/* 32 */ "seq", /* Used by: collation_list */
|
||||
/* 33 */ "name",
|
||||
/* 34 */ "id", /* Used by: foreign_key_list */
|
||||
/* 35 */ "seq",
|
||||
/* 36 */ "table",
|
||||
/* 37 */ "from",
|
||||
/* 38 */ "to",
|
||||
/* 39 */ "on_update",
|
||||
/* 40 */ "on_delete",
|
||||
/* 41 */ "match",
|
||||
/* 42 */ "table", /* Used by: foreign_key_check */
|
||||
/* 43 */ "rowid",
|
||||
/* 44 */ "parent",
|
||||
/* 45 */ "fkid",
|
||||
/* 46 */ "busy", /* Used by: wal_checkpoint */
|
||||
/* 47 */ "log",
|
||||
/* 48 */ "checkpointed",
|
||||
/* 49 */ "timeout", /* Used by: busy_timeout */
|
||||
/* 50 */ "database", /* Used by: lock_status */
|
||||
/* 51 */ "status",
|
||||
};
|
||||
|
||||
/* Definitions of all built-in pragmas */
|
||||
@@ -163,7 +165,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "busy_timeout",
|
||||
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 46, 1,
|
||||
/* ColNames: */ 49, 1,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "cache_size",
|
||||
@@ -200,7 +202,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "collation_list",
|
||||
/* ePragTyp: */ PragTyp_COLLATION_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 26, 2,
|
||||
/* ColNames: */ 32, 2,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
||||
@@ -235,14 +237,14 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "database_list",
|
||||
/* ePragTyp: */ PragTyp_DATABASE_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
||||
/* ColNames: */ 35, 3,
|
||||
/* ColNames: */ 26, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
||||
{/* zName: */ "default_cache_size",
|
||||
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
|
||||
/* ColNames: */ 45, 1,
|
||||
/* ColNames: */ 0, 1,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -272,14 +274,14 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "foreign_key_check",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
||||
/* ColNames: */ 31, 4,
|
||||
/* ColNames: */ 42, 4,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
||||
{/* zName: */ "foreign_key_list",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 0, 8,
|
||||
/* ColNames: */ 34, 8,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -315,7 +317,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "function_list",
|
||||
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 41, 2,
|
||||
/* ColNames: */ 29, 2,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#endif
|
||||
@@ -324,12 +326,12 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ePragTyp: */ PragTyp_HEXKEY,
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 2 },
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "hexrekey",
|
||||
/* ePragTyp: */ PragTyp_HEXKEY,
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 3 },
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
#if !defined(SQLITE_OMIT_CHECK)
|
||||
@@ -351,12 +353,12 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "index_info",
|
||||
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 15, 3,
|
||||
/* ColNames: */ 12, 3,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "index_list",
|
||||
/* ePragTyp: */ PragTyp_INDEX_LIST,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 26, 5,
|
||||
/* ColNames: */ 21, 5,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "index_xinfo",
|
||||
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
||||
@@ -391,11 +393,6 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
{/* zName: */ "legacy_alter_table",
|
||||
/* ePragTyp: */ PragTyp_FLAG,
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ SQLITE_LegacyAlter },
|
||||
{/* zName: */ "legacy_file_format",
|
||||
/* ePragTyp: */ PragTyp_FLAG,
|
||||
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
||||
@@ -413,7 +410,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "lock_status",
|
||||
/* ePragTyp: */ PragTyp_LOCK_STATUS,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 43, 2,
|
||||
/* ColNames: */ 50, 2,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
@@ -439,7 +436,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "module_list",
|
||||
/* ePragTyp: */ PragTyp_MODULE_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 9, 1,
|
||||
/* ColNames: */ 31, 1,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#endif
|
||||
@@ -472,7 +469,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "pragma_list",
|
||||
/* ePragTyp: */ PragTyp_PRAGMA_LIST,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
/* ColNames: */ 9, 1,
|
||||
/* ColNames: */ 31, 1,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -503,10 +500,10 @@ static const PragmaName aPragmaName[] = {
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
{/* zName: */ "rekey",
|
||||
/* ePragTyp: */ PragTyp_KEY,
|
||||
/* ePragTyp: */ PragTyp_REKEY,
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 1 },
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
{/* zName: */ "reverse_unordered_selects",
|
||||
@@ -559,7 +556,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "stats",
|
||||
/* ePragTyp: */ PragTyp_STATS,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
||||
/* ColNames: */ 21, 5,
|
||||
/* ColNames: */ 7, 5,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
@@ -573,13 +570,8 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "table_info",
|
||||
/* ePragTyp: */ PragTyp_TABLE_INFO,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 8, 6,
|
||||
/* ColNames: */ 1, 6,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "table_xinfo",
|
||||
/* ePragTyp: */ PragTyp_TABLE_INFO,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
||||
/* ColNames: */ 8, 7,
|
||||
/* iArg: */ 1 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
{/* zName: */ "temp_store",
|
||||
@@ -592,18 +584,6 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ePragFlg: */ PragFlg_NoColumns1,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
{/* zName: */ "textkey",
|
||||
/* ePragTyp: */ PragTyp_KEY,
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 4 },
|
||||
{/* zName: */ "textrekey",
|
||||
/* ePragTyp: */ PragTyp_KEY,
|
||||
/* ePragFlg: */ 0,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 5 },
|
||||
#endif
|
||||
{/* zName: */ "threads",
|
||||
/* ePragTyp: */ PragTyp_THREADS,
|
||||
@@ -655,7 +635,7 @@ static const PragmaName aPragmaName[] = {
|
||||
{/* zName: */ "wal_checkpoint",
|
||||
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ColNames: */ 38, 3,
|
||||
/* ColNames: */ 46, 3,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
@@ -666,4 +646,4 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_WriteSchema },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 62 on by default, 81 total. */
|
||||
/* Number of pragmas: 60 on by default, 77 total. */
|
||||
|
||||
-288
@@ -709,294 +709,6 @@ static int sqlite3LockAndPrepare(
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
/*
|
||||
** Checks if the specified token is a table, column, or function name,
|
||||
** based on the databases associated with the statement being prepared.
|
||||
** If the function fails, zero is returned and pRc is filled with the
|
||||
** error code.
|
||||
*/
|
||||
static int shouldTreatAsIdentifier(
|
||||
sqlite3 *db, /* Database handle. */
|
||||
const char *zToken, /* Pointer to start of token to be checked */
|
||||
int nToken, /* Length of token to be checked */
|
||||
int *pRc /* Pointer to error code upon failure */
|
||||
){
|
||||
int bFound = 0; /* Non-zero if token is an identifier name. */
|
||||
int i, j; /* Database and column loop indexes. */
|
||||
Schema *pSchema; /* Schema for current database. */
|
||||
Hash *pHash; /* Hash table of tables for current database. */
|
||||
HashElem *e; /* Hash element for hash table iteration. */
|
||||
Table *pTab; /* Database table for columns being checked. */
|
||||
|
||||
if( sqlite3IsRowidN(zToken, nToken) ){
|
||||
return 1;
|
||||
}
|
||||
if( nToken>0 ){
|
||||
int hash = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zToken[0]], nToken);
|
||||
if( sqlite3FunctionSearchN(hash, zToken, nToken) ) return 1;
|
||||
}
|
||||
assert( db!=0 );
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pHash = &db->aFunc;
|
||||
if( sqlite3HashFindN(pHash, zToken, nToken) ){
|
||||
bFound = 1;
|
||||
break;
|
||||
}
|
||||
pSchema = db->aDb[i].pSchema;
|
||||
if( pSchema==0 ) continue;
|
||||
pHash = &pSchema->tblHash;
|
||||
if( sqlite3HashFindN(pHash, zToken, nToken) ){
|
||||
bFound = 1;
|
||||
break;
|
||||
}
|
||||
for(e=sqliteHashFirst(pHash); e; e=sqliteHashNext(e)){
|
||||
pTab = sqliteHashData(e);
|
||||
if( pTab==0 ) continue;
|
||||
pHash = pTab->pColHash;
|
||||
if( pHash==0 ){
|
||||
pTab->pColHash = pHash = sqlite3_malloc(sizeof(Hash));
|
||||
if( pHash ){
|
||||
sqlite3HashInit(pHash);
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
Column *pCol = &pTab->aCol[j];
|
||||
sqlite3HashInsert(pHash, pCol->zName, pCol);
|
||||
}
|
||||
}else{
|
||||
*pRc = SQLITE_NOMEM_BKPT;
|
||||
bFound = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if( pHash && sqlite3HashFindN(pHash, zToken, nToken) ){
|
||||
bFound = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return bFound;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to estimate the final output buffer size needed for the fully
|
||||
** normalized version of the specified SQL string. This should take into
|
||||
** account any potential expansion that could occur (e.g. via IN clauses
|
||||
** being expanded, etc). This size returned is the total number of bytes
|
||||
** including the NUL terminator.
|
||||
*/
|
||||
static int estimateNormalizedSize(
|
||||
const char *zSql, /* The original SQL string */
|
||||
int nSql, /* Length of original SQL string */
|
||||
u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */
|
||||
){
|
||||
int nOut = nSql + 4;
|
||||
const char *z = zSql;
|
||||
while( nOut<nSql*5 ){
|
||||
while( z[0]!=0 && z[0]!='I' && z[0]!='i' ){ z++; }
|
||||
if( z[0]==0 ) break;
|
||||
z++;
|
||||
if( z[0]!='N' && z[0]!='n' ) break;
|
||||
z++;
|
||||
while( sqlite3Isspace(z[0]) ){ z++; }
|
||||
if( z[0]!='(' ) break;
|
||||
z++;
|
||||
nOut += 5; /* ?,?,? */
|
||||
}
|
||||
return nOut;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the current token into the output buffer while dealing with quoted
|
||||
** identifiers. By default, all letters will be converted into lowercase.
|
||||
** If the bUpper flag is set, uppercase will be used. The piOut argument
|
||||
** will be used to update the target index into the output string.
|
||||
*/
|
||||
static void copyNormalizedToken(
|
||||
const char *zSql, /* The original SQL string */
|
||||
int iIn, /* Current index into the original SQL string */
|
||||
int nToken, /* Number of bytes in the current token */
|
||||
int tokenFlags, /* Flags returned by the tokenizer */
|
||||
char *zOut, /* The output string */
|
||||
int *piOut /* Pointer to target index into the output string */
|
||||
){
|
||||
int bQuoted = tokenFlags & SQLITE_TOKEN_QUOTED;
|
||||
int bKeyword = tokenFlags & SQLITE_TOKEN_KEYWORD;
|
||||
int j = *piOut, k = 0;
|
||||
for(; k<nToken; k++){
|
||||
if( bQuoted ){
|
||||
if( k==0 && iIn>0 ){
|
||||
zOut[j++] = '"';
|
||||
continue;
|
||||
}else if( k==nToken-1 ){
|
||||
zOut[j++] = '"';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( bKeyword ){
|
||||
zOut[j++] = sqlite3Toupper(zSql[iIn+k]);
|
||||
}else{
|
||||
zOut[j++] = sqlite3Tolower(zSql[iIn+k]);
|
||||
}
|
||||
}
|
||||
*piOut = j;
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform normalization of the SQL contained in the prepared statement and
|
||||
** store the result in the zNormSql field. The schema for the associated
|
||||
** databases are consulted while performing the normalization in order to
|
||||
** determine if a token appears to be an identifier. All identifiers are
|
||||
** left intact in the normalized SQL and all literals are replaced with a
|
||||
** single '?'.
|
||||
*/
|
||||
void sqlite3Normalize(
|
||||
Vdbe *pVdbe, /* VM being reprepared */
|
||||
const char *zSql, /* The original SQL string */
|
||||
int nSql, /* Size of the input string in bytes */
|
||||
u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */
|
||||
){
|
||||
sqlite3 *db; /* Database handle. */
|
||||
char *z; /* The output string */
|
||||
int nZ; /* Size of the output string in bytes */
|
||||
int i; /* Next character to read from zSql[] */
|
||||
int j; /* Next character to fill in on z[] */
|
||||
int tokenType = 0; /* Type of the next token */
|
||||
int prevTokenType = 0; /* Type of the previous token, except spaces */
|
||||
int n; /* Size of the next token */
|
||||
int nParen = 0; /* Nesting level of parenthesis */
|
||||
Hash inHash; /* Table of parenthesis levels to output index. */
|
||||
|
||||
db = sqlite3VdbeDb(pVdbe);
|
||||
assert( db!=0 );
|
||||
assert( pVdbe->zNormSql==0 );
|
||||
if( zSql==0 ) return;
|
||||
nZ = estimateNormalizedSize(zSql, nSql, prepFlags);
|
||||
z = sqlite3DbMallocRawNN(db, nZ);
|
||||
if( z==0 ) return;
|
||||
sqlite3HashInit(&inHash);
|
||||
for(i=j=0; i<nSql && zSql[i]; i+=n){
|
||||
int flags = 0;
|
||||
if( tokenType!=TK_SPACE ) prevTokenType = tokenType;
|
||||
n = sqlite3GetTokenNormalized((unsigned char*)zSql+i, &tokenType, &flags);
|
||||
switch( tokenType ){
|
||||
case TK_SPACE: {
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3HashClear(&inHash);
|
||||
return;
|
||||
}
|
||||
case TK_STRING:
|
||||
case TK_INTEGER:
|
||||
case TK_FLOAT:
|
||||
case TK_VARIABLE:
|
||||
case TK_BLOB: {
|
||||
z[j++] = '?';
|
||||
break;
|
||||
}
|
||||
case TK_LP:
|
||||
case TK_RP: {
|
||||
if( tokenType==TK_LP ){
|
||||
nParen++;
|
||||
if( prevTokenType==TK_IN ){
|
||||
assert( nParen<nSql );
|
||||
sqlite3HashInsert(&inHash, zSql+nParen, SQLITE_INT_TO_PTR(j));
|
||||
}
|
||||
}else{
|
||||
int jj;
|
||||
assert( nParen<nSql );
|
||||
jj = SQLITE_PTR_TO_INT(sqlite3HashFind(&inHash, zSql+nParen));
|
||||
if( jj>0 ){
|
||||
sqlite3HashInsert(&inHash, zSql+nParen, 0);
|
||||
assert( jj+6<nZ );
|
||||
memcpy(z+jj+1, "?,?,?", 5);
|
||||
j = jj+6;
|
||||
assert( nZ-1-j>=0 );
|
||||
assert( nZ-1-j<nZ );
|
||||
memset(z+j, 0, nZ-1-j);
|
||||
}
|
||||
nParen--;
|
||||
}
|
||||
assert( nParen>=0 );
|
||||
/* Fall through */
|
||||
}
|
||||
case TK_MINUS:
|
||||
case TK_SEMI:
|
||||
case TK_PLUS:
|
||||
case TK_STAR:
|
||||
case TK_SLASH:
|
||||
case TK_REM:
|
||||
case TK_EQ:
|
||||
case TK_LE:
|
||||
case TK_NE:
|
||||
case TK_LSHIFT:
|
||||
case TK_LT:
|
||||
case TK_RSHIFT:
|
||||
case TK_GT:
|
||||
case TK_GE:
|
||||
case TK_BITOR:
|
||||
case TK_CONCAT:
|
||||
case TK_COMMA:
|
||||
case TK_BITAND:
|
||||
case TK_BITNOT:
|
||||
case TK_DOT:
|
||||
case TK_IN:
|
||||
case TK_IS:
|
||||
case TK_NOT:
|
||||
case TK_NULL:
|
||||
case TK_ID: {
|
||||
if( tokenType==TK_NULL ){
|
||||
if( prevTokenType==TK_IS || prevTokenType==TK_NOT ){
|
||||
/* NULL is a keyword in this case, not a literal value */
|
||||
}else{
|
||||
/* Here the NULL is a literal value */
|
||||
z[j++] = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>0 && sqlite3IsIdChar(z[j-1]) && sqlite3IsIdChar(zSql[i]) ){
|
||||
z[j++] = ' ';
|
||||
}
|
||||
if( tokenType==TK_ID ){
|
||||
int i2 = i, n2 = n, rc = SQLITE_OK;
|
||||
if( nParen>0 ){
|
||||
assert( nParen<nSql );
|
||||
sqlite3HashInsert(&inHash, zSql+nParen, 0);
|
||||
}
|
||||
if( flags&SQLITE_TOKEN_QUOTED ){ i2++; n2-=2; }
|
||||
if( shouldTreatAsIdentifier(db, zSql+i2, n2, &rc)==0 ){
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3HashClear(&inHash);
|
||||
return;
|
||||
}
|
||||
if( sqlite3_keyword_check(zSql+i2, n2)==0 ){
|
||||
z[j++] = '?';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
copyNormalizedToken(zSql, i, n, flags, z, &j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( j<nZ && "one" );
|
||||
while( j>0 && z[j-1]==' ' ){ j--; }
|
||||
if( j>0 && z[j-1]!=';' ){ z[j++] = ';'; }
|
||||
z[j] = 0;
|
||||
assert( j<nZ && "two" );
|
||||
pVdbe->zNormSql = z;
|
||||
sqlite3HashClear(&inHash);
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/*
|
||||
** Rerun the compilation of a statement after a schema change.
|
||||
**
|
||||
|
||||
+53
-41
@@ -159,12 +159,12 @@ int sqlite3MatchSpanName(
|
||||
** (even if X is implied).
|
||||
** pExpr->iTable Set to the cursor number for the table obtained
|
||||
** from pSrcList.
|
||||
** pExpr->y.pTab Points to the Table structure of X.Y (even if
|
||||
** pExpr->pTab Points to the Table structure of X.Y (even if
|
||||
** X and/or Y are implied.)
|
||||
** pExpr->iColumn Set to the column number within the table.
|
||||
** pExpr->op Set to TK_COLUMN.
|
||||
** pExpr->pLeft Any expression this points to is deleted
|
||||
** pExpr->pRight Any expression this points to is deleted.
|
||||
** pExpr->x.pRight Any expression this points to is deleted.
|
||||
**
|
||||
** The zDb variable is the name of the database (the "X"). This value may be
|
||||
** NULL meaning that name is of the form Y.Z or Z. Any available database
|
||||
@@ -264,7 +264,7 @@ static int lookupName(
|
||||
continue;
|
||||
}
|
||||
if( IN_RENAME_OBJECT && pItem->zAlias ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->x.pTab);
|
||||
}
|
||||
}
|
||||
if( 0==(cntTab++) ){
|
||||
@@ -290,13 +290,13 @@ static int lookupName(
|
||||
}
|
||||
if( pMatch ){
|
||||
pExpr->iTable = pMatch->iCursor;
|
||||
pExpr->y.pTab = pMatch->pTab;
|
||||
sqlite3ExprAddTab(db, pExpr, pMatch->pTab);
|
||||
/* RIGHT JOIN not (yet) supported */
|
||||
assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
|
||||
if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
|
||||
ExprSetProperty(pExpr, EP_CanBeNull);
|
||||
}
|
||||
pSchema = pExpr->y.pTab->pSchema;
|
||||
pSchema = pExpr->x.pTab->pSchema;
|
||||
}
|
||||
} /* if( pSrcList ) */
|
||||
|
||||
@@ -353,7 +353,7 @@ static int lookupName(
|
||||
testcase( iCol==(-1) );
|
||||
if( IN_RENAME_OBJECT ){
|
||||
pExpr->iColumn = iCol;
|
||||
pExpr->y.pTab = pTab;
|
||||
sqlite3ExprAddTab(db, pExpr, pTab);
|
||||
eNewExprOp = TK_COLUMN;
|
||||
}else{
|
||||
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
|
||||
@@ -375,7 +375,7 @@ static int lookupName(
|
||||
testcase( iCol==32 );
|
||||
pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
||||
}
|
||||
pExpr->y.pTab = pTab;
|
||||
sqlite3ExprAddTab(db, pExpr, pTab);
|
||||
pExpr->iColumn = (i16)iCol;
|
||||
eNewExprOp = TK_TRIGGER;
|
||||
#endif /* SQLITE_OMIT_TRIGGER */
|
||||
@@ -428,9 +428,7 @@ static int lookupName(
|
||||
char *zAs = pEList->a[j].zName;
|
||||
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
|
||||
Expr *pOrig;
|
||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||
assert( pExpr->x.pList==0 );
|
||||
assert( pExpr->x.pSelect==0 );
|
||||
assert( pExpr->pLeft==0 );
|
||||
pOrig = pEList->a[j].pExpr;
|
||||
if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
|
||||
@@ -475,7 +473,6 @@ static int lookupName(
|
||||
assert( pExpr->op==TK_ID );
|
||||
if( ExprHasProperty(pExpr,EP_DblQuoted) ){
|
||||
pExpr->op = TK_STRING;
|
||||
pExpr->y.pTab = 0;
|
||||
return WRC_Prune;
|
||||
}
|
||||
if( sqlite3ExprIdToTrueFalse(pExpr) ){
|
||||
@@ -521,8 +518,11 @@ static int lookupName(
|
||||
*/
|
||||
sqlite3ExprDelete(db, pExpr->pLeft);
|
||||
pExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pExpr->pRight);
|
||||
pExpr->pRight = 0;
|
||||
if( pExpr->eX==EX_Right ){
|
||||
sqlite3ExprDelete(db, pExpr->x.pRight);
|
||||
pExpr->x.pRight = 0;
|
||||
pExpr->eX = EX_None;
|
||||
}
|
||||
pExpr->op = eNewExprOp;
|
||||
ExprSetProperty(pExpr, EP_Leaf);
|
||||
lookupname_end:
|
||||
@@ -553,9 +553,9 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
|
||||
if( p ){
|
||||
struct SrcList_item *pItem = &pSrc->a[iSrc];
|
||||
p->y.pTab = pItem->pTab;
|
||||
sqlite3ExprAddTab(db, p, pItem->pTab);
|
||||
p->iTable = pItem->iCursor;
|
||||
if( p->y.pTab->iPKey==iCol ){
|
||||
if( p->x.pTab->iPKey==iCol ){
|
||||
p->iColumn = -1;
|
||||
}else{
|
||||
p->iColumn = (ynVar)iCol;
|
||||
@@ -645,7 +645,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
pItem = pSrcList->a;
|
||||
assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->y.pTab = pItem->pTab;
|
||||
pExpr->pTab = pItem->pTab;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->iColumn = -1;
|
||||
pExpr->affinity = SQLITE_AFF_INTEGER;
|
||||
@@ -676,20 +676,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}else{
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
|
||||
pRight = pExpr->pRight;
|
||||
assert( pExpr->eX==EX_Right );
|
||||
pRight = pExpr->x.pRight;
|
||||
if( pRight->op==TK_ID ){
|
||||
zDb = 0;
|
||||
}else{
|
||||
assert( pRight->op==TK_DOT );
|
||||
assert( pRight->eX==EX_Right );
|
||||
zDb = pLeft->u.zToken;
|
||||
pLeft = pRight->pLeft;
|
||||
pRight = pRight->pRight;
|
||||
pRight = pRight->x.pRight;
|
||||
}
|
||||
zTable = pLeft->u.zToken;
|
||||
zColumn = pRight->u.zToken;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
|
||||
sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
|
||||
if( pExpr->eX==EX_Tab ){
|
||||
sqlite3RenameTokenRemap(pParse, (void*)&pExpr->x.pTab,(void*)pLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
|
||||
@@ -698,8 +702,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
/* Resolve function names
|
||||
*/
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pList = pExpr->x.pList; /* The argument list */
|
||||
int n = pList ? pList->nExpr : 0; /* Number of arguments */
|
||||
ExprList *pList; /* The argument list */
|
||||
int n; /* Number of arguments */
|
||||
int no_such_func = 0; /* True if no such function exists */
|
||||
int wrong_num_args = 0; /* True if wrong number of arguments */
|
||||
int is_agg = 0; /* True if is an aggregate function */
|
||||
@@ -708,7 +712,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
FuncDef *pDef; /* Information about the function */
|
||||
u8 enc = ENC(pParse->db); /* The database encoding */
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_List || pExpr->eX==EX_None );
|
||||
if( pExpr->eX==EX_List ){
|
||||
pList = pExpr->x.pList;
|
||||
n = pList->nExpr;
|
||||
}else{
|
||||
pList = 0;
|
||||
n = 0;
|
||||
}
|
||||
zId = pExpr->u.zToken;
|
||||
nId = sqlite3Strlen30(zId);
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
|
||||
@@ -779,18 +790,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
|| (pDef->xValue==0 && pDef->xInverse==0)
|
||||
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
|
||||
);
|
||||
if( pDef && pDef->xValue==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( pDef && pDef->xValue==0 && pExpr->pWin ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%.*s() may not be used as a window function", nId, zId
|
||||
);
|
||||
pNC->nErr++;
|
||||
}else if(
|
||||
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|
||||
|| (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin)
|
||||
|| (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
|| (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
|
||||
|| (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
||||
){
|
||||
const char *zType;
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
|
||||
zType = "window";
|
||||
}else{
|
||||
zType = "aggregate";
|
||||
@@ -820,7 +831,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( is_agg ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pNC->ncFlags &= ~(pExpr->y.pWin ? NC_AllowWin : NC_AllowAgg);
|
||||
pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
|
||||
#else
|
||||
pNC->ncFlags &= ~NC_AllowAgg;
|
||||
#endif
|
||||
@@ -829,17 +840,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
sqlite3WalkExprList(pWalker, pList);
|
||||
if( is_agg ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pExpr->y.pWin ){
|
||||
if( pExpr->pWin ){
|
||||
Select *pSel = pNC->pWinSelect;
|
||||
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition);
|
||||
sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy);
|
||||
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
|
||||
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef);
|
||||
sqlite3WalkExprList(pWalker, pExpr->pWin->pPartition);
|
||||
sqlite3WalkExprList(pWalker, pExpr->pWin->pOrderBy);
|
||||
sqlite3WalkExpr(pWalker, pExpr->pWin->pFilter);
|
||||
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef);
|
||||
if( 0==pSel->pWin
|
||||
|| 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin)
|
||||
|| 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin)
|
||||
){
|
||||
pExpr->y.pWin->pNextWin = pSel->pWin;
|
||||
pSel->pWin = pExpr->y.pWin;
|
||||
pExpr->pWin->pNextWin = pSel->pWin;
|
||||
pSel->pWin = pExpr->pWin;
|
||||
}
|
||||
pNC->ncFlags |= NC_AllowWin;
|
||||
}else
|
||||
@@ -873,7 +884,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
#endif
|
||||
case TK_IN: {
|
||||
testcase( pExpr->op==TK_IN );
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( pExpr->eX==EX_Select ){
|
||||
int nRef = pNC->nRef;
|
||||
notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
|
||||
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
||||
@@ -895,7 +906,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
assert( !ExprHasProperty(pExpr, EP_Reduced) );
|
||||
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
|
||||
** and "x IS NOT FALSE". */
|
||||
if( (pRight = pExpr->pRight)->op==TK_ID ){
|
||||
assert( pExpr->eX==EX_Right );
|
||||
if( (pRight = pExpr->x.pRight)->op==TK_ID ){
|
||||
int rc = resolveExprStep(pWalker, pRight);
|
||||
if( rc==WRC_Abort ) return WRC_Abort;
|
||||
if( pRight->op==TK_TRUEFALSE ){
|
||||
@@ -923,8 +935,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
|
||||
}
|
||||
}else{
|
||||
assert( pExpr->pRight!=0 );
|
||||
nRight = sqlite3ExprVectorSize(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
nRight = sqlite3ExprVectorSize(pExpr->x.pRight);
|
||||
}
|
||||
if( nLeft!=nRight ){
|
||||
testcase( pExpr->op==TK_EQ );
|
||||
@@ -1262,13 +1274,13 @@ static int resolveOrderGroupBy(
|
||||
for(j=0; j<pSelect->pEList->nExpr; j++){
|
||||
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pE, EP_WinFunc) ){
|
||||
if( pE->pWin ){
|
||||
/* Since this window function is being changed into a reference
|
||||
** to the same window function the result set, remove the instance
|
||||
** of this window function from the Select.pWin list. */
|
||||
Window **pp;
|
||||
for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
|
||||
if( *pp==pE->y.pWin ){
|
||||
if( *pp==pE->pWin ){
|
||||
*pp = (*pp)->pNextWin;
|
||||
}
|
||||
}
|
||||
|
||||
+73
-68
@@ -390,14 +390,14 @@ static void setJoinExpr(Expr *p, int iTable){
|
||||
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
||||
ExprSetVVAProperty(p, EP_NoReduce);
|
||||
p->iRightJoinTable = (i16)iTable;
|
||||
if( p->op==TK_FUNCTION && p->x.pList ){
|
||||
if( p->op==TK_FUNCTION && p->eX==EX_List ){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
setJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
||||
}
|
||||
}
|
||||
setJoinExpr(p->pLeft, iTable);
|
||||
p = p->pRight;
|
||||
p = p->eX==EX_Right ? p->x.pRight : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,14 +413,14 @@ static void unsetJoinExpr(Expr *p, int iTable){
|
||||
&& (iTable<0 || p->iRightJoinTable==iTable) ){
|
||||
ExprClearProperty(p, EP_FromJoin);
|
||||
}
|
||||
if( p->op==TK_FUNCTION && p->x.pList ){
|
||||
if( p->op==TK_FUNCTION && p->eX==EX_List ){
|
||||
int i;
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
unsetJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
||||
}
|
||||
}
|
||||
unsetJoinExpr(p->pLeft, iTable);
|
||||
p = p->pRight;
|
||||
p = p->eX==EX_Right ? p->x.pRight : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,8 +803,12 @@ static void selectExprDefer(
|
||||
struct ExprList_item *pItem = &pEList->a[i];
|
||||
if( pItem->u.x.iOrderByCol==0 ){
|
||||
Expr *pExpr = pItem->pExpr;
|
||||
Table *pTab = pExpr->y.pTab;
|
||||
if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab)
|
||||
Table *pTab;
|
||||
if( pExpr->op==TK_COLUMN
|
||||
&& pExpr->iColumn>=0
|
||||
&& ALWAYS(pExpr->eX==EX_Tab)
|
||||
&& (pTab = pExpr->x.pTab)!=0
|
||||
&& !IsVirtual(pTab)
|
||||
&& (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)
|
||||
){
|
||||
int j;
|
||||
@@ -822,16 +826,18 @@ static void selectExprDefer(
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
nKey = pPk->nKeyCol;
|
||||
}
|
||||
assert( pExpr->eX==EX_Tab );
|
||||
for(k=0; k<nKey; k++){
|
||||
Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0);
|
||||
if( pNew ){
|
||||
pNew->iTable = pExpr->iTable;
|
||||
pNew->y.pTab = pExpr->y.pTab;
|
||||
pNew->eX = EX_Tab;
|
||||
pNew->x.pTab = pExpr->x.pTab;
|
||||
pNew->iColumn = pPk ? pPk->aiColumn[k] : -1;
|
||||
pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew);
|
||||
}
|
||||
}
|
||||
pSort->aDefer[nDefer].pTab = pExpr->y.pTab;
|
||||
pSort->aDefer[nDefer].pTab = pExpr->x.pTab;
|
||||
pSort->aDefer[nDefer].iCsr = pExpr->iTable;
|
||||
pSort->aDefer[nDefer].nKey = nKey;
|
||||
nDefer++;
|
||||
@@ -1680,7 +1686,7 @@ static const char *columnTypeImpl(
|
||||
break;
|
||||
}
|
||||
|
||||
assert( pTab && pExpr->y.pTab==pTab );
|
||||
assert( pTab && pExpr->eX==EX_Tab && pExpr->x.pTab==pTab );
|
||||
if( pS ){
|
||||
/* The "table" is actually a sub-select or a view in the FROM clause
|
||||
** of the SELECT statement. Return the declaration type and origin
|
||||
@@ -1736,7 +1742,7 @@ static const char *columnTypeImpl(
|
||||
NameContext sNC;
|
||||
Select *pS = pExpr->x.pSelect;
|
||||
Expr *p = pS->pEList->a[0].pExpr;
|
||||
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
assert( pExpr->eX==EX_Select );
|
||||
sNC.pSrcList = pS->pSrc;
|
||||
sNC.pNext = pNC;
|
||||
sNC.pParse = pNC->pParse;
|
||||
@@ -1865,7 +1871,8 @@ static void generateColumnNames(
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
|
||||
assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
|
||||
/* Covering idx not yet coded: */
|
||||
assert( p->op!=TK_COLUMN || (p->eX==EX_Tab && p->x.pTab!=0) );
|
||||
if( pEList->a[i].zName ){
|
||||
/* An AS clause always takes first priority */
|
||||
char *zName = pEList->a[i].zName;
|
||||
@@ -1873,7 +1880,8 @@ static void generateColumnNames(
|
||||
}else if( srcName && p->op==TK_COLUMN ){
|
||||
char *zCol;
|
||||
int iCol = p->iColumn;
|
||||
pTab = p->y.pTab;
|
||||
assert( p->eX==EX_Tab );
|
||||
pTab = p->x.pTab;
|
||||
assert( pTab!=0 );
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
@@ -1957,14 +1965,17 @@ int sqlite3ColumnsFromExprList(
|
||||
}else{
|
||||
Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
|
||||
while( pColExpr->op==TK_DOT ){
|
||||
pColExpr = pColExpr->pRight;
|
||||
assert( pColExpr->eX==EX_Right );
|
||||
pColExpr = pColExpr->x.pRight;
|
||||
assert( pColExpr!=0 );
|
||||
}
|
||||
assert( pColExpr->op!=TK_AGG_COLUMN );
|
||||
if( pColExpr->op==TK_COLUMN ){
|
||||
/* For columns use the column name name */
|
||||
int iCol = pColExpr->iColumn;
|
||||
Table *pTab = pColExpr->y.pTab;
|
||||
Table *pTab;
|
||||
assert( pColExpr->eX==EX_Tab );
|
||||
pTab = pColExpr->x.pTab;
|
||||
assert( pTab!=0 );
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
|
||||
@@ -2125,7 +2136,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
|
||||
|
||||
/*
|
||||
** Compute the iLimit and iOffset fields of the SELECT based on the
|
||||
** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions
|
||||
** pLimit expressions. pLimit->pLeft and pLimit->x,pRight hold the expressions
|
||||
** that appear in the original SQL statement after the LIMIT and OFFSET
|
||||
** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
||||
** are the integer memory register numbers for counters used to compute
|
||||
@@ -2133,7 +2144,7 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
|
||||
** iLimit and iOffset are negative.
|
||||
**
|
||||
** This routine changes the values of iLimit and iOffset only if
|
||||
** a limit or offset is defined by pLimit->pLeft and pLimit->pRight. iLimit
|
||||
** a limit or offset is defined by pLimit->pLeft and pLimit->x.pRight. iLimit
|
||||
** and iOffset should have been preset to appropriate default values (zero)
|
||||
** prior to calling this routine.
|
||||
**
|
||||
@@ -2182,10 +2193,10 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
||||
VdbeComment((v, "LIMIT counter"));
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
|
||||
}
|
||||
if( pLimit->pRight ){
|
||||
if( pLimit->eX==EX_Right ){
|
||||
p->iOffset = iOffset = ++pParse->nMem;
|
||||
pParse->nMem++; /* Allocate an extra register for limit+offset */
|
||||
sqlite3ExprCode(pParse, pLimit->pRight, iOffset);
|
||||
sqlite3ExprCode(pParse, pLimit->x.pRight, iOffset);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
|
||||
VdbeComment((v, "OFFSET counter"));
|
||||
sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
|
||||
@@ -2318,13 +2329,6 @@ static void generateWithRecursiveQuery(
|
||||
Expr *pLimit; /* Saved LIMIT and OFFSET */
|
||||
int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( p->pWin ){
|
||||
sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Obtain authorization to do a recursive query */
|
||||
if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return;
|
||||
|
||||
@@ -3449,7 +3453,7 @@ static Expr *substExpr(
|
||||
Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
|
||||
Expr ifNullRow;
|
||||
assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
|
||||
assert( pExpr->pRight==0 );
|
||||
assert( pExpr->eX!=EX_Right );
|
||||
if( sqlite3ExprIsVector(pCopy) ){
|
||||
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
|
||||
}else{
|
||||
@@ -3478,11 +3482,20 @@ static Expr *substExpr(
|
||||
pExpr->iTable = pSubst->iNewTable;
|
||||
}
|
||||
pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
|
||||
pExpr->pRight = substExpr(pSubst, pExpr->pRight);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
substSelect(pSubst, pExpr->x.pSelect, 1);
|
||||
}else{
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
switch( pExpr->eX ){
|
||||
case EX_Select: {
|
||||
substSelect(pSubst, pExpr->x.pSelect, 1);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
substExprList(pSubst, pExpr->x.pList);
|
||||
break;
|
||||
}
|
||||
case EX_Right: {
|
||||
pExpr->x.pRight = substExpr(pSubst, pExpr->x.pRight);
|
||||
if( pExpr->x.pRight==0 ) pExpr->eX = EX_None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pExpr;
|
||||
@@ -3722,7 +3735,9 @@ static int flattenSubquery(
|
||||
** became arbitrary expressions, we were forced to add restrictions (13)
|
||||
** and (14). */
|
||||
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
||||
if( pSub->pLimit && pSub->pLimit->pRight ) return 0; /* Restriction (14) */
|
||||
if( pSub->pLimit && pSub->pLimit->eX==EX_Right ){
|
||||
return 0; /* Restriction (14) */
|
||||
}
|
||||
if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
@@ -4074,7 +4089,7 @@ static int flattenSubquery(
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** A structure to keep track of all of the column values that are fixed to
|
||||
** A structure to keep track of all of the column values that fixed to
|
||||
** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
|
||||
*/
|
||||
typedef struct WhereConst WhereConst;
|
||||
@@ -4086,28 +4101,13 @@ struct WhereConst {
|
||||
};
|
||||
|
||||
/*
|
||||
** Add a new entry to the pConst object. Except, do not add duplicate
|
||||
** pColumn entires.
|
||||
** Add a new entry to the pConst object
|
||||
*/
|
||||
static void constInsert(
|
||||
WhereConst *pConst, /* The WhereConst into which we are inserting */
|
||||
Expr *pColumn, /* The COLUMN part of the constraint */
|
||||
Expr *pValue /* The VALUE part of the constraint */
|
||||
WhereConst *pConst,
|
||||
Expr *pColumn,
|
||||
Expr *pValue
|
||||
){
|
||||
int i;
|
||||
assert( pColumn->op==TK_COLUMN );
|
||||
|
||||
/* 2018-10-25 ticket [cf5ed20f]
|
||||
** Make sure the same pColumn is not inserted more than once */
|
||||
for(i=0; i<pConst->nConst; i++){
|
||||
const Expr *pExpr = pConst->apExpr[i*2];
|
||||
assert( pExpr->op==TK_COLUMN );
|
||||
if( pExpr->iTable==pColumn->iTable
|
||||
&& pExpr->iColumn==pColumn->iColumn
|
||||
){
|
||||
return; /* Already present. Return without doing anything. */
|
||||
}
|
||||
}
|
||||
|
||||
pConst->nConst++;
|
||||
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
|
||||
@@ -4132,26 +4132,28 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
|
||||
if( pExpr==0 ) return;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
|
||||
if( pExpr->op==TK_AND ){
|
||||
findConstInWhere(pConst, pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
findConstInWhere(pConst, pExpr->x.pRight);
|
||||
findConstInWhere(pConst, pExpr->pLeft);
|
||||
return;
|
||||
}
|
||||
if( pExpr->op!=TK_EQ ) return;
|
||||
pRight = pExpr->pRight;
|
||||
assert( pExpr->eX==EX_Right );
|
||||
pRight = pExpr->x.pRight;
|
||||
pLeft = pExpr->pLeft;
|
||||
assert( pRight!=0 );
|
||||
assert( pLeft!=0 );
|
||||
if( pRight->op==TK_COLUMN
|
||||
&& !ExprHasProperty(pRight, EP_FixedCol)
|
||||
&& sqlite3ExprIsConstant(pLeft)
|
||||
&& sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
|
||||
&& sqlite3IsBinary(sqlite3ComparisonCollSeq(pConst->pParse,pLeft,pRight))
|
||||
){
|
||||
constInsert(pConst, pRight, pLeft);
|
||||
}else
|
||||
if( pLeft->op==TK_COLUMN
|
||||
&& !ExprHasProperty(pLeft, EP_FixedCol)
|
||||
&& sqlite3ExprIsConstant(pRight)
|
||||
&& sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
|
||||
&& sqlite3IsBinary(sqlite3ComparisonCollSeq(pConst->pParse,pLeft,pRight))
|
||||
){
|
||||
constInsert(pConst, pLeft, pRight);
|
||||
}
|
||||
@@ -4338,7 +4340,8 @@ static int pushDownWhereTerms(
|
||||
return 0; /* restriction (3) */
|
||||
}
|
||||
while( pWhere->op==TK_AND ){
|
||||
nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight,
|
||||
assert( pWhere->eX==EX_Right );
|
||||
nChng += pushDownWhereTerms(pParse, pSubq, pWhere->x.pRight,
|
||||
iCursor, isLeftJoin);
|
||||
pWhere = pWhere->pLeft;
|
||||
}
|
||||
@@ -4924,9 +4927,9 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
pE = pEList->a[k].pExpr;
|
||||
if( pE->op==TK_ASTERISK ) break;
|
||||
assert( pE->op!=TK_DOT || pE->pRight!=0 );
|
||||
assert( pE->op!=TK_DOT || pE->eX==EX_Right );
|
||||
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
|
||||
if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
|
||||
if( pE->op==TK_DOT && pE->x.pRight->op==TK_ASTERISK ) break;
|
||||
elistFlags |= pE->flags;
|
||||
}
|
||||
if( k<pEList->nExpr ){
|
||||
@@ -4944,7 +4947,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
pE = a[k].pExpr;
|
||||
elistFlags |= pE->flags;
|
||||
pRight = pE->pRight;
|
||||
pRight = pE->eX==EX_Right ? pE->x.pRight : 0;
|
||||
assert( pE->op!=TK_DOT || pRight!=0 );
|
||||
if( pE->op!=TK_ASTERISK
|
||||
&& (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK)
|
||||
@@ -5264,8 +5267,8 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
|
||||
if( pFunc->iDistinct>=0 ){
|
||||
Expr *pE = pFunc->pExpr;
|
||||
assert( !ExprHasProperty(pE, EP_xIsSelect) );
|
||||
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
|
||||
assert( pE->eX==EX_List || pE->eX==EX_None );
|
||||
if( pE->eX==EX_None || pE->x.pList->nExpr!=1 ){
|
||||
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
|
||||
"argument");
|
||||
pFunc->iDistinct = -1;
|
||||
@@ -5288,7 +5291,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
||||
struct AggInfo_func *pF;
|
||||
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
||||
ExprList *pList = pF->pExpr->x.pList;
|
||||
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
||||
assert( pF->pExpr->eX==EX_List || pF->pExpr->eX==EX_None );
|
||||
assert( pF->pExpr->eX==EX_List || pList==0 );
|
||||
sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
|
||||
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
||||
}
|
||||
@@ -5318,7 +5322,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||
int addrNext = 0;
|
||||
int regAgg;
|
||||
ExprList *pList = pF->pExpr->x.pList;
|
||||
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
||||
assert( pF->pExpr->eX==EX_List || pF->pExpr->eX==EX_None );
|
||||
if( pList ){
|
||||
nArg = pList->nExpr;
|
||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||
@@ -6208,10 +6212,11 @@ int sqlite3Select(
|
||||
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
||||
}
|
||||
for(i=0; i<sAggInfo.nFunc; i++){
|
||||
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
|
||||
sNC.ncFlags &= ~NC_InAggFunc;
|
||||
if( sAggInfo.aFunc[i].pExpr->eX==EX_List ){
|
||||
sNC.ncFlags |= NC_InAggFunc;
|
||||
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
|
||||
sNC.ncFlags &= ~NC_InAggFunc;
|
||||
}
|
||||
}
|
||||
sAggInfo.mxReg = pParse->nMem;
|
||||
if( db->mallocFailed ) goto select_end;
|
||||
|
||||
+142
-229
@@ -1273,7 +1273,7 @@ static void editFunc(
|
||||
if( bBin ){
|
||||
sqlite3_result_blob64(context, p, sz, sqlite3_free);
|
||||
}else{
|
||||
sqlite3_int64 i, j;
|
||||
int i, j;
|
||||
if( hasCRNL ){
|
||||
/* If the original contains \r\n then do no conversions back to \n */
|
||||
j = sz;
|
||||
@@ -3335,235 +3335,137 @@ static int run_schema_dump_query(
|
||||
}
|
||||
|
||||
/*
|
||||
** Text of help messages.
|
||||
**
|
||||
** The help text for each individual command begins with a line that starts
|
||||
** with ".". Subsequent lines are supplimental information.
|
||||
**
|
||||
** There must be two or more spaces between the end of the command and the
|
||||
** start of the description of what that command does.
|
||||
** Text of a help message
|
||||
*/
|
||||
static const char *(azHelp[]) = {
|
||||
static char zHelp[] =
|
||||
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
".archive ... Manage SQL archives",
|
||||
" Each command must have exactly one of the following options:",
|
||||
" -c, --create Create a new archive",
|
||||
" -u, --update Update or add files to an existing archive",
|
||||
" -t, --list List contents of archive",
|
||||
" -x, --extract Extract files from archive",
|
||||
" Optional arguments:",
|
||||
" -v, --verbose Print each filename as it is processed",
|
||||
" -f FILE, --file FILE Operate on archive FILE (default is current db)",
|
||||
" -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS",
|
||||
" -C DIR, --directory DIR Change to directory DIR to read/extract files",
|
||||
" -n, --dryrun Show the SQL that would have occurred",
|
||||
" Examples:",
|
||||
" .ar -cf archive.sar foo bar # Create archive.sar from files foo and bar",
|
||||
" .ar -tf archive.sar # List members of archive.sar",
|
||||
" .ar -xvf archive.sar # Verbosely extract files from archive.sar",
|
||||
" See also:",
|
||||
" http://sqlite.org/cli.html#sqlar_archive_support",
|
||||
".archive ... Manage SQL archives: \".archive --help\" for details\n"
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
".auth ON|OFF Show authorizer callbacks",
|
||||
".auth ON|OFF Show authorizer callbacks\n"
|
||||
#endif
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE",
|
||||
" --append Use the appendvfs",
|
||||
".bail on|off Stop after hitting an error. Default OFF",
|
||||
".binary on|off Turn binary output on or off. Default OFF",
|
||||
".cd DIRECTORY Change the working directory to DIRECTORY",
|
||||
".changes on|off Show number of rows changed by SQL",
|
||||
".check GLOB Fail if output since .testcase does not match",
|
||||
".clone NEWDB Clone data into NEWDB from the existing database",
|
||||
".databases List names and files of attached databases",
|
||||
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
|
||||
".dbinfo ?DB? Show status information about the database",
|
||||
".dump ?TABLE? ... Render all database content as SQL",
|
||||
" Options:",
|
||||
" --preserve-rowids Include ROWID values in the output",
|
||||
" --newlines Allow unescaped newline characters in output",
|
||||
" TABLE is LIKE pattern for the tables to dump",
|
||||
".echo on|off Turn command echo on or off",
|
||||
".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN",
|
||||
".excel Display the output of next command in a spreadsheet",
|
||||
".exit ?CODE? Exit this program with return-code CODE",
|
||||
".expert EXPERIMENTAL. Suggest indexes for specified queries",
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
|
||||
" Add \"--append\" to open using appendvfs.\n"
|
||||
".bail on|off Stop after hitting an error. Default OFF\n"
|
||||
".binary on|off Turn binary output on or off. Default OFF\n"
|
||||
".cd DIRECTORY Change the working directory to DIRECTORY\n"
|
||||
".changes on|off Show number of rows changed by SQL\n"
|
||||
".check GLOB Fail if output since .testcase does not match\n"
|
||||
".clone NEWDB Clone data into NEWDB from the existing database\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dbconfig ?op? ?val? List or change sqlite3_db_config() options\n"
|
||||
".dbinfo ?DB? Show status information about the database\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".echo on|off Turn command echo on or off\n"
|
||||
".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
|
||||
".excel Display the output of next command in a spreadsheet\n"
|
||||
".exit Exit this program\n"
|
||||
".expert EXPERIMENTAL. Suggest indexes for specified queries\n"
|
||||
/* Because explain mode comes on automatically now, the ".explain" mode
|
||||
** is removed from the help screen. It is still supported for legacy, however */
|
||||
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic",*/
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
|
||||
".headers on|off Turn display of headers on or off",
|
||||
".help ?-all? ?PATTERN? Show help text for PATTERN",
|
||||
".import FILE TABLE Import data from FILE into TABLE",
|
||||
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
|
||||
".headers on|off Turn display of headers on or off\n"
|
||||
".help Show this message\n"
|
||||
".import FILE TABLE Import data from FILE into TABLE\n"
|
||||
#ifndef SQLITE_OMIT_TEST_CONTROL
|
||||
".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
|
||||
".imposter INDEX TABLE Create imposter table TABLE on index INDEX\n"
|
||||
#endif
|
||||
".indexes ?TABLE? Show names of indexes",
|
||||
" If TABLE is specified, only show indexes for",
|
||||
" tables matching TABLE using the LIKE operator.",
|
||||
".indexes ?TABLE? Show names of all indexes\n"
|
||||
" If TABLE specified, only show indexes for tables\n"
|
||||
" matching LIKE pattern TABLE.\n"
|
||||
#ifdef SQLITE_ENABLE_IOTRACE
|
||||
".iotrace FILE Enable I/O diagnostic logging to FILE",
|
||||
".iotrace FILE Enable I/O diagnostic logging to FILE\n"
|
||||
#endif
|
||||
".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
|
||||
".lint OPTIONS Report potential schema issues.",
|
||||
" Options:",
|
||||
" fkey-indexes Find missing foreign key indexes",
|
||||
".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
|
||||
".lint OPTIONS Report potential schema issues. Options:\n"
|
||||
" fkey-indexes Find missing foreign key indexes\n"
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
".load FILE ?ENTRY? Load an extension library",
|
||||
".load FILE ?ENTRY? Load an extension library\n"
|
||||
#endif
|
||||
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
|
||||
".mode MODE ?TABLE? Set output mode",
|
||||
" MODE is one of:",
|
||||
" ascii Columns/rows delimited by 0x1F and 0x1E",
|
||||
" csv Comma-separated values",
|
||||
" column Left-aligned columns. (See .width)",
|
||||
" html HTML <table> code",
|
||||
" insert SQL insert statements for TABLE",
|
||||
" line One value per line",
|
||||
" list Values delimited by \"|\"",
|
||||
" quote Escape answers as for SQL",
|
||||
" tabs Tab-separated values",
|
||||
" tcl TCL list elements",
|
||||
".nullvalue STRING Use STRING in place of NULL values",
|
||||
".once (-e|-x|FILE) Output for the next SQL command only to FILE",
|
||||
" If FILE begins with '|' then open as a pipe",
|
||||
" Other options:",
|
||||
" -e Invoke system text editor",
|
||||
" -x Open in a spreadsheet",
|
||||
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
|
||||
" Options:",
|
||||
" --append Use appendvfs to append database to the end of FILE",
|
||||
" --new Initialize FILE to an empty database",
|
||||
" --readonly Open FILE readonly",
|
||||
" --zip FILE is a ZIP archive",
|
||||
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
|
||||
" If FILE begins with '|' then open it as a pipe.",
|
||||
".print STRING... Print literal STRING",
|
||||
".prompt MAIN CONTINUE Replace the standard prompts",
|
||||
".quit Exit this program",
|
||||
".read FILE Read input from FILE",
|
||||
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
|
||||
".save FILE Write in-memory database into FILE",
|
||||
".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off",
|
||||
".schema ?PATTERN? Show the CREATE statements matching PATTERN",
|
||||
" Options:",
|
||||
" --indent Try to pretty-print the schema",
|
||||
".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
|
||||
" Options:",
|
||||
" --init Create a new SELFTEST table",
|
||||
" -v Verbose output",
|
||||
".separator COL ?ROW? Change the column and row separators",
|
||||
".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
|
||||
".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
|
||||
" ascii Columns/rows delimited by 0x1F and 0x1E\n"
|
||||
" csv Comma-separated values\n"
|
||||
" column Left-aligned columns. (See .width)\n"
|
||||
" html HTML <table> code\n"
|
||||
" insert SQL insert statements for TABLE\n"
|
||||
" line One value per line\n"
|
||||
" list Values delimited by \"|\"\n"
|
||||
" quote Escape answers as for SQL\n"
|
||||
" tabs Tab-separated values\n"
|
||||
" tcl TCL list elements\n"
|
||||
".nullvalue STRING Use STRING in place of NULL values\n"
|
||||
".once (-e|-x|FILE) Output for the next SQL command only to FILE\n"
|
||||
" or invoke system text editor (-e) or spreadsheet (-x)\n"
|
||||
" on the output.\n"
|
||||
".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
|
||||
" The --new option starts with an empty file\n"
|
||||
" Other options: --readonly --append --zip\n"
|
||||
".output ?FILE? Send output to FILE or stdout\n"
|
||||
".print STRING... Print literal STRING\n"
|
||||
".prompt MAIN CONTINUE Replace the standard prompts\n"
|
||||
".quit Exit this program\n"
|
||||
".read FILENAME Execute SQL in FILENAME\n"
|
||||
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
|
||||
".save FILE Write in-memory database into FILE\n"
|
||||
".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
|
||||
".schema ?PATTERN? Show the CREATE statements matching PATTERN\n"
|
||||
" Add --indent for pretty-printing\n"
|
||||
".selftest ?--init? Run tests defined in the SELFTEST table\n"
|
||||
".separator COL ?ROW? Change the column separator and optionally the row\n"
|
||||
" separator for both the output mode and .import\n"
|
||||
#if defined(SQLITE_ENABLE_SESSION)
|
||||
".session ?NAME? CMD ... Create or control sessions",
|
||||
" Subcommands:",
|
||||
" attach TABLE Attach TABLE",
|
||||
" changeset FILE Write a changeset into FILE",
|
||||
" close Close one session",
|
||||
" enable ?BOOLEAN? Set or query the enable bit",
|
||||
" filter GLOB... Reject tables matching GLOBs",
|
||||
" indirect ?BOOLEAN? Mark or query the indirect status",
|
||||
" isempty Query whether the session is empty",
|
||||
" list List currently open session names",
|
||||
" open DB NAME Open a new session on DB",
|
||||
" patchset FILE Write a patchset into FILE",
|
||||
" If ?NAME? is omitted, the first defined session is used.",
|
||||
".session CMD ... Create or control sessions\n"
|
||||
#endif
|
||||
".sha3sum ... Compute a SHA3 hash of database content",
|
||||
" Options:",
|
||||
" --schema Also hash the sqlite_master table",
|
||||
" --sha3-224 Use the sha3-224 algorithm",
|
||||
" --sha3-256 Use the sha3-256 algorithm. This is the default.",
|
||||
" --sha3-384 Use the sha3-384 algorithm",
|
||||
" --sha3-512 Use the sha3-512 algorithm",
|
||||
" Any other argument is a LIKE pattern for tables to hash",
|
||||
".sha3sum ?OPTIONS...? Compute a SHA3 hash of database content\n"
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell",
|
||||
".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
|
||||
#endif
|
||||
".show Show the current values for various settings",
|
||||
".stats ?on|off? Show stats or turn stats on or off",
|
||||
".show Show the current values for various settings\n"
|
||||
".stats ?on|off? Show stats or turn stats on or off\n"
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
".system CMD ARGS... Run CMD ARGS... in a system shell",
|
||||
".system CMD ARGS... Run CMD ARGS... in a system shell\n"
|
||||
#endif
|
||||
".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
|
||||
".testcase NAME Begin redirecting output to 'testcase-out.txt'",
|
||||
".timeout MS Try opening locked tables for MS milliseconds",
|
||||
".timer on|off Turn SQL timer on or off",
|
||||
".trace FILE|off Output each SQL statement as it is run",
|
||||
".vfsinfo ?AUX? Information about the top-level VFS",
|
||||
".vfslist List all available VFSes",
|
||||
".vfsname ?AUX? Print the name of the VFS stack",
|
||||
".width NUM1 NUM2 ... Set column widths for \"column\" mode",
|
||||
" Negative values right-justify",
|
||||
};
|
||||
".tables ?TABLE? List names of tables\n"
|
||||
" If TABLE specified, only list tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".testcase NAME Begin redirecting output to 'testcase-out.txt'\n"
|
||||
".timeout MS Try opening locked tables for MS milliseconds\n"
|
||||
".timer on|off Turn SQL timer on or off\n"
|
||||
".trace FILE|off Output each SQL statement as it is run\n"
|
||||
".vfsinfo ?AUX? Information about the top-level VFS\n"
|
||||
".vfslist List all available VFSes\n"
|
||||
".vfsname ?AUX? Print the name of the VFS stack\n"
|
||||
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
|
||||
" Negative values right-justify\n"
|
||||
;
|
||||
|
||||
#if defined(SQLITE_ENABLE_SESSION)
|
||||
/*
|
||||
** Output help text.
|
||||
**
|
||||
** zPattern describes the set of commands for which help text is provided.
|
||||
** If zPattern is NULL, then show all commands, but only give a one-line
|
||||
** description of each.
|
||||
**
|
||||
** Return the number of matches.
|
||||
** Print help information for the ".sessions" command
|
||||
*/
|
||||
static int showHelp(FILE *out, const char *zPattern){
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int n = 0;
|
||||
char *zPat;
|
||||
if( zPattern==0
|
||||
|| zPattern[0]=='0'
|
||||
|| strcmp(zPattern,"-a")==0
|
||||
|| strcmp(zPattern,"-all")==0
|
||||
){
|
||||
/* Show all commands, but only one line per command */
|
||||
if( zPattern==0 ) zPattern = "";
|
||||
for(i=0; i<ArraySize(azHelp); i++){
|
||||
if( azHelp[i][0]=='.' || zPattern[0] ){
|
||||
utf8_printf(out, "%s\n", azHelp[i]);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Look for commands that for which zPattern is an exact prefix */
|
||||
zPat = sqlite3_mprintf(".%s*", zPattern);
|
||||
for(i=0; i<ArraySize(azHelp); i++){
|
||||
if( sqlite3_strglob(zPat, azHelp[i])==0 ){
|
||||
utf8_printf(out, "%s\n", azHelp[i]);
|
||||
j = i+1;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
sqlite3_free(zPat);
|
||||
if( n ){
|
||||
if( n==1 ){
|
||||
/* when zPattern is a prefix of exactly one command, then include the
|
||||
** details of that command, which should begin at offset j */
|
||||
while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){
|
||||
utf8_printf(out, "%s\n", azHelp[j]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
/* Look for commands that contain zPattern anywhere. Show the complete
|
||||
** text of all commands that match. */
|
||||
zPat = sqlite3_mprintf("%%%s%%", zPattern);
|
||||
for(i=0; i<ArraySize(azHelp); i++){
|
||||
if( azHelp[i][0]=='.' ) j = i;
|
||||
if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
|
||||
utf8_printf(out, "%s\n", azHelp[j]);
|
||||
while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
|
||||
j++;
|
||||
utf8_printf(out, "%s\n", azHelp[j]);
|
||||
}
|
||||
i = j;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
sqlite3_free(zPat);
|
||||
}
|
||||
return n;
|
||||
void session_help(ShellState *p){
|
||||
raw_printf(p->out,
|
||||
".session ?NAME? SUBCOMMAND ?ARGS...?\n"
|
||||
"If ?NAME? is omitted, the first defined session is used.\n"
|
||||
"Subcommands:\n"
|
||||
" attach TABLE Attach TABLE\n"
|
||||
" changeset FILE Write a changeset into FILE\n"
|
||||
" close Close one session\n"
|
||||
" enable ?BOOLEAN? Set or query the enable bit\n"
|
||||
" filter GLOB... Reject tables matching GLOBs\n"
|
||||
" indirect ?BOOLEAN? Mark or query the indirect status\n"
|
||||
" isempty Query whether the session is empty\n"
|
||||
" list List currently open session names\n"
|
||||
" open DB NAME Open a new session on DB\n"
|
||||
" patchset FILE Write a patchset into FILE\n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Forward reference */
|
||||
static int process_input(ShellState *p, FILE *in);
|
||||
@@ -3593,7 +3495,7 @@ static char *readFile(const char *zName, int *pnByte){
|
||||
nIn = ftell(in);
|
||||
rewind(in);
|
||||
pBuf = sqlite3_malloc64( nIn+1 );
|
||||
if( pBuf==0 ){ fclose(in); return 0; }
|
||||
if( pBuf==0 ) return 0;
|
||||
nRead = fread(pBuf, nIn, 1, in);
|
||||
fclose(in);
|
||||
if( nRead!=1 ){
|
||||
@@ -4977,7 +4879,6 @@ static void shellPreparePrintf(
|
||||
char *z;
|
||||
va_start(ap, zFmt);
|
||||
z = sqlite3_vmprintf(zFmt, ap);
|
||||
va_end(ap);
|
||||
if( z==0 ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
}else{
|
||||
@@ -5040,7 +4941,32 @@ struct ArCommand {
|
||||
** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
|
||||
*/
|
||||
static int arUsage(FILE *f){
|
||||
showHelp(f,"archive");
|
||||
raw_printf(f,
|
||||
"\n"
|
||||
"Usage: .ar [OPTION...] [FILE...]\n"
|
||||
"The .ar command manages sqlar archives.\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" .ar -cf archive.sar foo bar # Create archive.sar from files foo and bar\n"
|
||||
" .ar -tf archive.sar # List members of archive.sar\n"
|
||||
" .ar -xvf archive.sar # Verbosely extract files from archive.sar\n"
|
||||
"\n"
|
||||
"Each command line must feature exactly one command option:\n"
|
||||
" -c, --create Create a new archive\n"
|
||||
" -u, --update Update or add files to an existing archive\n"
|
||||
" -t, --list List contents of archive\n"
|
||||
" -x, --extract Extract files from archive\n"
|
||||
"\n"
|
||||
"And zero or more optional options:\n"
|
||||
" -v, --verbose Print each filename as it is processed\n"
|
||||
" -f FILE, --file FILE Operate on archive FILE (default is current db)\n"
|
||||
" -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS\n"
|
||||
" -C DIR, --directory DIR Change to directory DIR to read/extract files\n"
|
||||
" -n, --dryrun Show the SQL that would have occurred\n"
|
||||
"\n"
|
||||
"See also: http://sqlite.org/cli.html#sqlar_archive_support\n"
|
||||
"\n"
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -5147,7 +5073,6 @@ static int arParseCommand(
|
||||
struct ArSwitch *pEnd = &aSwitch[nSwitch];
|
||||
|
||||
if( nArg<=1 ){
|
||||
utf8_printf(stderr, "Wrong number of arguments. Usage:\n");
|
||||
return arUsage(stderr);
|
||||
}else{
|
||||
char *z = azArg[1];
|
||||
@@ -5919,10 +5844,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
|
||||
if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
|
||||
static const struct DbConfigChoices {
|
||||
const char *zName;
|
||||
int op;
|
||||
} aDbConfig[] = {
|
||||
static const struct DbConfigChoices {const char *zName; int op;} aDbConfig[] = {
|
||||
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
|
||||
{ "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
|
||||
{ "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
|
||||
@@ -6169,14 +6091,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
|
||||
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
|
||||
if( nArg>=2 ){
|
||||
n = showHelp(p->out, azArg[1]);
|
||||
if( n==0 ){
|
||||
utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
|
||||
}
|
||||
}else{
|
||||
showHelp(p->out, 0);
|
||||
}
|
||||
utf8_printf(p->out, "%s", zHelp);
|
||||
}else
|
||||
|
||||
if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
|
||||
@@ -7180,7 +7095,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else
|
||||
/* If no command name matches, show a syntax error */
|
||||
session_syntax_error:
|
||||
showHelp(p->out, "session");
|
||||
session_help(p);
|
||||
}else
|
||||
#endif
|
||||
|
||||
@@ -8860,7 +8775,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
*/
|
||||
if( stdin_is_interactive ){
|
||||
char *zHome;
|
||||
char *zHistory;
|
||||
char *zHistory = 0;
|
||||
int nHistory;
|
||||
printf(
|
||||
"SQLite version %s %.19s\n" /*extra-version-info*/
|
||||
@@ -8873,10 +8788,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
printf(".\nUse \".open FILENAME\" to reopen on a "
|
||||
"persistent database.\n");
|
||||
}
|
||||
zHistory = getenv("SQLITE_HISTORY");
|
||||
if( zHistory ){
|
||||
zHistory = strdup(zHistory);
|
||||
}else if( (zHome = find_home_dir(0))!=0 ){
|
||||
zHome = find_home_dir(0);
|
||||
if( zHome ){
|
||||
nHistory = strlen30(zHome) + 20;
|
||||
if( (zHistory = malloc(nHistory))!=0 ){
|
||||
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
|
||||
|
||||
+2
-19
@@ -3609,19 +3609,9 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** on this hint by avoiding the use of [lookaside memory] so as not to
|
||||
** deplete the limited store of lookaside memory. Future versions of
|
||||
** SQLite may act on this hint differently.
|
||||
**
|
||||
** [[SQLITE_PREPARE_NORMALIZE]] ^(<dt>SQLITE_PREPARE_NORMALIZE</dt>
|
||||
** <dd>The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized
|
||||
** representation of the SQL statement should be calculated and then
|
||||
** associated with the prepared statement, which can be obtained via
|
||||
** the [sqlite3_normalized_sql()] interface. The semantics used to
|
||||
** normalize a SQL statement are unspecified and subject to change.
|
||||
** At a minimum, literal values will be replaced with suitable
|
||||
** placeholders.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_PREPARE_PERSISTENT 0x01
|
||||
#define SQLITE_PREPARE_NORMALIZE 0x02
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compiling An SQL Statement
|
||||
@@ -3779,11 +3769,6 @@ int sqlite3_prepare16_v3(
|
||||
** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
|
||||
** string containing the SQL text of prepared statement P with
|
||||
** [bound parameters] expanded.
|
||||
** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8
|
||||
** string containing the normalized SQL text of prepared statement P. The
|
||||
** semantics used to normalize a SQL statement are unspecified and subject
|
||||
** to change. At a minimum, literal values will be replaced with suitable
|
||||
** placeholders.
|
||||
**
|
||||
** ^(For example, if a prepared statement is created using the SQL
|
||||
** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
|
||||
@@ -3799,16 +3784,14 @@ int sqlite3_prepare16_v3(
|
||||
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
|
||||
** option causes sqlite3_expanded_sql() to always return NULL.
|
||||
**
|
||||
** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P)
|
||||
** are managed by SQLite and are automatically freed when the prepared
|
||||
** statement is finalized.
|
||||
** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
|
||||
** automatically freed when the prepared statement is finalized.
|
||||
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
||||
** is obtained from [sqlite3_malloc()] and must be free by the application
|
||||
** by passing it to [sqlite3_free()].
|
||||
*/
|
||||
const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
||||
const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||
|
||||
@@ -310,15 +310,12 @@ struct sqlite3_api_routines {
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -606,8 +603,6 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+28
-34
@@ -1312,8 +1312,6 @@ struct FuncDefHash {
|
||||
FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
|
||||
};
|
||||
|
||||
#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
|
||||
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
/*
|
||||
** Information held in the "sqlite3" database connection object and used
|
||||
@@ -1538,7 +1536,6 @@ struct sqlite3 {
|
||||
#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/
|
||||
#define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_ResetDatabase 0x02000000 /* Reset the database */
|
||||
#define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */
|
||||
|
||||
/* Flags used only if debugging */
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -1945,9 +1942,6 @@ struct VTable {
|
||||
struct Table {
|
||||
char *zName; /* Name of the table or view */
|
||||
Column *aCol; /* Information about each column */
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
Hash *pColHash; /* All columns indexed by name */
|
||||
#endif
|
||||
Index *pIndex; /* List of SQL indexes on this table. */
|
||||
Select *pSelect; /* NULL for tables. Points to definition if a view. */
|
||||
FKey *pFKey; /* Linked list of all foreign keys in this table */
|
||||
@@ -2284,12 +2278,6 @@ struct IndexSample {
|
||||
tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */
|
||||
};
|
||||
|
||||
/*
|
||||
** Possible values to use within the flags argument to sqlite3GetToken().
|
||||
*/
|
||||
#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */
|
||||
#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */
|
||||
|
||||
/*
|
||||
** Each token coming out of the lexer is an instance of
|
||||
** this structure. Tokens are also used as part of an expression.
|
||||
@@ -2431,6 +2419,8 @@ typedef int ynVar;
|
||||
struct Expr {
|
||||
u8 op; /* Operation performed by this node */
|
||||
char affinity; /* The affinity of the column or 0 if not a column */
|
||||
u8 eV; /* Which element of v-union is used */
|
||||
u8 eX; /* Which element of x-union is used */
|
||||
u32 flags; /* Various flags. EP_* See below */
|
||||
union {
|
||||
char *zToken; /* Token value. Zero terminated and dequoted */
|
||||
@@ -2443,10 +2433,12 @@ struct Expr {
|
||||
*********************************************************************/
|
||||
|
||||
Expr *pLeft; /* Left subnode */
|
||||
Expr *pRight; /* Right subnode */
|
||||
union {
|
||||
Expr *pRight; /* Right subnode */
|
||||
ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */
|
||||
Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */
|
||||
Table *pTab; /* Table for TK_COLUMN expressions. Can be NULL
|
||||
** for a column of an index on an expression */
|
||||
} x;
|
||||
|
||||
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
|
||||
@@ -2471,13 +2463,25 @@ struct Expr {
|
||||
** TK_COLUMN: the value of p5 for OP_Column
|
||||
** TK_AGG_FUNCTION: nesting depth */
|
||||
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||
union {
|
||||
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
||||
** for a column of an index on an expression */
|
||||
Window *pWin; /* TK_FUNCTION: Window definition for the func */
|
||||
} y;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
Window *pWin; /* Window definition for window functions */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for the Expr.eV and Expr.eX fields:
|
||||
*/
|
||||
#define EV_None 0 /* Expr.v is not used */
|
||||
#define EV_Left 1 /* Expr.v.pLeft */
|
||||
#define EV_Vector 2 /* Expr.v.pVector */
|
||||
#define EV_Win 3 /* Expr.v.pWin */
|
||||
|
||||
#define EX_None 0 /* Expr.x is not used */
|
||||
#define EX_Right 1 /* Expr.x.pRight */
|
||||
#define EX_List 2 /* Expr.x.pList */
|
||||
#define EX_Select 3 /* Expr.x.pSelect */
|
||||
#define EX_Tab 4 /* Expr.x.pTab */
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags field.
|
||||
*/
|
||||
@@ -2492,7 +2496,7 @@ struct Expr {
|
||||
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
||||
#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
|
||||
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
/* 0x000800 -- Available for reuse */
|
||||
#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
|
||||
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
||||
@@ -2505,7 +2509,6 @@ struct Expr {
|
||||
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
||||
#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
||||
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
||||
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
||||
|
||||
/*
|
||||
** The EP_Propagate mask is a set of properties that automatically propagate
|
||||
@@ -3191,7 +3194,6 @@ struct AuthContext {
|
||||
*/
|
||||
#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
|
||||
/* Also used in P2 (not P5) of OP_Delete */
|
||||
#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */
|
||||
#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
|
||||
#define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */
|
||||
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
|
||||
@@ -3808,10 +3810,13 @@ Expr *sqlite3Expr(sqlite3*,int,const char*);
|
||||
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
|
||||
Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
|
||||
void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
|
||||
void sqlite3PExprAddExprList(Parse*, Expr*, ExprList*);
|
||||
void sqlite3ExprAddTab(sqlite3*, Expr*, Table*);
|
||||
Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
|
||||
Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
|
||||
void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
|
||||
void sqlite3ExprDelete(sqlite3*, Expr*);
|
||||
void sqlite3ExprClearXUnion(sqlite3*,Expr*);
|
||||
ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
||||
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
|
||||
void sqlite3ExprListSetSortOrder(ExprList*,int);
|
||||
@@ -4011,9 +4016,6 @@ int sqlite3ExprIsInteger(Expr*, int*);
|
||||
int sqlite3ExprCanBeNull(const Expr*);
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||
int sqlite3IsRowid(const char*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
int sqlite3IsRowidN(const char*, int);
|
||||
#endif
|
||||
void sqlite3GenerateRowDelete(
|
||||
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
|
||||
@@ -4040,9 +4042,6 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
||||
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
||||
IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
||||
Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
FuncDef *sqlite3FunctionSearchN(int,const char*,int);
|
||||
#endif
|
||||
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
|
||||
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
|
||||
void sqlite3RegisterBuiltinFunctions(void);
|
||||
@@ -4246,9 +4245,6 @@ void sqlite3AlterFunctions(void);
|
||||
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
int sqlite3GetTokenNormalized(const unsigned char *, int *, int *);
|
||||
#endif
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
||||
int sqlite3CodeSubselect(Parse*, Expr *, int, int);
|
||||
@@ -4406,12 +4402,10 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
void sqlite3ParserReset(Parse*);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
void sqlite3Normalize(Vdbe*, const char*, int, u8);
|
||||
#endif
|
||||
int sqlite3Reprepare(Vdbe*);
|
||||
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
||||
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
||||
CollSeq *sqlite3ComparisonCollSeq(Parse*,Expr*,Expr*);
|
||||
CollSeq *sqlite3ComparisonExprCollSeq(Parse*,Expr*);
|
||||
int sqlite3TempInMemory(const sqlite3*);
|
||||
const char *sqlite3JournalModename(int);
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
@@ -3497,7 +3497,6 @@ static int SQLITE_TCLAPI DbMain(
|
||||
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
|
||||
#endif
|
||||
|
||||
if( objc==1 ) return sqliteCmdUsage(interp, objv);
|
||||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
|
||||
+1
-99
@@ -4218,7 +4218,6 @@ static int SQLITE_TCLAPI test_prepare_v2(
|
||||
char *zCopy = 0; /* malloc() copy of zSql */
|
||||
int bytes;
|
||||
const char *zTail = 0;
|
||||
const char **pzTail;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char zBuf[50];
|
||||
int rc;
|
||||
@@ -4243,8 +4242,7 @@ static int SQLITE_TCLAPI test_prepare_v2(
|
||||
zCopy = malloc(n);
|
||||
memcpy(zCopy, zSql, n);
|
||||
}
|
||||
pzTail = objc>=5 ? &zTail : 0;
|
||||
rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, pzTail);
|
||||
rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
|
||||
free(zCopy);
|
||||
zTail = &zSql[(zTail - zCopy)];
|
||||
|
||||
@@ -4271,79 +4269,6 @@ static int SQLITE_TCLAPI test_prepare_v2(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare_v3 DB sql bytes flags ?tailvar?
|
||||
**
|
||||
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
|
||||
** database handle <DB> and flags <flags>. The parameter <tailval> is
|
||||
** the name of a global variable that is set to the unused portion of
|
||||
** <sql> (if any). A STMT handle is returned.
|
||||
*/
|
||||
static int SQLITE_TCLAPI test_prepare_v3(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zSql;
|
||||
char *zCopy = 0; /* malloc() copy of zSql */
|
||||
int bytes, flags;
|
||||
const char *zTail = 0;
|
||||
const char **pzTail;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char zBuf[50];
|
||||
int rc;
|
||||
|
||||
if( objc!=6 && objc!=5 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetString(objv[0]), " DB sql bytes flags tailvar", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zSql = Tcl_GetString(objv[2]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[4], &flags) ) return TCL_ERROR;
|
||||
|
||||
/* Instead of using zSql directly, make a copy into a buffer obtained
|
||||
** directly from malloc(). The idea is to make it easier for valgrind
|
||||
** to spot buffer overreads. */
|
||||
if( bytes>=0 ){
|
||||
zCopy = malloc(bytes);
|
||||
memcpy(zCopy, zSql, bytes);
|
||||
}else{
|
||||
int n = (int)strlen(zSql) + 1;
|
||||
zCopy = malloc(n);
|
||||
memcpy(zCopy, zSql, n);
|
||||
}
|
||||
pzTail = objc>=6 ? &zTail : 0;
|
||||
rc = sqlite3_prepare_v3(db, zCopy, bytes, (unsigned int)flags,&pStmt,pzTail);
|
||||
free(zCopy);
|
||||
zTail = &zSql[(zTail - zCopy)];
|
||||
|
||||
assert(rc==SQLITE_OK || pStmt==0);
|
||||
Tcl_ResetResult(interp);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
if( rc==SQLITE_OK && zTail && objc>=6 ){
|
||||
if( bytes>=0 ){
|
||||
bytes = bytes - (int)(zTail-zSql);
|
||||
}
|
||||
Tcl_ObjSetVar2(interp, objv[5], 0, Tcl_NewStringObj(zTail, bytes), 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( pStmt==0 );
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
|
||||
Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( pStmt ){
|
||||
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_prepare_tkt3134 DB
|
||||
**
|
||||
@@ -4751,25 +4676,6 @@ static int SQLITE_TCLAPI test_ex_sql(
|
||||
sqlite3_free(z);
|
||||
return TCL_OK;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
static int SQLITE_TCLAPI test_norm_sql(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "STMT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
Tcl_SetResult(interp, (char *)sqlite3_normalized_sql(pStmt), TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_column_count STMT
|
||||
@@ -7740,7 +7646,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_prepare", test_prepare ,0 },
|
||||
{ "sqlite3_prepare16", test_prepare16 ,0 },
|
||||
{ "sqlite3_prepare_v2", test_prepare_v2 ,0 },
|
||||
{ "sqlite3_prepare_v3", test_prepare_v3 ,0 },
|
||||
{ "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0},
|
||||
{ "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
|
||||
{ "sqlite3_finalize", test_finalize ,0 },
|
||||
@@ -7752,9 +7657,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_step", test_step ,0 },
|
||||
{ "sqlite3_sql", test_sql ,0 },
|
||||
{ "sqlite3_expanded_sql", test_ex_sql ,0 },
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
{ "sqlite3_normalized_sql", test_norm_sql ,0 },
|
||||
#endif
|
||||
{ "sqlite3_next_stmt", test_next_stmt ,0 },
|
||||
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
|
||||
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
|
||||
|
||||
@@ -762,12 +762,6 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
|
||||
Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_NORMALIZE)
|
||||
Tcl_SetVar2(interp, "sqlite_options", "normalize", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "normalize", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_WINDOWFUNC
|
||||
Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -545,73 +545,6 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
/*
|
||||
** Return the length (in bytes) of the token that begins at z[0].
|
||||
** Store the token type in *tokenType before returning. If flags has
|
||||
** SQLITE_TOKEN_NORMALIZE flag enabled, use the identifier token type
|
||||
** for keywords. Add SQLITE_TOKEN_QUOTED to flags if the token was
|
||||
** actually a quoted identifier. Add SQLITE_TOKEN_KEYWORD to flags
|
||||
** if the token was recognized as a keyword; this is useful when the
|
||||
** SQLITE_TOKEN_NORMALIZE flag is used, because it enables the caller
|
||||
** to differentiate between a keyword being treated as an identifier
|
||||
** (for normalization purposes) and an actual identifier.
|
||||
*/
|
||||
int sqlite3GetTokenNormalized(
|
||||
const unsigned char *z,
|
||||
int *tokenType,
|
||||
int *flags
|
||||
){
|
||||
int n;
|
||||
unsigned char iClass = aiClass[*z];
|
||||
if( iClass==CC_KYWD ){
|
||||
int i;
|
||||
for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
|
||||
if( IdChar(z[i]) ){
|
||||
/* This token started out using characters that can appear in keywords,
|
||||
** but z[i] is a character not allowed within keywords, so this must
|
||||
** be an identifier instead */
|
||||
i++;
|
||||
while( IdChar(z[i]) ){ i++; }
|
||||
*tokenType = TK_ID;
|
||||
return i;
|
||||
}
|
||||
*tokenType = TK_ID;
|
||||
n = keywordCode((char*)z, i, tokenType);
|
||||
/* If the token is no longer considered to be an identifier, then it is a
|
||||
** keyword of some kind. Make the token back into an identifier and then
|
||||
** set the SQLITE_TOKEN_KEYWORD flag. Several non-identifier tokens are
|
||||
** used verbatim, including IN, IS, NOT, and NULL. */
|
||||
switch( *tokenType ){
|
||||
case TK_ID: {
|
||||
/* do nothing, handled by caller */
|
||||
break;
|
||||
}
|
||||
case TK_IN:
|
||||
case TK_IS:
|
||||
case TK_NOT:
|
||||
case TK_NULL: {
|
||||
*flags |= SQLITE_TOKEN_KEYWORD;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*tokenType = TK_ID;
|
||||
*flags |= SQLITE_TOKEN_KEYWORD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
n = sqlite3GetToken(z, tokenType);
|
||||
/* If the token is considered to be an identifier and the character class
|
||||
** of the first character is a quote, set the SQLITE_TOKEN_QUOTED flag. */
|
||||
if( *tokenType==TK_ID && (iClass==CC_QUOTE || iClass==CC_QUOTE2) ){
|
||||
*flags |= SQLITE_TOKEN_QUOTED;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
/*
|
||||
** Run the parser on the given SQL string. The parser structure is
|
||||
** passed in. An SQLITE_ status code is returned. If an error occurs
|
||||
|
||||
+20
-13
@@ -238,10 +238,10 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
|
||||
}
|
||||
if( p->pLimit ){
|
||||
sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
|
||||
if( p->pLimit->pRight ){
|
||||
sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->eX==EX_Right);
|
||||
if( p->pLimit->eX==EX_Right ){
|
||||
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
|
||||
sqlite3TreeViewExpr(pView, p->pLimit->x.pRight, 0);
|
||||
sqlite3TreeViewPop(pView);
|
||||
}
|
||||
sqlite3TreeViewPop(pView);
|
||||
@@ -468,9 +468,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
"IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE"
|
||||
};
|
||||
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
|
||||
assert( pExpr->pRight );
|
||||
assert( pExpr->pRight->op==TK_TRUEFALSE );
|
||||
x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
assert( pExpr->x.pRight->op==TK_TRUEFALSE );
|
||||
x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->x.pRight);
|
||||
zUniOp = azOp[x];
|
||||
break;
|
||||
}
|
||||
@@ -497,7 +497,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pWin = pExpr->y.pWin;
|
||||
pWin = pExpr->pWin;
|
||||
#else
|
||||
pWin = 0;
|
||||
#endif
|
||||
@@ -532,10 +532,15 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
case TK_IN: {
|
||||
sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
}else{
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
switch( pExpr->eX ){
|
||||
case EX_Select: {
|
||||
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -596,7 +601,8 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
case TK_MATCH: {
|
||||
sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
|
||||
pExpr->iTable, pExpr->iColumn, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3TreeViewExpr(pView, pExpr->x.pRight, 0);
|
||||
break;
|
||||
}
|
||||
case TK_VECTOR: {
|
||||
@@ -621,7 +627,8 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
if( zBinOp ){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zBinOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
sqlite3TreeViewExpr(pView, pExpr->x.pRight, 0);
|
||||
}else if( zUniOp ){
|
||||
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
|
||||
+1
-1
@@ -913,7 +913,7 @@ static void updateVirtualTable(
|
||||
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */
|
||||
sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
|
||||
}
|
||||
}
|
||||
if( HasRowid(pTab) ){
|
||||
|
||||
+12
-26
@@ -2894,25 +2894,17 @@ case OP_MakeRecord: {
|
||||
if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++;
|
||||
}
|
||||
nByte = nHdr+nData;
|
||||
if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
|
||||
/* Make sure the output register has a buffer large enough to store
|
||||
** the new record. The output register (pOp->p3) is not allowed to
|
||||
** be one of the input registers (because the following call to
|
||||
** sqlite3VdbeMemClearAndResize() could clobber the value before it is used).
|
||||
*/
|
||||
if( nByte+nZero<=pOut->szMalloc ){
|
||||
/* The output register is already large enough to hold the record.
|
||||
** No error checks or buffer enlargement is required */
|
||||
pOut->z = pOut->zMalloc;
|
||||
}else{
|
||||
/* Need to make sure that the output is not too big and then enlarge
|
||||
** the output register to hold the full result */
|
||||
if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
|
||||
goto no_mem;
|
||||
}
|
||||
if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
|
||||
goto no_mem;
|
||||
}
|
||||
zNewRecord = (u8 *)pOut->z;
|
||||
|
||||
@@ -5768,7 +5760,7 @@ case OP_ParseSchema: {
|
||||
{
|
||||
zMaster = MASTER_NAME;
|
||||
initData.db = db;
|
||||
initData.iDb = iDb;
|
||||
initData.iDb = pOp->p1;
|
||||
initData.pzErrMsg = &p->zErrMsg;
|
||||
initData.mInitFlags = 0;
|
||||
zSql = sqlite3MPrintf(db,
|
||||
@@ -6965,11 +6957,10 @@ case OP_VFilter: { /* jump */
|
||||
**
|
||||
** If the VColumn opcode is being used to fetch the value of
|
||||
** an unchanging column during an UPDATE operation, then the P5
|
||||
** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange()
|
||||
** function to return true inside the xColumn method of the virtual
|
||||
** table implementation. The P5 column might also contain other
|
||||
** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
|
||||
** unused by OP_VColumn.
|
||||
** value is 1. Otherwise, P5 is 0. The P5 value is returned
|
||||
** by sqlite3_vtab_nochange() routine and can be used
|
||||
** by virtual table implementations to return special "no-change"
|
||||
** marks which can be more efficient, depending on the virtual table.
|
||||
*/
|
||||
case OP_VColumn: {
|
||||
sqlite3_vtab *pVtab;
|
||||
@@ -6991,8 +6982,7 @@ case OP_VColumn: {
|
||||
assert( pModule->xColumn );
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
sContext.pOut = pDest;
|
||||
testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && pOp->p5!=0 );
|
||||
if( pOp->p5 & OPFLAG_NOCHNG ){
|
||||
if( pOp->p5 ){
|
||||
sqlite3VdbeMemSetNull(pDest);
|
||||
pDest->flags = MEM_Null|MEM_Zero;
|
||||
pDest->u.nZero = 0;
|
||||
@@ -7069,10 +7059,7 @@ case OP_VNext: { /* jump */
|
||||
case OP_VRename: {
|
||||
sqlite3_vtab *pVtab;
|
||||
Mem *pName;
|
||||
int isLegacy;
|
||||
|
||||
isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
db->flags |= SQLITE_LegacyAlter;
|
||||
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
pName = &aMem[pOp->p1];
|
||||
assert( pVtab->pModule->xRename );
|
||||
@@ -7086,7 +7073,6 @@ case OP_VRename: {
|
||||
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
if( isLegacy==0 ) db->flags &= ~SQLITE_LegacyAlter;
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
p->expired = 0;
|
||||
if( rc ) goto abort_due_to_error;
|
||||
|
||||
@@ -406,9 +406,6 @@ struct Vdbe {
|
||||
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
||||
u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
|
||||
char *zSql; /* Text of the SQL statement that generated this */
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
char *zNormSql; /* Normalization of the associated SQL statement */
|
||||
#endif
|
||||
void *pFree; /* Free this when deleting the vdbe */
|
||||
VdbeFrame *pFrame; /* Parent frame */
|
||||
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
|
||||
|
||||
@@ -1702,16 +1702,6 @@ char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
/*
|
||||
** Return the normalized SQL associated with a prepared statement.
|
||||
*/
|
||||
const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
return p ? p->zNormSql : 0;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_NORMALIZE */
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/*
|
||||
** Allocate and populate an UnpackedRecord structure based on the serialized
|
||||
|
||||
+3
-20
@@ -64,13 +64,6 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){
|
||||
}
|
||||
assert( p->zSql==0 );
|
||||
p->zSql = sqlite3DbStrNDup(p->db, z, n);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
assert( p->zNormSql==0 );
|
||||
if( p->zSql && (prepFlags & SQLITE_PREPARE_NORMALIZE)!=0 ){
|
||||
sqlite3Normalize(p, p->zSql, n, prepFlags);
|
||||
assert( p->zNormSql!=0 || p->db->mallocFailed );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,11 +85,6 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
||||
zTmp = pA->zSql;
|
||||
pA->zSql = pB->zSql;
|
||||
pB->zSql = zTmp;
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
zTmp = pA->zNormSql;
|
||||
pA->zNormSql = pB->zNormSql;
|
||||
pB->zNormSql = zTmp;
|
||||
#endif
|
||||
pB->expmask = pA->expmask;
|
||||
pB->prepFlags = pA->prepFlags;
|
||||
memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter));
|
||||
@@ -1387,9 +1375,9 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
||||
if( zOp ){
|
||||
sqlite3_str_appendf(p, "%s(", zOp);
|
||||
displayP4Expr(p, pExpr->pLeft);
|
||||
if( pExpr->pRight ){
|
||||
if( pExpr->eX==EX_Right ){
|
||||
sqlite3_str_append(p, ",", 1);
|
||||
displayP4Expr(p, pExpr->pRight);
|
||||
displayP4Expr(p, pExpr->x.pRight);
|
||||
}
|
||||
sqlite3_str_append(p, ")", 1);
|
||||
}
|
||||
@@ -3168,9 +3156,6 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
||||
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
sqlite3DbFree(db, p->zNormSql);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
{
|
||||
int i;
|
||||
@@ -4572,9 +4557,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
(void)getVarint32((u8*)m.z, szHdr);
|
||||
testcase( szHdr==3 );
|
||||
testcase( szHdr==m.n );
|
||||
testcase( szHdr>0x7fffffff );
|
||||
assert( m.n>=0 );
|
||||
if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
|
||||
if( unlikely(szHdr<3 || (int)szHdr>m.n) ){
|
||||
goto idx_rowid_corruption;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -328,6 +328,7 @@ void sqlite3VtabBeginParse(
|
||||
Token *pModuleName, /* Name of the module for the virtual table */
|
||||
int ifNotExists /* No error if the table already exists */
|
||||
){
|
||||
int iDb; /* The database the table is being created in */
|
||||
Table *pTable; /* The new virtual table */
|
||||
sqlite3 *db; /* Database connection */
|
||||
|
||||
@@ -337,6 +338,8 @@ void sqlite3VtabBeginParse(
|
||||
assert( 0==pTable->pIndex );
|
||||
|
||||
db = pParse->db;
|
||||
iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
|
||||
assert( iDb>=0 );
|
||||
|
||||
assert( pTable->nModuleArg==0 );
|
||||
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
|
||||
@@ -356,8 +359,6 @@ void sqlite3VtabBeginParse(
|
||||
** The second call, to obtain permission to create the table, is made now.
|
||||
*/
|
||||
if( pTable->azModuleArg ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
|
||||
assert( iDb>=0 ); /* The database the table is being created in */
|
||||
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
|
||||
pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
|
||||
}
|
||||
@@ -1052,8 +1053,7 @@ FuncDef *sqlite3VtabOverloadFunction(
|
||||
/* Check to see the left operand is a column in a virtual table */
|
||||
if( NEVER(pExpr==0) ) return pDef;
|
||||
if( pExpr->op!=TK_COLUMN ) return pDef;
|
||||
pTab = pExpr->y.pTab;
|
||||
if( pTab==0 ) return pDef;
|
||||
if( pExpr->eX!=EX_Tab || (pTab = pExpr->x.pTab)==0 ) return pDef;
|
||||
if( !IsVirtual(pTab) ) return pDef;
|
||||
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
|
||||
assert( pVtab!=0 );
|
||||
|
||||
+15
-10
@@ -45,18 +45,23 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
|
||||
if( rc ) return rc & WRC_Abort;
|
||||
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
|
||||
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
|
||||
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
|
||||
if( pExpr->pRight ){
|
||||
pExpr = pExpr->pRight;
|
||||
continue;
|
||||
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
|
||||
}else if( pExpr->x.pList ){
|
||||
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
|
||||
switch( pExpr->eX ){
|
||||
case EX_Right: {
|
||||
pExpr = pExpr->x.pRight;
|
||||
continue;
|
||||
}
|
||||
case EX_Select: {
|
||||
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
if( !ExprHasProperty(pExpr, EP_Reduced) && pExpr->pWin ){
|
||||
Window *pWin = pExpr->pWin;
|
||||
if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort;
|
||||
if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort;
|
||||
if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort;
|
||||
|
||||
+61
-57
@@ -253,7 +253,9 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
||||
){
|
||||
if( (pTerm->eOperator & WO_EQUIV)!=0
|
||||
&& pScan->nEquiv<ArraySize(pScan->aiCur)
|
||||
&& (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN
|
||||
&& ALWAYS(pTerm->pExpr->eX==EX_Right)
|
||||
&& (pX = sqlite3ExprSkipCollate(pTerm->pExpr->x.pRight))->op
|
||||
==TK_COLUMN
|
||||
){
|
||||
int j;
|
||||
for(j=0; j<pScan->nEquiv; j++){
|
||||
@@ -278,15 +280,15 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
||||
continue;
|
||||
}
|
||||
assert(pX->pLeft);
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse,
|
||||
pX->pLeft, pX->pRight);
|
||||
pColl = sqlite3ComparisonExprCollSeq(pParse, pX);
|
||||
if( pColl==0 ) pColl = pParse->db->pDfltColl;
|
||||
if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
|
||||
&& (pX = pTerm->pExpr->pRight)->op==TK_COLUMN
|
||||
&& ALWAYS(pTerm->pExpr->eX==EX_Right)
|
||||
&& (pX = pTerm->pExpr->x.pRight)->op==TK_COLUMN
|
||||
&& pX->iTable==pScan->aiCur[0]
|
||||
&& pX->iColumn==pScan->aiColumn[0]
|
||||
){
|
||||
@@ -789,7 +791,7 @@ static void constructAutomaticIndex(
|
||||
Expr *pX = pTerm->pExpr;
|
||||
idxCols |= cMask;
|
||||
pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
|
||||
pColl = sqlite3ComparisonExprCollSeq(pParse, pX);
|
||||
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
|
||||
n++;
|
||||
}
|
||||
@@ -1006,7 +1008,8 @@ static sqlite3_index_info *allocateIndexInfo(
|
||||
assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
|
||||
|
||||
if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
|
||||
&& sqlite3ExprIsVector(pTerm->pExpr->pRight)
|
||||
&& ALWAYS(pTerm->pExpr->eX==EX_Right)
|
||||
&& sqlite3ExprIsVector(pTerm->pExpr->x.pRight)
|
||||
){
|
||||
if( i<16 ) mNoOmit |= (1 << i);
|
||||
if( op==WO_LT ) pIdxCons[j].op = WO_LE;
|
||||
@@ -1366,11 +1369,13 @@ static int whereRangeSkipScanEst(
|
||||
|
||||
pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]);
|
||||
if( pLower ){
|
||||
rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->pRight, aff, &p1);
|
||||
assert( pLower->pExpr->eX==EX_Right );
|
||||
rc = sqlite3Stat4ValueFromExpr(pParse, pLower->pExpr->x.pRight, aff, &p1);
|
||||
nLower = 0;
|
||||
}
|
||||
if( pUpper && rc==SQLITE_OK ){
|
||||
rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->pRight, aff, &p2);
|
||||
assert( pUpper->pExpr->eX==EX_Right );
|
||||
rc = sqlite3Stat4ValueFromExpr(pParse, pUpper->pExpr->x.pRight, aff, &p2);
|
||||
nUpper = p2 ? 0 : p->nSample;
|
||||
}
|
||||
|
||||
@@ -1532,7 +1537,9 @@ static int whereRangeScanEst(
|
||||
/* If possible, improve on the iLower estimate using ($P:$L). */
|
||||
if( pLower ){
|
||||
int n; /* Values extracted from pExpr */
|
||||
Expr *pExpr = pLower->pExpr->pRight;
|
||||
Expr *pExpr;
|
||||
assert( pLower->pExpr->eX==EX_Right );
|
||||
pExpr = pLower->pExpr->x.pRight;
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n);
|
||||
if( rc==SQLITE_OK && n ){
|
||||
tRowcnt iNew;
|
||||
@@ -1549,7 +1556,9 @@ static int whereRangeScanEst(
|
||||
/* If possible, improve on the iUpper estimate using ($P:$U). */
|
||||
if( pUpper ){
|
||||
int n; /* Values extracted from pExpr */
|
||||
Expr *pExpr = pUpper->pExpr->pRight;
|
||||
Expr *pExpr;
|
||||
assert( pUpper->pExpr->eX==EX_Right );
|
||||
pExpr = pUpper->pExpr->x.pRight;
|
||||
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n);
|
||||
if( rc==SQLITE_OK && n ){
|
||||
tRowcnt iNew;
|
||||
@@ -2126,14 +2135,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
int rc;
|
||||
|
||||
/* Stop the search once we hit the query planner search limit */
|
||||
if( pBuilder->iPlanLimit==0 ){
|
||||
WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n"));
|
||||
if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0;
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
pBuilder->iPlanLimit--;
|
||||
|
||||
/* If pBuilder->pOrSet is defined, then only keep track of the costs
|
||||
** and prereqs.
|
||||
*/
|
||||
@@ -2287,7 +2288,9 @@ static void whereLoopOutputAdjust(
|
||||
** guess a reasonable truth probability. */
|
||||
pLoop->nOut--;
|
||||
if( pTerm->eOperator&(WO_EQ|WO_IS) ){
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
Expr *pRight;
|
||||
assert( pTerm->pExpr->eX==EX_Right );
|
||||
pRight = pTerm->pExpr->x.pRight;
|
||||
testcase( pTerm->pExpr->op==TK_IS );
|
||||
if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
|
||||
k = 10;
|
||||
@@ -2336,9 +2339,13 @@ static int whereRangeVectorLen(
|
||||
char aff; /* Comparison affinity */
|
||||
char idxaff = 0; /* Indexed columns affinity */
|
||||
CollSeq *pColl; /* Comparison collation sequence */
|
||||
Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
|
||||
Expr *pRhs = pTerm->pExpr->pRight;
|
||||
if( pRhs->flags & EP_xIsSelect ){
|
||||
Expr *pLhs;
|
||||
Expr *pRhs;
|
||||
pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
|
||||
assert( pTerm->pExpr->eX==EX_Right );
|
||||
pRhs = pTerm->pExpr->x.pRight;
|
||||
assert( pRhs->eX==EX_Select || pRhs->eX==EX_List );
|
||||
if( pRhs->eX==EX_Select ){
|
||||
pRhs = pRhs->x.pSelect->pEList->a[i].pExpr;
|
||||
}else{
|
||||
pRhs = pRhs->x.pList->a[i].pExpr;
|
||||
@@ -2361,7 +2368,7 @@ static int whereRangeVectorLen(
|
||||
idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
|
||||
if( aff!=idxaff ) break;
|
||||
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
||||
pColl = sqlite3ComparisonCollSeq(pParse, pLhs, pRhs);
|
||||
if( pColl==0 ) break;
|
||||
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break;
|
||||
}
|
||||
@@ -2496,24 +2503,29 @@ static int whereLoopAddBtreeIndex(
|
||||
|
||||
if( eOp & WO_IN ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
|
||||
int i;
|
||||
nIn = 46; assert( 46==sqlite3LogEst(25) );
|
||||
|
||||
/* The expression may actually be of the form (x, y) IN (SELECT...).
|
||||
** In this case there is a separate term for each of (x) and (y).
|
||||
** However, the nIn multiplier should only be applied once, not once
|
||||
** for each such term. The following loop checks that pTerm is the
|
||||
** first such term in use, and sets nIn back to 0 if it is not. */
|
||||
for(i=0; i<pNew->nLTerm-1; i++){
|
||||
if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
|
||||
switch( pExpr->eX ){
|
||||
case EX_Select: {
|
||||
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
|
||||
int i;
|
||||
nIn = 46; assert( 46==sqlite3LogEst(25) );
|
||||
|
||||
/* The expression may actually be of the form (x, y) IN (SELECT...).
|
||||
** In this case there is a separate term for each of (x) and (y).
|
||||
** However, the nIn multiplier should only be applied once, not once
|
||||
** for each such term. The following loop checks that pTerm is the
|
||||
** first such term in use, and sets nIn back to 0 if it is not. */
|
||||
for(i=0; i<pNew->nLTerm-1; i++){
|
||||
if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
/* "x IN (value, value, ...)" */
|
||||
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
|
||||
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
|
||||
** changes "x IN (?)" into "x=?". */
|
||||
break;
|
||||
}
|
||||
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
|
||||
/* "x IN (value, value, ...)" */
|
||||
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
|
||||
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
|
||||
** changes "x IN (?)" into "x=?". */
|
||||
}
|
||||
if( pProbe->hasStat1 ){
|
||||
LogEst M, logK, safetyMargin;
|
||||
@@ -2628,16 +2640,17 @@ static int whereLoopAddBtreeIndex(
|
||||
if( nInMul==0
|
||||
&& pProbe->nSample
|
||||
&& pNew->u.btree.nEq<=pProbe->nSampleCol
|
||||
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
|
||||
&& ((eOp & WO_IN)==0 || pTerm->pExpr->eX==EX_List)
|
||||
&& OptimizationEnabled(db, SQLITE_Stat34)
|
||||
){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){
|
||||
if( (eOp & (WO_EQ|WO_IS))!=0 ){
|
||||
testcase( eOp & WO_EQ );
|
||||
testcase( eOp & WO_IS );
|
||||
testcase( eOp & WO_ISNULL );
|
||||
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
|
||||
}else{
|
||||
assert( pExpr->eX==EX_Right );
|
||||
rc = whereEqualScanEst(pParse, pBuilder, pExpr->x.pRight, &nOut);
|
||||
}else if( pExpr->eX==EX_List ){
|
||||
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
|
||||
}
|
||||
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
|
||||
@@ -2791,7 +2804,8 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
|
||||
Parse *pParse = pWC->pWInfo->pParse;
|
||||
while( pWhere->op==TK_AND ){
|
||||
if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
|
||||
pWhere = pWhere->pRight;
|
||||
assert( pWhere->eX==EX_Right );
|
||||
pWhere = pWhere->x.pRight;
|
||||
}
|
||||
if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
|
||||
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
||||
@@ -3246,7 +3260,7 @@ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
|
||||
int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
|
||||
Expr *pX = pHidden->pWC->a[iTerm].pExpr;
|
||||
if( pX->pLeft ){
|
||||
pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
|
||||
pC = sqlite3ComparisonExprCollSeq(pHidden->pParse,pX);
|
||||
}
|
||||
zRet = (pC ? pC->zName : sqlite3StrBINARY);
|
||||
}
|
||||
@@ -3540,11 +3554,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
/* Loop over the tables in the join, from left to right */
|
||||
pNew = pBuilder->pNew;
|
||||
whereLoopInit(pNew);
|
||||
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
|
||||
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
|
||||
Bitmask mUnusable = 0;
|
||||
pNew->iTab = iTab;
|
||||
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
|
||||
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
|
||||
if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
|
||||
/* This condition is true when pItem is the FROM clause term on the
|
||||
@@ -3570,15 +3582,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
|
||||
}
|
||||
mPrior |= pNew->maskSelf;
|
||||
if( rc || db->mallocFailed ){
|
||||
if( rc==SQLITE_DONE ){
|
||||
/* We hit the query planner search limit set by iPlanLimit */
|
||||
sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search");
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( rc || db->mallocFailed ) break;
|
||||
}
|
||||
|
||||
whereLoopClear(db, pNew);
|
||||
|
||||
@@ -402,33 +402,12 @@ struct WhereLoopBuilder {
|
||||
int nRecValid; /* Number of valid fields currently in pRec */
|
||||
#endif
|
||||
unsigned int bldFlags; /* SQLITE_BLDF_* flags */
|
||||
unsigned int iPlanLimit; /* Search limiter */
|
||||
};
|
||||
|
||||
/* Allowed values for WhereLoopBuider.bldFlags */
|
||||
#define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */
|
||||
#define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */
|
||||
|
||||
/* The WhereLoopBuilder.iPlanLimit is used to limit the number of
|
||||
** index+constraint combinations the query planner will consider for a
|
||||
** particular query. If this parameter is unlimited, then certain
|
||||
** pathological queries can spend excess time in the sqlite3WhereBegin()
|
||||
** routine. The limit is high enough that is should not impact real-world
|
||||
** queries.
|
||||
**
|
||||
** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is
|
||||
** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM
|
||||
** clause is processed, so that every table in a join is guaranteed to be
|
||||
** able to propose a some index+constraint combinations even if the initial
|
||||
** baseline limit was exhausted by prior tables of the join.
|
||||
*/
|
||||
#ifndef SQLITE_QUERY_PLANNER_LIMIT
|
||||
# define SQLITE_QUERY_PLANNER_LIMIT 20000
|
||||
#endif
|
||||
#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR
|
||||
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The WHERE clause processing routine has two halves. The
|
||||
** first part does the start of the WHERE loop and the second
|
||||
|
||||
+32
-17
@@ -435,7 +435,9 @@ static Expr *removeUnindexableInClauseTerms(
|
||||
}
|
||||
sqlite3ExprListDelete(db, pOrigRhs);
|
||||
sqlite3ExprListDelete(db, pOrigLhs);
|
||||
assert( pNew->pLeft->eX==EX_List );
|
||||
pNew->pLeft->x.pList = pLhs;
|
||||
if( pLhs==0 ) pNew->pLeft->eX = EX_None;
|
||||
pNew->x.pSelect->pEList = pRhs;
|
||||
if( pLhs && pLhs->nExpr==1 ){
|
||||
/* Take care here not to generate a TK_VECTOR containing only a
|
||||
@@ -502,7 +504,8 @@ static int codeEqualityTerm(
|
||||
assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
|
||||
assert( iTarget>0 );
|
||||
if( pX->op==TK_EQ || pX->op==TK_IS ){
|
||||
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
|
||||
assert( pX->eX==EX_Right );
|
||||
iReg = sqlite3ExprCodeTarget(pParse, pX->x.pRight, iTarget);
|
||||
}else if( pX->op==TK_ISNULL ){
|
||||
iReg = iTarget;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
|
||||
@@ -538,7 +541,7 @@ static int codeEqualityTerm(
|
||||
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
|
||||
}
|
||||
|
||||
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
|
||||
if( pX->eX!=EX_Select || pX->x.pSelect->pEList->nExpr==1 ){
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
|
||||
}else{
|
||||
sqlite3 *db = pParse->db;
|
||||
@@ -734,7 +737,7 @@ static int codeAllEqualityTerms(
|
||||
}
|
||||
}
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
if( pTerm->pExpr->flags & EP_xIsSelect ){
|
||||
if( pTerm->pExpr->eX==EX_Select ){
|
||||
/* No affinity ever needs to be (or should be) applied to a value
|
||||
** from the RHS of an "? IN (SELECT ...)" expression. The
|
||||
** sqlite3FindInIndex() routine has already ensured that the
|
||||
@@ -742,7 +745,9 @@ static int codeAllEqualityTerms(
|
||||
if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
|
||||
}
|
||||
}else if( (pTerm->eOperator & WO_ISNULL)==0 ){
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
Expr *pRight;
|
||||
assert( pTerm->pExpr->eX==EX_Right );
|
||||
pRight = pTerm->pExpr->x.pRight;
|
||||
if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
||||
VdbeCoverage(v);
|
||||
@@ -1074,7 +1079,7 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
|
||||
assert( nReg>0 );
|
||||
if( p && sqlite3ExprIsVector(p) ){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
if( (p->flags & EP_xIsSelect) ){
|
||||
if( p->eX==EX_Select ){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
|
||||
@@ -1117,7 +1122,7 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
pExpr->y.pTab = 0;
|
||||
/* pExpr->pTab = 0; */
|
||||
return WRC_Prune;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
@@ -1262,7 +1267,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
|
||||
addrNotFound = pLevel->addrNxt;
|
||||
}else{
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
Expr *pRight = pExpr->eX==EX_Right ? pExpr->x.pRight : 0;
|
||||
codeExprOrVector(pParse, pRight, iTarget, 1);
|
||||
}
|
||||
}
|
||||
@@ -1307,8 +1313,11 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
assert( pCompare!=0 || db->mallocFailed );
|
||||
if( pCompare ){
|
||||
pCompare->pLeft = pTerm->pExpr->pLeft;
|
||||
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
|
||||
assert( pCompare->eX==EX_None );
|
||||
pRight = sqlite3Expr(db, TK_REGISTER, 0);
|
||||
if( pRight ){
|
||||
pCompare->x.pRight = pRight;
|
||||
pCompare->eX = EX_Right;
|
||||
pRight->iTable = iReg+j+2;
|
||||
sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
|
||||
}
|
||||
@@ -1393,9 +1402,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pX = pStart->pExpr;
|
||||
assert( pX!=0 );
|
||||
testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
|
||||
if( sqlite3ExprIsVector(pX->pRight) ){
|
||||
assert( pX->eX==EX_Right );
|
||||
if( sqlite3ExprIsVector(pX->x.pRight) ){
|
||||
r1 = rTemp = sqlite3GetTempReg(pParse);
|
||||
codeExprOrVector(pParse, pX->pRight, r1, 1);
|
||||
codeExprOrVector(pParse, pX->x.pRight, r1, 1);
|
||||
testcase( pX->op==TK_GT );
|
||||
testcase( pX->op==TK_GE );
|
||||
testcase( pX->op==TK_LT );
|
||||
@@ -1406,7 +1416,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
assert( pX->op!=TK_LT || op==OP_SeekLE );
|
||||
assert( pX->op!=TK_LE || op==OP_SeekLE );
|
||||
}else{
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pX->x.pRight, &rTemp);
|
||||
disableTerm(pLevel, pStart);
|
||||
op = aMoveOp[(pX->op - TK_GT)];
|
||||
}
|
||||
@@ -1426,19 +1436,20 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
Expr *pX;
|
||||
pX = pEnd->pExpr;
|
||||
assert( pX!=0 );
|
||||
assert( pX->eX==EX_Right );
|
||||
assert( (pEnd->wtFlags & TERM_VNULL)==0 );
|
||||
testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
|
||||
testcase( pEnd->wtFlags & TERM_VIRTUAL );
|
||||
memEndValue = ++pParse->nMem;
|
||||
codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
|
||||
if( 0==sqlite3ExprIsVector(pX->pRight)
|
||||
codeExprOrVector(pParse, pX->x.pRight, memEndValue, 1);
|
||||
if( 0==sqlite3ExprIsVector(pX->x.pRight)
|
||||
&& (pX->op==TK_LT || pX->op==TK_GT)
|
||||
){
|
||||
testOp = bRev ? OP_Le : OP_Ge;
|
||||
}else{
|
||||
testOp = bRev ? OP_Lt : OP_Gt;
|
||||
}
|
||||
if( 0==sqlite3ExprIsVector(pX->pRight) ){
|
||||
if( 0==sqlite3ExprIsVector(pX->x.pRight) ){
|
||||
disableTerm(pLevel, pEnd);
|
||||
}
|
||||
}
|
||||
@@ -1622,7 +1633,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
/* Seek the index cursor to the start of the range. */
|
||||
nConstraint = nEq;
|
||||
if( pRangeStart ){
|
||||
Expr *pRight = pRangeStart->pExpr->pRight;
|
||||
Expr *pRight;
|
||||
assert( pRangeStart->pExpr->eX==EX_Right );
|
||||
pRight = pRangeStart->pExpr->x.pRight;
|
||||
codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
|
||||
whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
|
||||
if( (pRangeStart->wtFlags & TERM_VNULL)==0
|
||||
@@ -1674,7 +1687,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
*/
|
||||
nConstraint = nEq;
|
||||
if( pRangeEnd ){
|
||||
Expr *pRight = pRangeEnd->pExpr->pRight;
|
||||
Expr *pRight;
|
||||
assert( pRangeEnd->pExpr->eX==EX_Right );
|
||||
pRight = pRangeEnd->pExpr->x.pRight;
|
||||
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
|
||||
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
|
||||
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
|
||||
@@ -2194,7 +2209,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( pAlt==0 ) continue;
|
||||
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
||||
if( (pAlt->eOperator & WO_IN)
|
||||
&& (pAlt->pExpr->flags & EP_xIsSelect)
|
||||
&& (pAlt->pExpr->eX==EX_Select)
|
||||
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
|
||||
){
|
||||
continue;
|
||||
|
||||
+89
-55
@@ -119,15 +119,17 @@ static int allowedOp(int op){
|
||||
** is not commuted.
|
||||
*/
|
||||
static void exprCommute(Parse *pParse, Expr *pExpr){
|
||||
u16 expRight = (pExpr->pRight->flags & EP_Collate);
|
||||
u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
|
||||
u16 expRight, expLeft;
|
||||
assert( pExpr->eX==EX_Right );
|
||||
expRight = (pExpr->x.pRight->flags & EP_Collate);
|
||||
expLeft = (pExpr->pLeft->flags & EP_Collate);
|
||||
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
|
||||
if( expRight==expLeft ){
|
||||
/* Either X and Y both have COLLATE operator or neither do */
|
||||
if( expRight ){
|
||||
/* Both X and Y have COLLATE operators. Make sure X is always
|
||||
** used by clearing the EP_Collate flag from Y. */
|
||||
pExpr->pRight->flags &= ~EP_Collate;
|
||||
pExpr->x.pRight->flags &= ~EP_Collate;
|
||||
}else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
|
||||
/* Neither X nor Y have COLLATE operators, but X has a non-default
|
||||
** collating sequence. So add the EP_Collate marker on X to cause
|
||||
@@ -135,7 +137,7 @@ static void exprCommute(Parse *pParse, Expr *pExpr){
|
||||
pExpr->pLeft->flags |= EP_Collate;
|
||||
}
|
||||
}
|
||||
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
|
||||
SWAP(Expr*,pExpr->x.pRight,pExpr->pLeft);
|
||||
if( pExpr->op>=TK_GT ){
|
||||
assert( TK_LT==TK_GT+2 );
|
||||
assert( TK_GE==TK_LE+2 );
|
||||
@@ -280,8 +282,9 @@ static int isLikeOrGlob(
|
||||
|| (zNew[0]+1=='0' && iTo==1)
|
||||
){
|
||||
if( pLeft->op!=TK_COLUMN
|
||||
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|
||||
|| IsVirtual(pLeft->y.pTab) /* Value might be numeric */
|
||||
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|
||||
|| NEVER(pLeft->eX!=EX_Tab)
|
||||
|| IsVirtual(pLeft->x.pTab) /* Value might be numeric */
|
||||
){
|
||||
sqlite3ExprDelete(db, pPrefix);
|
||||
sqlite3ValueFree(pVal);
|
||||
@@ -382,7 +385,7 @@ static int isAuxiliaryVtabOperator(
|
||||
** MATCH(expression,vtab_column)
|
||||
*/
|
||||
pCol = pList->a[1].pExpr;
|
||||
if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
||||
if( pCol->op==TK_COLUMN && pCol->eX==EX_Tab && IsVirtual(pCol->x.pTab) ){
|
||||
for(i=0; i<ArraySize(aOp); i++){
|
||||
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
|
||||
*peOp2 = aOp[i].eOp2;
|
||||
@@ -404,12 +407,12 @@ static int isAuxiliaryVtabOperator(
|
||||
** with function names in an arbitrary case.
|
||||
*/
|
||||
pCol = pList->a[0].pExpr;
|
||||
if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
||||
if( pCol->op==TK_COLUMN && pCol->eX==EX_Tab && IsVirtual(pCol->x.pTab) ){
|
||||
sqlite3_vtab *pVtab;
|
||||
sqlite3_module *pMod;
|
||||
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
|
||||
void *pNotUsed;
|
||||
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
|
||||
pVtab = sqlite3GetVTable(db, pCol->x.pTab)->pVtab;
|
||||
assert( pVtab!=0 );
|
||||
assert( pVtab->pModule!=0 );
|
||||
pMod = (sqlite3_module *)pVtab->pModule;
|
||||
@@ -426,11 +429,12 @@ static int isAuxiliaryVtabOperator(
|
||||
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
|
||||
int res = 0;
|
||||
Expr *pLeft = pExpr->pLeft;
|
||||
Expr *pRight = pExpr->pRight;
|
||||
if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){
|
||||
Expr *pRight = 0;
|
||||
if( pLeft->op==TK_COLUMN && pLeft->eX==EX_Tab && IsVirtual(pLeft->x.pTab) ){
|
||||
res++;
|
||||
}
|
||||
if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){
|
||||
if( pExpr->eX==EX_Right && (pRight = pExpr->x.pRight)->op==TK_COLUMN
|
||||
&& pRight->eX==EX_Tab && IsVirtual(pRight->x.pTab) ){
|
||||
res++;
|
||||
SWAP(Expr*, pLeft, pRight);
|
||||
}
|
||||
@@ -516,10 +520,14 @@ static void whereCombineDisjuncts(
|
||||
if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
|
||||
if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
|
||||
&& (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
|
||||
assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
|
||||
assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
|
||||
if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
|
||||
if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return;
|
||||
assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->eX==EX_Right );
|
||||
assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->eX==EX_Right );
|
||||
if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ){
|
||||
return;
|
||||
}
|
||||
if( sqlite3ExprCompare(0,pOne->pExpr->x.pRight, pTwo->pExpr->x.pRight,-1) ){
|
||||
return;
|
||||
}
|
||||
/* If we reach this point, it means the two subterms can be combined */
|
||||
if( (eOp & (eOp-1))!=0 ){
|
||||
if( eOp & (WO_LT|WO_LE) ){
|
||||
@@ -827,7 +835,8 @@ static void exprAnalyzeOrTerm(
|
||||
** of both right and left sides must be such that no type
|
||||
** conversions are required on the right. (Ticket #2249)
|
||||
*/
|
||||
affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight);
|
||||
assert( pOrTerm->pExpr->eX==EX_Right );
|
||||
affRight = sqlite3ExprAffinity(pOrTerm->pExpr->x.pRight);
|
||||
affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft);
|
||||
if( affRight!=0 && affRight!=affLeft ){
|
||||
okToChngToIN = 0;
|
||||
@@ -853,25 +862,28 @@ static void exprAnalyzeOrTerm(
|
||||
assert( pOrTerm->eOperator & WO_EQ );
|
||||
assert( pOrTerm->leftCursor==iCursor );
|
||||
assert( pOrTerm->u.leftColumn==iColumn );
|
||||
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
|
||||
assert( pOrTerm->pExpr->eX==EX_Right );
|
||||
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->x.pRight, 0);
|
||||
pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup);
|
||||
pLeft = pOrTerm->pExpr->pLeft;
|
||||
}
|
||||
assert( pLeft!=0 );
|
||||
pDup = sqlite3ExprDup(db, pLeft, 0);
|
||||
pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
|
||||
if( pNew ){
|
||||
if( pNew && pList ){
|
||||
int idxNew;
|
||||
transferJoinMarkings(pNew, pExpr);
|
||||
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
||||
assert( pNew->eX==EX_None );
|
||||
pNew->eX = EX_List;
|
||||
pNew->x.pList = pList;
|
||||
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew);
|
||||
/* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */
|
||||
/* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm used again */
|
||||
markTermAsChild(pWC, idxNew, idxTerm);
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
sqlite3ExprDelete(db, pNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -900,15 +912,16 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
|
||||
aff1 = sqlite3ExprAffinity(pExpr->pLeft);
|
||||
aff2 = sqlite3ExprAffinity(pExpr->pRight);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
aff2 = sqlite3ExprAffinity(pExpr->x.pRight);
|
||||
if( aff1!=aff2
|
||||
&& (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2))
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
pColl = sqlite3ComparisonExprCollSeq(pParse, pExpr);
|
||||
if( sqlite3IsBinary(pColl) ) return 1;
|
||||
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->x.pRight);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1053,17 +1066,25 @@ static void exprAnalyze(
|
||||
prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
|
||||
op = pExpr->op;
|
||||
if( op==TK_IN ){
|
||||
assert( pExpr->pRight==0 );
|
||||
assert( pExpr->eX!=EX_Right );
|
||||
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
|
||||
}else{
|
||||
pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
|
||||
switch( pExpr->eX ){
|
||||
case EX_Select: {
|
||||
pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet,pExpr->x.pList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if( op==TK_ISNULL ){
|
||||
pTerm->prereqRight = 0;
|
||||
}else{
|
||||
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
|
||||
assert( op!=TK_ISNULL || pExpr->eX!=EX_Right );
|
||||
if( pExpr->eX==EX_Right ){
|
||||
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->x.pRight);
|
||||
}else{
|
||||
pTerm->prereqRight = 0;
|
||||
}
|
||||
}
|
||||
pMaskSet->bVarSelect = 0;
|
||||
prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
|
||||
@@ -1084,10 +1105,16 @@ static void exprAnalyze(
|
||||
pTerm->eOperator = 0;
|
||||
if( allowedOp(op) ){
|
||||
int aiCurCol[2];
|
||||
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
|
||||
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
|
||||
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
|
||||
Expr *pLeft, *pRight;
|
||||
u16 opMask;
|
||||
|
||||
pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
|
||||
if( pExpr->eX==EX_Right ){
|
||||
pRight = sqlite3ExprSkipCollate(pExpr->x.pRight);
|
||||
}else{
|
||||
pRight = 0;
|
||||
}
|
||||
opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
|
||||
if( pTerm->iField>0 ){
|
||||
assert( op==TK_IN );
|
||||
assert( pLeft->op==TK_VECTOR );
|
||||
@@ -1328,17 +1355,18 @@ static void exprAnalyze(
|
||||
if( pWC->op==TK_AND
|
||||
&& (pExpr->op==TK_EQ || pExpr->op==TK_IS)
|
||||
&& (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
|
||||
&& sqlite3ExprVectorSize(pExpr->pRight)==nLeft
|
||||
&& ( (pExpr->pLeft->flags & EP_xIsSelect)==0
|
||||
|| (pExpr->pRight->flags & EP_xIsSelect)==0)
|
||||
&& ALWAYS(pExpr->eX==EX_Right)
|
||||
&& sqlite3ExprVectorSize(pExpr->x.pRight)==nLeft
|
||||
&& ( pExpr->pLeft->eX!=EX_Select || pExpr->x.pRight->eX!=EX_Select )
|
||||
){
|
||||
int i;
|
||||
for(i=0; i<nLeft; i++){
|
||||
int idxNew;
|
||||
Expr *pNew;
|
||||
Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
|
||||
Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
|
||||
Expr *pNew, *pLeft, *pRight;
|
||||
|
||||
pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
|
||||
assert( pExpr->eX==EX_Right );
|
||||
pRight = sqlite3ExprForVectorField(pParse, pExpr->x.pRight, i);
|
||||
pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
|
||||
transferJoinMarkings(pNew, pExpr);
|
||||
idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
|
||||
@@ -1446,8 +1474,9 @@ void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
||||
if( pE2->op!=op ){
|
||||
whereClauseInsert(pWC, pExpr, 0);
|
||||
}else{
|
||||
assert( pE2->eX==EX_Right );
|
||||
sqlite3WhereSplit(pWC, pE2->pLeft, op);
|
||||
sqlite3WhereSplit(pWC, pE2->pRight, op);
|
||||
sqlite3WhereSplit(pWC, pE2->x.pRight, op);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1506,14 +1535,20 @@ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
|
||||
}
|
||||
mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
|
||||
if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
|
||||
if( p->pRight ){
|
||||
mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
|
||||
assert( p->x.pList==0 );
|
||||
}else if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
|
||||
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
|
||||
}else if( p->x.pList ){
|
||||
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
|
||||
switch( p->eX ){
|
||||
case EX_Right: {
|
||||
mask |= sqlite3WhereExprUsageNN(pMaskSet, p->x.pRight);
|
||||
break;
|
||||
}
|
||||
case EX_Select: {
|
||||
if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
|
||||
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
|
||||
break;
|
||||
}
|
||||
case EX_List: {
|
||||
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
@@ -1573,7 +1608,6 @@ void sqlite3WhereTabFuncArgs(
|
||||
pArgs = pItem->u1.pFuncArg;
|
||||
if( pArgs==0 ) return;
|
||||
for(j=k=0; j<pArgs->nExpr; j++){
|
||||
Expr *pRhs;
|
||||
while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
|
||||
if( k>=pTab->nCol ){
|
||||
sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
|
||||
@@ -1584,10 +1618,10 @@ void sqlite3WhereTabFuncArgs(
|
||||
if( pColRef==0 ) return;
|
||||
pColRef->iTable = pItem->iCursor;
|
||||
pColRef->iColumn = k++;
|
||||
pColRef->y.pTab = pTab;
|
||||
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
|
||||
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
|
||||
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
|
||||
pColRef->x.pTab = pTab;
|
||||
pColRef->eX = EX_Tab;
|
||||
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
|
||||
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0));
|
||||
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -624,12 +624,12 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
switch( pExpr->op ){
|
||||
|
||||
case TK_FUNCTION:
|
||||
if( !ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
if( pExpr->pWin==0 ){
|
||||
break;
|
||||
}else{
|
||||
Window *pWin;
|
||||
for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){
|
||||
if( pExpr->y.pWin==pWin ){
|
||||
if( pExpr->pWin==pWin ){
|
||||
assert( pWin->pOwner==pExpr );
|
||||
return WRC_Prune;
|
||||
}
|
||||
@@ -746,7 +746,7 @@ static ExprList *exprListAppendList(
|
||||
*/
|
||||
int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p->pWin && p->pPrior==0 ){
|
||||
if( p->pWin ){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3 *db = pParse->db;
|
||||
Select *pSub = 0; /* The subquery */
|
||||
@@ -959,13 +959,11 @@ windowAllocErr:
|
||||
*/
|
||||
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
|
||||
if( p ){
|
||||
assert( p->op==TK_FUNCTION );
|
||||
/* This routine is only called for the parser. If pWin was not
|
||||
** allocated due to an OOM, then the parser would fail before ever
|
||||
** invoking this routine */
|
||||
if( ALWAYS(pWin) ){
|
||||
p->y.pWin = pWin;
|
||||
ExprSetProperty(p, EP_WinFunc);
|
||||
p->pWin = pWin;
|
||||
pWin->pOwner = p;
|
||||
if( p->flags & EP_Distinct ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
@@ -2128,7 +2126,7 @@ static void windowCodeDefaultStep(
|
||||
*/
|
||||
Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
|
||||
Window *pNew = 0;
|
||||
if( ALWAYS(p) ){
|
||||
if( p ){
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(Window));
|
||||
if( pNew ){
|
||||
pNew->zName = sqlite3DbStrDup(db, p->zName);
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ set testprefix alterauth
|
||||
set ::auth [list]
|
||||
proc xAuth {type args} {
|
||||
if {$type == "SQLITE_ALTER_TABLE"} {
|
||||
lappend ::auth [concat $type [lrange $args 0 3]]
|
||||
lappend ::auth [concat $type $args]
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
# 2018 October 6
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set testprefix alterauth2
|
||||
|
||||
set ::auth [list]
|
||||
proc xAuth {type args} {
|
||||
lappend ::auth [concat $type [lrange $args 0 3]]
|
||||
if {$type=="SQLITE_READ" && [lindex $args 0] == "t2"} breakpoint
|
||||
return SQLITE_OK
|
||||
}
|
||||
db auth xAuth
|
||||
|
||||
proc do_auth_test {tn sql authcode} {
|
||||
set script "
|
||||
set ::auth \[list\]
|
||||
execsql {$sql}
|
||||
lsort -unique \[set ::auth\]
|
||||
"
|
||||
|
||||
set normal [list {*}$authcode]
|
||||
uplevel [list do_test $tn $script $normal]
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
DELETE FROM t1 WHERE a<new.a;
|
||||
END;
|
||||
|
||||
CREATE TEMP TRIGGER tr2 AFTER UPDATE OF a, b ON t1 BEGIN
|
||||
UPDATE t1 SET a=a+1 WHERE new.b<b;
|
||||
END;
|
||||
}
|
||||
|
||||
do_auth_test 1.1 {
|
||||
ALTER TABLE t1 RENAME TO t2;
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t1 {} {}}
|
||||
{SQLITE_FUNCTION {} like {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_rename_table {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_rename_test {} {}}
|
||||
{SQLITE_FUNCTION {} substr {} {}}
|
||||
{SQLITE_READ sqlite_master name main {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_READ sqlite_temp_master name temp {}}
|
||||
{SQLITE_READ sqlite_temp_master sql temp {}}
|
||||
{SQLITE_READ sqlite_temp_master tbl_name temp {}}
|
||||
{SQLITE_READ sqlite_temp_master type temp {}}
|
||||
{SQLITE_SELECT {} {} {} {}}
|
||||
{SQLITE_UPDATE sqlite_master name main {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
{SQLITE_UPDATE sqlite_master tbl_name main {}}
|
||||
{SQLITE_UPDATE sqlite_temp_master sql temp {}}
|
||||
{SQLITE_UPDATE sqlite_temp_master tbl_name temp {}}
|
||||
}
|
||||
|
||||
do_auth_test 1.2 {
|
||||
ALTER TABLE t2 RENAME a TO aaa;
|
||||
} {
|
||||
{SQLITE_ALTER_TABLE main t2 {} {}}
|
||||
{SQLITE_FUNCTION {} like {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_rename_column {} {}}
|
||||
{SQLITE_FUNCTION {} sqlite_rename_test {} {}}
|
||||
{SQLITE_READ sqlite_master name main {}}
|
||||
{SQLITE_READ sqlite_master sql main {}}
|
||||
{SQLITE_READ sqlite_master tbl_name main {}}
|
||||
{SQLITE_READ sqlite_master type main {}}
|
||||
{SQLITE_READ sqlite_temp_master name temp {}}
|
||||
{SQLITE_READ sqlite_temp_master sql temp {}}
|
||||
{SQLITE_READ sqlite_temp_master type temp {}}
|
||||
{SQLITE_SELECT {} {} {} {}}
|
||||
{SQLITE_UPDATE sqlite_master sql main {}}
|
||||
{SQLITE_UPDATE sqlite_temp_master sql temp {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -1,470 +0,0 @@
|
||||
# 2018 September 20
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix alterlegacy
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE t1(a, b, CHECK(t1.a != t1.b));
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE INDEX t2expr ON t2(a) WHERE t2.b>0;
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))}
|
||||
{CREATE TABLE t2(a, b)}
|
||||
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
|
||||
}
|
||||
|
||||
# Legacy behavior is to corrupt the schema in this case, as the table name in
|
||||
# the CHECK constraint is incorrect after "t1" is renamed. This version is
|
||||
# slightly different - it rejects the change and rolls back the transaction.
|
||||
do_catchsql_test 1.2 {
|
||||
ALTER TABLE t1 RENAME TO t1new;
|
||||
} {1 {no such column: t1.a}}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
CREATE TABLE t3(c, d);
|
||||
ALTER TABLE t3 RENAME TO t3new;
|
||||
DROP TABLE t3new;
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))}
|
||||
{CREATE TABLE t2(a, b)}
|
||||
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
|
||||
}
|
||||
|
||||
|
||||
do_catchsql_test 1.3 {
|
||||
ALTER TABLE t2 RENAME TO t2new;
|
||||
} {1 {no such column: t2.b}}
|
||||
do_execsql_test 1.4 {
|
||||
SELECT sql FROM sqlite_master
|
||||
} {
|
||||
{CREATE TABLE t1(a, b, CHECK(t1.a != t1.b))}
|
||||
{CREATE TABLE t2(a, b)}
|
||||
{CREATE INDEX t2expr ON t2(a) WHERE t2.b>0}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
ifcapable vtab {
|
||||
register_echo_module db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE abc(a, b, c);
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
CREATE VIRTUAL TABLE eee USING echo('abc');
|
||||
SELECT * FROM eee;
|
||||
} {1 2 3}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
ALTER TABLE eee RENAME TO fff;
|
||||
SELECT * FROM fff;
|
||||
} {1 2 3}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_catchsql_test 2.2 {
|
||||
ALTER TABLE fff RENAME TO ggg;
|
||||
} {1 {no such module: echo}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE txx(a, b, c);
|
||||
INSERT INTO txx VALUES(1, 2, 3);
|
||||
CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx;
|
||||
CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one;
|
||||
CREATE VIEW temp.ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx;
|
||||
}
|
||||
|
||||
do_execsql_test 3.1.1 {
|
||||
SELECT * FROM vvv;
|
||||
} {1 2 3}
|
||||
do_execsql_test 3.1.2a {
|
||||
ALTER TABLE txx RENAME TO "t xx";
|
||||
}
|
||||
do_catchsql_test 3.1.2b {
|
||||
SELECT * FROM vvv;
|
||||
} {1 {no such table: main.txx}}
|
||||
do_execsql_test 3.1.3 {
|
||||
SELECT sql FROM sqlite_master WHERE name='vvv';
|
||||
} {{CREATE VIEW vvv AS SELECT main.txx.a, txx.b, c FROM txx}}
|
||||
|
||||
|
||||
do_catchsql_test 3.2.1 {
|
||||
SELECT * FROM uuu;
|
||||
} {1 {no such table: main.txx}}
|
||||
do_execsql_test 3.2.2 {
|
||||
SELECT sql FROM sqlite_master WHERE name='uuu';;
|
||||
} {{CREATE VIEW uuu AS SELECT main.one.a, one.b, c FROM txx AS one}}
|
||||
|
||||
do_catchsql_test 3.3.1 {
|
||||
SELECT * FROM ttt;
|
||||
} {1 {no such table: txx}}
|
||||
do_execsql_test 3.3.2 {
|
||||
SELECT sql FROM sqlite_temp_master WHERE name='ttt';
|
||||
} {{CREATE VIEW ttt AS SELECT main.txx.a, txx.b, one.b, main.one.a FROM txx AS one, txx}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE table t1(x, y);
|
||||
CREATE table t2(a, b);
|
||||
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
|
||||
SELECT t1.x, * FROM t1, t2;
|
||||
INSERT INTO t2 VALUES(new.x, new.y);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
ALTER TABLE t1 RENAME TO t11;
|
||||
}
|
||||
do_catchsql_test 4.1a {
|
||||
INSERT INTO t11 VALUES(2, 2);
|
||||
} {1 {no such table: main.t1}}
|
||||
do_execsql_test 4.1b {
|
||||
ALTER TABLE t11 RENAME TO t1;
|
||||
ALTER TABLE t2 RENAME TO t22;
|
||||
}
|
||||
do_catchsql_test 4.1c {
|
||||
INSERT INTO t1 VALUES(3, 3);
|
||||
} {1 {no such table: main.t2}}
|
||||
|
||||
proc squish {a} {
|
||||
string trim [regsub -all {[[:space:]][[:space:]]*} $a { }]
|
||||
}
|
||||
db func squish squish
|
||||
do_test 4.2 {
|
||||
execsql { SELECT squish(sql) FROM sqlite_master WHERE name = 'tr1' }
|
||||
} [list [squish {
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON "t1" BEGIN
|
||||
SELECT t1.x, * FROM t1, t2;
|
||||
INSERT INTO t2 VALUES(new.x, new.y);
|
||||
END
|
||||
}]]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE t9(a, b, c);
|
||||
CREATE TABLE t10(a, b, c);
|
||||
CREATE TEMP TABLE t9(a, b, c);
|
||||
|
||||
CREATE TRIGGER temp.t9t AFTER INSERT ON temp.t9 BEGIN
|
||||
INSERT INTO t10 VALUES(new.a, new.b, new.c);
|
||||
END;
|
||||
|
||||
INSERT INTO temp.t9 VALUES(1, 2, 3);
|
||||
SELECT * FROM t10;
|
||||
} {1 2 3}
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
ALTER TABLE temp.t9 RENAME TO 't1234567890'
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
CREATE VIEW v AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
|
||||
SELECT * FROM v;
|
||||
} {1 2 3 4}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
ALTER TABLE t2 RENAME TO one;
|
||||
} {}
|
||||
|
||||
do_catchsql_test 5.4 {
|
||||
SELECT * FROM v
|
||||
} {1 {no such table: main.t2}}
|
||||
|
||||
do_execsql_test 5.5 {
|
||||
ALTER TABLE one RENAME TO t2;
|
||||
DROP VIEW v;
|
||||
CREATE VIEW temp.vv AS SELECT one.a, one.b, t2.a, t2.b FROM t1 AS one, t2;
|
||||
SELECT * FROM vv;
|
||||
} {1 2 3 4}
|
||||
|
||||
do_execsql_test 5.6 {
|
||||
ALTER TABLE t2 RENAME TO one;
|
||||
} {}
|
||||
do_catchsql_test 5.7 {
|
||||
SELECT * FROM vv
|
||||
} {1 {no such table: t2}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
ifcapable vtab {
|
||||
register_tcl_module db
|
||||
proc tcl_command {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1(a, b, c)"
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 6.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
|
||||
}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
ALTER TABLE x1 RENAME TO x2;
|
||||
SELECT sql FROM sqlite_master WHERE name = 'x2'
|
||||
} {{CREATE VIRTUAL TABLE "x2" USING tcl(tcl_command)}}
|
||||
|
||||
do_execsql_test 7.1 {
|
||||
CREATE TABLE ddd(db, sql, zOld, zNew, bTemp);
|
||||
INSERT INTO ddd VALUES(
|
||||
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', 'ddd', NULL, 0
|
||||
), (
|
||||
'main', 'CREATE TABLE x1(i INTEGER, t TEXT)', NULL, 'eee', 0
|
||||
), (
|
||||
'main', NULL, 'ddd', 'eee', 0
|
||||
);
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
do_execsql_test 8.1 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
ATTACH 'test.db2' AS aux;
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE aux.p1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE aux.c1(x INTEGER PRIMARY KEY, y REFERENCES p1(a));
|
||||
INSERT INTO aux.p1 VALUES(1, 1);
|
||||
INSERT INTO aux.p1 VALUES(2, 2);
|
||||
INSERT INTO aux.c1 VALUES(NULL, 2);
|
||||
CREATE TABLE aux.c2(x INTEGER PRIMARY KEY, y REFERENCES c1(a));
|
||||
}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
ALTER TABLE aux.p1 RENAME TO ppp;
|
||||
}
|
||||
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO aux.c1 VALUES(NULL, 1);
|
||||
SELECT sql FROM aux.sqlite_master WHERE name = 'c1';
|
||||
} {{CREATE TABLE c1(x INTEGER PRIMARY KEY, y REFERENCES "ppp"(a))}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE VIEW v1 AS SELECT * FROM t2;
|
||||
}
|
||||
do_execsql_test 9.1 {
|
||||
ALTER TABLE t1 RENAME TO t3;
|
||||
} {}
|
||||
do_execsql_test 9.1b {
|
||||
ALTER TABLE t3 RENAME TO t1;
|
||||
} {}
|
||||
do_execsql_test 9.2 {
|
||||
DROP VIEW v1;
|
||||
CREATE TRIGGER tr AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO t2 VALUES(new.a);
|
||||
END;
|
||||
}
|
||||
do_execsql_test 9.3 {
|
||||
ALTER TABLE t1 RENAME TO t3;
|
||||
} {}
|
||||
|
||||
forcedelete test.db2
|
||||
do_execsql_test 9.4 {
|
||||
ALTER TABLE t3 RENAME TO t1;
|
||||
DROP TRIGGER tr;
|
||||
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TRIGGER tr AFTER INSERT ON t1 WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END;
|
||||
|
||||
CREATE TABLE aux.t1(x);
|
||||
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END;
|
||||
}
|
||||
do_execsql_test 9.5 {
|
||||
ALTER TABLE main.t1 RENAME TO t3;
|
||||
}
|
||||
do_execsql_test 9.6 {
|
||||
SELECT sql FROM sqlite_temp_master;
|
||||
SELECT sql FROM sqlite_master WHERE type='trigger';
|
||||
} {
|
||||
{CREATE TRIGGER tr AFTER INSERT ON aux.t1 BEGIN SELECT 1, 2, 3; END}
|
||||
{CREATE TRIGGER tr AFTER INSERT ON "t3" WHEN new.a IS NULL BEGIN SELECT 1, 2, 3; END}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
ifcapable fts5 {
|
||||
do_execsql_test 10.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE VIRTUAL TABLE fff USING fts5(x, y, z);
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
BEGIN;
|
||||
INSERT INTO fff VALUES('a', 'b', 'c');
|
||||
ALTER TABLE fff RENAME TO ggg;
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
SELECT * FROM ggg;
|
||||
} {a b c}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete test.db2
|
||||
db func trigger trigger
|
||||
set ::trigger [list]
|
||||
proc trigger {args} {
|
||||
lappend ::trigger $args
|
||||
}
|
||||
do_execsql_test 11.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t1(a, b, c);
|
||||
CREATE TABLE main.t1(a, b, c);
|
||||
CREATE TEMP TRIGGER tr AFTER INSERT ON aux.t1 BEGIN
|
||||
SELECT trigger(new.a, new.b, new.c);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 11.1 {
|
||||
INSERT INTO main.t1 VALUES(1, 2, 3);
|
||||
INSERT INTO aux.t1 VALUES(4, 5, 6);
|
||||
}
|
||||
do_test 11.2 { set ::trigger } {{4 5 6}}
|
||||
|
||||
do_execsql_test 11.3 {
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t1}
|
||||
|
||||
do_execsql_test 11.4 {
|
||||
ALTER TABLE main.t1 RENAME TO t2;
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t1}
|
||||
|
||||
do_execsql_test 11.5 {
|
||||
ALTER TABLE aux.t1 RENAME TO t2;
|
||||
SELECT name, tbl_name FROM sqlite_temp_master;
|
||||
} {tr t2}
|
||||
|
||||
do_execsql_test 11.6 {
|
||||
INSERT INTO aux.t2 VALUES(7, 8, 9);
|
||||
}
|
||||
do_test 11.7 { set ::trigger } {{4 5 6} {7 8 9}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 12.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE t1(a);
|
||||
CREATE TABLE t2(w);
|
||||
CREATE TRIGGER temp.r1 AFTER INSERT ON main.t2 BEGIN
|
||||
INSERT INTO t1(a) VALUES(new.w);
|
||||
END;
|
||||
CREATE TEMP TABLE t2(x);
|
||||
}
|
||||
|
||||
do_execsql_test 12.1 {
|
||||
ALTER TABLE main.t2 RENAME TO t3;
|
||||
}
|
||||
|
||||
do_execsql_test 12.2 {
|
||||
INSERT INTO t3 VALUES('WWW');
|
||||
SELECT * FROM t1;
|
||||
} {WWW}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
ifcapable rtree {
|
||||
do_execsql_test 14.0 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy);
|
||||
|
||||
CREATE TABLE "mytable" ( "fid" INTEGER PRIMARY KEY, "geom" BLOB);
|
||||
|
||||
CREATE TRIGGER tr1 AFTER UPDATE OF "geom" ON "mytable"
|
||||
WHEN OLD."fid" = NEW."fid" AND NEW."geom" IS NULL BEGIN
|
||||
DELETE FROM rt WHERE id = OLD."fid";
|
||||
END;
|
||||
|
||||
INSERT INTO mytable VALUES(1, X'abcd');
|
||||
}
|
||||
|
||||
do_execsql_test 14.1 {
|
||||
UPDATE mytable SET geom = X'1234'
|
||||
}
|
||||
|
||||
do_execsql_test 14.2 {
|
||||
ALTER TABLE mytable RENAME TO mytable_renamed;
|
||||
}
|
||||
|
||||
do_execsql_test 14.3 {
|
||||
CREATE TRIGGER tr2 AFTER INSERT ON mytable_renamed BEGIN
|
||||
DELETE FROM rt WHERE id=(SELECT min(id) FROM rt);
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 14.4 {
|
||||
ALTER TABLE mytable_renamed RENAME TO mytable2;
|
||||
}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 14.5 {
|
||||
PRAGMA legacy_alter_table = 1;
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||
CREATE TRIGGER xyz AFTER INSERT ON t1 BEGIN
|
||||
SELECT a, b FROM v1;
|
||||
END;
|
||||
}
|
||||
do_execsql_test 14.6 {
|
||||
ALTER TABLE t1 RENAME TO tt1;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -72,30 +72,4 @@ do_faultsim_test 3 -prep {
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE rr(a, b);
|
||||
CREATE VIEW vv AS SELECT * FROM rr;
|
||||
|
||||
CREATE TRIGGER vv1 INSTEAD OF INSERT ON vv BEGIN
|
||||
SELECT 1, 2, 3;
|
||||
END;
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON rr BEGIN
|
||||
INSERT INTO vv VALUES(new.a, new.b);
|
||||
END;
|
||||
} {}
|
||||
|
||||
faultsim_save_and_close
|
||||
do_faultsim_test 4 -faults oom-* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT * FROM sqlite_master }
|
||||
} -body {
|
||||
execsql {
|
||||
ALTER TABLE rr RENAME a TO c;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -459,49 +459,6 @@ do_execsql_test 14.6 {
|
||||
ALTER TABLE t1 RENAME TO tt1;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 15.0 {
|
||||
CREATE TABLE t1(a integer NOT NULL PRIMARY KEY);
|
||||
CREATE VIEW v1 AS SELECT a FROM t1;
|
||||
CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
|
||||
UPDATE t1 SET a = NEW.a;
|
||||
END;
|
||||
CREATE TRIGGER tr2 INSTEAD OF INSERT ON v1 BEGIN
|
||||
SELECT new.a;
|
||||
END;
|
||||
CREATE TABLE t2 (b);
|
||||
}
|
||||
|
||||
do_execsql_test 15.1 {
|
||||
INSERT INTO v1 VALUES(1);
|
||||
ALTER TABLE t2 RENAME TO t3;
|
||||
}
|
||||
|
||||
do_execsql_test 15.2 {
|
||||
CREATE TABLE x(f1 integer NOT NULL);
|
||||
CREATE VIEW y AS SELECT f1 AS f1 FROM x;
|
||||
CREATE TRIGGER t INSTEAD OF UPDATE OF f1 ON y BEGIN
|
||||
UPDATE x SET f1 = NEW.f1;
|
||||
END;
|
||||
CREATE TABLE z (f1 integer NOT NULL PRIMARY KEY);
|
||||
ALTER TABLE z RENAME TO z2;
|
||||
}
|
||||
|
||||
do_execsql_test 15.3 {
|
||||
INSERT INTO x VALUES(1), (2), (3);
|
||||
ALTER TABLE x RENAME f1 TO f2;
|
||||
SELECT * FROM x;
|
||||
} {1 2 3}
|
||||
|
||||
do_execsql_test 15.4 {
|
||||
UPDATE y SET f1 = 'x' WHERE f1 = 1;
|
||||
SELECT * FROM x;
|
||||
} {x x x}
|
||||
|
||||
do_execsql_test 15.5 {
|
||||
SELECT sql FROM sqlite_master WHERE name = 'y';
|
||||
} {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# 2018 September 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix altertab
|
||||
|
||||
# If SQLITE_OMIT_ALTERTABLE is defined, omit this file.
|
||||
ifcapable !altertable {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
ifcapable fts5 {
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE rr(a, b);
|
||||
CREATE VIRTUAL TABLE ff USING fts5(a, b);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON rr BEGIN
|
||||
INSERT INTO ff VALUES(new.a, new.b);
|
||||
END;
|
||||
INSERT INTO rr VALUES('hello', 'world');
|
||||
SELECT * FROM ff;
|
||||
} {hello world}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
ALTER TABLE ff RENAME TO ffff;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO rr VALUES('in', 'tcl');
|
||||
SELECT * FROM ffff;
|
||||
} {hello world in tcl}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-2
@@ -2598,8 +2598,7 @@ do_test auth-8.2 {
|
||||
# invocation with no column name specified, compilation fails.
|
||||
#
|
||||
set ::authargs [list]
|
||||
proc auth {op args} {
|
||||
foreach {a b c d} $args break
|
||||
proc auth {op a b c d} {
|
||||
lappend ::authargs $op $a $b $c $d
|
||||
if {$op == "SQLITE_READ"} { return "SQLITE_DENY" }
|
||||
return "SQLITE_OK"
|
||||
|
||||
@@ -117,57 +117,4 @@ for {set param1 0} {$param1<16} {incr param1} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that a parameter passed to a table-valued function cannot be
|
||||
# used to drive an index. i.e. that in the following:
|
||||
#
|
||||
# SELECT * FROM tbl, vtab(tbl.x);
|
||||
#
|
||||
# The implicit constraint "tbl.x = vtab.hidden" is not optimized using
|
||||
# an index on tbl.x.
|
||||
#
|
||||
reset_db
|
||||
register_tcl_module db
|
||||
proc vtab_command {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1(a, b, c, d HIDDEN)"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
set clist [lindex $args 0]
|
||||
if {[llength $clist]!=1} { error "unexpected constraint list" }
|
||||
catch { array unset C }
|
||||
array set C [lindex $clist 0]
|
||||
if {$C(usable)} {
|
||||
return [list omit 0 idxnum 555 rows 10 cost 100]
|
||||
}
|
||||
return [list cost 100000000]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
|
||||
CREATE TABLE t1 (x INT PRIMARY KEY);
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1, x1 WHERE x1.d=t1.x;
|
||||
} {
|
||||
3 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 0:}
|
||||
7 0 0 {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (x=?)}
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1, x1(t1.x)
|
||||
} {
|
||||
3 0 0 {SCAN TABLE t1}
|
||||
5 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bestindex4
|
||||
set testprefix bestindex5
|
||||
|
||||
ifcapable !vtab {
|
||||
finish_test
|
||||
@@ -247,4 +247,3 @@ do_execsql_test 3.5 { SELECT rowid, * FROM t4 WHERE rowid!=1 OR x!='245'; } {}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
Binary file not shown.
-131
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
** 2018-10-26
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This program is designed for fuzz-testing SQLite database files using
|
||||
** the -fsanitize=fuzzer option of clang.
|
||||
**
|
||||
** The -fsanitize=fuzzer option causes a main() to be inserted automatically.
|
||||
** That main() invokes LLVMFuzzerTestOneInput(D,S) to be invoked repeatedly.
|
||||
** Each D is a fuzzed database file. The code in this file runs various
|
||||
** SQL statements against that database, trying to provoke a failure.
|
||||
**
|
||||
** For best results the seed database files should have these tables:
|
||||
**
|
||||
** Table "t1" with columns "a" and "b"
|
||||
** Tables "t2" and "t3 with the same number of compatible columns
|
||||
** "t3" should have a column names "x"
|
||||
** Table "t4" with a column "x" that is compatible with t3.x.
|
||||
**
|
||||
** Any of these tables can be virtual tables, for example FTS or RTree tables.
|
||||
**
|
||||
** To run this test:
|
||||
**
|
||||
** mkdir dir
|
||||
** cp dbfuzz2-seed*.db dir
|
||||
** clang-6.0 -I. -g -O1 -fsanitize=fuzzer \
|
||||
** -DTHREADSAFE=0 -DSQLITE_ENABLE_DESERIALIZE \
|
||||
** -DSQLITE_ENABLE_DBSTAT_VTAB dbfuzz2.c sqlite3.c -ldl
|
||||
** ./a.out dir
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** This is the is the SQL that is run against the database.
|
||||
*/
|
||||
static const char *azSql[] = {
|
||||
"PRAGMA integrity_check;",
|
||||
"SELECT * FROM sqlite_master;",
|
||||
"SELECT sum(length(name)) FROM dbstat;",
|
||||
"UPDATE t1 SET b=a, a=b WHERE a<b;",
|
||||
"ALTER TABLE t1 RENAME TO alkjalkjdfiiiwuer987lkjwer82mx97sf98788s9789s;",
|
||||
"INSERT INTO t3 SELECT * FROM t2;",
|
||||
"DELETE FROM t3 WHERE x IN (SELECT x FROM t4);",
|
||||
"REINDEX;",
|
||||
"DROP TABLE t3;",
|
||||
"VACUUM;",
|
||||
};
|
||||
|
||||
/* Output verbosity level. 0 means complete silence */
|
||||
int eVerbosity = 0;
|
||||
|
||||
/* libFuzzer invokes this routine with fuzzed database files (in aData).
|
||||
** This routine run SQLite against the malformed database to see if it
|
||||
** can provoke a failure or malfunction.
|
||||
*/
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){
|
||||
unsigned char *a;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
if( eVerbosity>=1 ){
|
||||
printf("************** nByte=%d ***************\n", (int)nByte);
|
||||
fflush(stdout);
|
||||
}
|
||||
rc = sqlite3_open(":memory:", &db);
|
||||
if( rc ) return 1;
|
||||
a = sqlite3_malloc64(nByte);
|
||||
if( a==0 ) return 1;
|
||||
memcpy(a, aData, nByte);
|
||||
sqlite3_deserialize(db, "main", a, nByte, nByte,
|
||||
SQLITE_DESERIALIZE_RESIZEABLE |
|
||||
SQLITE_DESERIALIZE_FREEONCLOSE);
|
||||
for(i=0; i<sizeof(azSql)/sizeof(azSql[0]); i++){
|
||||
if( eVerbosity>=1 ){
|
||||
printf("%s\n", azSql[i]);
|
||||
fflush(stdout);
|
||||
}
|
||||
sqlite3_exec(db, azSql[i], 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(db);
|
||||
if( sqlite3_memory_used()!=0 ){
|
||||
fprintf(stderr,"Memory leak: %lld bytes\n", sqlite3_memory_used());
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* libFuzzer invokes this routine once when the executable starts, to
|
||||
** process the command-line arguments.
|
||||
*/
|
||||
int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){
|
||||
int i, j;
|
||||
int argc = *pArgc;
|
||||
char **newArgv;
|
||||
char **argv = *pArgv;
|
||||
newArgv = malloc( sizeof(char*)*(argc+1) );
|
||||
if( newArgv==0 ) return 0;
|
||||
newArgv[0] = argv[0];
|
||||
for(i=j=1; i<argc; i++){
|
||||
char *z = argv[i];
|
||||
if( z[0]=='-' ){
|
||||
z++;
|
||||
if( z[0]=='-' ) z++;
|
||||
if( strcmp(z,"v")==0 ){
|
||||
eVerbosity++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
newArgv[j++] = argv[i];
|
||||
}
|
||||
newArgv[j] = 0;
|
||||
*pArgv = newArgv;
|
||||
*pArgc = j;
|
||||
return 0;
|
||||
}
|
||||
+2
-2
@@ -379,9 +379,9 @@ foreach ::lookaside_buffer_size {0 64 120} {
|
||||
# The following tests focus on DBSTATUS_CACHE_USED_SHARED
|
||||
#
|
||||
ifcapable shared_cache {
|
||||
if {([permutation]=="memsys3"
|
||||
if {[permutation]=="memsys3"
|
||||
|| [permutation]=="memsys5"
|
||||
|| $::tcl_platform(os)=="Linux") && ![sqlite3 -has-codec]} {
|
||||
|| $::tcl_platform(os)=="Linux"} {
|
||||
proc do_cacheused_test {tn db res} {
|
||||
set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0]
|
||||
set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0]
|
||||
|
||||
Binary file not shown.
@@ -130,14 +130,12 @@ do_eqp_test like3-5.101 {
|
||||
do_execsql_test like3-5.110 {
|
||||
SELECT x FROM t5a WHERE x LIKE '/a%';
|
||||
} {/abc}
|
||||
ifcapable !icu {
|
||||
do_eqp_test like3-5.111 {
|
||||
SELECT x FROM t5a WHERE x LIKE '/a%';
|
||||
} {
|
||||
QUERY PLAN
|
||||
`--SEARCH TABLE t5a USING COVERING INDEX sqlite_autoindex_t5a_1 (x>? AND x<?)
|
||||
}
|
||||
}
|
||||
do_execsql_test like3-5.120 {
|
||||
SELECT x FROM t5a WHERE x LIKE '^12%' ESCAPE '^';
|
||||
} {123}
|
||||
|
||||
@@ -72,293 +72,4 @@ foreach {tnum sql norm} {
|
||||
do_test $tnum [list sqlite3_normalize $sql] $norm
|
||||
}
|
||||
|
||||
ifcapable normalize {
|
||||
do_test 200 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b);
|
||||
}
|
||||
} {}
|
||||
do_test 201 {
|
||||
set STMT [sqlite3_prepare_v3 $DB \
|
||||
"SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 0 TAIL]
|
||||
|
||||
sqlite3_bind_null $STMT 1
|
||||
} {}
|
||||
do_test 202 {
|
||||
sqlite3_normalized_sql $STMT
|
||||
} {}
|
||||
do_test 203 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 210 {
|
||||
set STMT [sqlite3_prepare_v3 $DB \
|
||||
"SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 2 TAIL]
|
||||
|
||||
sqlite3_bind_null $STMT 1
|
||||
} {}
|
||||
do_test 211 {
|
||||
sqlite3_normalized_sql $STMT
|
||||
} {SELECT a,b FROM t1 WHERE b=?ORDER BY a;}
|
||||
do_test 212 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 220 {
|
||||
set STMT [sqlite3_prepare_v3 $DB \
|
||||
"SELECT a, b FROM t1 WHERE b = 'a' ORDER BY a;" -1 2 TAIL]
|
||||
} {/^[0-9A-Fa-f]+$/}
|
||||
do_test 221 {
|
||||
sqlite3_normalized_sql $STMT
|
||||
} {SELECT a,b FROM t1 WHERE b=?ORDER BY a;}
|
||||
do_test 222 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 297 {
|
||||
execsql {
|
||||
DROP TABLE t1;
|
||||
}
|
||||
} {}
|
||||
do_test 298 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c,d,e,"col f",w,x,y,z);
|
||||
CREATE TABLE t2(x,"col y");
|
||||
}
|
||||
} {}
|
||||
do_test 299 {
|
||||
sqlite3_create_function db
|
||||
} {SQLITE_OK}
|
||||
|
||||
foreach {tnum sql flags norm} {
|
||||
300
|
||||
{SELECT * FROM t1 WHERE a IN (1) AND b=51.42}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE a IN(?,?,?)AND b=?;}}
|
||||
|
||||
310
|
||||
{SELECT a, b+15, c FROM t1 WHERE d NOT IN (SELECT x FROM t2);}
|
||||
0x2
|
||||
{0 {SELECT a,b+?,c FROM t1 WHERE d NOT IN(SELECT x FROM t2);}}
|
||||
|
||||
320
|
||||
{ SELECT NULL, b FROM t1 -- comment text
|
||||
WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */
|
||||
SELECT a FROM t)
|
||||
OR e='hello';
|
||||
}
|
||||
0x2
|
||||
{0 {SELECT?,b FROM t1 WHERE d IN(WITH t(a)AS(VALUES(?))SELECT a FROM t)OR e=?;}}
|
||||
|
||||
321
|
||||
{/*Initial comment*/
|
||||
-- another comment line
|
||||
SELECT NULL /* comment */ , b FROM t1 -- comment text
|
||||
WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */
|
||||
SELECT a FROM t)
|
||||
OR e='hello';
|
||||
}
|
||||
0x2
|
||||
{0 {SELECT?,b FROM t1 WHERE d IN(WITH t(a)AS(VALUES(?))SELECT a FROM t)OR e=?;}}
|
||||
|
||||
330
|
||||
{/* Query containing parameters */
|
||||
SELECT x,$::abc(15),y,@abc,z,?99,w FROM t1 /* Trailing comment */}
|
||||
0x2
|
||||
{0 {SELECT x,?,y,?,z,?,w FROM t1;}}
|
||||
|
||||
340
|
||||
{/* Long list on the RHS of IN */
|
||||
SELECT 15 IN (1,2,3,(SELECT * FROM t1),'xyz',x'abcd',22*(x+5),null);}
|
||||
0x2
|
||||
{1 {(1) no such column: x}}
|
||||
|
||||
350
|
||||
{SELECT x'abc'; -- illegal token}
|
||||
0x2
|
||||
{1 {(1) unrecognized token: "x'abc'"}}
|
||||
|
||||
360
|
||||
{SELECT a,NULL,b FROM t1 WHERE c IS NOT NULL or D is null or e=5}
|
||||
0x2
|
||||
{0 {SELECT a,?,b FROM t1 WHERE c IS NOT NULL OR d IS NULL OR e=?;}}
|
||||
|
||||
370
|
||||
{/* IN list exactly 5 bytes long */
|
||||
SELECT * FROM t1 WHERE x IN (1,2,3);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
400
|
||||
{SELECT a FROM t1 WHERE x IN (1,2,3) AND sqlite_version();}
|
||||
0x2
|
||||
{0 {SELECT a FROM t1 WHERE x IN(?,?,?)AND sqlite_version();}}
|
||||
|
||||
410
|
||||
{SELECT a FROM t1 WHERE x IN (1,2,3) AND hex8();}
|
||||
0x2
|
||||
{1 {(1) wrong number of arguments to function hex8()}}
|
||||
|
||||
420
|
||||
{SELECT a FROM t1 WHERE x IN (1,2,3) AND hex8('abc');}
|
||||
0x2
|
||||
{0 {SELECT a FROM t1 WHERE x IN(?,?,?)AND hex8(?);}}
|
||||
|
||||
430
|
||||
{SELECT "a" FROM t1 WHERE "x" IN ("1","2",'3');}
|
||||
0x2
|
||||
{0 {SELECT"a"FROM t1 WHERE"x"IN(?,?,?);}}
|
||||
|
||||
440
|
||||
{SELECT 'a' FROM t1 WHERE 'x';}
|
||||
0x2
|
||||
{0 {SELECT?FROM t1 WHERE?;}}
|
||||
|
||||
450
|
||||
{SELECT [a] FROM t1 WHERE [x];}
|
||||
0x2
|
||||
{0 {SELECT"a"FROM t1 WHERE"x";}}
|
||||
|
||||
460
|
||||
{SELECT * FROM t1 WHERE x IN (x);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(x);}}
|
||||
|
||||
470
|
||||
{SELECT * FROM t1 WHERE x IN (x,a);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(x,a);}}
|
||||
|
||||
480
|
||||
{SELECT * FROM t1 WHERE x IN ([x],"a");}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN("x","a");}}
|
||||
|
||||
500
|
||||
{SELECT * FROM t1 WHERE x IN ([x],"a",'b',sqlite_version());}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN("x","a",?,sqlite_version());}}
|
||||
|
||||
520
|
||||
{SELECT * FROM t1 WHERE x IN (SELECT x FROM t1);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1);}}
|
||||
|
||||
540
|
||||
{SELECT * FROM t1 WHERE x IN ((SELECT x FROM t1));}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
550
|
||||
{SELECT a, a+1, a||'b', a+"b" FROM t1;}
|
||||
0x2
|
||||
{0 {SELECT a,a+?,a||?,a+"b"FROM t1;}}
|
||||
|
||||
570
|
||||
{SELECT * FROM t1 WHERE x IN (1);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
580
|
||||
{SELECT * FROM t1 WHERE x IN (1,2);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
590
|
||||
{SELECT * FROM t1 WHERE x IN (1,2,3);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
600
|
||||
{SELECT * FROM t1 WHERE x IN (1,2,3,4);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
610
|
||||
{SELECT * FROM t1 WHERE x IN (SELECT x FROM t1);}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1);}}
|
||||
|
||||
620
|
||||
{SELECT * FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (1,2,3));}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(?,?,?));}}
|
||||
|
||||
630
|
||||
{SELECT * FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (x));}
|
||||
0x2
|
||||
{0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(x));}}
|
||||
|
||||
640
|
||||
{SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (
|
||||
SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (
|
||||
SELECT x FROM t1 WHERE x IN (x)))));}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(x)))));}}
|
||||
|
||||
650
|
||||
{SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (
|
||||
SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (
|
||||
SELECT x FROM t1 WHERE x IN (1)))));}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(?,?,?)))));}}
|
||||
|
||||
660
|
||||
{SELECT x FROM t1 WHERE x IN (1) UNION ALL SELECT x FROM t1 WHERE x IN (1);}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IN(?,?,?)UNION ALL SELECT x FROM t1 WHERE x IN(?,?,?);}}
|
||||
|
||||
670
|
||||
{SELECT "col f", [col f] FROM t1;}
|
||||
0x2
|
||||
{0 {SELECT"col f","col f"FROM t1;}}
|
||||
|
||||
680
|
||||
{SELECT a, "col f" FROM t1 LEFT OUTER JOIN t2 ON [t1].[col f] == [t2].[col y];}
|
||||
0x2
|
||||
{0 {SELECT a,"col f"FROM t1 LEFT OUTER JOIN t2 ON"t1"."col f"=="t2"."col y";}}
|
||||
|
||||
690
|
||||
{SELECT * FROM ( WITH x AS ( SELECT * FROM t1 WHERE x IN ( 1)) SELECT 10);}
|
||||
0x2
|
||||
{0 {SELECT*FROM(WITH x AS(SELECT*FROM t1 WHERE x IN(?,?,?))SELECT?);}}
|
||||
|
||||
700
|
||||
{SELECT rowid, oid, _rowid_ FROM t1;}
|
||||
0x2
|
||||
{0 {SELECT rowid,oid,_rowid_ FROM t1;}}
|
||||
|
||||
710
|
||||
{SELECT x FROM t1 WHERE x IS NULL;}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IS NULL;}}
|
||||
|
||||
740
|
||||
{SELECT x FROM t1 WHERE x IS NOT NULL;}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IS NOT NULL;}}
|
||||
|
||||
750
|
||||
{SELECT x FROM t1 WHERE x = NULL;}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x=?;}}
|
||||
|
||||
760
|
||||
{SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');}
|
||||
0x2
|
||||
{0 {SELECT x FROM t1 WHERE x IN("x"IS NOT NULL,?,?,?,"b",?);}}
|
||||
} {
|
||||
do_test $tnum {
|
||||
set code [catch {
|
||||
set STMT [sqlite3_prepare_v3 $DB $sql -1 $flags TAIL]
|
||||
sqlite3_normalized_sql $STMT
|
||||
} res]
|
||||
if {[info exists STMT]} {
|
||||
sqlite3_finalize $STMT; unset STMT
|
||||
}
|
||||
list $code $res
|
||||
} $norm
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-5
@@ -15,11 +15,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
if {[sqlite3 -has-codec]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
do_not_use_codec
|
||||
|
||||
do_execsql_test pragma3-100 {
|
||||
PRAGMA data_version;
|
||||
|
||||
@@ -79,7 +79,6 @@ array set ::Configs [strip_comments {
|
||||
-DSQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
-DSQLITE_THREADSAFE
|
||||
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
|
||||
-DSQLITE_USER_AUTHENTICATION=1
|
||||
}
|
||||
"Secure-Delete" {
|
||||
-O2
|
||||
|
||||
+30
-32
@@ -1145,40 +1145,38 @@ do_test shared-$av-16.8 {
|
||||
|
||||
# Shared cache on named memory databases attached to readonly connections.
|
||||
#
|
||||
if {![sqlite3 -has-codec]} {
|
||||
do_test shared-$av-16.8.1 {
|
||||
db1 close
|
||||
db2 close
|
||||
|
||||
sqlite3 db test1.db
|
||||
db eval {
|
||||
CREATE TABLE yy(a, b);
|
||||
INSERT INTO yy VALUES(77, 88);
|
||||
}
|
||||
db close
|
||||
|
||||
sqlite3 db1 test1.db -uri 1 -readonly 1
|
||||
sqlite3 db2 test2.db -uri 1
|
||||
|
||||
db1 eval {
|
||||
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
|
||||
CREATE TABLE shared.xx(a, b);
|
||||
INSERT INTO xx VALUES(55, 66);
|
||||
}
|
||||
db2 eval {
|
||||
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
|
||||
SELECT * FROM xx;
|
||||
}
|
||||
} {55 66}
|
||||
|
||||
do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
|
||||
do_test shared-$av-16.8.3 {
|
||||
list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
|
||||
} {1 {attempt to write a readonly database}}
|
||||
|
||||
do_test shared-$av-16.8.1 {
|
||||
db1 close
|
||||
db2 close
|
||||
}
|
||||
|
||||
sqlite3 db test1.db
|
||||
db eval {
|
||||
CREATE TABLE yy(a, b);
|
||||
INSERT INTO yy VALUES(77, 88);
|
||||
}
|
||||
db close
|
||||
|
||||
sqlite3 db1 test1.db -uri 1 -readonly 1
|
||||
sqlite3 db2 test2.db -uri 1
|
||||
|
||||
db1 eval {
|
||||
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
|
||||
CREATE TABLE shared.xx(a, b);
|
||||
INSERT INTO xx VALUES(55, 66);
|
||||
}
|
||||
db2 eval {
|
||||
ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
|
||||
SELECT * FROM xx;
|
||||
}
|
||||
} {55 66}
|
||||
|
||||
do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
|
||||
do_test shared-$av-16.8.3 {
|
||||
list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
|
||||
} {1 {attempt to write a readonly database}}
|
||||
|
||||
db1 close
|
||||
db2 close
|
||||
|
||||
} ;# end of autovacuum on/off loop
|
||||
|
||||
|
||||
+1
-1
@@ -378,7 +378,7 @@ do_test shell1-3.10.1 {
|
||||
} {1 1 1}
|
||||
do_test shell1-3.10.2 {
|
||||
# we allow .help to take extra args (it is help after all)
|
||||
set res [catchcmd "test.db" ".help *"]
|
||||
set res [catchcmd "test.db" ".help BAD"]
|
||||
# look for a few of the possible help commands
|
||||
list [regexp {.help} $res] \
|
||||
[regexp {.quit} $res] \
|
||||
|
||||
@@ -28,9 +28,6 @@ load_static_extension db remember
|
||||
do_execsql_test tabfunc01-1.1 {
|
||||
SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
|
||||
} {1 | 3 | 5 | 7 | 9 |}
|
||||
do_execsql_test tabfunc01-1.1b {
|
||||
PRAGMA table_xinfo(generate_series);
|
||||
} {0 value {} 0 {} 0 0 1 start {} 0 {} 0 1 2 stop {} 0 {} 0 1 3 step {} 0 {} 0 1}
|
||||
do_execsql_test tabfunc01-1.2 {
|
||||
SELECT *, '|' FROM generate_series LIMIT 5;
|
||||
} {0 | 1 | 2 | 3 | 4 |}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#
|
||||
# $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $
|
||||
|
||||
catch {sqlite3}
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
@@ -33,11 +31,6 @@ do_test tcl-1.1 {
|
||||
regsub {really_sqlite3} $msg {sqlite3} msg
|
||||
lappend v $msg
|
||||
} [list 1 "wrong # args: should be \"$r\""]
|
||||
do_test tcl-1.1.1 {
|
||||
set v [catch {sqlite3} msg]
|
||||
regsub {really_sqlite3} $msg {sqlite3} msg
|
||||
lappend v $msg
|
||||
} [list 1 "wrong # args: should be \"$r\""]
|
||||
do_test tcl-1.2 {
|
||||
set v [catch {db bogus} msg]
|
||||
lappend v $msg
|
||||
|
||||
+3
-4
@@ -682,8 +682,7 @@ do_test view-25.1 {
|
||||
}
|
||||
proc authLogDelete {code arg1 arg2 arg3 arg4 args} {
|
||||
if {$code=="SQLITE_DELETE" && [string match sqlite_stat* $arg1]} {
|
||||
# lappend ::log [list $code $arg1 $arg2 $arg3 $arg4 $args]
|
||||
lappend ::log [list $code $arg1 $arg2 $arg3 $arg4]
|
||||
lappend ::log [list $code $arg1 $arg2 $arg3 $arg4 $args]
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
@@ -693,8 +692,8 @@ do_test view-25.1 {
|
||||
set log
|
||||
} {}
|
||||
|
||||
set res [list {SQLITE_DELETE sqlite_stat1 {} main {}}]
|
||||
ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {}} }
|
||||
set res [list {SQLITE_DELETE sqlite_stat1 {} main {} {}}]
|
||||
ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {} {}} }
|
||||
do_test view-25.2 {
|
||||
set log ""
|
||||
db eval {DROP TABLE t25;}
|
||||
|
||||
@@ -46,18 +46,6 @@ do_test 1.2 {
|
||||
|
||||
integrity_check 1.3
|
||||
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db -vfs unix-excl
|
||||
do_execsql_test 2.1 {
|
||||
PRAGMA page_size=512;
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE t1(a,b);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<8200)
|
||||
INSERT INTO t1(a,b) SELECT x, zeroblob(300) FROM c;
|
||||
PRAGMA integrity_check;
|
||||
} {wal ok}
|
||||
|
||||
db close
|
||||
test_syscall pagesize -1
|
||||
finish_test
|
||||
|
||||
@@ -111,15 +111,4 @@ do_execsql_test 302 {
|
||||
AND B.id=subq.zz;
|
||||
} {1}
|
||||
|
||||
# 2018-10-25: Ticket [cf5ed20f]
|
||||
# Incorrect join result with duplicate WHERE clause constraint.
|
||||
#
|
||||
do_execsql_test 400 {
|
||||
CREATE TABLE x(a, b, c);
|
||||
CREATE TABLE y(a, b);
|
||||
INSERT INTO x VALUES (1, 0, 1);
|
||||
INSERT INTO y VALUES (1, 2);
|
||||
SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -549,49 +549,4 @@ do_execsql_test 12.110 {
|
||||
ORDER BY b LIMIT 2;
|
||||
} {2 B two 3 C three}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 13.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a int, b int);
|
||||
INSERT INTO t1 VALUES(1,11);
|
||||
INSERT INTO t1 VALUES(2,12);
|
||||
}
|
||||
|
||||
do_execsql_test 13.2.1 {
|
||||
SELECT a, rank() OVER(ORDER BY b) FROM t1;
|
||||
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
|
||||
} {
|
||||
1 1 2 2 2 1 1 2
|
||||
}
|
||||
do_execsql_test 13.2.2 {
|
||||
SELECT a, rank() OVER(ORDER BY b) FROM t1
|
||||
UNION ALL
|
||||
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
|
||||
} {
|
||||
1 1 2 2 2 1 1 2
|
||||
}
|
||||
do_execsql_test 13.3 {
|
||||
SELECT a, rank() OVER(ORDER BY b) FROM t1
|
||||
UNION
|
||||
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
|
||||
} {
|
||||
1 1 1 2 2 1 2 2
|
||||
}
|
||||
|
||||
do_execsql_test 13.4 {
|
||||
SELECT a, rank() OVER(ORDER BY b) FROM t1
|
||||
EXCEPT
|
||||
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
|
||||
} {
|
||||
1 1 2 2
|
||||
}
|
||||
|
||||
do_execsql_test 13.5 {
|
||||
SELECT a, rank() OVER(ORDER BY b) FROM t1
|
||||
INTERSECT
|
||||
SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
|
||||
} {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -358,32 +358,6 @@ execsql_test 10.3 {
|
||||
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
}
|
||||
|
||||
execsql_test 11.0 {
|
||||
DROP VIEW IF EXISTS v8;
|
||||
DROP TABLE IF EXISTS t8;
|
||||
CREATE TABLE t8(t INT, total INT);
|
||||
INSERT INTO t8 VALUES(0,2);
|
||||
INSERT INTO t8 VALUES(5,1);
|
||||
INSERT INTO t8 VALUES(10,1);
|
||||
}
|
||||
|
||||
execsql_test 11.1 {
|
||||
SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8;
|
||||
}
|
||||
|
||||
execsql_test 11.2 {
|
||||
CREATE VIEW v8 AS SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8;
|
||||
}
|
||||
|
||||
execsql_test 11.3 {
|
||||
SELECT * FROM v8;
|
||||
}
|
||||
|
||||
execsql_test 11.4 {
|
||||
SELECT * FROM (
|
||||
SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8
|
||||
) sub;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+9
-57
@@ -1217,20 +1217,13 @@ do_execsql_test 9.2 {
|
||||
SELECT dense_rank() OVER (PARTITION BY x) FROM t2
|
||||
} {1 1 1 1 1 1 1}
|
||||
|
||||
|
||||
do_test 9.3 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT x, percent_rank() OVER (PARTITION BY x ORDER BY x) FROM t2}] {
|
||||
lappend myres [format %.4f [set r]]
|
||||
lappend myres [format %.2f [set r]]
|
||||
}
|
||||
set res2 {1.0000 0.0000 1.0000 0.0000 1.0000 0.0000 4.0000 0.0000 4.0000 0.0000 6.0000 0.0000 7.0000 0.0000}
|
||||
foreach r [set myres] r2 [set res2] {
|
||||
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
|
||||
error "list element [set i] does not match: got=[set r] expected=[set r2]"
|
||||
}
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
set myres
|
||||
} {1.00 0.00 1.00 0.00 1.00 0.00 4.00 0.00 4.00 0.00 6.00 0.00 7.00 0.00}
|
||||
|
||||
do_execsql_test 9.4 {
|
||||
SELECT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
|
||||
@@ -1240,35 +1233,21 @@ do_execsql_test 9.5 {
|
||||
SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
|
||||
} {1 1 4 4 6 6 7 7}
|
||||
|
||||
|
||||
do_test 9.6 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] {
|
||||
lappend myres [format %.4f [set r]]
|
||||
lappend myres [format %.2f [set r]]
|
||||
}
|
||||
set res2 {0.0000 0.0000 0.0000}
|
||||
foreach r [set myres] r2 [set res2] {
|
||||
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
|
||||
error "list element [set i] does not match: got=[set r] expected=[set r2]"
|
||||
}
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
set myres
|
||||
} {0.00 0.00 0.00}
|
||||
|
||||
do_test 9.7 {
|
||||
set myres {}
|
||||
foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] {
|
||||
lappend myres [format %.4f [set r]]
|
||||
lappend myres [format %.2f [set r]]
|
||||
}
|
||||
set res2 {1.0000 1.0000 1.0000}
|
||||
foreach r [set myres] r2 [set res2] {
|
||||
if {[set r]<([set r2]-0.0001) || [set r]>([set r2]+0.0001)} {
|
||||
error "list element [set i] does not match: got=[set r] expected=[set r2]"
|
||||
}
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
set myres
|
||||
} {1.00 1.00 1.00}
|
||||
|
||||
do_execsql_test 10.0 {
|
||||
DROP TABLE IF EXISTS t7;
|
||||
@@ -1290,31 +1269,4 @@ do_execsql_test 10.3 {
|
||||
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
|
||||
} {1 {} 2 4 3 {} 4 8 5 1 6 {}}
|
||||
|
||||
do_execsql_test 11.0 {
|
||||
DROP VIEW IF EXISTS v8;
|
||||
DROP TABLE IF EXISTS t8;
|
||||
CREATE TABLE t8(t INT, total INT);
|
||||
INSERT INTO t8 VALUES(0,2);
|
||||
INSERT INTO t8 VALUES(5,1);
|
||||
INSERT INTO t8 VALUES(10,1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 11.1 {
|
||||
SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8;
|
||||
} {0 1 2}
|
||||
|
||||
do_execsql_test 11.2 {
|
||||
CREATE VIEW v8 AS SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8;
|
||||
} {}
|
||||
|
||||
do_execsql_test 11.3 {
|
||||
SELECT * FROM v8;
|
||||
} {0 1 2}
|
||||
|
||||
do_execsql_test 11.4 {
|
||||
SELECT * FROM (
|
||||
SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8
|
||||
) sub;
|
||||
} {0 1 2}
|
||||
|
||||
finish_test
|
||||
|
||||
+15
-16
@@ -147,17 +147,17 @@ do_execsql_test 5.5 {
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
ifcapable !icu {
|
||||
do_execsql_test 6.0 {
|
||||
SELECT LIKE('!', '', '!') x WHERE x;
|
||||
} {}
|
||||
do_execsql_test 6.1 {
|
||||
SELECT LIKE("!","","!")""WHeRE"";
|
||||
} {}
|
||||
do_catchsql_test 6.2 {
|
||||
SELECT LIKE("!","","!")""window"";
|
||||
} {1 {near "window": syntax error}}
|
||||
}
|
||||
do_execsql_test 6.0 {
|
||||
SELECT LIKE('!', '', '!') x WHERE x;
|
||||
} {}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
SELECT LIKE("!","","!")""WHeRE"";
|
||||
} {}
|
||||
|
||||
do_catchsql_test 6.2 {
|
||||
SELECT LIKE("!","","!")""window"";
|
||||
} {1 {near "window": syntax error}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
@@ -166,11 +166,9 @@ do_execsql_test 7.0 {
|
||||
INSERT INTO t1 VALUES('');
|
||||
}
|
||||
|
||||
ifcapable !icu {
|
||||
do_execsql_test 7.1 {
|
||||
SELECT count(*) FROM t1 WHERE x LIKE '!' ESCAPE '!';
|
||||
} {0}
|
||||
}
|
||||
do_execsql_test 7.1 {
|
||||
SELECT count(*) FROM t1 WHERE x LIKE '!' ESCAPE '!';
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -338,3 +336,4 @@ do_execsql_test 11.2 {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -865,27 +865,6 @@ do_catchsql_test 16.1 {
|
||||
SELECT * FROM i;
|
||||
} {1 {recursive aggregate queries not supported}}
|
||||
|
||||
# Or window-function recursive queries. Ticket e8275b41.
|
||||
#
|
||||
ifcapable windowfunc {
|
||||
do_catchsql_test 16.2 {
|
||||
WITH RECURSIVE
|
||||
i(x) AS (VALUES(1) UNION SELECT count(*) OVER () FROM i)
|
||||
SELECT * FROM i;
|
||||
} {1 {cannot use window functions in recursive queries}}
|
||||
do_catchsql_test 16.3 {
|
||||
WITH RECURSIVE
|
||||
t(id, parent) AS (VALUES(1,2)),
|
||||
q(id, parent, rn) AS (
|
||||
VALUES(1,2,3)
|
||||
UNION ALL
|
||||
SELECT t.*, ROW_NUMBER() OVER (ORDER BY t.id) AS rn
|
||||
FROM q JOIN t ON t.parent = q.id
|
||||
)
|
||||
SELECT * FROM q;
|
||||
} {1 {cannot use window functions in recursive queries}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 17.1 {
|
||||
WITH x(a) AS (
|
||||
|
||||
+8
-58
@@ -220,17 +220,9 @@ set pragma_def {
|
||||
|
||||
NAME: table_info
|
||||
FLAG: NeedSchema Result1 SchemaOpt
|
||||
ARG: 0
|
||||
COLS: cid name type notnull dflt_value pk
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: table_xinfo
|
||||
TYPE: TABLE_INFO
|
||||
FLAG: NeedSchema Result1 SchemaOpt
|
||||
ARG: 1
|
||||
COLS: cid name type notnull dflt_value pk hidden
|
||||
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
||||
|
||||
NAME: stats
|
||||
FLAG: NeedSchema Result0 SchemaReq
|
||||
COLS: tbl idx wdth hght flgs
|
||||
@@ -367,33 +359,16 @@ set pragma_def {
|
||||
IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
|
||||
NAME: key
|
||||
TYPE: KEY
|
||||
ARG: 0
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: rekey
|
||||
TYPE: KEY
|
||||
ARG: 1
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: hexkey
|
||||
TYPE: HEXKEY
|
||||
ARG: 2
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: hexrekey
|
||||
TYPE: HEXKEY
|
||||
ARG: 3
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: textkey
|
||||
TYPE: KEY
|
||||
ARG: 4
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: textrekey
|
||||
TYPE: KEY
|
||||
ARG: 5
|
||||
IF: defined(SQLITE_HAS_CODEC)
|
||||
|
||||
NAME: activate_extensions
|
||||
@@ -407,11 +382,6 @@ set pragma_def {
|
||||
|
||||
NAME: optimize
|
||||
FLAG: Result1 NeedSchema
|
||||
|
||||
NAME: legacy_alter_table
|
||||
TYPE: FLAG
|
||||
ARG: SQLITE_LegacyAlter
|
||||
IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
||||
}
|
||||
|
||||
# Open the output file
|
||||
@@ -435,20 +405,20 @@ set cols {}
|
||||
set cols_list {}
|
||||
set arg 0
|
||||
proc record_one {} {
|
||||
global name type if arg allbyname typebyif flags cols all_cols
|
||||
global name type if arg allbyname typebyif flags cols allcols
|
||||
global cols_list colUsedBy
|
||||
if {$name==""} return
|
||||
if {$cols!=""} {
|
||||
if {![info exists all_cols($cols)]} {
|
||||
set all_cols($cols) 1
|
||||
if {![info exists allcols($cols)]} {
|
||||
lappend cols_list $cols
|
||||
set allcols($cols) [llength $cols_list]
|
||||
}
|
||||
set cx $cols
|
||||
set cx $allcols($cols)
|
||||
lappend colUsedBy($cols) $name
|
||||
} else {
|
||||
set cx 0
|
||||
}
|
||||
set allbyname($name) [list $type $arg $if $flags $cols]
|
||||
set allbyname($name) [list $type $arg $if $flags $cx]
|
||||
set name {}
|
||||
set type {}
|
||||
set if {}
|
||||
@@ -530,13 +500,6 @@ foreach f [lsort [array names allflags]] {
|
||||
set fv [expr {$fv*2}]
|
||||
}
|
||||
|
||||
# Sort the column lists so that longer column lists occur first
|
||||
#
|
||||
proc colscmp {a b} {
|
||||
return [expr {[llength $b] - [llength $a]}]
|
||||
}
|
||||
set cols_list [lsort -command colscmp $cols_list]
|
||||
|
||||
# Generate the array of column names used by pragmas that act like
|
||||
# queries.
|
||||
#
|
||||
@@ -545,23 +508,10 @@ puts $fd "** or that return single-column results where the name of the"
|
||||
puts $fd "** result column is different from the name of the pragma\n*/"
|
||||
puts $fd "static const char *const pragCName\[\] = {"
|
||||
set offset 0
|
||||
set allcollist {}
|
||||
foreach cols $cols_list {
|
||||
set n [llength $cols]
|
||||
set limit [expr {[llength $allcollist] - $n}]
|
||||
for {set i 0} {$i<$limit} {incr i} {
|
||||
set sublist [lrange $allcollist $i [expr {$i+$n-1}]]
|
||||
if {$sublist==$cols} {
|
||||
puts $fd [format "%27s/* $colUsedBy($cols) reuses $i */" ""]
|
||||
set cols_offset($cols) $i
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$i<$limit} continue
|
||||
set cols_offset($cols) $offset
|
||||
set cols_offset($allcols($cols)) $offset
|
||||
set ub " /* Used by: $colUsedBy($cols) */"
|
||||
foreach c $cols {
|
||||
lappend allcollist $c
|
||||
puts $fd [format " /* %3d */ %-14s%s" $offset \"$c\", $ub]
|
||||
set ub ""
|
||||
incr offset
|
||||
@@ -587,12 +537,12 @@ set current_if {}
|
||||
set spacer [format { %26s } {}]
|
||||
foreach name $allnames {
|
||||
foreach {type arg if flag cx} $allbyname($name) break
|
||||
if {$cx==0 || $cx==""} {
|
||||
if {$cx==0} {
|
||||
set cy 0
|
||||
set nx 0
|
||||
} else {
|
||||
set cy $cols_offset($cx)
|
||||
set nx [llength $cx]
|
||||
set nx [llength [lindex $cols_list [expr {$cx-1}]]]
|
||||
}
|
||||
if {$if!=$current_if} {
|
||||
if {$current_if!=""} {
|
||||
|
||||
Reference in New Issue
Block a user