Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
-3.19.3
+3.20.0
Index: autoconf/Makefile.am
==================================================================
--- autoconf/Makefile.am
+++ autoconf/Makefile.am
@@ -10,11 +10,11 @@
EXTRA_sqlite3_SOURCES = sqlite3.c
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS
-include_HEADERS = sqlite3.h sqlite3ext.h msvc.h
+include_HEADERS = sqlite3.h sqlite3ext.h
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
Index: configure
==================================================================
--- configure
+++ configure
@@ -1,8 +1,8 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.19.3.
+# Generated by GNU Autoconf 2.69 for sqlite 3.20.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
@@ -724,12 +724,12 @@
MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.19.3'
-PACKAGE_STRING='sqlite 3.19.3'
+PACKAGE_VERSION='3.20.0'
+PACKAGE_STRING='sqlite 3.20.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
# Factoring default headers for most tests.
ac_includes_default="\
@@ -1461,11 +1461,11 @@
#
if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.19.3 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.20.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE. See below for descriptions of some of the useful variables.
@@ -1526,11 +1526,11 @@
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.19.3:";;
+ short | recursive ) echo "Configuration of sqlite 3.20.0:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
@@ -1650,11 +1650,11 @@
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.19.3
+sqlite configure 3.20.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
@@ -2069,11 +2069,11 @@
} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.19.3, which was
+It was created by sqlite $as_me 3.20.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
_ACEOF
@@ -12149,11 +12149,11 @@
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# Save the log message, to keep $0 and so on meaningful, and to
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.19.3, which was
+This file was extended by sqlite $as_me 3.20.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
CONFIG_LINKS = $CONFIG_LINKS
@@ -12215,11 +12215,11 @@
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-sqlite config.status 3.19.3
+sqlite config.status 3.20.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
Index: doc/lemon.html
==================================================================
--- doc/lemon.html
+++ doc/lemon.html
@@ -20,10 +20,30 @@
in long-running programs such as graphical user interfaces
or embedded controllers.
This document is an introduction to the Lemon
parser generator.
+
+Security Note
+
+The language parser code created by Lemon is very robust and
+is well-suited for use in internet-facing applications that need to
+safely process maliciously crafted inputs.
+
+
The "lemon.exe" command-line tool itself works great when given a valid
+input grammar file and almost always gives helpful
+error messages for malformed inputs. However, it is possible for
+a malicious user to craft a grammar file that will cause
+lemon.exe to crash.
+We do not see this as a problem, as lemon.exe is not intended to be used
+with hostile inputs.
+To summarize:
+
+
+- Parser code generated by lemon → Robust and secure
+
- The "lemon.exe" command line tool itself → Not so much
+
Theory of Operation
The main goal of Lemon is to translate a context free grammar (CFG)
for a particular language into C code that implements a parser for
Index: ext/fts5/fts5_hash.c
==================================================================
--- ext/fts5/fts5_hash.c
+++ ext/fts5/fts5_hash.c
@@ -169,14 +169,15 @@
if( !apNew ) return SQLITE_NOMEM;
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
for(i=0; inSlot; i++){
while( apOld[i] ){
- int iHash;
+ unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), strlen(fts5EntryKey(p)));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
+ (int)strlen(fts5EntryKey(p)));
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
}
@@ -475,11 +476,11 @@
const char *pTerm, int nTerm, /* Query term */
const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
int *pnDoclist /* OUT: Size of doclist in bytes */
){
unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
- char *zKey;
+ char *zKey = 0;
Fts5HashEntry *p;
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
zKey = fts5EntryKey(p);
if( memcmp(zKey, pTerm, nTerm)==0 && zKey[nTerm]==0 ) break;
Index: ext/fts5/fts5_test_tok.c
==================================================================
--- ext/fts5/fts5_test_tok.c
+++ ext/fts5/fts5_test_tok.c
@@ -180,11 +180,11 @@
){
fts5_api *pApi = (fts5_api*)pCtx;
Fts5tokTable *pTab = 0;
int rc;
char **azDequote = 0;
- int nDequote;
+ int nDequote = 0;
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(input HIDDEN, token, start, end, position)"
);
Index: ext/fts5/test/fts5rank.test
==================================================================
--- ext/fts5/test/fts5rank.test
+++ ext/fts5/test/fts5rank.test
@@ -88,10 +88,11 @@
do_test 2.7 {
execsql { SELECT rowid FROM tt('a') ORDER BY rank; } db
} {1 3 2}
+db2 close
#--------------------------------------------------------------------------
# At one point there was a problem with queries such as:
#
# ... MATCH 'x OR y' ORDER BY rank;
Index: ext/misc/amatch.c
==================================================================
--- ext/misc/amatch.c
+++ ext/misc/amatch.c
@@ -999,23 +999,17 @@
}
/* Circumvent compiler warnings about the use of strcpy() by supplying
** our own implementation.
*/
-#if defined(__OpenBSD__)
static void amatchStrcpy(char *dest, const char *src){
while( (*(dest++) = *(src++))!=0 ){}
}
static void amatchStrcat(char *dest, const char *src){
while( *dest ) dest++;
amatchStrcpy(dest, src);
}
-#else
-# define amatchStrcpy strcpy
-# define amatchStrcat strcat
-#endif
-
/*
** Add a new amatch_word object to the queue.
**
** If a prior amatch_word object with the same zWord, and nMatch
Index: ext/misc/series.c
==================================================================
--- ext/misc/series.c
+++ ext/misc/series.c
@@ -31,11 +31,11 @@
** HOW IT WORKS
**
** The generate_series "function" is really a virtual table with the
** following schema:
**
-** CREATE FUNCTION generate_series(
+** CREATE TABLE generate_series(
** value,
** start HIDDEN,
** stop HIDDEN,
** step HIDDEN
** );
ADDED ext/misc/stmts.c
Index: ext/misc/stmts.c
==================================================================
--- /dev/null
+++ ext/misc/stmts.c
@@ -0,0 +1,299 @@
+/*
+** 2017-05-31
+**
+** 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
+** about all prepared statements for the database connection.
+**
+** Usage example:
+**
+** .load ./stmts
+** .mode line
+** .header on
+** SELECT * FROM stmts;
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include
+#include
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** The following macros are used to cast pointers to integers.
+** The way you do this varies from one compiler
+** to the next, so we have developed the following set of #if statements
+** to generate appropriate macros for a wide range of compilers.
+*/
+#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
+# define SQLITE_PTR_TO_INT64(X) ((sqlite3_int64)(__PTRDIFF_TYPE__)(X))
+#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
+# define SQLITE_PTR_TO_INT64(X) ((sqlite3_int64)(((char*)X)-(char*)0))
+#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
+# define SQLITE_PTR_TO_INT64(X) ((sqlite3_int64)(intptr_t)(X))
+#else /* Generates a warning - but it always works */
+# define SQLITE_PTR_TO_INT64(X) ((sqlite3_int64)(X))
+#endif
+
+
+/* stmts_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a stmts virtual table
+*/
+typedef struct stmts_vtab stmts_vtab;
+struct stmts_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this stmts vtab */
+};
+
+/* stmts_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 stmts_cursor stmts_cursor;
+struct stmts_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/*
+** The stmtsConnect() method is invoked to create a new
+** stmts_vtab that describes the generate_stmts virtual table.
+**
+** Think of this routine as the constructor for stmts_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the stmts_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against generate_stmts will look like.
+*/
+static int stmtsConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ stmts_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define STMTS_COLUMN_PTR 0 /* Numeric value of the statement pointer */
+#define STMTS_COLUMN_SQL 1 /* SQL for the statement */
+#define STMTS_COLUMN_NCOL 2 /* Number of result columns */
+#define STMTS_COLUMN_RO 3 /* True if read-only */
+#define STMTS_COLUMN_BUSY 4 /* True if currently busy */
+#define STMTS_COLUMN_NSCAN 5 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
+#define STMTS_COLUMN_NSORT 6 /* SQLITE_STMTSTATUS_SORT */
+#define STMTS_COLUMN_NAIDX 7 /* SQLITE_STMTSTATUS_AUTOINDEX */
+#define STMTS_COLUMN_NSTEP 8 /* SQLITE_STMTSTATUS_VM_STEP */
+#define STMTS_COLUMN_MEM 9 /* SQLITE_STMTSTATUS_MEMUSED */
+
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(ptr,sql,ncol,ro,busy,nscan,nsort,naidx,nstep,mem)");
+ 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 stmts_cursor objects.
+*/
+static int stmtsDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new stmts_cursor object.
+*/
+static int stmtsOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ stmts_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((stmts_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a stmts_cursor.
+*/
+static int stmtsClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a stmts_cursor to its next row of output.
+*/
+static int stmtsNext(sqlite3_vtab_cursor *cur){
+ stmts_cursor *pCur = (stmts_cursor*)cur;
+ pCur->iRowid++;
+ pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the stmts_cursor
+** is currently pointing.
+*/
+static int stmtsColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ stmts_cursor *pCur = (stmts_cursor*)cur;
+ switch( i ){
+ case STMTS_COLUMN_PTR: {
+ sqlite3_result_int64(ctx, SQLITE_PTR_TO_INT64(pCur->pStmt));
+ break;
+ }
+ case STMTS_COLUMN_SQL: {
+ sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case STMTS_COLUMN_NCOL: {
+ sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
+ break;
+ }
+ case STMTS_COLUMN_RO: {
+ sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
+ break;
+ }
+ case STMTS_COLUMN_BUSY: {
+ sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
+ break;
+ }
+ case STMTS_COLUMN_NSCAN:
+ case STMTS_COLUMN_NSORT:
+ case STMTS_COLUMN_NAIDX:
+ case STMTS_COLUMN_NSTEP:
+ case STMTS_COLUMN_MEM: {
+ sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
+ i-STMTS_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
+ 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 stmtsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ stmts_cursor *pCur = (stmts_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int stmtsEof(sqlite3_vtab_cursor *cur){
+ stmts_cursor *pCur = (stmts_cursor*)cur;
+ return pCur->pStmt==0;
+}
+
+/*
+** This method is called to "rewind" the stmts_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to stmtsColumn() or stmtsRowid() or
+** stmtsEof().
+*/
+static int stmtsFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ stmts_cursor *pCur = (stmts_cursor *)pVtabCursor;
+ pCur->pStmt = 0;
+ pCur->iRowid = 0;
+ return stmtsNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the generate_stmts virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int stmtsBestIndex(
+ 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
+** generate_stmts virtual table.
+*/
+static sqlite3_module stmtsModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ stmtsConnect, /* xConnect */
+ stmtsBestIndex, /* xBestIndex */
+ stmtsDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ stmtsOpen, /* xOpen - open a cursor */
+ stmtsClose, /* xClose - close a cursor */
+ stmtsFilter, /* xFilter - configure scan constraints */
+ stmtsNext, /* xNext - advance a cursor */
+ stmtsEof, /* xEof - check for end of scan */
+ stmtsColumn, /* xColumn - read data */
+ stmtsRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_stmts_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( sqlite3_libversion_number()<3008012 ){
+ *pzErrMsg = sqlite3_mprintf(
+ "generate_stmts() requires SQLite 3.8.12 or later");
+ return SQLITE_ERROR;
+ }
+ rc = sqlite3_create_module(db, "stmts", &stmtsModule, 0);
+#endif
+ return rc;
+}
Index: ext/rbu/rbuvacuum.test
==================================================================
--- ext/rbu/rbuvacuum.test
+++ ext/rbu/rbuvacuum.test
@@ -296,10 +296,18 @@
} {SQLITE_ERROR}
do_test 2.1.2 {
list [catch { rbu close } msg] $msg
} {1 {SQLITE_ERROR - cannot vacuum wal mode database}}
+do_test 2.1.3 {
+ sqlite3rbu_vacuum rbu test.db state.db
+ rbu step
+} {SQLITE_ERROR}
+do_test 2.1.4 {
+ list [catch { rbu close_no_error } msg] $msg
+} {1 SQLITE_ERROR}
+
reset_db
do_execsql_test 2.2.0 {
CREATE TABLE tx(a PRIMARY KEY, b BLOB);
INSERT INTO tx VALUES(1, randomblob(900));
INSERT INTO tx SELECT a+1, randomblob(900) FROM tx;
Index: ext/rbu/sqlite3rbu.c
==================================================================
--- ext/rbu/sqlite3rbu.c
+++ ext/rbu/sqlite3rbu.c
@@ -3785,11 +3785,15 @@
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
rbuEditErrmsg(p);
rc = p->rc;
- *pzErrmsg = p->zErrmsg;
+ if( pzErrmsg ){
+ *pzErrmsg = p->zErrmsg;
+ }else{
+ sqlite3_free(p->zErrmsg);
+ }
sqlite3_free(p->zState);
sqlite3_free(p);
}else{
rc = SQLITE_NOMEM;
*pzErrmsg = 0;
Index: ext/rbu/sqlite3rbu.h
==================================================================
--- ext/rbu/sqlite3rbu.h
+++ ext/rbu/sqlite3rbu.h
@@ -418,14 +418,14 @@
** as fully applied. Otherwise, assuming no error has occurred, save the
** current state of the RBU update appliation to the RBU database.
**
** If an error has already occurred as part of an sqlite3rbu_step()
** or sqlite3rbu_open() call, or if one occurs within this function, an
-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
-** point to a buffer containing a utf-8 formatted English language error
-** message. It is the responsibility of the caller to eventually free any
-** such buffer using sqlite3_free().
+** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
+** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
+** English language error message. It is the responsibility of the caller to
+** eventually free any such buffer using sqlite3_free().
**
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
** update has been partially applied, or SQLITE_DONE if it has been
** completely applied.
*/
Index: ext/rbu/test_rbu.c
==================================================================
--- ext/rbu/test_rbu.c
+++ ext/rbu/test_rbu.c
@@ -76,10 +76,11 @@
{"dbMain_eval", 3, "SQL"}, /* 4 */
{"bp_progress", 2, ""}, /* 5 */
{"db", 3, "RBU"}, /* 6 */
{"state", 2, ""}, /* 7 */
{"progress", 2, ""}, /* 8 */
+ {"close_no_error", 2, ""}, /* 9 */
{0,0,0}
};
int iCmd;
if( objc<2 ){
@@ -100,15 +101,20 @@
int rc = sqlite3rbu_step(pRbu);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
break;
}
+ case 9: /* close_no_error */
case 1: /* close */ {
char *zErrmsg = 0;
int rc;
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
- rc = sqlite3rbu_close(pRbu, &zErrmsg);
+ if( iCmd==1 ){
+ rc = sqlite3rbu_close(pRbu, &zErrmsg);
+ }else{
+ rc = sqlite3rbu_close(pRbu, 0);
+ }
if( rc==SQLITE_OK || rc==SQLITE_DONE ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
assert( zErrmsg==0 );
}else{
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
Index: ext/session/sessionat.test
==================================================================
--- ext/session/sessionat.test
+++ ext/session/sessionat.test
@@ -207,10 +207,39 @@
INSERT INTO t6 VALUES(4, 4, 4, 4, 4);
}]
list [catch { sqlite3changeset_concat $c1 $c2} msg] $msg
} {1 SQLITE_SCHEMA}
+ #-----------------------------------------------------------------------
+ db2 close
+ sqlite3 db2 test.db
+ do_execsql_test $tn.6.0 {
+ CREATE TABLE t7(a INTEGER PRIMARY KEY, b) %WR%;
+ INSERT INTO t7 VALUES(1, 1);
+ INSERT INTO t7 VALUES(2, 2);
+ INSERT INTO t7 VALUES(3, 3);
+ }
+
+ do_test $tn.6.1 {
+ set c1 [sql_exec_changeset db {
+ INSERT INTO t7 VALUES(4, 4);
+ DELETE FROM t7 WHERE a=1;
+ UPDATE t7 SET b=222 WHERE a=2;
+ }]
+ set cinv [sqlite3changeset_invert $c1]
+ execsql { SELECT * FROM t7 }
+ } {2 222 3 3 4 4}
+
+ do_execsql_test -db db2 $tn.6.2 {
+ ALTER TABLE t7 ADD COLUMN c DEFAULT 'ccc'
+ }
+
+ proc xConfict {args} { return "OMIT" }
+ do_test $tn.6.3 {
+ sqlite3changeset_apply db $cinv xConflict
+ execsql { SELECT * FROM t7 }
+ } {1 1 ccc 2 2 ccc 3 3 ccc}
}]
}
finish_test
ADDED ext/session/sessiondiff.test
Index: ext/session/sessiondiff.test
==================================================================
--- /dev/null
+++ ext/session/sessiondiff.test
@@ -0,0 +1,114 @@
+# 2015-07-31
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests for the [sqldiff --changeset] command.
+#
+#
+if {![info exists testdir]} {
+ set testdir [file join [file dirname [info script]] .. .. test]
+}
+source $testdir/tester.tcl
+ifcapable !session {finish_test; return}
+set testprefix sessiondiff
+
+set PROG [test_find_sqldiff]
+db close
+
+proc sqlesc {id} {
+ set ret "'[string map {' ''} $id]'"
+ set ret
+}
+
+proc database_cksum {db1} {
+ set txt ""
+
+ sqlite3 dbtmp $db1
+ foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] {
+ set cols [list]
+ dbtmp eval "PRAGMA table_info = [sqlesc $tbl]" {
+ lappend cols "quote( $name )"
+ }
+ append txt [dbtmp eval \
+ "SELECT [join $cols {||'.'||}] FROM [sqlesc $tbl] ORDER BY 1"
+ ]
+ }
+ dbtmp close
+
+ md5 $txt
+}
+
+proc readfile {filename} {
+ set fd [open $filename]
+ fconfigure $fd -translation binary -encoding binary
+ set data [read $fd]
+ close $fd
+ set data
+}
+
+proc get_changeset {db1 db2} {
+ exec $::PROG --changeset changeset.bin $db1 $db2
+ set bin [readfile changeset.bin]
+ return $bin
+}
+
+proc xConflict {args} {
+ return ""
+}
+
+proc do_changeset_test {tn sql1 sql2} {
+ forcedelete test.db123 test.db124
+
+ sqlite3 db test.db123
+ db eval $sql1
+ db close
+
+ sqlite3 db test.db124
+ db eval $sql2
+
+ set cs [get_changeset test.db124 test.db123]
+ sqlite3changeset_apply db $cs xConflict
+ db close
+
+ set database_cksum1 [database_cksum test.db123]
+ set database_cksum2 [database_cksum test.db124]
+
+ uplevel [list \
+ do_test $tn [list string compare $database_cksum1 $database_cksum2] 0
+ ]
+}
+
+do_changeset_test 1.0 {
+ CREATE TABLE t1(x PRIMARY KEY);
+} {
+ CREATE TABLE t1(x PRIMARY KEY);
+}
+
+do_changeset_test 1.1 {
+ CREATE TABLE t1(x PRIMARY KEY);
+ CREATE TABLE t2(x PRIMARY KEY, y);
+ INSERT INTO t2 VALUES(1, 2);
+} {
+ CREATE TABLE t1(x PRIMARY KEY);
+ CREATE TABLE t2(x PRIMARY KEY, y);
+ INSERT INTO t2 VALUES(3, 4);
+}
+
+do_changeset_test 1.2 {
+ CREATE TABLE t2(a, b, c, PRIMARY KEY(b, c));
+ INSERT INTO t2 VALUES(1, 2, 3);
+ INSERT INTO t2 VALUES(4, 5, 6);
+} {
+ CREATE TABLE t2(a, b, c, PRIMARY KEY(b, c));
+ INSERT INTO t2 VALUES(1, 2, 11);
+ INSERT INTO t2 VALUES(7, 8, 9);
+}
+
+finish_test
Index: ext/session/sqlite3session.c
==================================================================
--- ext/session/sqlite3session.c
+++ ext/session/sqlite3session.c
@@ -2834,15 +2834,16 @@
sessionDiscardData(&p->in);
p->in.iCurrent = p->in.iNext;
op = p->in.aData[p->in.iNext++];
- if( op=='T' || op=='P' ){
+ while( op=='T' || op=='P' ){
p->bPatchset = (op=='P');
if( sessionChangesetReadTblhdr(p) ) return p->rc;
if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
p->in.iCurrent = p->in.iNext;
+ if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
op = p->in.aData[p->in.iNext++];
}
p->op = op;
p->bIndirect = p->in.aData[p->in.iNext++];
Index: src/attach.c
==================================================================
--- src/attach.c
+++ src/attach.c
@@ -67,11 +67,12 @@
const char *zName;
const char *zFile;
char *zPath = 0;
char *zErr = 0;
unsigned int flags;
- Db *aNew;
+ Db *aNew; /* New array of Db pointers */
+ Db *pNew; /* Db object for the newly attached database */
char *zErrDyn = 0;
sqlite3_vfs *pVfs;
UNUSED_PARAMETER(NotUsed);
@@ -115,12 +116,12 @@
}else{
aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
- aNew = &db->aDb[db->nDb];
- memset(aNew, 0, sizeof(*aNew));
+ pNew = &db->aDb[db->nDb];
+ memset(pNew, 0, sizeof(*pNew));
/* Open the database file. If the btree is successfully opened, use
** it to obtain the database schema. At this point the schema may
** or may not be initialized.
*/
@@ -132,41 +133,41 @@
sqlite3_free(zErr);
return;
}
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
- rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
+ rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
sqlite3_free( zPath );
db->nDb++;
db->skipBtreeMutex = 0;
if( rc==SQLITE_CONSTRAINT ){
rc = SQLITE_ERROR;
zErrDyn = sqlite3MPrintf(db, "database is already attached");
}else if( rc==SQLITE_OK ){
Pager *pPager;
- aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
- if( !aNew->pSchema ){
+ pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt);
+ if( !pNew->pSchema ){
rc = SQLITE_NOMEM_BKPT;
- }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
+ }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){
zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
rc = SQLITE_ERROR;
}
- sqlite3BtreeEnter(aNew->pBt);
- pPager = sqlite3BtreePager(aNew->pBt);
+ sqlite3BtreeEnter(pNew->pBt);
+ pPager = sqlite3BtreePager(pNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
- sqlite3BtreeSecureDelete(aNew->pBt,
+ sqlite3BtreeSecureDelete(pNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
- sqlite3BtreeSetPagerFlags(aNew->pBt,
+ sqlite3BtreeSetPagerFlags(pNew->pBt,
PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
#endif
- sqlite3BtreeLeave(aNew->pBt);
+ sqlite3BtreeLeave(pNew->pBt);
}
- aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
- aNew->zDbSName = sqlite3DbStrDup(db, zName);
- if( rc==SQLITE_OK && aNew->zDbSName==0 ){
+ pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ pNew->zDbSName = sqlite3DbStrDup(db, zName);
+ if( rc==SQLITE_OK && pNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT;
}
#ifdef SQLITE_HAS_CODEC
Index: src/btree.c
==================================================================
--- src/btree.c
+++ src/btree.c
@@ -775,11 +775,11 @@
assert( nKey==(i64)(int)nKey );
pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
goto moveto_done;
}
}else{
pIdxKey = 0;
}
@@ -1004,11 +1004,11 @@
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3PagerUnref(pDbPage);
- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
+ if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
return SQLITE_OK;
}
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
#define ptrmapPut(w,x,y,z,rc)
@@ -1389,11 +1389,11 @@
u8 *pAddr;
int sz2 = 0;
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
if( iFree2 ){
- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT;
+ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
sz2 = get2byte(&data[iFree2+2]);
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}
@@ -1420,17 +1420,17 @@
testcase( pc==iCellLast );
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( pc>=iCellFirst && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrkusableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
testcase( pc+size==usableSize );
put2byte(pAddr, cbrk);
@@ -1446,11 +1446,11 @@
}
data[hdr+7] = 0;
defragment_out:
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
data[hdr+1] = 0;
data[hdr+2] = 0;
@@ -1485,11 +1485,11 @@
do{
int size; /* Size of the free slot */
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
** increasing offset. */
if( pc>usableSize-4 || pcpgno);
return 0;
}
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
** freeblock form a big-endian integer which is the size of the freeblock
** in bytes, including the 4-byte header. */
@@ -1496,11 +1496,11 @@
size = get2byte(&aData[pc+2]);
if( (x = size - nByte)>=0 ){
testcase( x==4 );
testcase( x==3 );
if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
- *pRc = SQLITE_CORRUPT_BKPT;
+ *pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
return 0;
}else if( x<4 ){
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
** number of bytes in fragments may not exceed 60. */
if( aData[hdr+7]>57 ) return 0;
@@ -1563,11 +1563,11 @@
assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
}
/* If there is enough space between gap and top for one more cell pointer
** array entry offset, and if the freelist is not empty, then search the
@@ -1659,15 +1659,15 @@
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))pgno);
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
+ if( iFreeBlk>iLast ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
assert( iFreeBlk>iPtr || iFreeBlk==0 );
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
** iPtr: The address of a pointer to iFreeBlk
@@ -1674,13 +1674,15 @@
**
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
*/
if( iFreeBlk && iEnd+3>=iFreeBlk ){
nFrag = iFreeBlk - iEnd;
- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd > pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
/* If iPtr is another freeblock (that is, if iPtr is not the freelist
@@ -1688,24 +1690,24 @@
** coalesced onto the end of iPtr.
*/
if( iPtr>hdr+1 ){
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
if( iPtrEnd+3>=iStart ){
- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
+ if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
nFrag += iStart - iPtrEnd;
iSize = iEnd - iPtr;
iStart = iPtr;
}
}
- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
+ if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
data[hdr+7] -= nFrag;
}
if( iStart==get2byte(&data[hdr+5]) ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
- if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
+ if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
@@ -1769,11 +1771,11 @@
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
** an error. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -1785,138 +1787,140 @@
** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
** guarantee that the page is well-formed. It only shows that
** we failed to detect any corruption.
*/
static int btreeInitPage(MemPage *pPage){
+ int pc; /* Address of a freeblock within pPage->aData[] */
+ u8 hdr; /* Offset to beginning of page header */
+ u8 *data; /* Equal to pPage->aData */
+ BtShared *pBt; /* The main btree structure */
+ int usableSize; /* Amount of usable space on each page */
+ u16 cellOffset; /* Offset from start of page to first cell pointer */
+ int nFree; /* Number of unused bytes on the page */
+ int top; /* First byte of the cell content area */
+ int iCellFirst; /* First allowable cell or freeblock offset */
+ int iCellLast; /* Last possible cell or freeblock offset */
assert( pPage->pBt!=0 );
assert( pPage->pBt->db!=0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
-
- if( !pPage->isInit ){
- int pc; /* Address of a freeblock within pPage->aData[] */
- u8 hdr; /* Offset to beginning of page header */
- u8 *data; /* Equal to pPage->aData */
- BtShared *pBt; /* The main btree structure */
- int usableSize; /* Amount of usable space on each page */
- u16 cellOffset; /* Offset from start of page to first cell pointer */
- int nFree; /* Number of unused bytes on the page */
- int top; /* First byte of the cell content area */
- int iCellFirst; /* First allowable cell or freeblock offset */
- int iCellLast; /* Last possible cell or freeblock offset */
-
- pBt = pPage->pBt;
-
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
- ** the b-tree page type. */
- if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
- assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
- pPage->maskPage = (u16)(pBt->pageSize - 1);
- pPage->nOverflow = 0;
- usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
- pPage->aDataEnd = &data[usableSize];
- pPage->aCellIdx = &data[cellOffset];
- pPage->aDataOfst = &data[pPage->childPtrSize];
- /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
- ** the start of the cell content area. A zero value for this integer is
- ** interpreted as 65536. */
- top = get2byteNotZero(&data[hdr+5]);
- /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
- ** number of cells on the page. */
- pPage->nCell = get2byte(&data[hdr+3]);
- if( pPage->nCell>MX_CELL(pBt) ){
- /* To many cells for a single page. The page must be corrupt */
- return SQLITE_CORRUPT_BKPT;
- }
- testcase( pPage->nCell==MX_CELL(pBt) );
- /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
- ** possible for a root page of a table that contains no rows) then the
- ** offset to the cell content area will equal the page size minus the
- ** bytes of reserved space. */
- assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
-
- /* A malformed database page might cause us to read past the end
- ** of page when parsing a cell.
- **
- ** The following block of code checks early to see if a cell extends
- ** past the end of a page boundary and causes SQLITE_CORRUPT to be
- ** returned if it does.
- */
- iCellFirst = cellOffset + 2*pPage->nCell;
- iCellLast = usableSize - 4;
- if( pBt->db->flags & SQLITE_CellSizeCk ){
- int i; /* Index into the cell pointer array */
- int sz; /* Size of a cell */
-
- if( !pPage->leaf ) iCellLast--;
- for(i=0; inCell; i++){
- pc = get2byteAligned(&data[cellOffset+i*2]);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT;
- }
- sz = pPage->xCellSize(pPage, &data[pc]);
- testcase( pc+sz==usableSize );
- if( pc+sz>usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }
- }
- if( !pPage->leaf ) iCellLast++;
- }
-
- /* Compute the total free space on the page
- ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
- ** start of the first freeblock on the page, or is zero if there are no
- ** freeblocks. */
- pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
- if( pc>0 ){
- u32 next, size;
- if( pciCellLast ){
- return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */
- }
- next = get2byte(&data[pc]);
- size = get2byte(&data[pc+2]);
- nFree = nFree + size;
- if( next<=pc+size+3 ) break;
- pc = next;
- }
- if( next>0 ){
- return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */
- }
- if( pc+size>(unsigned int)usableSize ){
- return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */
- }
- }
-
- /* At this point, nFree contains the sum of the offset to the start
- ** of the cell-content area plus the number of free bytes within
- ** the cell-content area. If this is greater than the usable-size
- ** of the page, then the page must be corrupted. This check also
- ** serves to verify that the offset to the start of the cell-content
- ** area, according to the page header, lies within the page.
- */
- if( nFree>usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }
- pPage->nFree = (u16)(nFree - iCellFirst);
- pPage->isInit = 1;
- }
+ assert( pPage->isInit==0 );
+
+ pBt = pPage->pBt;
+ hdr = pPage->hdrOffset;
+ data = pPage->aData;
+ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
+ ** the b-tree page type. */
+ if( decodeFlags(pPage, data[hdr]) ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
+ pPage->maskPage = (u16)(pBt->pageSize - 1);
+ pPage->nOverflow = 0;
+ usableSize = pBt->usableSize;
+ pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
+ pPage->aDataEnd = &data[usableSize];
+ pPage->aCellIdx = &data[cellOffset];
+ pPage->aDataOfst = &data[pPage->childPtrSize];
+ /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
+ ** the start of the cell content area. A zero value for this integer is
+ ** interpreted as 65536. */
+ top = get2byteNotZero(&data[hdr+5]);
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
+ pPage->nCell = get2byte(&data[hdr+3]);
+ if( pPage->nCell>MX_CELL(pBt) ){
+ /* To many cells for a single page. The page must be corrupt */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ testcase( pPage->nCell==MX_CELL(pBt) );
+ /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
+ ** possible for a root page of a table that contains no rows) then the
+ ** offset to the cell content area will equal the page size minus the
+ ** bytes of reserved space. */
+ assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
+
+ /* A malformed database page might cause us to read past the end
+ ** of page when parsing a cell.
+ **
+ ** The following block of code checks early to see if a cell extends
+ ** past the end of a page boundary and causes SQLITE_CORRUPT to be
+ ** returned if it does.
+ */
+ iCellFirst = cellOffset + 2*pPage->nCell;
+ iCellLast = usableSize - 4;
+ if( pBt->db->flags & SQLITE_CellSizeCk ){
+ int i; /* Index into the cell pointer array */
+ int sz; /* Size of a cell */
+
+ if( !pPage->leaf ) iCellLast--;
+ for(i=0; inCell; i++){
+ pc = get2byteAligned(&data[cellOffset+i*2]);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ if( pciCellLast ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ sz = pPage->xCellSize(pPage, &data[pc]);
+ testcase( pc+sz==usableSize );
+ if( pc+sz>usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ }
+ if( !pPage->leaf ) iCellLast++;
+ }
+
+ /* Compute the total free space on the page
+ ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
+ ** start of the first freeblock on the page, or is zero if there are no
+ ** freeblocks. */
+ pc = get2byte(&data[hdr+1]);
+ nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
+ if( pc>0 ){
+ u32 next, size;
+ if( pcpgno);
+ }
+ while( 1 ){
+ if( pc>iCellLast ){
+ /* Freeblock off the end of the page */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ next = get2byte(&data[pc]);
+ size = get2byte(&data[pc+2]);
+ nFree = nFree + size;
+ if( next<=pc+size+3 ) break;
+ pc = next;
+ }
+ if( next>0 ){
+ /* Freeblock not in ascending order */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ if( pc+size>(unsigned int)usableSize ){
+ /* Last freeblock extends past page end */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ }
+
+ /* At this point, nFree contains the sum of the offset to the start
+ ** of the cell-content area plus the number of free bytes within
+ ** the cell-content area. If this is greater than the usable-size
+ ** of the page, then the page must be corrupted. This check also
+ ** serves to verify that the offset to the start of the cell-content
+ ** area, according to the page header, lies within the page.
+ */
+ if( nFree>usableSize ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
+ pPage->nFree = (u16)(nFree - iCellFirst);
+ pPage->isInit = 1;
return SQLITE_OK;
}
/*
** Set up a raw page so that it looks like a database page holding
@@ -2076,11 +2080,11 @@
assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
/* If obtaining a child page for a cursor, we must verify that the page is
** compatible with the root page. */
if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pgno);
releasePage(*ppPage);
goto getAndInitPage_error;
}
return SQLITE_OK;
@@ -3364,11 +3368,11 @@
int rc; /* Return code */
BtShared *pBt = pPage->pBt;
Pgno pgno = pPage->pgno;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- rc = btreeInitPage(pPage);
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
if( rc!=SQLITE_OK ) return rc;
nCell = pPage->nCell;
for(i=0; ipBt->mutex) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
put4byte(pPage->aData, iTo);
}else{
int i;
int nCell;
int rc;
- rc = btreeInitPage(pPage);
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
if( rc ) return rc;
nCell = pPage->nCell;
for(i=0; ixParseCell(pPage, pCell, &info);
if( info.nLocal pPage->aData+pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
if( iFrom==get4byte(pCell+info.nSize-4) ){
put4byte(pCell+info.nSize-4, iTo);
break;
}
@@ -3444,11 +3448,11 @@
}
if( i==nCell ){
if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
}
}
return SQLITE_OK;
@@ -4552,11 +4556,11 @@
/* Trying to read or write past the end of the data is an error. The
** conditional above is really:
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
/* Check if data must be read/written to/from the btree page itself. */
if( offsetinfo.nLocal ){
int a = amt;
@@ -4699,11 +4703,12 @@
iIdx++;
}
}
if( rc==SQLITE_OK && amt>0 ){
- return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */
+ /* Overflow chain ends prematurely */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
return rc;
}
/*
@@ -4965,11 +4970,11 @@
** if pCur->iPage>=0). But this is not so if the database is corrupted
** in such a way that page pRoot is linked into a second b-tree table
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
}
skip_init:
pCur->ix = 0;
pCur->info.nSize = 0;
@@ -5170,20 +5175,23 @@
return SQLITE_OK;
}
/* If the requested key is one more than the previous key, then
** try to get there using sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this ase, only a little more slowely */
+ ** is still obtained without this case, only a little more slowely */
if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
*pRes = 0;
- rc = sqlite3BtreeNext(pCur, pRes);
- if( rc ) return rc;
- if( *pRes==0 ){
+ rc = sqlite3BtreeNext(pCur, 0);
+ if( rc==SQLITE_OK ){
getCellInfo(pCur);
if( pCur->info.nKey==intKey ){
return SQLITE_OK;
}
+ }else if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ }else{
+ return rc;
}
}
}
}
@@ -5235,11 +5243,13 @@
for(;;){
i64 nCellKey;
pCell = findCellPastPtr(pPage, idx);
if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
- if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
+ if( pCell>=pPage->aDataEnd ){
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
+ }
}
}
getVarint(pCell, (u64*)&nCellKey);
if( nCellKeypgno);
goto moveto_finish;
}
pCellKey = sqlite3Malloc( nCell+18 );
if( pCellKey==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -5413,47 +5423,44 @@
}
return n;
}
/*
-** Advance the cursor to the next entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the last entry in the database before
-** this routine was called, then set *pRes=1.
+** Advance the cursor to the next entry in the database.
+** Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE cursor is already pointing at the last element
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreeNext(). That routine is optimized
** for the common case of merely incrementing the cell counter BtCursor.aiIdx
** to the next cell on the current page. The (slower) btreeNext() helper
** routine is called when it is necessary to move to a different page or
** to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
+** an SQL index and this routine could have been skipped if the SQL index
+** had been a unique index. The flags argument is a hint to the implement.
+** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int flags){
int rc;
int idx;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- assert( *pRes==0 );
+ assert( flags==0 );
if( pCur->eState!=CURSOR_VALID ){
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ){
@@ -5481,19 +5488,18 @@
if( rc ) return rc;
return moveToLeftmost(pCur);
}
do{
if( pCur->iPage==0 ){
- *pRes = 1;
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
}while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
- return sqlite3BtreeNext(pCur, pRes);
+ return sqlite3BtreeNext(pCur, flags);
}else{
return SQLITE_OK;
}
}
if( pPage->leaf ){
@@ -5500,71 +5506,66 @@
return SQLITE_OK;
}else{
return moveToLeftmost(pCur);
}
}
-int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+int sqlite3BtreeNext(BtCursor *pCur, int flags){
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
+ assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- *pRes = 0;
- if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
+ if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, 0);
pPage = pCur->apPage[pCur->iPage];
if( (++pCur->ix)>=pPage->nCell ){
pCur->ix--;
- return btreeNext(pCur, pRes);
+ return btreeNext(pCur, 0);
}
if( pPage->leaf ){
return SQLITE_OK;
}else{
return moveToLeftmost(pCur);
}
}
/*
-** Step the cursor to the back to the previous entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the first entry in the database before
-** this routine was called, then set *pRes=1.
+** Step the cursor to the back to the previous entry in the database.
+** Return values:
+**
+** SQLITE_OK success
+** SQLITE_DONE the cursor is already on the first element of the table
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreePrevious(). That routine is optimized
** for the common case of merely decrementing the cell counter BtCursor.aiIdx
** to the previous cell on the current page. The (slower) btreePrevious()
** helper routine is called when it is necessary to move to a different page
** or to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+**
+** If bit 0x01 of the flags argument is 1, then the cursor corresponds to
+** an SQL index and this routine could have been skipped if the SQL index
+** had been a unique index. The flags argument is a hint to the implement.
+** SQLite btree implementation does not use this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int flags){
int rc;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 );
+ assert( flags==0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
assert( pCur->info.nSize==0 );
if( pCur->eState!=CURSOR_VALID ){
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext<0 ){
@@ -5584,41 +5585,38 @@
rc = moveToRightmost(pCur);
}else{
while( pCur->ix==0 ){
if( pCur->iPage==0 ){
pCur->eState = CURSOR_INVALID;
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
}
assert( pCur->info.nSize==0 );
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
pCur->ix--;
pPage = pCur->apPage[pCur->iPage];
if( pPage->intKey && !pPage->leaf ){
- rc = sqlite3BtreePrevious(pCur, pRes);
+ rc = sqlite3BtreePrevious(pCur, flags);
}else{
rc = SQLITE_OK;
}
}
return rc;
}
-int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+int sqlite3BtreePrevious(BtCursor *pCur, int flags){
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
+ assert( flags==0 || flags==1 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- *pRes = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->ix==0
|| pCur->apPage[pCur->iPage]->leaf==0
){
- return btreePrevious(pCur, pRes);
+ return btreePrevious(pCur, 0);
}
pCur->ix--;
return SQLITE_OK;
}
@@ -5722,11 +5720,11 @@
** the freelist is empty. */
iTrunk = get4byte(&pPage1->aData[32]);
}
testcase( iTrunk==mxPage );
if( iTrunk>mxPage || nSearch++ > n ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
}else{
rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
}
if( rc ){
pTrunk = 0;
@@ -5751,11 +5749,11 @@
*ppPage = pTrunk;
pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList
&& (nearby==iTrunk || (iTrunkaData[8]);
if( iNewTrunk>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
rc = btreeGetUnusedPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
@@ -5850,11 +5848,11 @@
}
iPage = get4byte(&aData[8+closest*4]);
testcase( iPage==mxPage );
if( iPage>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iPage==mxPage );
if( !searchList
|| (iPage==nearby || (iPagexParseCell(pPage, pCell, pInfo);
if( pInfo->nLocal==pInfo->nPayload ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
- return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
+ /* Cell extends past end of page */
+ return SQLITE_CORRUPT_PGNO(pPage->pgno);
}
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
@@ -8335,12 +8334,12 @@
** from the internal node. The 'previous' entry is used for this instead
** of the 'next' entry, as the previous entry is always a part of the
** sub-tree headed by the child page of the cell being deleted. This makes
** balancing the tree following the delete operation easier. */
if( !pPage->leaf ){
- int notUsed = 0;
- rc = sqlite3BtreePrevious(pCur, ¬Used);
+ rc = sqlite3BtreePrevious(pCur, 0);
+ assert( rc!=SQLITE_DONE );
if( rc ) return rc;
}
/* Save the positions of any other cursors open on this table before
** making any modifications. */
Index: src/btree.h
==================================================================
--- src/btree.h
+++ src/btree.h
@@ -284,13 +284,13 @@
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int flags, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
-int sqlite3BtreeNext(BtCursor*, int *pRes);
+int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
-int sqlite3BtreePrevious(BtCursor*, int *pRes);
+int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
Index: src/build.c
==================================================================
--- src/build.c
+++ src/build.c
@@ -937,11 +937,15 @@
}
pTable->zName = zName;
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nTabRef = 1;
+#ifdef SQLITE_DEFAULT_ROWEST
+ pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
+#else
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
+#endif
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
/* If this is the magic sqlite_sequence table used by autoincrement,
** then record a pointer to this table in the main database structure
Index: src/ctime.c
==================================================================
--- src/ctime.c
+++ src/ctime.c
@@ -14,33 +14,50 @@
** SQLite was built with.
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-#include "sqliteInt.h"
+
+/* These macros are provided to "stringify" the value of the define
+** for those options in which the value is meaningful. */
+#define CTIMEOPT_VAL_(opt) #opt
+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
/*
** An array of names of all compile-time options. This array should
** be sorted A-Z.
**
** This array looks large, but in a typical installation actually uses
** only a handful of compile-time options, so most times this array is usually
** rather short and uses little memory space.
*/
-static const char * const azCompileOpt[] = {
+static const char * const sqlite3azCompileOpt[] = {
-/* These macros are provided to "stringify" the value of the define
-** for those options in which the value is meaningful. */
-#define CTIMEOPT_VAL_(opt) #opt
-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
-
+/*
+** BEGIN CODE GENERATED BY tool/mkctime.tcl
+*/
#if SQLITE_32BIT_ROWID
"32BIT_ROWID",
#endif
#if SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
+#if SQLITE_64BIT_STATS
+ "64BIT_STATS",
+#endif
+#if SQLITE_ALLOW_COVERING_INDEX_SCAN
+ "ALLOW_COVERING_INDEX_SCAN",
+#endif
+#if SQLITE_ALLOW_URI_AUTHORITY
+ "ALLOW_URI_AUTHORITY",
+#endif
+#ifdef SQLITE_BITMASK_TYPE
+ "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
+#endif
+#if SQLITE_BUG_COMPATIBLE_20160819
+ "BUG_COMPATIBLE_20160819",
+#endif
#if SQLITE_CASE_SENSITIVE_LIKE
"CASE_SENSITIVE_LIKE",
#endif
#if SQLITE_CHECK_PAGES
"CHECK_PAGES",
@@ -55,35 +72,104 @@
"COMPILER=gcc-" __VERSION__,
#endif
#if SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
-#ifdef SQLITE_DEBUG
+#if SQLITE_DEBUG
"DEBUG",
#endif
-#if SQLITE_DEFAULT_LOCKING_MODE
+#if SQLITE_DEFAULT_AUTOMATIC_INDEX
+ "DEFAULT_AUTOMATIC_INDEX",
+#endif
+#if SQLITE_DEFAULT_AUTOVACUUM
+ "DEFAULT_AUTOVACUUM",
+#endif
+#ifdef SQLITE_DEFAULT_CACHE_SIZE
+ "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
+#endif
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+ "DEFAULT_CKPTFULLFSYNC",
+#endif
+#ifdef SQLITE_DEFAULT_FILE_FORMAT
+ "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
+#endif
+#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
+ "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
+#endif
+#if SQLITE_DEFAULT_FOREIGN_KEYS
+ "DEFAULT_FOREIGN_KEYS",
+#endif
+#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
+ "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
+#endif
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
-#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
+#ifdef SQLITE_DEFAULT_LOOKASIDE
+ "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE),
+#endif
+#if SQLITE_DEFAULT_MEMSTATUS
+ "DEFAULT_MEMSTATUS",
+#endif
+#ifdef SQLITE_DEFAULT_MMAP_SIZE
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
-#if SQLITE_DEFAULT_SYNCHRONOUS
+#ifdef SQLITE_DEFAULT_PAGE_SIZE
+ "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
+#endif
+#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
+ "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
+#endif
+#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
+ "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
+#endif
+#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
+ "DEFAULT_RECURSIVE_TRIGGERS",
+#endif
+#ifdef SQLITE_DEFAULT_ROWEST
+ "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
+#endif
+#ifdef SQLITE_DEFAULT_SECTOR_SIZE
+ "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
+#endif
+#ifdef SQLITE_DEFAULT_SYNCHRONOUS
"DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
#endif
-#if SQLITE_DEFAULT_WAL_SYNCHRONOUS
+#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+ "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
+#endif
+#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
"DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
#endif
+#ifdef SQLITE_DEFAULT_WORKER_THREADS
+ "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
+#endif
#if SQLITE_DIRECT_OVERFLOW_READ
"DIRECT_OVERFLOW_READ",
#endif
#if SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
#endif
+#if SQLITE_DISABLE_FTS3_UNICODE
+ "DISABLE_FTS3_UNICODE",
+#endif
+#if SQLITE_DISABLE_FTS4_DEFERRED
+ "DISABLE_FTS4_DEFERRED",
+#endif
+#if SQLITE_DISABLE_INTRINSIC
+ "DISABLE_INTRINSIC",
+#endif
#if SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
-#if SQLITE_ENABLE_8_3_NAMES
+#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+ "DISABLE_PAGECACHE_OVERFLOW_STATS",
+#endif
+#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ "DISABLE_SKIPAHEAD_DISTINCT",
+#endif
+#ifdef SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
#if SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR",
#endif
@@ -93,10 +179,19 @@
#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD",
#endif
#if SQLITE_ENABLE_COLUMN_METADATA
"ENABLE_COLUMN_METADATA",
+#endif
+#if SQLITE_ENABLE_COLUMN_USED_MASK
+ "ENABLE_COLUMN_USED_MASK",
+#endif
+#if SQLITE_ENABLE_COSTMULT
+ "ENABLE_COSTMULT",
+#endif
+#if SQLITE_ENABLE_CURSOR_HINTS
+ "ENABLE_CURSOR_HINTS",
#endif
#if SQLITE_ENABLE_DBSTAT_VTAB
"ENABLE_DBSTAT_VTAB",
#endif
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -112,15 +207,21 @@
"ENABLE_FTS3",
#endif
#if SQLITE_ENABLE_FTS3_PARENTHESIS
"ENABLE_FTS3_PARENTHESIS",
#endif
+#if SQLITE_ENABLE_FTS3_TOKENIZER
+ "ENABLE_FTS3_TOKENIZER",
+#endif
#if SQLITE_ENABLE_FTS4
"ENABLE_FTS4",
#endif
#if SQLITE_ENABLE_FTS5
"ENABLE_FTS5",
+#endif
+#if SQLITE_ENABLE_HIDDEN_COLUMNS
+ "ENABLE_HIDDEN_COLUMNS",
#endif
#if SQLITE_ENABLE_ICU
"ENABLE_ICU",
#endif
#if SQLITE_ENABLE_IOTRACE
@@ -130,11 +231,11 @@
"ENABLE_JSON1",
#endif
#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
"ENABLE_MEMORY_MANAGEMENT",
#endif
@@ -141,30 +242,90 @@
#if SQLITE_ENABLE_MEMSYS3
"ENABLE_MEMSYS3",
#endif
#if SQLITE_ENABLE_MEMSYS5
"ENABLE_MEMSYS5",
+#endif
+#if SQLITE_ENABLE_MULTIPLEX
+ "ENABLE_MULTIPLEX",
+#endif
+#if SQLITE_ENABLE_NULL_TRIM
+ "ENABLE_NULL_TRIM",
#endif
#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK",
+#endif
+#if SQLITE_ENABLE_PREUPDATE_HOOK
+ "ENABLE_PREUPDATE_HOOK",
+#endif
+#if SQLITE_ENABLE_RBU
+ "ENABLE_RBU",
#endif
#if SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
+#endif
+#if SQLITE_ENABLE_SELECTTRACE
+ "ENABLE_SELECTTRACE",
+#endif
+#if SQLITE_ENABLE_SESSION
+ "ENABLE_SESSION",
+#endif
+#if SQLITE_ENABLE_SNAPSHOT
+ "ENABLE_SNAPSHOT",
+#endif
+#if SQLITE_ENABLE_SQLLOG
+ "ENABLE_SQLLOG",
#endif
#if defined(SQLITE_ENABLE_STAT4)
"ENABLE_STAT4",
#elif defined(SQLITE_ENABLE_STAT3)
"ENABLE_STAT3",
+#endif
+#if SQLITE_ENABLE_STMT_SCANSTATUS
+ "ENABLE_STMT_SCANSTATUS",
+#endif
+#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ "ENABLE_UNKNOWN_SQL_FUNCTION",
#endif
#if SQLITE_ENABLE_UNLOCK_NOTIFY
"ENABLE_UNLOCK_NOTIFY",
#endif
#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
"ENABLE_UPDATE_DELETE_LIMIT",
#endif
-#if defined(SQLITE_ENABLE_URI_00_ERROR)
+#if SQLITE_ENABLE_URI_00_ERROR
"ENABLE_URI_00_ERROR",
+#endif
+#if SQLITE_ENABLE_VFSTRACE
+ "ENABLE_VFSTRACE",
+#endif
+#if SQLITE_ENABLE_WHERETRACE
+ "ENABLE_WHERETRACE",
+#endif
+#if SQLITE_ENABLE_ZIPVFS
+ "ENABLE_ZIPVFS",
+#endif
+#if SQLITE_EXPLAIN_ESTIMATED_ROWS
+ "EXPLAIN_ESTIMATED_ROWS",
+#endif
+#if SQLITE_EXTRA_IFNULLROW
+ "EXTRA_IFNULLROW",
+#endif
+#ifdef SQLITE_EXTRA_INIT
+ "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
+#endif
+#ifdef SQLITE_EXTRA_SHUTDOWN
+ "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
+#endif
+#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
+ "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
+#endif
+#if SQLITE_FTS5_ENABLE_TEST_MI
+ "FTS5_ENABLE_TEST_MI",
+#endif
+#if SQLITE_FTS5_NO_WITHOUT_ROWID
+ "FTS5_NO_WITHOUT_ROWID",
#endif
#if SQLITE_HAS_CODEC
"HAS_CODEC",
#endif
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
@@ -177,30 +338,117 @@
"IGNORE_AFP_LOCK_ERRORS",
#endif
#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
"IGNORE_FLOCK_LOCK_ERRORS",
#endif
-#ifdef SQLITE_INT64_TYPE
+#if SQLITE_INLINE_MEMCPY
+ "INLINE_MEMCPY",
+#endif
+#if SQLITE_INT64_TYPE
"INT64_TYPE",
#endif
-#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
+#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
+ "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
+#endif
+#if SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS",
#endif
#if SQLITE_LOCK_TRACE
"LOCK_TRACE",
#endif
-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
+#if SQLITE_LOG_CACHE_SPILL
+ "LOG_CACHE_SPILL",
+#endif
+#ifdef SQLITE_MALLOC_SOFT_LIMIT
+ "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
+#endif
+#ifdef SQLITE_MAX_ATTACHED
+ "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
+#endif
+#ifdef SQLITE_MAX_COLUMN
+ "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
+#endif
+#ifdef SQLITE_MAX_COMPOUND_SELECT
+ "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
+#endif
+#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
+ "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
+#endif
+#ifdef SQLITE_MAX_EXPR_DEPTH
+ "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
+#endif
+#ifdef SQLITE_MAX_FUNCTION_ARG
+ "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
+#endif
+#ifdef SQLITE_MAX_LENGTH
+ "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
+#endif
+#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
+ "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
+#endif
+#ifdef SQLITE_MAX_MEMORY
+ "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
+#endif
+#ifdef SQLITE_MAX_MMAP_SIZE
"MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
#endif
+#ifdef SQLITE_MAX_MMAP_SIZE_
+ "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
+#endif
+#ifdef SQLITE_MAX_PAGE_COUNT
+ "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
+#endif
+#ifdef SQLITE_MAX_PAGE_SIZE
+ "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
+#endif
#ifdef SQLITE_MAX_SCHEMA_RETRY
"MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
#endif
+#ifdef SQLITE_MAX_SQL_LENGTH
+ "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
+#endif
+#ifdef SQLITE_MAX_TRIGGER_DEPTH
+ "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
+#endif
+#ifdef SQLITE_MAX_VARIABLE_NUMBER
+ "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
+#endif
+#ifdef SQLITE_MAX_VDBE_OP
+ "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
+#endif
+#ifdef SQLITE_MAX_WORKER_THREADS
+ "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
+#endif
#if SQLITE_MEMDEBUG
"MEMDEBUG",
#endif
#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
"MIXED_ENDIAN_64BIT_FLOAT",
+#endif
+#if SQLITE_MMAP_READWRITE
+ "MMAP_READWRITE",
+#endif
+#if SQLITE_MUTEX_NOOP
+ "MUTEX_NOOP",
+#endif
+#if SQLITE_MUTEX_NREF
+ "MUTEX_NREF",
+#endif
+#if SQLITE_MUTEX_OMIT
+ "MUTEX_OMIT",
+#endif
+#if SQLITE_MUTEX_PTHREADS
+ "MUTEX_PTHREADS",
+#endif
+#if SQLITE_MUTEX_W32
+ "MUTEX_W32",
+#endif
+#if SQLITE_NEED_ERR_NAME
+ "NEED_ERR_NAME",
+#endif
+#if SQLITE_NOINLINE
+ "NOINLINE",
#endif
#if SQLITE_NO_SYNC
"NO_SYNC",
#endif
#if SQLITE_OMIT_ALTERTABLE
@@ -249,10 +497,13 @@
"OMIT_COMPLETE",
#endif
#if SQLITE_OMIT_COMPOUND_SELECT
"OMIT_COMPOUND_SELECT",
#endif
+#if SQLITE_OMIT_CONFLICT_CLAUSE
+ "OMIT_CONFLICT_CLAUSE",
+#endif
#if SQLITE_OMIT_CTE
"OMIT_CTE",
#endif
#if SQLITE_OMIT_DATETIME_FUNCS
"OMIT_DATETIME_FUNCS",
@@ -278,10 +529,13 @@
#if SQLITE_OMIT_FOREIGN_KEY
"OMIT_FOREIGN_KEY",
#endif
#if SQLITE_OMIT_GET_TABLE
"OMIT_GET_TABLE",
+#endif
+#if SQLITE_OMIT_HEX_INTEGER
+ "OMIT_HEX_INTEGER",
#endif
#if SQLITE_OMIT_INCRBLOB
"OMIT_INCRBLOB",
#endif
#if SQLITE_OMIT_INTEGRITY_CHECK
@@ -305,10 +559,16 @@
#if SQLITE_OMIT_OR_OPTIMIZATION
"OMIT_OR_OPTIMIZATION",
#endif
#if SQLITE_OMIT_PAGER_PRAGMAS
"OMIT_PAGER_PRAGMAS",
+#endif
+#if SQLITE_OMIT_PARSER_TRACE
+ "OMIT_PARSER_TRACE",
+#endif
+#if SQLITE_OMIT_POPEN
+ "OMIT_POPEN",
#endif
#if SQLITE_OMIT_PRAGMA
"OMIT_PRAGMA",
#endif
#if SQLITE_OMIT_PROGRESS_CALLBACK
@@ -327,18 +587,24 @@
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
#if SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
+#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES
+ "OMIT_SHUTDOWN_DIRECTORIES",
+#endif
#if SQLITE_OMIT_SUBQUERY
"OMIT_SUBQUERY",
#endif
#if SQLITE_OMIT_TCL_VARIABLE
"OMIT_TCL_VARIABLE",
#endif
#if SQLITE_OMIT_TEMPDB
"OMIT_TEMPDB",
+#endif
+#if SQLITE_OMIT_TEST_CONTROL
+ "OMIT_TEST_CONTROL",
#endif
#if SQLITE_OMIT_TRACE
"OMIT_TRACE",
#endif
#if SQLITE_OMIT_TRIGGER
@@ -365,16 +631,28 @@
#if SQLITE_OMIT_WSD
"OMIT_WSD",
#endif
#if SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
+#endif
+#if SQLITE_PCACHE_SEPARATE_HEADER
+ "PCACHE_SEPARATE_HEADER",
#endif
#if SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
+#if SQLITE_POWERSAFE_OVERWRITE
+ "POWERSAFE_OVERWRITE",
+#endif
+#if SQLITE_PREFER_PROXY_LOCKING
+ "PREFER_PROXY_LOCKING",
+#endif
#if SQLITE_PROXY_DEBUG
"PROXY_DEBUG",
+#endif
+#if SQLITE_REVERSE_UNORDERED_SELECTS
+ "REVERSE_UNORDERED_SELECTS",
#endif
#if SQLITE_RTREE_INT_ONLY
"RTREE_INT_ONLY",
#endif
#if SQLITE_SECURE_DELETE
@@ -381,83 +659,77 @@
"SECURE_DELETE",
#endif
#if SQLITE_SMALL_STACK
"SMALL_STACK",
#endif
+#ifdef SQLITE_SORTER_PMASZ
+ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
+#endif
#if SQLITE_SOUNDEX
"SOUNDEX",
+#endif
+#ifdef SQLITE_STAT4_SAMPLES
+ "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
+#endif
+#ifdef SQLITE_STMTJRNL_SPILL
+ "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
+#endif
+#if SQLITE_SUBSTR_COMPATIBILITY
+ "SUBSTR_COMPATIBILITY",
#endif
#if SQLITE_SYSTEM_MALLOC
"SYSTEM_MALLOC",
#endif
#if SQLITE_TCL
"TCL",
#endif
-#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
+#ifdef SQLITE_TEMP_STORE
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
#if SQLITE_TEST
"TEST",
#endif
#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+#elif defined(THREADSAFE)
+ "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
+#else
+ "THREADSAFE=1",
+#endif
+#if SQLITE_UNLINK_AFTER_CLOSE
+ "UNLINK_AFTER_CLOSE",
#endif
#if SQLITE_UNTESTABLE
- "UNTESTABLE"
+ "UNTESTABLE",
+#endif
+#if SQLITE_USER_AUTHENTICATION
+ "USER_AUTHENTICATION",
#endif
#if SQLITE_USE_ALLOCA
"USE_ALLOCA",
#endif
-#if SQLITE_USER_AUTHENTICATION
- "USER_AUTHENTICATION",
+#if SQLITE_USE_FCNTL_TRACE
+ "USE_FCNTL_TRACE",
+#endif
+#if SQLITE_USE_URI
+ "USE_URI",
+#endif
+#if SQLITE_VDBE_COVERAGE
+ "VDBE_COVERAGE",
#endif
#if SQLITE_WIN32_MALLOC
"WIN32_MALLOC",
#endif
#if SQLITE_ZERO_MALLOC
- "ZERO_MALLOC"
+ "ZERO_MALLOC",
#endif
+/*
+** END CODE GENERATED BY tool/mkctime.tcl
+*/
};
-/*
-** Given the name of a compile-time option, return true if that option
-** was used and false if not.
-**
-** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
-** is not required for a match.
-*/
-int sqlite3_compileoption_used(const char *zOptName){
- int i, n;
-
-#if SQLITE_ENABLE_API_ARMOR
- if( zOptName==0 ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
- if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
- n = sqlite3Strlen30(zOptName);
-
- /* Since ArraySize(azCompileOpt) is normally in single digits, a
- ** linear search is adequate. No need for a binary search. */
- for(i=0; i=0 && Ndb, pPk), nPk);
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
}else{
/* Add the rowid of the row to be deleted to the RowSet */
- nKey = 1; /* OP_Seek always uses a single rowid */
+ nKey = 1; /* OP_DeferredSeek always uses a single rowid */
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
}
/* If this DELETE cannot use the ONEPASS strategy, this is the
Index: src/expr.c
==================================================================
--- src/expr.c
+++ src/expr.c
@@ -1486,11 +1486,13 @@
}
pList = pNew;
pList->nAlloc *= 2;
}
pItem = &pList->a[pList->nExpr++];
- memset(pItem, 0, sizeof(*pItem));
+ assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) );
+ assert( offsetof(struct ExprList_item,pExpr)==0 );
+ memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName));
pItem->pExpr = pExpr;
return pList;
no_mem:
/* Avoid leaking memory if malloc has failed. */
@@ -1770,14 +1772,16 @@
pWalker->eCode = 0;
return WRC_Abort;
}
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
w.xSelectCallback = selectNodeIsConstant;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -1861,13 +1865,13 @@
** optimization, so we take the easy way out and simply require the
** GROUP BY to use the BINARY collating sequence.
*/
int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = exprNodeIsConstantOrGroupBy;
+ w.xSelectCallback = 0;
w.u.pGroupBy = pGroupBy;
w.pParse = pParse;
sqlite3WalkExpr(&w, p);
return w.eCode;
}
@@ -1891,14 +1895,16 @@
** Walk an expression tree. Return 1 if the expression contains a
** subquery of some kind. Return 0 if there are no subqueries.
*/
int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
w.xSelectCallback = selectNodeIsConstant;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
sqlite3WalkExpr(&w, p);
return w.eCode==0;
}
#endif
@@ -4899,12 +4905,12 @@
*/
int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
Walker w;
struct SrcCount cnt;
assert( pExpr->op==TK_AGG_FUNCTION );
- memset(&w, 0, sizeof(w));
w.xExprCallback = exprSrcCount;
+ w.xSelectCallback = 0;
w.u.pSrcCount = &cnt;
cnt.pSrc = pSrcList;
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
@@ -5072,13 +5078,17 @@
}
}
return WRC_Continue;
}
static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pWalker);
UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth++;
return WRC_Continue;
+}
+static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
+ UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth--;
}
/*
** Analyze the pExpr expression looking for aggregate functions and
** for variables that need to be added to AggInfo object that pNC->pAggInfo
@@ -5088,13 +5098,14 @@
** This routine should only be called after the expression has been
** analyzed by sqlite3ResolveExprNames().
*/
void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = analyzeAggregate;
w.xSelectCallback = analyzeAggregatesInSelect;
+ w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
+ w.walkerDepth = 0;
w.u.pNC = pNC;
assert( pNC->pSrcList!=0 );
sqlite3WalkExpr(&w, pExpr);
}
Index: src/fkey.c
==================================================================
--- src/fkey.c
+++ src/fkey.c
@@ -631,14 +631,16 @@
sqlite3ResolveExprNames(&sNameContext, pWhere);
/* Create VDBE to loop through the entries in pSrc that match the WHERE
** clause. For each row found, increment either the deferred or immediate
** foreign key constraint counter. */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
- sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
- if( pWInfo ){
- sqlite3WhereEnd(pWInfo);
+ if( pParse->nErr==0 ){
+ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
+ if( pWInfo ){
+ sqlite3WhereEnd(pWInfo);
+ }
}
/* Clean up the WHERE clause constructed above. */
sqlite3ExprDelete(db, pWhere);
if( iFkIfZero ){
Index: src/insert.c
==================================================================
--- src/insert.c
+++ src/insert.c
@@ -519,14 +519,14 @@
Trigger *pTrigger; /* List of triggers on pTab, if required */
int tmask; /* Mask of trigger times */
#endif
db = pParse->db;
- memset(&dest, 0, sizeof(dest));
if( pParse->nErr || db->mallocFailed ){
goto insert_cleanup;
}
+ dest.iSDParm = 0; /* Suppress a harmless compiler warning */
/* If the Select object is really just a simple VALUES() list with a
** single row (the common case) then keep that one row of values
** and discard the other (unused) parts of the pSelect object
*/
Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -868,10 +868,11 @@
int rc, n;
n = nKey1=0 && Nfd) );
assert( pPager->tempFile==0 );
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the number of pages in the database is not available from the
- ** WAL sub-system, determine the page counte based on the size of
+ ** WAL sub-system, determine the page count based on the size of
** the database file. If the size of the database file is not an
** integer multiple of the page-size, round up the result.
*/
if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
i64 n = 0; /* Size of db file in bytes */
@@ -3310,27 +3310,25 @@
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
- Pgno nPage; /* Size of the database file */
-
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) return rc;
- if( nPage==0 ){
- rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
- if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
- isWal = 0;
- }else{
- rc = sqlite3OsAccess(
- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
- );
- }
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+ );
if( rc==SQLITE_OK ){
if( isWal ){
- testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
- rc = sqlite3PagerOpenWal(pPager, 0);
+ Pgno nPage; /* Size of the database file */
+
+ rc = pagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ }else{
+ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
+ rc = sqlite3PagerOpenWal(pPager, 0);
+ }
}else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
pPager->journalMode = PAGER_JOURNALMODE_DELETE;
}
}
}
@@ -5284,23 +5282,18 @@
**
** There is a vanishingly small chance that a change will not be
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
- Pgno nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)];
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) goto failed;
-
- if( nPage>0 ){
- IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
+ if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_IOERR_SHORT_READ ){
goto failed;
}
- }else{
memset(dbFileVers, 0, sizeof(dbFileVers));
}
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager);
Index: src/pcache.h
==================================================================
--- src/pcache.h
+++ src/pcache.h
@@ -24,25 +24,25 @@
*/
struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
+ PCache *pCache; /* PRIVATE: Cache that owns this page */
PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
u32 pageHash; /* Hash of page content */
#endif
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
- ** Elements above are public. All that follows is private to pcache.c
- ** and should not be accessed by other modules.
+ ** Elements above, except pCache, are public. All that follow are
+ ** private to pcache.c and should not be accessed by other modules.
+ ** pCache is grouped with the public elements for efficiency.
*/
i16 nRef; /* Number of users of this page */
- PCache *pCache; /* Cache that owns this page */
-
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
};
/* Bit values for PgHdr.flags */
Index: src/pragma.h
==================================================================
--- src/pragma.h
+++ src/pragma.h
@@ -265,11 +265,11 @@
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
{/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
/* ColNames: */ 39, 4,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
{/* zName: */ "foreign_key_list",
@@ -352,11 +352,11 @@
/* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "integrity_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "journal_mode",
@@ -447,11 +447,11 @@
/* iArg: */ SQLITE_QueryOnly },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "quick_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{/* zName: */ "read_uncommitted",
Index: src/resolve.c
==================================================================
--- src/resolve.c
+++ src/resolve.c
@@ -1428,41 +1428,33 @@
Expr *pExpr /* The expression to be analyzed. */
){
u16 savedHasAgg;
Walker w;
- if( pExpr==0 ) return 0;
-#if SQLITE_MAX_EXPR_DEPTH>0
- {
- Parse *pParse = pNC->pParse;
- if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
- return 1;
- }
- pParse->nHeight += pExpr->nHeight;
- }
-#endif
+ if( pExpr==0 ) return SQLITE_OK;
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
w.pParse = pNC->pParse;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.xSelectCallback2 = 0;
- w.walkerDepth = 0;
- w.eCode = 0;
w.u.pNC = pNC;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ w.pParse->nHeight += pExpr->nHeight;
+ if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
+ return SQLITE_ERROR;
+ }
+#endif
sqlite3WalkExpr(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
- pNC->pParse->nHeight -= pExpr->nHeight;
+ w.pParse->nHeight -= pExpr->nHeight;
#endif
- if( pNC->nErr>0 || w.pParse->nErr>0 ){
- ExprSetProperty(pExpr, EP_Error);
- }
if( pNC->ncFlags & NC_HasAgg ){
ExprSetProperty(pExpr, EP_Agg);
}
pNC->ncFlags |= savedHasAgg;
- return ExprHasProperty(pExpr, EP_Error);
+ return pNC->nErr>0 || w.pParse->nErr>0;
}
/*
** Resolve all names for all expression in an expression list. This is
** just like sqlite3ResolveExprNames() except that it works for an expression
@@ -1499,13 +1491,13 @@
NameContext *pOuterNC /* Name context for parent SELECT statement */
){
Walker w;
assert( p!=0 );
- memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
+ w.xSelectCallback2 = 0;
w.pParse = pParse;
w.u.pNC = pOuterNC;
sqlite3WalkSelect(&w, p);
}
Index: src/select.c
==================================================================
--- src/select.c
+++ src/select.c
@@ -1029,11 +1029,11 @@
/*
** Allocate a KeyInfo object sufficient for an index of N key columns and
** X extra columns.
*/
KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1);
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
p->nField = (u16)N;
p->nXField = (u16)X;
@@ -3203,13 +3203,16 @@
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
pCopy = &ifNullRow;
}
pNew = sqlite3ExprDup(db, pCopy, 0);
- if( pNew && (pExpr->flags & EP_FromJoin) ){
+ if( pNew && pSubst->isLeftJoin ){
+ ExprSetProperty(pNew, EP_CanBeNull);
+ }
+ if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
pNew->iRightJoinTable = pExpr->iRightJoinTable;
- pNew->flags |= EP_FromJoin;
+ ExprSetProperty(pNew, EP_FromJoin);
}
sqlite3ExprDelete(db, pExpr);
pExpr = pNew;
}
}
@@ -3498,11 +3501,11 @@
**
** which is not at all the same thing.
**
** If the subquery is the right operand of a LEFT JOIN, then the outer
** query cannot be an aggregate. This is an artifact of the way aggregates
- ** are processed - there is not mechanism to determine if the LEFT JOIN
+ ** are processed - there is no mechanism to determine if the LEFT JOIN
** table should be all-NULL.
**
** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
@@ -4608,10 +4611,29 @@
int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return WRC_Continue;
}
+/*
+** No-op routine for the parse-tree walker for SELECT statements.
+** subquery in the parser tree.
+*/
+int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
+}
+
+#if SQLITE_DEBUG
+/*
+** Always assert. This xSelectCallback2 implementation proves that the
+** xSelectCallback2 is never invoked.
+*/
+void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ assert( 0 );
+}
+#endif
/*
** This routine "expands" a SELECT statement and all of its subqueries.
** For additional information on what it means to "expand" a SELECT
** statement, see the comment on the selectExpand worker callback above.
**
@@ -4623,15 +4645,15 @@
** The calling function can detect the problem by looking at pParse->nErr
** and/or pParse->db->mallocFailed.
*/
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
if( pParse->hasCompound ){
w.xSelectCallback = convertCompoundSelectToSubquery;
+ w.xSelectCallback2 = 0;
sqlite3WalkSelect(&w, pSelect);
}
w.xSelectCallback = selectExpander;
w.xSelectCallback2 = selectPopWith;
sqlite3WalkSelect(&w, pSelect);
@@ -4687,11 +4709,11 @@
** Use this routine after name resolution.
*/
static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY
Walker w;
- memset(&w, 0, sizeof(w));
+ w.xSelectCallback = sqlite3SelectWalkNoop;
w.xSelectCallback2 = selectAddSubqueryTypeInfo;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
sqlite3WalkSelect(&w, pSelect);
#endif
@@ -5268,10 +5290,13 @@
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
}
pPrior = isSelfJoinView(pTabList, pItem);
if( pPrior ){
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
+ explainSetInteger(pItem->iSelectId, pPrior->iSelectId);
+ assert( pPrior->pSelect!=0 );
+ pSub->nSelectRow = pPrior->pSelect->nSelectRow;
}else{
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
}
Index: src/shell.c
==================================================================
--- src/shell.c
+++ src/shell.c
@@ -16,15 +16,29 @@
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif
/*
-** If requested, include the SQLite compiler options file for MSVC.
+** Warning pragmas copied from msvc.h in the core.
*/
-#if defined(INCLUDE_MSVC_H)
-#include "msvc.h"
-#endif
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4130)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
/*
** No support for loadable extensions in VxWorks.
*/
#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
@@ -492,10 +506,22 @@
static int strlen30(const char *z){
const char *z2 = z;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
+
+/*
+** Return the length of a string in characters. Multibyte UTF8 characters
+** count as a single character.
+*/
+static int strlenChar(const char *z){
+ int n = 0;
+ while( *z ){
+ if( (0xc0&*(z++))!=0x80 ) n++;
+ }
+ return n;
+}
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
@@ -700,10 +726,65 @@
upr = mid-1;
}
}
return 0;
}
+
+/*
+** SQL function: shell_add_schema(S,X)
+**
+** Add the schema name X to the CREATE statement in S and return the result.
+** Examples:
+**
+** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
+**
+** Also works on
+**
+** CREATE INDEX
+** CREATE UNIQUE INDEX
+** CREATE VIEW
+** CREATE TRIGGER
+** CREATE VIRTUAL TABLE
+**
+** This UDF is used by the .schema command to insert the schema name of
+** attached databases into the middle of the sqlite_master.sql field.
+*/
+static void shellAddSchemaName(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ static const char *aPrefix[] = {
+ "TABLE",
+ "INDEX",
+ "UNIQUE INDEX",
+ "VIEW",
+ "TRIGGER",
+ "VIRTUAL TABLE"
+ };
+ int i = 0;
+ const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
+ const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
+ assert( nVal==2 );
+ if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
+ for(i=0; inullValue);
+ n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue);
if( wactualWidth) ){
p->actualWidth[i] = w;
}
@@ -1938,12 +2019,12 @@
if( iactualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
- if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
- w = strlen30(azArg[i]);
+ if( p->cMode==MODE_Explain && azArg[i] && strlenChar(azArg[i])>w ){
+ w = strlenChar(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
if( p->iIndentnIndent ){
utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
@@ -2995,11 +3076,11 @@
azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
if( sqlite3_column_int(pStmt, 5) ){
nPK++;
if( nPK==1
&& sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
- "INTEGER")==0
+ "INTEGER")==0
){
isIPK = 1;
}else{
isIPK = 0;
}
@@ -3232,10 +3313,11 @@
".auth ON|OFF Show authorizer callbacks\n"
#endif
".backup ?DB? FILE Backup DB (default \"main\") to FILE\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"
".dbinfo ?DB? Show status information about the database\n"
@@ -3277,12 +3359,12 @@
" 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 FILENAME Output for the next SQL command only to FILENAME\n"
- ".open ?--new? ?FILE? Close existing database and reopen FILE\n"
- " The --new starts with an empty file\n"
+ ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n"
+ " The --new option starts with an empty file\n"
".output ?FILENAME? Send output to FILENAME 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"
@@ -3343,12 +3425,12 @@
/* Forward reference */
static int process_input(ShellState *p, FILE *in);
/*
** Read the content of file zName into memory obtained from sqlite3_malloc64()
-** and return a pointer to the buffer. The caller is responsible for freeing
-** the memory.
+** and return a pointer to the buffer. The caller is responsible for freeing
+** the memory.
**
** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
** read.
**
** For convenience, a nul-terminator byte is always appended to the data read
@@ -3507,10 +3589,13 @@
sha3Func, 0, 0);
sqlite3_create_function(p->db, "sha3_query", 1, SQLITE_UTF8, 0,
sha3QueryFunc, 0, 0);
sqlite3_create_function(p->db, "sha3_query", 2, SQLITE_UTF8, 0,
sha3QueryFunc, 0, 0);
+ sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
+ shellAddSchemaName, 0, 0);
+
}
}
/*
** Do C-language style dequoting.
@@ -4351,19 +4436,19 @@
** the child table name and the child column name.
**
** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
**
** If either of the named tables or columns do not exist, this function
-** returns an empty string. An empty string is also returned if both tables
+** returns an empty string. An empty string is also returned if both tables
** and columns exist but have the same default collation sequence. Or,
** if both exist but the default collation sequences are different, this
** function returns the string " COLLATE ", where
** is the default collation sequence of the parent column.
*/
static void shellFkeyCollateClause(
- sqlite3_context *pCtx,
- int nVal,
+ sqlite3_context *pCtx,
+ int nVal,
sqlite3_value **apVal
){
sqlite3 *db = sqlite3_context_db_handle(pCtx);
const char *zParent;
const char *zParentCol;
@@ -4370,11 +4455,11 @@
const char *zParentSeq;
const char *zChild;
const char *zChildCol;
const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
int rc;
-
+
assert( nVal==4 );
zParent = (const char*)sqlite3_value_text(apVal[0]);
zParentCol = (const char*)sqlite3_value_text(apVal[1]);
zChild = (const char*)sqlite3_value_text(apVal[2]);
zChildCol = (const char*)sqlite3_value_text(apVal[3]);
@@ -4492,11 +4577,11 @@
azArg[0], azArg[1]
);
return SQLITE_ERROR;
}
}
-
+
/* Register the fkey_collate_clause() SQL function */
rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
0, shellFkeyCollateClause, 0, 0
);
@@ -4535,23 +4620,23 @@
if( res<0 ){
raw_printf(stderr, "Error: internal error");
break;
}else{
- if( bGroupByParent
+ if( bGroupByParent
&& (bVerbose || res==0)
- && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
+ && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
){
raw_printf(out, "-- Parent table %s\n", zParent);
sqlite3_free(zPrev);
zPrev = sqlite3_mprintf("%s", zParent);
}
if( res==0 ){
raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
}else if( bVerbose ){
- raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
+ raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
zIndent, zFrom, zTarget
);
}
}
}
@@ -4728,10 +4813,29 @@
}else{
raw_printf(stderr, "Usage: .binary on|off\n");
rc = 1;
}
}else
+
+ if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+ if( nArg==2 ){
+#if defined(_WIN32) || defined(WIN32)
+ wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
+ rc = !SetCurrentDirectoryW(z);
+ sqlite3_free(z);
+#else
+ rc = chdir(azArg[1]);
+#endif
+ if( rc ){
+ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
+ rc = 1;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .cd DIRECTORY\n");
+ rc = 1;
+ }
+ }else
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
@@ -5641,16 +5745,21 @@
rc = 1;
}
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+ ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
+ const char *zDiv = 0;
+ int iSchema = 0;
+
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
+ initText(&sSelect);
if( nArg>=2 && optionMatch(azArg[1], "indent") ){
data.cMode = data.mode = MODE_Pretty;
nArg--;
if( nArg==2 ) azArg[1] = azArg[2];
}
@@ -5684,37 +5793,66 @@
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
rc = SQLITE_OK;
}else{
- char *zSql;
- zSql = sqlite3_mprintf(
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE lower(tbl_name) LIKE %Q"
- " AND type!='meta' AND sql NOTNULL "
- "ORDER BY rowid", azArg[1]);
- rc = sqlite3_exec(p->db, zSql, callback, &data, &zErrMsg);
- sqlite3_free(zSql);
+ zDiv = "(";
}
}else if( nArg==1 ){
- rc = sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
- "ORDER BY rowid",
- callback, &data, &zErrMsg
- );
+ zDiv = "(";
}else{
raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
}
+ if( zDiv ){
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+ -1, &pStmt, 0);
+ appendText(&sSelect, "SELECT sql FROM", 0);
+ iSchema = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+ char zScNum[30];
+ sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
+ appendText(&sSelect, zDiv, 0);
+ zDiv = " UNION ALL ";
+ if( strcmp(zDb, "main")!=0 ){
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ".sqlite_master", 0);
+ }else{
+ appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ appendText(&sSelect, ") WHERE ", 0);
+ if( nArg>1 ){
+ char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
+ if( strchr(azArg[1], '.') ){
+ appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
+ }else{
+ appendText(&sSelect, "lower(tbl_name)", 0);
+ }
+ appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, zQarg, 0);
+ appendText(&sSelect, " AND ", 0);
+ sqlite3_free(zQarg);
+ }
+ appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
+ " ORDER BY snum, rowid", 0);
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ freeText(&sSelect);
+ }
if( zErrMsg ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}else if( rc != SQLITE_OK ){
@@ -5952,23 +6090,15 @@
if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
int bIsInit = 0; /* True to initialize the SELFTEST table */
int bVerbose = 0; /* Verbose output */
int bSelftestExists; /* True if SELFTEST already exists */
- char **azTest = 0; /* Content of the SELFTEST table */
- int nRow = 0; /* Number of rows in the SELFTEST table */
- int nCol = 4; /* Number of columns in the SELFTEST table */
- int i; /* Loop counter */
+ int i, k; /* Loop counters */
int nTest = 0; /* Number of tests runs */
int nErr = 0; /* Number of errors seen */
ShellText str; /* Answer for a query */
- static char *azDefaultTest[] = {
- 0, 0, 0, 0,
- "0", "memo", "Missing SELFTEST table - default checks only", "",
- "1", "run", "PRAGMA integrity_check", "ok"
- };
- static const int nDefaultRow = 2;
+ sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
open_db(p,0);
for(i=1; idb,
- "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
- &azTest, &nRow, &nCol, 0);
+ initText(&str);
+ appendText(&str, "x", 0);
+ for(k=bSelftestExists; k>=0; k--){
+ if( k==1 ){
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
+ -1, &pStmt, 0);
+ }else{
+ rc = sqlite3_prepare_v2(p->db,
+ "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
+ " (1,'run','PRAGMA integrity_check','ok')",
+ -1, &pStmt, 0);
+ }
if( rc ){
raw_printf(stderr, "Error querying the selftest table\n");
rc = 1;
- sqlite3_free_table(azTest);
- goto meta_command_exit;
- }else if( nRow==0 ){
- sqlite3_free_table(azTest);
- azTest = azDefaultTest;
- nRow = nDefaultRow;
- }
- }else{
- azTest = azDefaultTest;
- nRow = nDefaultRow;
- }
- initText(&str);
- appendText(&str, "x", 0);
- for(i=1; i<=nRow; i++){
- int tno = atoi(azTest[i*nCol]);
- const char *zOp = azTest[i*nCol+1];
- const char *zSql = azTest[i*nCol+2];
- const char *zAns = azTest[i*nCol+3];
-
- if( bVerbose>0 ){
- char *zQuote = sqlite3_mprintf("%q", zSql);
- printf("%d: %s %s\n", tno, zOp, zSql);
- sqlite3_free(zQuote);
- }
- if( strcmp(zOp,"memo")==0 ){
- utf8_printf(p->out, "%s\n", zSql);
- }else
- if( strcmp(zOp,"run")==0 ){
- char *zErrMsg = 0;
- str.n = 0;
- str.z[0] = 0;
- rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
- nTest++;
- if( bVerbose ){
- utf8_printf(p->out, "Result: %s\n", str.z);
- }
- if( rc || zErrMsg ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
- sqlite3_free(zErrMsg);
- }else if( strcmp(zAns,str.z)!=0 ){
- nErr++;
- rc = 1;
- utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
- utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
- }
- }else
- {
- utf8_printf(stderr,
- "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
- rc = 1;
- break;
- }
- }
- freeText(&str);
- if( azTest!=azDefaultTest ) sqlite3_free_table(azTest);
+ sqlite3_finalize(pStmt);
+ goto meta_command_exit;
+ }
+ for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ int tno = sqlite3_column_int(pStmt, 0);
+ const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
+ const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
+ const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
+
+ k = 0;
+ if( bVerbose>0 ){
+ char *zQuote = sqlite3_mprintf("%q", zSql);
+ printf("%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_free(zQuote);
+ }
+ if( strcmp(zOp,"memo")==0 ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else
+ if( strcmp(zOp,"run")==0 ){
+ char *zErrMsg = 0;
+ str.n = 0;
+ str.z[0] = 0;
+ rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
+ nTest++;
+ if( bVerbose ){
+ utf8_printf(p->out, "Result: %s\n", str.z);
+ }
+ if( rc || zErrMsg ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_free(zErrMsg);
+ }else if( strcmp(zAns,str.z)!=0 ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
+ }
+ }else
+ {
+ utf8_printf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ rc = 1;
+ break;
+ }
+ } /* End loop over rows of content from SELFTEST */
+ sqlite3_finalize(pStmt);
+ } /* End loop over k */
+ freeText(&str);
utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
}else
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
@@ -6097,12 +6228,12 @@
z++;
if( z[0]=='-' ) z++;
if( strcmp(z,"schema")==0 ){
bSchema = 1;
}else
- if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
- || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
+ if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
+ || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
){
iSize = atoi(&z[5]);
}else
if( strcmp(z,"debug")==0 ){
bDebug = 1;
@@ -6266,63 +6397,51 @@
|| strncmp(azArg[0], "indexes", n)==0) )
){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
- char *zSql = 0;
int ii;
+ ShellText s;
+ initText(&s);
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return shellDatabaseError(p->db);
- /* Create an SQL statement to query for the list of tables in the
- ** main and all attached databases where the table name matches the
- ** LIKE pattern bound to variable "?1". */
- if( c=='t' ){
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1");
- }else if( nArg>2 ){
+ if( nArg>2 && c=='i' ){
/* It is an historical accident that the .indexes command shows an error
** when called with the wrong number of arguments whereas the .tables
** command does not. */
raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
goto meta_command_exit;
- }else{
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_master"
- " WHERE type='index'"
- " AND tbl_name LIKE ?1");
}
- for(ii=0; zSql && sqlite3_step(pStmt)==SQLITE_ROW; ii++){
+ for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
- if( zDbName==0 || ii==0 ) continue;
+ if( zDbName==0 ) continue;
+ if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
+ if( sqlite3_stricmp(zDbName, "main")==0 ){
+ appendText(&s, "SELECT name FROM ", 0);
+ }else{
+ appendText(&s, "SELECT ", 0);
+ appendText(&s, zDbName, '\'');
+ appendText(&s, "||'.'||name FROM ", 0);
+ }
+ appendText(&s, zDbName, '"');
+ appendText(&s, ".sqlite_master ", 0);
if( c=='t' ){
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT '%q.' || name FROM \"%w\".sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1", zSql, zDbName, zDbName);
+ appendText(&s," WHERE type IN ('table','view')"
+ " AND name NOT LIKE 'sqlite_%'"
+ " AND name LIKE ?1", 0);
}else{
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT '%q.' || name FROM \"%w\".sqlite_master"
- " WHERE type='index'"
- " AND tbl_name LIKE ?1", zSql, zDbName, zDbName);
+ appendText(&s," WHERE type='index'"
+ " AND tbl_name LIKE ?1", 0);
}
}
rc = sqlite3_finalize(pStmt);
- if( zSql && rc==SQLITE_OK ){
- zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
- if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- }
- sqlite3_free(zSql);
- if( !zSql ) return shellNomemError();
+ appendText(&s, " ORDER BY 1", 0);
+ rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
+ freeText(&s);
if( rc ) return shellDatabaseError(p->db);
/* Run the SQL statement prepared by the above block. Store the results
** as an array of nul-terminated strings in azResult[]. */
nRow = nAlloc = 0;
Index: src/sqlite.h.in
==================================================================
--- src/sqlite.h.in
+++ src/sqlite.h.in
@@ -5619,11 +5619,13 @@
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
-** does not.
+** does not. If the table name parameter T in a call to
+** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
+** undefined behavior.
**
** ^The column is identified by the second, third and fourth parameters to
** this function. ^(The second parameter is either the name of the database
** (i.e. "main", "temp", or an attached database) containing the specified
** table or NULL.)^ ^If it is NULL, then all attached databases are searched
@@ -7132,17 +7134,24 @@
** by the prepared statement if that number is less than or equal
** to 2147483647. The number of virtual machine operations can be
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
+**
+** [[SQLITE_STMTSTATUS_MEMUSED]] SQLITE_STMTSTATUS_MEMUSED
+** ^This is the approximate number of bytes of heap memory
+** used to store the prepared statement. ^This value is not actually
+** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
+** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
**
**
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4
+#define SQLITE_STMTSTATUS_MEMUSED 5
/*
** CAPI3REF: Custom Page Cache Object
**
** The sqlite3_pcache type is opaque. It is implemented by
Index: src/sqliteInt.h
==================================================================
--- src/sqliteInt.h
+++ src/sqliteInt.h
@@ -272,10 +272,15 @@
** threads can use SQLite as long as no two threads try to use the same
** database connection at the same time.
**
** Older versions of SQLite used an optional THREADSAFE macro.
** We support that for legacy.
+**
+** To ensure that the correct value of "THREADSAFE" is reported when querying
+** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this
+** logic is partially replicated in ctime.c. If it is updated here, it should
+** also be updated there.
*/
#if !defined(SQLITE_THREADSAFE)
# if defined(THREADSAFE)
# define SQLITE_THREADSAFE THREADSAFE
# else
@@ -587,11 +592,10 @@
** Provide a default value for SQLITE_TEMP_STORE in case it is not specified
** on the command-line
*/
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 1
-# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
#endif
/*
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
@@ -888,21 +892,19 @@
|| defined(__DragonFly__)
# define SQLITE_MAX_MMAP_SIZE 0x7fff0000 /* 2147418112 */
# else
# define SQLITE_MAX_MMAP_SIZE 0
# endif
-# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
#endif
/*
** The default MMAP_SIZE is zero on all platforms. Or, even if a larger
** default MMAP_SIZE is specified at compile-time, make sure that it does
** not exceed the maximum mmap size.
*/
#ifndef SQLITE_DEFAULT_MMAP_SIZE
# define SQLITE_DEFAULT_MMAP_SIZE 0
-# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */
#endif
#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
# undef SQLITE_DEFAULT_MMAP_SIZE
# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
#endif
@@ -2362,11 +2364,11 @@
** The following are the meanings of bits in the Expr.flags field.
*/
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
-#define EP_Error 0x000008 /* Expression contains one or more errors */
+ /* 0x000008 // available for use */
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
@@ -2829,14 +2831,14 @@
** An instance of this object describes where to put of the results of
** a SELECT statement.
*/
struct SelectDest {
u8 eDest; /* How to dispose of the results. On of SRT_* above. */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
int iSDParm; /* A parameter used by the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
+ char *zAffSdst; /* Affinity used when eDest==SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
/*
** During code generation of statements that do inserts into AUTOINCREMENT
@@ -3335,10 +3337,14 @@
int sqlite3WalkExprList(Walker*, ExprList*);
int sqlite3WalkSelect(Walker*, Select*);
int sqlite3WalkSelectExpr(Walker*, Select*);
int sqlite3WalkSelectFrom(Walker*, Select*);
int sqlite3ExprWalkNoop(Walker*, Expr*);
+int sqlite3SelectWalkNoop(Walker*, Select*);
+#ifdef SQLITE_DEBUG
+void sqlite3SelectWalkAssert2(Walker*, Select*);
+#endif
/*
** Return code from the parse-tree walking primitives and their
** callbacks.
*/
@@ -3396,15 +3402,18 @@
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
#ifdef SQLITE_DEBUG
int sqlite3NomemError(int);
int sqlite3IoerrnomemError(int);
+ int sqlite3CorruptPgnoError(int,Pgno);
# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
#else
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
#endif
/*
** FTS3 and FTS4 both require virtual table support
*/
@@ -4384,7 +4393,9 @@
int sqlite3ExprVectorSize(Expr *pExpr);
int sqlite3ExprIsVector(Expr *pExpr);
Expr *sqlite3VectorFieldSubexpr(Expr*, int);
Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
void sqlite3VectorErrorMsg(Parse*, Expr*);
+
+const char **sqlite3CompileOptions(int *pnOpt);
#endif /* SQLITEINT_H */
Index: src/tclsqlite.c
==================================================================
--- src/tclsqlite.c
+++ src/tclsqlite.c
@@ -159,10 +159,11 @@
SqlPreparedStmt *stmtLast; /* Last statement in the list */
int maxStmt; /* The next maximum number of stmtList */
int nStmt; /* Number of statements in stmtList */
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
int nStep, nSort, nIndex; /* Statistics for most recent operation */
+ int nVMStep; /* Another statistic for most recent operation */
int nTransaction; /* Number of nested [transaction] methods */
int openFlags; /* Flags used to open. (SQLITE_OPEN_URI) */
#ifdef SQLITE_TEST
int bLegacyPrepare; /* True to use sqlite3_prepare() */
#endif
@@ -1586,10 +1587,11 @@
rcs = sqlite3_reset(pStmt);
pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1);
pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1);
pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
+ pDb->nVMStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_VM_STEP,1);
dbReleaseColumnNames(p);
p->pPreStmt = 0;
if( rcs!=SQLITE_OK ){
/* If a run-time error occurs, report the error and stop reading
@@ -2853,11 +2855,11 @@
sqlite3_close(pSrc);
break;
}
/*
- ** $db status (step|sort|autoindex)
+ ** $db status (step|sort|autoindex|vmstep)
**
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
*/
case DB_STATUS: {
@@ -2872,13 +2874,15 @@
v = pDb->nStep;
}else if( strcmp(zOp, "sort")==0 ){
v = pDb->nSort;
}else if( strcmp(zOp, "autoindex")==0 ){
v = pDb->nIndex;
+ }else if( strcmp(zOp, "vmstep")==0 ){
+ v = pDb->nVMStep;
}else{
Tcl_AppendResult(interp,
- "bad argument: should be autoindex, step, or sort",
+ "bad argument: should be autoindex, step, sort or vmstep",
(char*)0);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
break;
Index: src/test3.c
==================================================================
--- src/test3.c
+++ src/test3.c
@@ -304,11 +304,15 @@
" ID\"", 0);
return TCL_ERROR;
}
pCur = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pCur->pBtree);
- rc = sqlite3BtreeNext(pCur, &res);
+ rc = sqlite3BtreeNext(pCur, 0);
+ if( rc==SQLITE_DONE ){
+ res = 1;
+ rc = SQLITE_OK;
+ }
sqlite3BtreeLeave(pCur->pBtree);
if( rc ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
return TCL_ERROR;
}
Index: src/test_fs.c
==================================================================
--- src/test_fs.c
+++ src/test_fs.c
@@ -543,10 +543,11 @@
if( zQuery[i]=='/' ) nDir = i;
}
zDir = zQuery;
}
}
+ if( nDir==0 ) nDir = 1;
sqlite3_bind_text(pCsr->pStmt, 1, zDir, nDir, SQLITE_TRANSIENT);
sqlite3_bind_text(pCsr->pStmt, 2, zRoot, nRoot, SQLITE_TRANSIENT);
sqlite3_bind_text(pCsr->pStmt, 3, zPrefix, nPrefix, SQLITE_TRANSIENT);
Index: src/trigger.c
==================================================================
--- src/trigger.c
+++ src/trigger.c
@@ -304,10 +304,11 @@
/* Make an entry in the sqlite_master table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
+ testcase( z==0 );
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
db->aDb[iDb].zDbSName, MASTER_NAME, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
Index: src/vacuum.c
==================================================================
--- src/vacuum.c
+++ src/vacuum.c
@@ -199,11 +199,11 @@
#ifdef SQLITE_HAS_CODEC
if( db->nextPagesize ){
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
+ sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
if( nKey ) db->nextPagesize = 0;
}
#endif
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
Index: src/vdbe.c
==================================================================
--- src/vdbe.c
+++ src/vdbe.c
@@ -571,11 +571,11 @@
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
int iCompare = 0; /* Result of last comparison */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
+ unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
@@ -604,10 +604,12 @@
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
assert( 0 < db->nProgressOps );
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
+ }else{
+ nProgressLimit = 0xffffffff;
}
#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
if( p->pc==0
@@ -781,11 +783,11 @@
** of VDBE ops have been executed (either since this invocation of
** sqlite3VdbeExec() or since last time the progress callback was called).
** If the progress callback returns non-zero, exit the virtual machine with
** a return code SQLITE_ABORT.
*/
- if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
+ if( nVmStep>=nProgressLimit && db->xProgress!=0 ){
assert( db->nProgressOps!=0 );
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
if( db->xProgress(db->pProgressArg) ){
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
@@ -1323,11 +1325,11 @@
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
/* Run the progress counter just before returning.
*/
if( db->xProgress!=0
- && nVmStep>=nProgressLimit
+ && nVmStep>=nProgressLimit
&& db->xProgress(db->pProgressArg)!=0
){
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -2494,11 +2496,13 @@
Mem *pReg; /* PseudoTable input register */
pC = p->apCsr[pOp->p1];
p2 = pOp->p2;
- /* If the cursor cache is stale, bring it up-to-date */
+ /* If the cursor cache is stale (meaning it is not currently point at
+ ** the correct row) then bring it up-to-date by doing the necessary
+ ** B-Tree seek. */
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
if( rc ) goto abort_due_to_error;
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
@@ -3976,21 +3980,35 @@
sqlite3_search_count++;
#endif
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0;
- rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
res = 0;
}
}else{
assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0;
- rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
*/
res = sqlite3BtreeEof(pC->uc.pCursor);
@@ -5092,16 +5110,14 @@
** invoked. This opcode advances the cursor to the next sorted
** record, or jumps to P2 if there are no more sorted records.
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
- int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
- res = 0;
- rc = sqlite3VdbeSorterNext(db, pC, &res);
+ rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
case OP_PrevIfOpen: /* jump */
case OP_NextIfOpen: /* jump */
if( p->apCsr[pOp->p1]==0 ) break;
/* Fall through */
@@ -5108,16 +5124,13 @@
case OP_Prev: /* jump */
case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1nCursor );
assert( pOp->p5aCounter) );
pC = p->apCsr[pOp->p1];
- res = pOp->p3;
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
- assert( res==0 || (res==1 && pC->isTable==0) );
- testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
@@ -5128,25 +5141,25 @@
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last );
- rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
+ rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
next_tail:
pC->cacheStatus = CACHE_STALE;
- VdbeBranchTaken(res==0,2);
- if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ VdbeBranchTaken(rc==SQLITE_OK,2);
+ if( rc==SQLITE_OK ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
goto jump_to_p2_and_check_for_interrupt;
- }else{
- pC->nullRow = 1;
}
+ if( rc!=SQLITE_DONE ) goto abort_due_to_error;
+ rc = SQLITE_OK;
+ pC->nullRow = 1;
goto check_for_interrupt;
}
/* Opcode: IdxInsert P1 P2 P3 P4 P5
** Synopsis: key=r[P2]
@@ -5253,12 +5266,12 @@
pC->cacheStatus = CACHE_STALE;
pC->seekResult = 0;
break;
}
-/* Opcode: Seek P1 * P3 P4 *
-** Synopsis: Move P3 to P1.rowid
+/* Opcode: DeferredSeek P1 * P3 P4 *
+** Synopsis: Move P3 to P1.rowid if needed
**
** P1 is an open index cursor and P3 is a cursor on the corresponding
** table. This opcode does a deferred seek of the P3 table cursor
** to the row that corresponds to the current row of P1.
**
@@ -5281,15 +5294,15 @@
** the end of the index key pointed to by cursor P1. This integer should be
** the rowid of the table entry to which this index entry points.
**
** See also: Rowid, MakeRecord.
*/
-case OP_Seek:
-case OP_IdxRowid: { /* out2 */
- VdbeCursor *pC; /* The P1 index cursor */
- VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
- i64 rowid; /* Rowid that P1 current points to */
+case OP_DeferredSeek:
+case OP_IdxRowid: { /* out2 */
+ VdbeCursor *pC; /* The P1 index cursor */
+ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
+ i64 rowid; /* Rowid that P1 current points to */
assert( pOp->p1>=0 && pOp->p1nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
@@ -5311,11 +5324,11 @@
rowid = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( pOp->opcode==OP_Seek ){
+ if( pOp->opcode==OP_DeferredSeek ){
assert( pOp->p3>=0 && pOp->p3nCursor );
pTabCur = p->apCsr[pOp->p3];
assert( pTabCur!=0 );
assert( pTabCur->eCurType==CURTYPE_BTREE );
assert( pTabCur->uc.pCursor!=0 );
Index: src/vdbe.h
==================================================================
--- src/vdbe.h
+++ src/vdbe.h
@@ -61,11 +61,11 @@
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
- int (*xAdvance)(BtCursor *, int *);
+ int (*xAdvance)(BtCursor *, int);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
Index: src/vdbeInt.h
==================================================================
--- src/vdbeInt.h
+++ src/vdbeInt.h
@@ -504,11 +504,11 @@
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
-int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
+int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#if !defined(SQLITE_OMIT_SHARED_CACHE)
Index: src/vdbeapi.c
==================================================================
--- src/vdbeapi.c
+++ src/vdbeapi.c
@@ -1317,12 +1317,14 @@
pVar = &p->aVar[i-1];
rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel);
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
- sqlite3Error(p->db, rc);
- rc = sqlite3ApiExit(p->db, rc);
+ if( rc ){
+ sqlite3Error(p->db, rc);
+ rc = sqlite3ApiExit(p->db, rc);
+ }
}
sqlite3_mutex_leave(p->db->mutex);
}else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
xDel((void*)zData);
}
@@ -1652,12 +1654,23 @@
if( !pStmt ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- v = pVdbe->aCounter[op];
- if( resetFlag ) pVdbe->aCounter[op] = 0;
+ if( op==SQLITE_STMTSTATUS_MEMUSED ){
+ sqlite3 *db = pVdbe->db;
+ sqlite3_mutex_enter(db->mutex);
+ v = 0;
+ db->pnBytesFreed = (int*)&v;
+ sqlite3VdbeClearObject(db, pVdbe);
+ sqlite3DbFree(db, pVdbe);
+ db->pnBytesFreed = 0;
+ sqlite3_mutex_leave(db->mutex);
+ }else{
+ v = pVdbe->aCounter[op];
+ if( resetFlag ) pVdbe->aCounter[op] = 0;
+ }
return (int)v;
}
/*
** Return the SQL associated with a prepared statement
Index: src/vdbeaux.c
==================================================================
--- src/vdbeaux.c
+++ src/vdbeaux.c
@@ -2158,21 +2158,22 @@
** statement. This is now set at compile time, rather than during
** execution of the vdbe program so that sqlite3_column_count() can
** be called on an SQL statement before sqlite3_step().
*/
void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
- Mem *pColName;
int n;
sqlite3 *db = p->db;
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlite3DbFree(db, p->aColName);
+ if( p->nResColumn ){
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ sqlite3DbFree(db, p->aColName);
+ }
n = nResColumn*COLNAME_N;
p->nResColumn = (u16)nResColumn;
- p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
+ p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
- initMemArray(p->aColName, n, p->db, MEM_Null);
+ initMemArray(p->aColName, n, db, MEM_Null);
}
/*
** Set the name of the idx'th column to be returned by the SQL statement.
** zName must be a pointer to a nul terminated string.
@@ -2818,14 +2819,14 @@
sqlite3BeginBenignMalloc();
if( db->pErr==0 ) db->pErr = sqlite3ValueNew(db);
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->bBenignMalloc--;
- db->errCode = rc;
- }else{
- sqlite3Error(db, rc);
+ }else if( db->pErr ){
+ sqlite3ValueSetNull(db->pErr);
}
+ db->errCode = rc;
return rc;
}
#ifdef SQLITE_ENABLE_SQLLOG
/*
@@ -3729,23 +3730,24 @@
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
int rc;
const void *v1, *v2;
- int n1, n2;
Mem c1;
Mem c2;
sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null);
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
- n1 = v1==0 ? 0 : c1.n;
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
- n2 = v2==0 ? 0 : c2.n;
- rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ if( (v1==0 || v2==0) ){
+ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ rc = 0;
+ }else{
+ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
+ }
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
return rc;
}
}
Index: src/vdbemem.c
==================================================================
--- src/vdbemem.c
+++ src/vdbemem.c
@@ -1323,11 +1323,11 @@
if( enc!=SQLITE_UTF8 ){
rc = sqlite3VdbeChangeEncoding(pVal, enc);
}
}else if( op==TK_UMINUS ) {
/* This branch happens for multiple negative signs. Ex: -(-5) */
- if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal)
+ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx)
&& pVal!=0
){
sqlite3VdbeMemNumerify(pVal);
if( pVal->flags & MEM_Real ){
pVal->u.r = -pVal->u.r;
Index: src/vdbesort.c
==================================================================
--- src/vdbesort.c
+++ src/vdbesort.c
@@ -813,13 +813,13 @@
int n1;
int n2;
int res;
- getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
- getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
- res = memcmp(v1, v2, MIN(n1, n2));
+ getVarint32(&p1[1], n1);
+ getVarint32(&p2[1], n2);
+ res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
if( res==0 ){
res = n1 - n2;
}
if( res==0 ){
@@ -2610,13 +2610,17 @@
vdbeSorterRewindDebug("rewinddone");
return rc;
}
/*
-** Advance to the next element in the sorter.
+** Advance to the next element in the sorter. Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE end of data
+** otherwise some kind of error.
*/
-int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
+int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
VdbeSorter *pSorter;
int rc; /* Return code */
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
@@ -2626,25 +2630,26 @@
assert( pSorter->bUseThreads==0 || pSorter->pReader );
assert( pSorter->bUseThreads==1 || pSorter->pMerger );
#if SQLITE_MAX_WORKER_THREADS>0
if( pSorter->bUseThreads ){
rc = vdbePmaReaderNext(pSorter->pReader);
- *pbEof = (pSorter->pReader->pFd==0);
+ if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
}else
#endif
/*if( !pSorter->bUseThreads )*/ {
+ int res = 0;
assert( pSorter->pMerger!=0 );
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
- rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
+ rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
+ if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
}
}else{
SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext;
pFree->u.pNext = 0;
if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
- *pbEof = !pSorter->list.pList;
- rc = SQLITE_OK;
+ rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
}
return rc;
}
/*
Index: src/walker.c
==================================================================
--- src/walker.c
+++ src/walker.c
@@ -122,40 +122,33 @@
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
** on the compound select chain, p->pPrior.
**
** If it is not NULL, the xSelectCallback() callback is invoked before
** the walk of the expressions and FROM clause. The xSelectCallback2()
-** method, if it is not NULL, is invoked following the walk of the
-** expressions and FROM clause.
+** method is invoked following the walk of the expressions and FROM clause,
+** but only if both xSelectCallback and xSelectCallback2 are both non-NULL
+** and if the expressions and FROM clause both return WRC_Continue;
**
** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request.
**
** If the Walker does not have an xSelectCallback() then this routine
** is a no-op returning WRC_Continue.
*/
int sqlite3WalkSelect(Walker *pWalker, Select *p){
int rc;
- if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
- return WRC_Continue;
- }
- rc = WRC_Continue;
- pWalker->walkerDepth++;
- while( p ){
- if( pWalker->xSelectCallback ){
- rc = pWalker->xSelectCallback(pWalker, p);
- if( rc ) break;
- }
+ if( p==0 || pWalker->xSelectCallback==0 ) return WRC_Continue;
+ do{
+ rc = pWalker->xSelectCallback(pWalker, p);
+ if( rc ) return rc & WRC_Abort;
if( sqlite3WalkSelectExpr(pWalker, p)
|| sqlite3WalkSelectFrom(pWalker, p)
){
- pWalker->walkerDepth--;
return WRC_Abort;
}
if( pWalker->xSelectCallback2 ){
pWalker->xSelectCallback2(pWalker, p);
}
p = p->pPrior;
- }
- pWalker->walkerDepth--;
- return rc & WRC_Abort;
+ }while( p!=0 );
+ return WRC_Continue;
}
Index: src/where.c
==================================================================
--- src/where.c
+++ src/where.c
@@ -1190,11 +1190,11 @@
iGap = (iGap*2)/3;
}else{
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
- aStat[1] = pIdx->aAvgEq[iCol];
+ aStat[1] = pIdx->aAvgEq[nField-1];
}
/* Restore the pRec->nField value before returning. */
pRec->nField = nField;
return i;
@@ -1943,20 +1943,21 @@
}
}
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
-** supplanted by pTemplate.
+** replaced by pTemplate.
**
-** Return NULL if the WhereLoop list contains an entry that can supplant
-** pTemplate, in other words if pTemplate does not belong on the list.
+** Return NULL if pTemplate does not belong on the WhereLoop list.
+** In other words if pTemplate ought to be dropped from further consideration.
**
-** If pX is a WhereLoop that pTemplate can supplant, then return the
+** If pX is a WhereLoop that pTemplate can replace, then return the
** link that points to pX.
**
-** If pTemplate cannot supplant any existing element of the list but needs
-** to be added to the list, then return a pointer to the tail of the list.
+** If pTemplate cannot replace any existing element of the list but needs
+** to be added to the list as a new entry, then return a pointer to the
+** tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
const WhereLoop *pTemplate
){
@@ -2097,12 +2098,14 @@
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
sqlite3DebugPrintf("replace: ");
whereLoopPrint(p, pBuilder->pWC);
+ sqlite3DebugPrintf(" with: ");
+ }else{
+ sqlite3DebugPrintf(" add: ");
}
- sqlite3DebugPrintf(" add: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
if( p==0 ){
/* Allocate a new WhereLoop to add to the end of the list */
@@ -3998,12 +4001,12 @@
/* The current candidate is no better than any of the mxChoice
** paths currently in the best-so-far buffer. So discard
** this candidate as not viable. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
}
@@ -4017,30 +4020,40 @@
jj = mxI;
}
pTo = &aTo[jj];
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
/* Control reaches here if best-so-far path pTo=aTo[jj] covers the
- ** same set of loops and has the sam isOrdered setting as the
+ ** same set of loops and has the same isOrdered setting as the
** candidate path. Check to see if the candidate should replace
- ** pTo or if the candidate should be skipped */
- if( pTo->rCostrCost==rCost && pTo->nRow<=nOut) ){
+ ** pTo or if the candidate should be skipped.
+ **
+ ** The conditional is an expanded vector comparison equivalent to:
+ ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
+ */
+ if( pTo->rCostrCost==rCost
+ && (pTo->nRownRow==nOut && pTo->rUnsorted<=rUnsorted)
+ )
+ )
+ ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Skip %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Skip %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
+ sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
testcase( pTo->rCost==rCost );
continue;
@@ -4049,16 +4062,16 @@
/* Control reaches here if the candidate path is better than the
** pTo path. Replace pTo with the candidate. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Update %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Update %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
+ sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
/* pWLoop is a winner. Add it to the set of best so far */
pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf;
@@ -4278,10 +4291,35 @@
#endif
return 1;
}
return 0;
}
+
+/*
+** Helper function for exprIsDeterministic().
+*/
+static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return true if the expression contains no non-deterministic SQL
+** functions. Do not consider non-deterministic SQL functions that are
+** part of sub-select statements.
+*/
+static int exprIsDeterministic(Expr *p){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.eCode = 1;
+ w.xExprCallback = exprNodeIsDeterministic;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
@@ -4477,21 +4515,10 @@
*/
initMaskSet(pMaskSet);
sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
- /* Special case: a WHERE clause that is constant. Evaluate the
- ** expression and either jump over all of the code or fall thru.
- */
- for(ii=0; iinTerm; ii++){
- if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){
- sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak,
- SQLITE_JUMPIFNULL);
- sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
- }
- }
-
/* Special case: No FROM clause
*/
if( nTabList==0 ){
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
@@ -4525,10 +4552,29 @@
#endif
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
if( db->mallocFailed ) goto whereBeginError;
+
+ /* Special case: WHERE terms that do not refer to any tables in the join
+ ** (constant expressions). Evaluate each such term, and jump over all the
+ ** generated code if the result is not true.
+ **
+ ** Do not do this if the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not strictly required, but
+ ** preserves SQLite's legacy behaviour in the following two cases:
+ **
+ ** FROM ... WHERE random()>0; -- eval random() once per row
+ ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ */
+ for(ii=0; iinTerm; ii++){
+ WhereTerm *pT = &sWLB.pWC->a[ii];
+ if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
+ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pT->wtFlags |= TERM_CODED;
+ }
+ }
if( wctrlFlags & WHERE_WANT_DISTINCT ){
if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
@@ -4562,11 +4608,11 @@
WhereLoop *p;
int i;
static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
"ABCDEFGHIJKLMNOPQRSTUVWYXZ";
for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
- p->cId = zLabel[i%sizeof(zLabel)];
+ p->cId = zLabel[i%(sizeof(zLabel)-1)];
whereLoopPrint(p, sWLB.pWC);
}
}
#endif
Index: src/wherecode.c
==================================================================
--- src/wherecode.c
+++ src/wherecode.c
@@ -964,14 +964,14 @@
** function generates code to do a deferred seek of cursor iCur to the
** rowid stored in register iRowid.
**
** Normally, this is just:
**
-** OP_Seek $iCur $iRowid
+** OP_DeferredSeek $iCur $iRowid
**
** However, if the scan currently being coded is a branch of an OR-loop and
-** the statement currently being coded is a SELECT, then P3 of the OP_Seek
+** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
** is set to iIdxCur and P4 is set to point to an array of integers
** containing one entry for each column of the table cursor iCur is open
** on. For each table column, if the column is the i'th column of the
** index, then the corresponding array entry is set to (i+1). If the column
** does not appear in the index at all, the array entry is set to 0.
@@ -986,11 +986,11 @@
Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
- sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
+ sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
Table *pTab = pIdx->pTable;
Index: test/ctime.test
==================================================================
--- test/ctime.test
+++ test/ctime.test
@@ -58,10 +58,28 @@
set ans [ catchsql {
PRAGMA compile_options;
} ]
list [ lindex $ans 0 ] [ expr { [lsort [lindex $ans 1]]==[lindex $ans 1] } ]
} {0 1}
+
+# Check the THREADSAFE option for SQLITE_THREADSAFE=2 builds (there are
+# a couple of these configurations in releasetest.tcl).
+#
+ifcapable threadsafe2 {
+ foreach {tn opt res} {
+ 1 SQLITE_THREADSAFE 1
+ 2 THREADSAFE 1
+ 3 THREADSAFE=0 0
+ 4 THREADSAFE=1 0
+ 5 THREADSAFE=2 1
+ 6 THREADSAFE= 0
+ } {
+ do_execsql_test ctime-1.3.$tn {
+ SELECT sqlite_compileoption_used($opt)
+ } $res
+ }
+}
# SQLITE_THREADSAFE should pretty much always be defined
# one way or the other, and it must have a value of 0 or 1.
do_test ctime-1.4.1 {
catchsql {
Index: test/eqp.test
==================================================================
--- test/eqp.test
+++ test/eqp.test
@@ -186,28 +186,28 @@
1 0 0 {SCAN TABLE t1 AS sub}
}
do_eqp_test 3.1.2 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
+ 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.3 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
+ 0 0 0 {SCAN TABLE t1}
}
do_eqp_test 3.1.4 {
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
} {
- 0 0 0 {SCAN TABLE t1}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1}
+ 0 0 0 {SCAN TABLE t1}
}
det 3.2.1 {
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
} {
Index: test/fts4unicode.test
==================================================================
--- test/fts4unicode.test
+++ test/fts4unicode.test
@@ -382,11 +382,13 @@
do_isspace_test 6.$T.11 $T 8198
do_isspace_test 6.$T.12 $T 8199
do_isspace_test 6.$T.13 $T 8200
do_isspace_test 6.$T.14 $T 8201
do_isspace_test 6.$T.15 $T 8202
- do_isspace_test 6.$T.16 $T 8239
+ if {$T!="icu"} {
+ do_isspace_test 6.$T.16 $T 8239
+ }
do_isspace_test 6.$T.17 $T 8287
do_isspace_test 6.$T.18 $T 12288
if {$T!="icu"} {
do_isspace_test 6.$T.19 $T {32 160 5760 6158}
Index: test/join.test
==================================================================
--- test/join.test
+++ test/join.test
@@ -760,7 +760,24 @@
SELECT *, '|' FROM t3 LEFT JOIN v2 ON a=x WHERE b+1=x;
} {2 2 1 |}
do_execsql_test join-14.12 {
SELECT *, '|' FROM t3 LEFT JOIN v2 ON a=x ORDER BY b;
} {4 {} {} | 2 2 1 |}
+
+# Verify the fix for ticket
+# https://www.sqlite.org/src/info/892fc34f173e99d8
+#
+db close
+sqlite3 db :memory:
+do_execsql_test join-14.20 {
+ CREATE TABLE t1(id INTEGER PRIMARY KEY);
+ CREATE TABLE t2(id INTEGER PRIMARY KEY, c2 INTEGER);
+ CREATE TABLE t3(id INTEGER PRIMARY KEY, c3 INTEGER);
+ INSERT INTO t1(id) VALUES(456);
+ INSERT INTO t3(id) VALUES(1),(2);
+ SELECT t1.id, x2.id, x3.id
+ FROM t1
+ LEFT JOIN (SELECT * FROM t2) AS x2 ON t1.id=x2.c2
+ LEFT JOIN t3 AS x3 ON x2.id=x3.c3;
+} {456 {} {}}
finish_test
Index: test/kvtest.c
==================================================================
--- test/kvtest.c
+++ test/kvtest.c
@@ -69,18 +69,25 @@
" BLOBs each of size M bytes. The page size of the new database\n"
" file will be X. Additional options:\n"
"\n"
" --variance V Randomly vary M by plus or minus V\n"
"\n"
-" kvtest export DBFILE DIRECTORY\n"
+" kvtest export DBFILE DIRECTORY [--tree]\n"
"\n"
" Export all the blobs in the kv table of DBFILE into separate\n"
-" files in DIRECTORY.\n"
+" files in DIRECTORY. DIRECTORY is created if it does not previously\n"
+" exist. If the --tree option is used, then the blobs are written\n"
+" into a hierarchy of directories, using names like 00/00/00,\n"
+" 00/00/01, 00/00/02, and so forth. Without the --tree option, all\n"
+" files are in the top-level directory with names like 000000, 000001,\n"
+" 000002, and so forth.\n"
+"\n"
+" kvtest stat DBFILE [options]\n"
"\n"
-" kvtest stat DBFILE\n"
+" Display summary information about DBFILE. Options:\n"
"\n"
-" Display summary information about DBFILE\n"
+" --vacuum Run VACUUM on the database file\n"
"\n"
" kvtest run DBFILE [options]\n"
"\n"
" Run a performance test. DBFILE can be either the name of a\n"
" database or a directory containing sample files. Options:\n"
@@ -88,16 +95,22 @@
" --asc Read blobs in ascending order\n"
" --blob-api Use the BLOB API\n"
" --cache-size N Database cache size\n"
" --count N Read N blobs\n"
" --desc Read blobs in descending order\n"
+" --fsync Synchronous file writes\n"
+" --integrity-check Run \"PRAGMA integrity_check\" after test\n"
" --max-id N Maximum blob key to use\n"
" --mmap N Mmap as much as N bytes of DBFILE\n"
+" --multitrans Each read or write in its own transaction\n"
+" --nocheckpoint Omit the checkpoint on WAL mode writes\n"
+" --nosync Set \"PRAGMA synchronous=OFF\"\n"
" --jmode MODE Set MODE journal mode prior to starting\n"
" --random Read blobs in a random order\n"
" --start N Start reading with this blob key\n"
" --stats Output operating stats before exiting\n"
+" --update Do an overwrite test\n"
;
/* Reference resources used */
#include
#include
@@ -109,17 +122,43 @@
#ifndef _WIN32
# include
#else
/* Provide Windows equivalent for the needed parts of unistd.h */
+# include
# include
# define R_OK 2
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# define access _access
#endif
+#include
+
+/*
+** The following macros are used to cast pointers to integers and
+** integers to pointers. The way you do this varies from one compiler
+** to the next, so we have developed the following set of #if statements
+** to generate appropriate macros for a wide range of compilers.
+**
+** The correct "ANSI" way to do this is to use the intptr_t type.
+** Unfortunately, that typedef is not available on all compilers, or
+** if it is available, it requires an #include of specific headers
+** that vary from one machine to the next.
+**
+** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
+** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
+** So we have to define the macros in different ways depending on the
+** compiler.
+*/
+#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
+# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
+# define SQLITE_PTR_TO_INT(X) ((sqlite3_int64)(__PTRDIFF_TYPE__)(X))
+#else
+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
+# define SQLITE_PTR_TO_INT(X) ((sqlite3_int64)(intptr_t)(X))
+#endif
/*
** Show thqe help text and quit.
*/
static void showHelp(void){
@@ -199,27 +238,45 @@
/*
** Check the filesystem object zPath. Determine what it is:
**
-** PATH_DIR A directory
+** PATH_DIR A single directory holding many files
+** PATH_TREE A directory hierarchy with files at the leaves
** PATH_DB An SQLite database
** PATH_NEXIST Does not exist
** PATH_OTHER Something else
+**
+** PATH_DIR means all of the separate files are grouped together
+** into a single directory with names like 000000, 000001, 000002, and
+** so forth. PATH_TREE means there is a hierarchy of directories so
+** that no single directory has too many entries. The files have names
+** like 00/00/00, 00/00/01, 00/00/02 and so forth. The decision between
+** PATH_DIR and PATH_TREE is determined by the presence of a subdirectory
+** named "00" at the top-level.
*/
#define PATH_DIR 1
-#define PATH_DB 2
+#define PATH_TREE 2
+#define PATH_DB 3
#define PATH_NEXIST 0
#define PATH_OTHER 99
static int pathType(const char *zPath){
struct stat x;
int rc;
if( access(zPath,R_OK) ) return PATH_NEXIST;
memset(&x, 0, sizeof(x));
rc = stat(zPath, &x);
if( rc<0 ) return PATH_OTHER;
- if( S_ISDIR(x.st_mode) ) return PATH_DIR;
+ if( S_ISDIR(x.st_mode) ){
+ char *zLayer1 = sqlite3_mprintf("%s/00", zPath);
+ memset(&x, 0, sizeof(x));
+ rc = stat(zLayer1, &x);
+ sqlite3_free(zLayer1);
+ if( rc<0 ) return PATH_DIR;
+ if( S_ISDIR(x.st_mode) ) return PATH_TREE;
+ return PATH_DIR;
+ }
if( (x.st_size%512)==0 ) return PATH_DB;
return PATH_OTHER;
}
/*
@@ -326,24 +383,34 @@
char *zDb;
int i, rc;
sqlite3 *db;
char *zSql;
sqlite3_stmt *pStmt;
+ int doVacuum = 0;
assert( strcmp(argv[1],"stat")==0 );
assert( argc>=3 );
zDb = argv[2];
for(i=3; i=3 );
+ if( argc<4 ) fatalError("Usage: kvtest export DATABASE DIRECTORY [OPTIONS]");
zDb = argv[2];
- if( argc!=4 ) fatalError("Usage: kvtest export DATABASE DIRECTORY");
zDir = argv[3];
- if( pathType(zDir)!=PATH_DIR ){
+ kvtest_mkdir(zDir);
+ for(i=4; i=3 );
@@ -658,15 +835,45 @@
if( eType==PATH_NEXIST ) fatalError("object does not exist: \"%s\"", zDb);
for(i=3; iiMax ) iKey = 1;
@@ -833,17 +1076,37 @@
if( pStmt ) sqlite3_finalize(pStmt);
if( pBlob ) sqlite3_blob_close(pBlob);
if( bStats ){
display_stats(db, 0);
}
- if( db ) sqlite3_close(db);
+ if( db ){
+ if( !doMultiTrans ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
+ if( !noCheckpoint ){
+ sqlite3_close(db);
+ db = 0;
+ }
+ }
tmElapsed = timeOfDay() - tmStart;
+ if( db && noCheckpoint ){
+ sqlite3_close(db);
+ db = 0;
+ }
if( nExtra ){
printf("%d cycles due to %d misses\n", nCount, nExtra);
}
if( eType==PATH_DB ){
printf("SQLite version: %s\n", sqlite3_libversion());
+ if( doIntegrityCk ){
+ sqlite3_open(zDb, &db);
+ sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &pStmt, 0);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ printf("integrity-check: %s\n", sqlite3_column_text(pStmt, 0));
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_close(db);
+ db = 0;
+ }
}
printf("--count %d --max-id %d", nCount-nExtra, iMax);
switch( eOrder ){
case ORDER_RANDOM: printf(" --random\n"); break;
case ORDER_DESC: printf(" --desc\n"); break;
@@ -850,15 +1113,21 @@
default: printf(" --asc\n"); break;
}
if( eType==PATH_DB ){
printf("--cache-size %d --jmode %s\n", iCache, zJMode);
printf("--mmap %d%s\n", mmapSize, bBlobApi ? " --blob-api" : "");
+ if( noSync ) printf("--nosync\n");
}
if( iPagesize ) printf("Database page size: %d\n", iPagesize);
printf("Total elapsed time: %.3f\n", tmElapsed/1000.0);
- printf("Microseconds per BLOB read: %.3f\n", tmElapsed*1000.0/nCount);
- printf("Content read rate: %.1f MB/s\n", nTotal/(1000.0*tmElapsed));
+ if( isUpdateTest ){
+ printf("Microseconds per BLOB write: %.3f\n", tmElapsed*1000.0/nCount);
+ printf("Content write rate: %.1f MB/s\n", nTotal/(1000.0*tmElapsed));
+ }else{
+ printf("Microseconds per BLOB read: %.3f\n", tmElapsed*1000.0/nCount);
+ printf("Content read rate: %.1f MB/s\n", nTotal/(1000.0*tmElapsed));
+ }
return 0;
}
int main(int argc, char **argv){
Index: test/releasetest.tcl
==================================================================
--- test/releasetest.tcl
+++ test/releasetest.tcl
@@ -177,11 +177,11 @@
"Locking-Style" {
-O2
-DSQLITE_ENABLE_LOCKING_STYLE=1
}
"Apple" {
- -O1 # Avoid a compiler bug in gcc 4.2.1 build 5658
+ -Os
-DHAVE_GMTIME_R=1
-DHAVE_ISNAN=1
-DHAVE_LOCALTIME_R=1
-DHAVE_PREAD=1
-DHAVE_PWRITE=1
Index: test/vtabH.test
==================================================================
--- test/vtabH.test
+++ test/vtabH.test
@@ -214,28 +214,32 @@
close $fd
}
} {}
set pwd [pwd]
- do_execsql_test 3.5 {
- SELECT path, size FROM fstree WHERE path GLOB $pwd || '/subdir/*' ORDER BY 1
- } [list \
- "$pwd/subdir/x1.txt" 143 \
- "$pwd/subdir/x2.txt" 153 \
- ]
- do_execsql_test 3.6 {
- SELECT path, size FROM fstree WHERE path LIKE $pwd || '/subdir/%' ORDER BY 1
- } [list \
- "$pwd/subdir/x1.txt" 143 \
- "$pwd/subdir/x2.txt" 153 \
- ]
- do_execsql_test 3.7 {
- SELECT sum(size) FROM fstree WHERE path LIKE $pwd || '/subdir/%'
- } 296
- do_execsql_test 3.8 {
- SELECT size FROM fstree WHERE path = $pwd || '/subdir/x1.txt'
- } 143
+ if {![string match {*[_%]*} $pwd]} {
+ do_execsql_test 3.5 {
+ SELECT path, size FROM fstree
+ WHERE path GLOB $pwd || '/subdir/*' ORDER BY 1
+ } [list \
+ "$pwd/subdir/x1.txt" 143 \
+ "$pwd/subdir/x2.txt" 153 \
+ ]
+ do_execsql_test 3.6 {
+ SELECT path, size FROM fstree
+ WHERE path LIKE $pwd || '/subdir/%' ORDER BY 1
+ } [list \
+ "$pwd/subdir/x1.txt" 143 \
+ "$pwd/subdir/x2.txt" 153 \
+ ]
+ do_execsql_test 3.7 {
+ SELECT sum(size) FROM fstree WHERE path LIKE $pwd || '/subdir/%'
+ } 296
+ do_execsql_test 3.8 {
+ SELECT size FROM fstree WHERE path = $pwd || '/subdir/x1.txt'
+ } 143
+ }
}
finish_test
Index: test/whereF.test
==================================================================
--- test/whereF.test
+++ test/whereF.test
@@ -116,7 +116,64 @@
CREATE TABLE t4(a,b,c,d,e, PRIMARY KEY(a,b,c));
CREATE INDEX t4adc ON t4(a,d,c);
CREATE UNIQUE INDEX t4aebc ON t4(a,e,b,c);
EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?;
} {/a=. AND b=./}
+
+#-------------------------------------------------------------------------
+# Test the following case:
+#
+# ... FROM t1, t2 WHERE (
+# t2.rowid = +t1.rowid OR (t2.f2 = t1.f1 AND t1.f1!=-1)
+# )
+#
+# where there is an index on t2(f2). The planner should use "t1" as the
+# outer loop. The inner loop, on "t2", is an OR optimization. One pass
+# for:
+#
+# t2.rowid = $1
+#
+# and another for:
+#
+# t2.f2=$1 AND $1!=-1
+#
+# the test is to ensure that on the second pass, the ($1!=-1) condition
+# is tested before any seek operations are performed - i.e. outside of
+# the loop through the f2=$1 range of the t2(f2) index.
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE TABLE t1(f1);
+ CREATE TABLE t2(f2);
+ CREATE INDEX t2f ON t2(f2);
+
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+ INSERT INTO t1 VALUES(-1);
+
+ WITH w(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM w WHERE i<1000
+ )
+ INSERT INTO t2 SELECT -1 FROM w;
+}
+
+do_execsql_test 5.1 {
+ SELECT count(*) FROM t1, t2 WHERE t2.rowid = +t1.rowid
+} {4}
+do_test 5.2 { expr [db status vmstep]<200 } 1
+
+do_execsql_test 5.3 {
+ SELECT count(*) FROM t1, t2 WHERE (
+ t2.rowid = +t1.rowid OR t2.f2 = t1.f1
+ )
+} {4000}
+do_test 5.4 { expr [db status vmstep]>1000 } 1
+
+do_execsql_test 5.5 {
+ SELECT count(*) FROM t1, t2 WHERE (
+ t2.rowid = +t1.rowid OR (t2.f2 = t1.f1 AND t1.f1!=-1)
+ )
+} {4}
+do_test 5.6 { expr [db status vmstep]<200 } 1
finish_test
Index: test/with1.test
==================================================================
--- test/with1.test
+++ test/with1.test
@@ -987,8 +987,22 @@
UNION SELECT round(1<1+x)
FROM xyz ORDER BY 1
)
SELECT 1 FROM xyz;
} 1
+
+# EXPLAIN QUERY PLAN on a self-join of a CTE
+#
+do_execsql_test 19.1 {
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1(x);
+ EXPLAIN QUERY PLAN
+ WITH
+ x1(a) AS (values(100))
+ INSERT INTO t1(x)
+ SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2);
+ SELECT * FROM t1;
+} {0 0 0 {SCAN SUBQUERY 1} 0 1 1 {SCAN SUBQUERY 1}}
+
finish_test
Index: tool/mkautoconfamal.sh
==================================================================
--- tool/mkautoconfamal.sh
+++ tool/mkautoconfamal.sh
@@ -49,11 +49,10 @@
cp sqlite3.c $TMPSPACE
cp sqlite3.h $TMPSPACE
cp sqlite3ext.h $TMPSPACE
cp $TOP/sqlite3.1 $TMPSPACE
cp $TOP/sqlite3.pc.in $TMPSPACE
-cp $TOP/src/msvc.h $TMPSPACE
cp $TOP/src/shell.c $TMPSPACE
cp $TOP/src/sqlite3.rc $TMPSPACE
cp $TOP/tool/Replace.cs $TMPSPACE
cat $TMPSPACE/configure.ac |
ADDED tool/mkctimec.tcl
Index: tool/mkctimec.tcl
==================================================================
--- /dev/null
+++ tool/mkctimec.tcl
@@ -0,0 +1,311 @@
+#!/usr/bin/tclsh
+#
+# To build the
+#
+# const char **azCompileOpt[]
+#
+# declaration used in src/ctime.c, run this script.
+#
+
+# All Boolean compile time options.
+#
+set boolean_options {
+ SQLITE_32BIT_ROWID
+ SQLITE_4_BYTE_ALIGNED_MALLOC
+ SQLITE_64BIT_STATS
+ SQLITE_ALLOW_COVERING_INDEX_SCAN
+ SQLITE_ALLOW_URI_AUTHORITY
+ SQLITE_BUG_COMPATIBLE_20160819
+ SQLITE_CASE_SENSITIVE_LIKE
+ SQLITE_CHECK_PAGES
+ SQLITE_COVERAGE_TEST
+ SQLITE_DEBUG
+ SQLITE_DEFAULT_AUTOMATIC_INDEX
+ SQLITE_DEFAULT_AUTOVACUUM
+ SQLITE_DEFAULT_CKPTFULLFSYNC
+ SQLITE_DEFAULT_FOREIGN_KEYS
+ SQLITE_DEFAULT_LOCKING_MODE
+ SQLITE_DEFAULT_MEMSTATUS
+ SQLITE_DEFAULT_RECURSIVE_TRIGGERS
+ SQLITE_DEFAULT_SYNCHRONOUS
+ SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ SQLITE_DIRECT_OVERFLOW_READ
+ SQLITE_DISABLE_DIRSYNC
+ SQLITE_DISABLE_FTS3_UNICODE
+ SQLITE_DISABLE_FTS4_DEFERRED
+ SQLITE_DISABLE_INTRINSIC
+ SQLITE_DISABLE_LFS
+ SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+ SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ SQLITE_ENABLE_8_3_NAMES
+ SQLITE_ENABLE_API_ARMOR
+ SQLITE_ENABLE_ATOMIC_WRITE
+ SQLITE_ENABLE_CEROD
+ SQLITE_ENABLE_COLUMN_METADATA
+ SQLITE_ENABLE_COLUMN_USED_MASK
+ SQLITE_ENABLE_COSTMULT
+ SQLITE_ENABLE_CURSOR_HINTS
+ SQLITE_ENABLE_DBSTAT_VTAB
+ SQLITE_ENABLE_EXPENSIVE_ASSERT
+ SQLITE_ENABLE_FTS1
+ SQLITE_ENABLE_FTS2
+ SQLITE_ENABLE_FTS3
+ SQLITE_ENABLE_FTS3_PARENTHESIS
+ SQLITE_ENABLE_FTS3_TOKENIZER
+ SQLITE_ENABLE_FTS4
+ SQLITE_ENABLE_FTS5
+ SQLITE_ENABLE_HIDDEN_COLUMNS
+ SQLITE_ENABLE_ICU
+ SQLITE_ENABLE_IOTRACE
+ SQLITE_ENABLE_JSON1
+ SQLITE_ENABLE_LOAD_EXTENSION
+ SQLITE_ENABLE_LOCKING_STYLE
+ SQLITE_ENABLE_MEMORY_MANAGEMENT
+ SQLITE_ENABLE_MEMSYS3
+ SQLITE_ENABLE_MEMSYS5
+ SQLITE_ENABLE_MULTIPLEX
+ SQLITE_ENABLE_NULL_TRIM
+ SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+ SQLITE_ENABLE_PREUPDATE_HOOK
+ SQLITE_ENABLE_RBU
+ SQLITE_ENABLE_RTREE
+ SQLITE_ENABLE_SELECTTRACE
+ SQLITE_ENABLE_SESSION
+ SQLITE_ENABLE_SNAPSHOT
+ SQLITE_ENABLE_SQLLOG
+ SQLITE_ENABLE_STMT_SCANSTATUS
+ SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ SQLITE_ENABLE_UNLOCK_NOTIFY
+ SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ SQLITE_ENABLE_URI_00_ERROR
+ SQLITE_ENABLE_VFSTRACE
+ SQLITE_ENABLE_WHERETRACE
+ SQLITE_ENABLE_ZIPVFS
+ SQLITE_EXPLAIN_ESTIMATED_ROWS
+ SQLITE_EXTRA_IFNULLROW
+ SQLITE_FTS5_ENABLE_TEST_MI
+ SQLITE_FTS5_NO_WITHOUT_ROWID
+ SQLITE_HAS_CODEC
+ SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ SQLITE_IGNORE_AFP_LOCK_ERRORS
+ SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+ SQLITE_INLINE_MEMCPY
+ SQLITE_INT64_TYPE
+ SQLITE_LIKE_DOESNT_MATCH_BLOBS
+ SQLITE_LOCK_TRACE
+ SQLITE_LOG_CACHE_SPILL
+ SQLITE_MEMDEBUG
+ SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+ SQLITE_MMAP_READWRITE
+ SQLITE_MUTEX_NOOP
+ SQLITE_MUTEX_NREF
+ SQLITE_MUTEX_OMIT
+ SQLITE_MUTEX_PTHREADS
+ SQLITE_MUTEX_W32
+ SQLITE_NEED_ERR_NAME
+ SQLITE_NOINLINE
+ SQLITE_NO_SYNC
+ SQLITE_OMIT_ALTERTABLE
+ SQLITE_OMIT_ANALYZE
+ SQLITE_OMIT_ATTACH
+ SQLITE_OMIT_AUTHORIZATION
+ SQLITE_OMIT_AUTOINCREMENT
+ SQLITE_OMIT_AUTOINIT
+ SQLITE_OMIT_AUTOMATIC_INDEX
+ SQLITE_OMIT_AUTORESET
+ SQLITE_OMIT_AUTOVACUUM
+ SQLITE_OMIT_BETWEEN_OPTIMIZATION
+ SQLITE_OMIT_BLOB_LITERAL
+ SQLITE_OMIT_BTREECOUNT
+ SQLITE_OMIT_CAST
+ SQLITE_OMIT_CHECK
+ SQLITE_OMIT_COMPLETE
+ SQLITE_OMIT_COMPOUND_SELECT
+ SQLITE_OMIT_CONFLICT_CLAUSE
+ SQLITE_OMIT_CTE
+ SQLITE_OMIT_DATETIME_FUNCS
+ SQLITE_OMIT_DECLTYPE
+ SQLITE_OMIT_DEPRECATED
+ SQLITE_OMIT_DISKIO
+ SQLITE_OMIT_EXPLAIN
+ SQLITE_OMIT_FLAG_PRAGMAS
+ SQLITE_OMIT_FLOATING_POINT
+ SQLITE_OMIT_FOREIGN_KEY
+ SQLITE_OMIT_GET_TABLE
+ SQLITE_OMIT_HEX_INTEGER
+ SQLITE_OMIT_INCRBLOB
+ SQLITE_OMIT_INTEGRITY_CHECK
+ SQLITE_OMIT_LIKE_OPTIMIZATION
+ SQLITE_OMIT_LOAD_EXTENSION
+ SQLITE_OMIT_LOCALTIME
+ SQLITE_OMIT_LOOKASIDE
+ SQLITE_OMIT_MEMORYDB
+ SQLITE_OMIT_OR_OPTIMIZATION
+ SQLITE_OMIT_PAGER_PRAGMAS
+ SQLITE_OMIT_PARSER_TRACE
+ SQLITE_OMIT_POPEN
+ SQLITE_OMIT_PRAGMA
+ SQLITE_OMIT_PROGRESS_CALLBACK
+ SQLITE_OMIT_QUICKBALANCE
+ SQLITE_OMIT_REINDEX
+ SQLITE_OMIT_SCHEMA_PRAGMAS
+ SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+ SQLITE_OMIT_SHARED_CACHE
+ SQLITE_OMIT_SHUTDOWN_DIRECTORIES
+ SQLITE_OMIT_SUBQUERY
+ SQLITE_OMIT_TCL_VARIABLE
+ SQLITE_OMIT_TEMPDB
+ SQLITE_OMIT_TEST_CONTROL
+ SQLITE_OMIT_TRACE
+ SQLITE_OMIT_TRIGGER
+ SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+ SQLITE_OMIT_UTF16
+ SQLITE_OMIT_VACUUM
+ SQLITE_OMIT_VIEW
+ SQLITE_OMIT_VIRTUALTABLE
+ SQLITE_OMIT_WAL
+ SQLITE_OMIT_WSD
+ SQLITE_OMIT_XFER_OPT
+ SQLITE_PCACHE_SEPARATE_HEADER
+ SQLITE_PERFORMANCE_TRACE
+ SQLITE_POWERSAFE_OVERWRITE
+ SQLITE_PREFER_PROXY_LOCKING
+ SQLITE_PROXY_DEBUG
+ SQLITE_REVERSE_UNORDERED_SELECTS
+ SQLITE_RTREE_INT_ONLY
+ SQLITE_SECURE_DELETE
+ SQLITE_SMALL_STACK
+ SQLITE_SOUNDEX
+ SQLITE_SUBSTR_COMPATIBILITY
+ SQLITE_SYSTEM_MALLOC
+ SQLITE_TCL
+ SQLITE_TEST
+ SQLITE_UNLINK_AFTER_CLOSE
+ SQLITE_UNTESTABLE
+ SQLITE_USE_ALLOCA
+ SQLITE_USE_FCNTL_TRACE
+ SQLITE_USER_AUTHENTICATION
+ SQLITE_USE_URI
+ SQLITE_VDBE_COVERAGE
+ SQLITE_WIN32_MALLOC
+ SQLITE_ZERO_MALLOC
+}
+
+# All compile time options for which the assigned value is other than boolean.
+#
+set value_options {
+ SQLITE_BITMASK_TYPE
+ SQLITE_DEFAULT_CACHE_SIZE
+ SQLITE_DEFAULT_FILE_FORMAT
+ SQLITE_DEFAULT_FILE_PERMISSIONS
+ SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
+ SQLITE_DEFAULT_LOCKING_MODE
+ SQLITE_DEFAULT_LOOKASIDE
+ SQLITE_DEFAULT_MMAP_SIZE
+ SQLITE_DEFAULT_PAGE_SIZE
+ SQLITE_DEFAULT_PCACHE_INITSZ
+ SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
+ SQLITE_DEFAULT_ROWEST
+ SQLITE_DEFAULT_SECTOR_SIZE
+ SQLITE_DEFAULT_SYNCHRONOUS
+ SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+ SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ SQLITE_DEFAULT_WORKER_THREADS
+ SQLITE_ENABLE_8_3_NAMES
+ SQLITE_ENABLE_LOCKING_STYLE
+ SQLITE_EXTRA_INIT
+ SQLITE_EXTRA_SHUTDOWN
+ SQLITE_FTS3_MAX_EXPR_DEPTH
+ SQLITE_INTEGRITY_CHECK_ERROR_MAX
+ SQLITE_MALLOC_SOFT_LIMIT
+ SQLITE_MAX_ATTACHED
+ SQLITE_MAX_COLUMN
+ SQLITE_MAX_COMPOUND_SELECT
+ SQLITE_MAX_DEFAULT_PAGE_SIZE
+ SQLITE_MAX_EXPR_DEPTH
+ SQLITE_MAX_FUNCTION_ARG
+ SQLITE_MAX_LENGTH
+ SQLITE_MAX_LIKE_PATTERN_LENGTH
+ SQLITE_MAX_MEMORY
+ SQLITE_MAX_MMAP_SIZE
+ SQLITE_MAX_MMAP_SIZE_
+ SQLITE_MAX_PAGE_COUNT
+ SQLITE_MAX_PAGE_SIZE
+ SQLITE_MAX_SCHEMA_RETRY
+ SQLITE_MAX_SQL_LENGTH
+ SQLITE_MAX_TRIGGER_DEPTH
+ SQLITE_MAX_VARIABLE_NUMBER
+ SQLITE_MAX_VDBE_OP
+ SQLITE_MAX_WORKER_THREADS
+ SQLITE_SORTER_PMASZ
+ SQLITE_STAT4_SAMPLES
+ SQLITE_STMTJRNL_SPILL
+ SQLITE_TEMP_STORE
+}
+
+# Options that require custom code.
+#
+set options(ENABLE_STAT3) {
+#if defined(SQLITE_ENABLE_STAT4)
+ "ENABLE_STAT4",
+#elif defined(SQLITE_ENABLE_STAT3)
+ "ENABLE_STAT3",
+#endif
+}
+set options(COMPILER) {
+#if defined(__clang__) && defined(__clang_major__)
+ "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
+ CTIMEOPT_VAL(__clang_minor__) "."
+ CTIMEOPT_VAL(__clang_patchlevel__),
+#elif defined(_MSC_VER)
+ "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
+#elif defined(__GNUC__) && defined(__VERSION__)
+ "COMPILER=gcc-" __VERSION__,
+#endif
+}
+set options(HAVE_ISNAN) {
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
+ "HAVE_ISNAN",
+#endif
+}
+set options(THREADSAFE) {
+#if defined(SQLITE_THREADSAFE)
+ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+#elif defined(THREADSAFE)
+ "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
+#else
+ "THREADSAFE=1"
+#endif
+}
+
+proc trim_name {in} {
+ set ret $in
+ if {[string range $in 0 6]=="SQLITE_"} {
+ set ret [string range $in 7 end]
+ }
+ return $ret
+}
+
+foreach b $boolean_options {
+ set name [trim_name $b]
+ set options($name) [subst {
+#if $b
+ "$name",
+#endif
+}]
+}
+
+foreach v $value_options {
+ set name [trim_name $v]
+ set options($name) [subst {
+#ifdef $v
+ "$name=" CTIMEOPT_VAL($v),
+#endif
+}]
+}
+
+foreach o [lsort [array names options]] {
+ puts [string trim $options($o)]
+}
+
+
Index: tool/mkpragmatab.tcl
==================================================================
--- tool/mkpragmatab.tcl
+++ tool/mkpragmatab.tcl
@@ -261,11 +261,11 @@
FLAG: NeedSchema Result1 SchemaOpt
COLS: id seq table from to on_update on_delete match
IF: !defined(SQLITE_OMIT_FOREIGN_KEY)
NAME: foreign_key_check
- FLAG: NeedSchema
+ FLAG: NeedSchema Result0
COLS: table rowid parent fkid
IF: !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
NAME: parser_trace
IF: defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
@@ -272,16 +272,16 @@
NAME: case_sensitive_like
FLAG: NoColumns
NAME: integrity_check
- FLAG: NeedSchema
+ FLAG: NeedSchema Result0 Result1
IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK)
NAME: quick_check
TYPE: INTEGRITY_CHECK
- FLAG: NeedSchema
+ FLAG: NeedSchema Result0 Result1
IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK)
NAME: encoding
FLAG: Result0 NoColumns1
IF: !defined(SQLITE_OMIT_UTF16)
Index: tool/mksqlite3c.tcl
==================================================================
--- tool/mksqlite3c.tcl
+++ tool/mksqlite3c.tcl
@@ -281,14 +281,14 @@
# Process the source files. Process files containing commonly
# used subroutines first in order to help the compiler find
# inlining opportunities.
#
foreach file {
+ ctime.c
sqliteInt.h
global.c
- ctime.c
status.c
date.c
os.c
fault.c
Index: tool/spaceanal.tcl
==================================================================
--- tool/spaceanal.tcl
+++ tool/spaceanal.tcl
@@ -422,19 +422,24 @@
# payload_percent: Payload bytes used as a percentage of $storage.
# total_unused: Unused bytes on pages.
# avg_payload: Average payload per btree entry.
# avg_fanout: Average fanout for internal pages.
# avg_unused: Average unused bytes per btree entry.
+ # avg_meta: Average metadata overhead per entry.
# ovfl_cnt_percent: Percentage of btree entries that use overflow pages.
#
set total_pages [expr {$leaf_pages+$int_pages+$ovfl_pages}]
set total_pages_percent [percent $total_pages $file_pgcnt]
set storage [expr {$total_pages*$pageSize}]
set payload_percent [percent $payload $storage {of storage consumed}]
set total_unused [expr {$ovfl_unused+$int_unused+$leaf_unused}]
set avg_payload [divide $payload $nentry]
set avg_unused [divide $total_unused $nentry]
+ set total_meta [expr {$storage - $payload - $total_unused}]
+ set total_meta [expr {$total_meta + 4*($ovfl_pages - $ovfl_cnt)}]
+ set meta_percent [percent $total_meta $storage {of metadata}]
+ set avg_meta [divide $total_meta $nentry]
if {$int_pages>0} {
# TODO: Is this formula correct?
set nTab [mem eval "
SELECT count(*) FROM (
SELECT DISTINCT tblname FROM space_used WHERE $where AND is_index=0
@@ -458,13 +463,15 @@
set pct [expr {$compressed_size*100.0/$storage}]
set pct [format {%5.1f%%} $pct]
statline {Bytes used after compression} $compressed_size $pct
}
statline {Bytes of payload} $payload $payload_percent
+ statline {Bytes of metadata} $total_meta $meta_percent
if {$cnt==1} {statline {B-tree depth} $depth}
statline {Average payload per entry} $avg_payload
statline {Average unused bytes per entry} $avg_unused
+ statline {Average metadata per entry} $avg_meta
if {[info exists avg_fanout]} {
statline {Average fanout} $avg_fanout
}
if {$showFrag && $total_pages>1} {
set fragmentation [percent $gap_cnt [expr {$total_pages-1}]]
@@ -755,10 +762,20 @@
The amount of payload stored under this category. Payload is the data
part of table entries and the key part of index entries. The percentage
at the right is the bytes of payload divided by the bytes of storage
consumed.
+Bytes of metadata
+
+ The amount of formatting and structural information stored in the
+ table or index. Metadata includes the btree page header, the cell pointer
+ array, the size field for each cell, the left child pointer or non-leaf
+ cells, the overflow pointers for overflow cells, and the rowid value for
+ rowid table cells. In other words, metadata is everything that is neither
+ unused space nor content. The record header in the payload is counted as
+ content, not metadata.
+
Average payload per entry
The average amount of payload on each entry. This is just the bytes of
payload divided by the number of entries.
Index: tool/sqldiff.c
==================================================================
--- tool/sqldiff.c
+++ tool/sqldiff.c
@@ -1665,11 +1665,11 @@
goto end_changeset_one_table;
}
putc('T', out);
putsVarint(out, (sqlite3_uint64)nCol);
- for(i=0; i