am 320e6966: add meta-files about 3rd party projects
Merge commit '320e6966e0d3ecf2eed56e9c2c03fe9e9040c84e'
* commit '320e6966e0d3ecf2eed56e9c2c03fe9e9040c84e':
add meta-files about 3rd party projects
diff --git a/android/OldPhoneNumberUtils.cpp b/android/OldPhoneNumberUtils.cpp
index 5f180dc..9c2f20e 100644
--- a/android/OldPhoneNumberUtils.cpp
+++ b/android/OldPhoneNumberUtils.cpp
@@ -173,7 +173,7 @@
* is no such character in a.
*/
static int indexOf(const char *a, char b) {
- char *ix = strchr(a, b);
+ const char *ix = strchr(a, b);
if (ix == NULL)
return -1;
diff --git a/dist/Android.mk b/dist/Android.mk
index 016968d..1396472 100644
--- a/dist/Android.mk
+++ b/dist/Android.mk
@@ -6,6 +6,8 @@
LOCAL_PATH:= $(call my-dir)
+common_sqlite_flags := -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_THREADSAFE=1 -DNDEBUG=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_BACKWARDS -DSQLITE_DEFAULT_FILE_FORMAT=4
+
common_src_files := sqlite3.c
# the device library
@@ -21,7 +23,7 @@
# SQLITE_TEMP_STORE=3 causes all TEMP files to go into RAM. and thats the behavior we want
# SQLITE_ENABLE_FTS3 enables usage of FTS3 - NOT FTS1 or 2.
# SQLITE_DEFAULT_AUTOVACUUM=1 causes the databases to be subject to auto-vacuum
-LOCAL_CFLAGS += -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_THREADSAFE=1 -DNDEBUG=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DSQLITE_DEFAULT_AUTOVACUUM=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_BACKWARDS
+LOCAL_CFLAGS += $(common_sqlite_flags)
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES := libdl
@@ -56,16 +58,18 @@
LOCAL_SRC_FILES := shell.c
-LOCAL_SHARED_LIBRARIES := libsqlite
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../android $(call include-path-for, system-core)/cutils
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../android
-
+LOCAL_SHARED_LIBRARIES := libsqlite \
+ libicuuc \
+ libicui18n \
+ libutils
ifneq ($(TARGET_ARCH),arm)
LOCAL_LDLIBS += -lpthread -ldl
endif
-LOCAL_CFLAGS += -DHAVE_USLEEP=1 -DTHREADSAFE=1 -DNDEBUG=1
+LOCAL_CFLAGS += $(common_sqlite_flags)
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
@@ -88,9 +92,7 @@
LOCAL_SRC_FILES := $(common_src_files) shell.c
-LOCAL_CFLAGS += -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_THREADSAFE=1 -DNDEBUG=1 -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1 -DNO_ANDROID_FUNCS=1 -DSQLITE_TEMP_STORE=3 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_BACKWARDS
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../android
+LOCAL_CFLAGS += $(common_sqlite_flags) -DNO_ANDROID_FUNCS=1
# sqlite3MemsysAlarm uses LOG()
LOCAL_STATIC_LIBRARIES += liblog
diff --git a/dist/shell.c b/dist/shell.c
index c72b78d..9c21103 100644
--- a/dist/shell.c
+++ b/dist/shell.c
@@ -24,6 +24,11 @@
#include "sqlite3.h"
#include <ctype.h>
#include <stdarg.h>
+// Begin Android Add
+#ifndef NO_ANDROID_FUNCS
+#include <sqlite3_android.h>
+#endif
+// End Android Add
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
# include <signal.h>
@@ -195,868 +200,6 @@
*/
#define UNUSED_PARAMETER(x) (void)(x)
-
-/**************************************************************************
-***************************************************************************
-** Begin genfkey logic.
-*/
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined SQLITE_OMIT_SUBQUERY
-
-#define GENFKEY_ERROR 1
-#define GENFKEY_DROPTRIGGER 2
-#define GENFKEY_CREATETRIGGER 3
-static int genfkey_create_triggers(sqlite3 *, const char *, void *,
- int (*)(void *, int, const char *)
-);
-
-struct GenfkeyCb {
- void *pCtx;
- int eType;
- int (*xData)(void *, int, const char *);
-};
-typedef struct GenfkeyCb GenfkeyCb;
-
-/* The code in this file defines a sqlite3 virtual-table module that
-** provides a read-only view of the current database schema. There is one
-** row in the schema table for each column in the database schema.
-*/
-#define SCHEMA \
-"CREATE TABLE x(" \
- "database," /* Name of database (i.e. main, temp etc.) */ \
- "tablename," /* Name of table */ \
- "cid," /* Column number (from left-to-right, 0 upward) */ \
- "name," /* Column name */ \
- "type," /* Specified type (i.e. VARCHAR(32)) */ \
- "not_null," /* Boolean. True if NOT NULL was specified */ \
- "dflt_value," /* Default value for this column */ \
- "pk" /* True if this column is part of the primary key */ \
-")"
-
-#define SCHEMA2 \
-"CREATE TABLE x(" \
- "database," /* Name of database (i.e. main, temp etc.) */ \
- "from_tbl," /* Name of table */ \
- "fkid," \
- "seq," \
- "to_tbl," \
- "from_col," \
- "to_col," \
- "on_update," \
- "on_delete," \
- "match" \
-")"
-
-#define SCHEMA3 \
-"CREATE TABLE x(" \
- "database," /* Name of database (i.e. main, temp etc.) */ \
- "tablename," /* Name of table */ \
- "seq," \
- "name," \
- "isunique" \
-")"
-
-#define SCHEMA4 \
-"CREATE TABLE x(" \
- "database," /* Name of database (i.e. main, temp etc.) */ \
- "indexname," /* Name of table */ \
- "seqno," \
- "cid," \
- "name" \
-")"
-
-#define SCHEMA5 \
-"CREATE TABLE x(" \
- "database," /* Name of database (i.e. main, temp etc.) */ \
- "triggername," /* Name of trigger */ \
- "dummy" /* Unused */ \
-")"
-
-typedef struct SchemaTable SchemaTable;
-static struct SchemaTable {
- const char *zName;
- const char *zObject;
- const char *zPragma;
- const char *zSchema;
-} aSchemaTable[] = {
- { "table_info", "table", "PRAGMA %Q.table_info(%Q)", SCHEMA },
- { "foreign_key_list", "table", "PRAGMA %Q.foreign_key_list(%Q)", SCHEMA2 },
- { "index_list", "table", "PRAGMA %Q.index_list(%Q)", SCHEMA3 },
- { "index_info", "index", "PRAGMA %Q.index_info(%Q)", SCHEMA4 },
- { "trigger_list", "trigger", "SELECT 1", SCHEMA5 },
- { 0, 0, 0, 0 }
-};
-
-typedef struct schema_vtab schema_vtab;
-typedef struct schema_cursor schema_cursor;
-
-/* A schema table object */
-struct schema_vtab {
- sqlite3_vtab base;
- sqlite3 *db;
- SchemaTable *pType;
-};
-
-/* A schema table cursor object */
-struct schema_cursor {
- sqlite3_vtab_cursor base;
- sqlite3_stmt *pDbList;
- sqlite3_stmt *pTableList;
- sqlite3_stmt *pColumnList;
- int rowid;
-};
-
-/*
-** Table destructor for the schema module.
-*/
-static int schemaDestroy(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
- return 0;
-}
-
-/*
-** Table constructor for the schema module.
-*/
-static int schemaCreate(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
-){
- int rc = SQLITE_NOMEM;
- schema_vtab *pVtab;
- SchemaTable *pType = &aSchemaTable[0];
-
- UNUSED_PARAMETER(pzErr);
- if( argc>3 ){
- int i;
- pType = 0;
- for(i=0; aSchemaTable[i].zName; i++){
- if( 0==strcmp(argv[3], aSchemaTable[i].zName) ){
- pType = &aSchemaTable[i];
- }
- }
- if( !pType ){
- return SQLITE_ERROR;
- }
- }
-
- pVtab = sqlite3_malloc(sizeof(schema_vtab));
- if( pVtab ){
- memset(pVtab, 0, sizeof(schema_vtab));
- pVtab->db = (sqlite3 *)pAux;
- pVtab->pType = pType;
- rc = sqlite3_declare_vtab(db, pType->zSchema);
- }
- *ppVtab = (sqlite3_vtab *)pVtab;
- return rc;
-}
-
-/*
-** Open a new cursor on the schema table.
-*/
-static int schemaOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
- int rc = SQLITE_NOMEM;
- schema_cursor *pCur;
- UNUSED_PARAMETER(pVTab);
- pCur = sqlite3_malloc(sizeof(schema_cursor));
- if( pCur ){
- memset(pCur, 0, sizeof(schema_cursor));
- *ppCursor = (sqlite3_vtab_cursor *)pCur;
- rc = SQLITE_OK;
- }
- return rc;
-}
-
-/*
-** Close a schema table cursor.
-*/
-static int schemaClose(sqlite3_vtab_cursor *cur){
- schema_cursor *pCur = (schema_cursor *)cur;
- sqlite3_finalize(pCur->pDbList);
- sqlite3_finalize(pCur->pTableList);
- sqlite3_finalize(pCur->pColumnList);
- sqlite3_free(pCur);
- return SQLITE_OK;
-}
-
-static void columnToResult(sqlite3_context *ctx, sqlite3_stmt *pStmt, int iCol){
- switch( sqlite3_column_type(pStmt, iCol) ){
- case SQLITE_NULL:
- sqlite3_result_null(ctx);
- break;
- case SQLITE_INTEGER:
- sqlite3_result_int64(ctx, sqlite3_column_int64(pStmt, iCol));
- break;
- case SQLITE_FLOAT:
- sqlite3_result_double(ctx, sqlite3_column_double(pStmt, iCol));
- break;
- case SQLITE_TEXT: {
- const char *z = (const char *)sqlite3_column_text(pStmt, iCol);
- sqlite3_result_text(ctx, z, -1, SQLITE_TRANSIENT);
- break;
- }
- }
-}
-
-/*
-** Retrieve a column of data.
-*/
-static int schemaColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
- schema_cursor *pCur = (schema_cursor *)cur;
- switch( i ){
- case 0:
- columnToResult(ctx, pCur->pDbList, 1);
- break;
- case 1:
- columnToResult(ctx, pCur->pTableList, 0);
- break;
- default:
- columnToResult(ctx, pCur->pColumnList, i-2);
- break;
- }
- return SQLITE_OK;
-}
-
-/*
-** Retrieve the current rowid.
-*/
-static int schemaRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
- schema_cursor *pCur = (schema_cursor *)cur;
- *pRowid = pCur->rowid;
- return SQLITE_OK;
-}
-
-static int finalize(sqlite3_stmt **ppStmt){
- int rc = sqlite3_finalize(*ppStmt);
- *ppStmt = 0;
- return rc;
-}
-
-static int schemaEof(sqlite3_vtab_cursor *cur){
- schema_cursor *pCur = (schema_cursor *)cur;
- return (pCur->pDbList ? 0 : 1);
-}
-
-/*
-** Advance the cursor to the next row.
-*/
-static int schemaNext(sqlite3_vtab_cursor *cur){
- int rc = SQLITE_OK;
- schema_cursor *pCur = (schema_cursor *)cur;
- schema_vtab *pVtab = (schema_vtab *)(cur->pVtab);
- char *zSql = 0;
-
- while( !pCur->pColumnList || SQLITE_ROW!=sqlite3_step(pCur->pColumnList) ){
- if( SQLITE_OK!=(rc = finalize(&pCur->pColumnList)) ) goto next_exit;
-
- while( !pCur->pTableList || SQLITE_ROW!=sqlite3_step(pCur->pTableList) ){
- if( SQLITE_OK!=(rc = finalize(&pCur->pTableList)) ) goto next_exit;
-
- assert(pCur->pDbList);
- while( SQLITE_ROW!=sqlite3_step(pCur->pDbList) ){
- rc = finalize(&pCur->pDbList);
- goto next_exit;
- }
-
- /* Set zSql to the SQL to pull the list of tables from the
- ** sqlite_master (or sqlite_temp_master) table of the database
- ** identfied by the row pointed to by the SQL statement pCur->pDbList
- ** (iterating through a "PRAGMA database_list;" statement).
- */
- if( sqlite3_column_int(pCur->pDbList, 0)==1 ){
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_temp_master WHERE type=%Q",
- pVtab->pType->zObject
- );
- }else{
- sqlite3_stmt *pDbList = pCur->pDbList;
- zSql = sqlite3_mprintf(
- "SELECT name FROM %Q.sqlite_master WHERE type=%Q",
- sqlite3_column_text(pDbList, 1), pVtab->pType->zObject
- );
- }
- if( !zSql ){
- rc = SQLITE_NOMEM;
- goto next_exit;
- }
-
- rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pTableList, 0);
- sqlite3_free(zSql);
- if( rc!=SQLITE_OK ) goto next_exit;
- }
-
- /* Set zSql to the SQL to the table_info pragma for the table currently
- ** identified by the rows pointed to by statements pCur->pDbList and
- ** pCur->pTableList.
- */
- zSql = sqlite3_mprintf(pVtab->pType->zPragma,
- sqlite3_column_text(pCur->pDbList, 1),
- sqlite3_column_text(pCur->pTableList, 0)
- );
-
- if( !zSql ){
- rc = SQLITE_NOMEM;
- goto next_exit;
- }
- rc = sqlite3_prepare(pVtab->db, zSql, -1, &pCur->pColumnList, 0);
- sqlite3_free(zSql);
- if( rc!=SQLITE_OK ) goto next_exit;
- }
- pCur->rowid++;
-
-next_exit:
- /* TODO: Handle rc */
- return rc;
-}
-
-/*
-** Reset a schema table cursor.
-*/
-static int schemaFilter(
- sqlite3_vtab_cursor *pVtabCursor,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
-){
- int rc;
- schema_vtab *pVtab = (schema_vtab *)(pVtabCursor->pVtab);
- schema_cursor *pCur = (schema_cursor *)pVtabCursor;
- UNUSED_PARAMETER(idxNum);
- UNUSED_PARAMETER(idxStr);
- UNUSED_PARAMETER(argc);
- UNUSED_PARAMETER(argv);
- pCur->rowid = 0;
- finalize(&pCur->pTableList);
- finalize(&pCur->pColumnList);
- finalize(&pCur->pDbList);
- rc = sqlite3_prepare(pVtab->db,"SELECT 0, 'main'", -1, &pCur->pDbList, 0);
- return (rc==SQLITE_OK ? schemaNext(pVtabCursor) : rc);
-}
-
-/*
-** Analyse the WHERE condition.
-*/
-static int schemaBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
- UNUSED_PARAMETER(tab);
- UNUSED_PARAMETER(pIdxInfo);
- return SQLITE_OK;
-}
-
-/*
-** A virtual table module that merely echos method calls into TCL
-** variables.
-*/
-static sqlite3_module schemaModule = {
- 0, /* iVersion */
- schemaCreate,
- schemaCreate,
- schemaBestIndex,
- schemaDestroy,
- schemaDestroy,
- schemaOpen, /* xOpen - open a cursor */
- schemaClose, /* xClose - close a cursor */
- schemaFilter, /* xFilter - configure scan constraints */
- schemaNext, /* xNext - advance a cursor */
- schemaEof, /* xEof */
- schemaColumn, /* xColumn - read data */
- schemaRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
-};
-
-/*
-** Extension load function.
-*/
-static int installSchemaModule(sqlite3 *db, sqlite3 *sdb){
- sqlite3_create_module(db, "schema", &schemaModule, (void *)sdb);
- return 0;
-}
-
-/*
-** sj(zValue, zJoin)
-**
-** The following block contains the implementation of an aggregate
-** function that returns a string. Each time the function is stepped,
-** it appends data to an internal buffer. When the aggregate is finalized,
-** the contents of the buffer are returned.
-**
-** The first time the aggregate is stepped the buffer is set to a copy
-** of the first argument. The second time and subsequent times it is
-** stepped a copy of the second argument is appended to the buffer, then
-** a copy of the first.
-**
-** Example:
-**
-** INSERT INTO t1(a) VALUES('1');
-** INSERT INTO t1(a) VALUES('2');
-** INSERT INTO t1(a) VALUES('3');
-** SELECT sj(a, ', ') FROM t1;
-**
-** => "1, 2, 3"
-**
-*/
-struct StrBuffer {
- char *zBuf;
-};
-typedef struct StrBuffer StrBuffer;
-static void joinFinalize(sqlite3_context *context){
- StrBuffer *p;
- p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
- sqlite3_result_text(context, p->zBuf, -1, SQLITE_TRANSIENT);
- sqlite3_free(p->zBuf);
-}
-static void joinStep(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- StrBuffer *p;
- UNUSED_PARAMETER(argc);
- p = (StrBuffer *)sqlite3_aggregate_context(context, sizeof(StrBuffer));
- if( p->zBuf==0 ){
- p->zBuf = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
- }else{
- char *zTmp = p->zBuf;
- p->zBuf = sqlite3_mprintf("%s%s%s",
- zTmp, sqlite3_value_text(argv[1]), sqlite3_value_text(argv[0])
- );
- sqlite3_free(zTmp);
- }
-}
-
-/*
-** dq(zString)
-**
-** This scalar function accepts a single argument and interprets it as
-** a text value. The return value is the argument enclosed in double
-** quotes. If any double quote characters are present in the argument,
-** these are escaped.
-**
-** dq('the raven "Nevermore."') == '"the raven ""Nevermore."""'
-*/
-static void doublequote(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int ii;
- char *zOut;
- char *zCsr;
- const char *zIn = (const char *)sqlite3_value_text(argv[0]);
- int nIn = sqlite3_value_bytes(argv[0]);
-
- UNUSED_PARAMETER(argc);
- zOut = sqlite3_malloc(nIn*2+3);
- zCsr = zOut;
- *zCsr++ = '"';
- for(ii=0; ii<nIn; ii++){
- *zCsr++ = zIn[ii];
- if( zIn[ii]=='"' ){
- *zCsr++ = '"';
- }
- }
- *zCsr++ = '"';
- *zCsr++ = '\0';
-
- sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
- sqlite3_free(zOut);
-}
-
-/*
-** multireplace(zString, zSearch1, zReplace1, ...)
-*/
-static void multireplace(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- int i = 0;
- char *zOut = 0;
- int nOut = 0;
- int nMalloc = 0;
- const char *zIn = (const char *)sqlite3_value_text(argv[0]);
- int nIn = sqlite3_value_bytes(argv[0]);
-
- while( i<nIn ){
- const char *zCopy = &zIn[i];
- int nCopy = 1;
- int nReplace = 1;
- int j;
- for(j=1; j<(argc-1); j+=2){
- const char *z = (const char *)sqlite3_value_text(argv[j]);
- int n = sqlite3_value_bytes(argv[j]);
- if( n<=(nIn-i) && 0==strncmp(z, zCopy, n) ){
- zCopy = (const char *)sqlite3_value_text(argv[j+1]);
- nCopy = sqlite3_value_bytes(argv[j+1]);
- nReplace = n;
- break;
- }
- }
- if( (nOut+nCopy)>nMalloc ){
- char *zNew;
- nMalloc = 16 + (nOut+nCopy)*2;
- zNew = (char*)sqlite3_realloc(zOut, nMalloc);
- if( zNew==0 ){
- sqlite3_result_error_nomem(context);
- return;
- }else{
- zOut = zNew;
- }
- }
- assert( nMalloc>=(nOut+nCopy) );
- memcpy(&zOut[nOut], zCopy, nCopy);
- i += nReplace;
- nOut += nCopy;
- }
-
- sqlite3_result_text(context, zOut, nOut, SQLITE_TRANSIENT);
- sqlite3_free(zOut);
-}
-
-/*
-** A callback for sqlite3_exec() invokes the callback specified by the
-** GenfkeyCb structure pointed to by the void* passed as the first argument.
-*/
-static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){
- GenfkeyCb *pCb = (GenfkeyCb *)p;
- UNUSED_PARAMETER(nArg);
- UNUSED_PARAMETER(azCol);
- return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]);
-}
-
-static int detectSchemaProblem(
- sqlite3 *db, /* Database connection */
- const char *zMessage, /* English language error message */
- const char *zSql, /* SQL statement to run */
- GenfkeyCb *pCb
-){
- sqlite3_stmt *pStmt;
- int rc;
- rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- char *zDel;
- int iFk = sqlite3_column_int(pStmt, 0);
- const char *zTab = (const char *)sqlite3_column_text(pStmt, 1);
- zDel = sqlite3_mprintf("Error in table %s: %s", zTab, zMessage);
- rc = pCb->xData(pCb->pCtx, pCb->eType, zDel);
- sqlite3_free(zDel);
- if( rc!=SQLITE_OK ) return rc;
- zDel = sqlite3_mprintf(
- "DELETE FROM temp.fkey WHERE from_tbl = %Q AND fkid = %d"
- , zTab, iFk
- );
- sqlite3_exec(db, zDel, 0, 0, 0);
- sqlite3_free(zDel);
- }
- sqlite3_finalize(pStmt);
- return SQLITE_OK;
-}
-
-/*
-** Create and populate temporary table "fkey".
-*/
-static int populateTempTable(sqlite3 *db, GenfkeyCb *pCallback){
- int rc;
-
- rc = sqlite3_exec(db,
- "CREATE VIRTUAL TABLE temp.v_fkey USING schema(foreign_key_list);"
- "CREATE VIRTUAL TABLE temp.v_col USING schema(table_info);"
- "CREATE VIRTUAL TABLE temp.v_idxlist USING schema(index_list);"
- "CREATE VIRTUAL TABLE temp.v_idxinfo USING schema(index_info);"
- "CREATE VIRTUAL TABLE temp.v_triggers USING schema(trigger_list);"
- "CREATE TABLE temp.fkey AS "
- "SELECT from_tbl, to_tbl, fkid, from_col, to_col, on_update, on_delete "
- "FROM temp.v_fkey WHERE database = 'main';"
- , 0, 0, 0
- );
- if( rc!=SQLITE_OK ) return rc;
-
- rc = detectSchemaProblem(db, "foreign key columns do not exist",
- "SELECT fkid, from_tbl "
- "FROM temp.fkey "
- "WHERE to_col IS NOT NULL AND NOT EXISTS (SELECT 1 "
- "FROM temp.v_col WHERE tablename=to_tbl AND name==to_col"
- ")", pCallback
- );
- if( rc!=SQLITE_OK ) return rc;
-
- /* At this point the temp.fkey table is mostly populated. If any foreign
- ** keys were specified so that they implicitly refer to they primary
- ** key of the parent table, the "to_col" values of the temp.fkey rows
- ** are still set to NULL.
- **
- ** This is easily fixed for single column primary keys, but not for
- ** composites. With a composite primary key, there is no way to reliably
- ** query sqlite for the order in which the columns that make up the
- ** composite key were declared i.e. there is no way to tell if the
- ** schema actually contains "PRIMARY KEY(a, b)" or "PRIMARY KEY(b, a)".
- ** Therefore, this case is not handled. The following function call
- ** detects instances of this case.
- */
- rc = detectSchemaProblem(db, "implicit mapping to composite primary key",
- "SELECT fkid, from_tbl "
- "FROM temp.fkey "
- "WHERE to_col IS NULL "
- "GROUP BY fkid, from_tbl HAVING count(*) > 1", pCallback
- );
- if( rc!=SQLITE_OK ) return rc;
-
- /* Detect attempts to implicitly map to the primary key of a table
- ** that has no primary key column.
- */
- rc = detectSchemaProblem(db, "implicit mapping to non-existant primary key",
- "SELECT fkid, from_tbl "
- "FROM temp.fkey "
- "WHERE to_col IS NULL AND NOT EXISTS "
- "(SELECT 1 FROM temp.v_col WHERE pk AND tablename = temp.fkey.to_tbl)"
- , pCallback
- );
- if( rc!=SQLITE_OK ) return rc;
-
- /* Fix all the implicit primary key mappings in the temp.fkey table. */
- rc = sqlite3_exec(db,
- "UPDATE temp.fkey SET to_col = "
- "(SELECT name FROM temp.v_col WHERE pk AND tablename=temp.fkey.to_tbl)"
- " WHERE to_col IS NULL;"
- , 0, 0, 0
- );
- if( rc!=SQLITE_OK ) return rc;
-
- /* Now check that all all parent keys are either primary keys or
- ** subject to a unique constraint.
- */
- rc = sqlite3_exec(db,
- "CREATE TABLE temp.idx2 AS SELECT "
- "il.tablename AS tablename,"
- "ii.indexname AS indexname,"
- "ii.name AS col "
- "FROM temp.v_idxlist AS il, temp.v_idxinfo AS ii "
- "WHERE il.isunique AND il.database='main' AND ii.indexname = il.name;"
- "INSERT INTO temp.idx2 "
- "SELECT tablename, 'pk', name FROM temp.v_col WHERE pk;"
-
- "CREATE TABLE temp.idx AS SELECT "
- "tablename, indexname, sj(dq(col),',') AS cols "
- "FROM (SELECT * FROM temp.idx2 ORDER BY col) "
- "GROUP BY tablename, indexname;"
-
- "CREATE TABLE temp.fkey2 AS SELECT "
- "fkid, from_tbl, to_tbl, sj(dq(to_col),',') AS cols "
- "FROM (SELECT * FROM temp.fkey ORDER BY to_col) "
- "GROUP BY fkid, from_tbl;"
-
- "CREATE TABLE temp.triggers AS SELECT "
- "triggername FROM temp.v_triggers WHERE database='main' AND "
- "triggername LIKE 'genfkey%';"
- , 0, 0, 0
- );
- if( rc!=SQLITE_OK ) return rc;
- rc = detectSchemaProblem(db, "foreign key is not unique",
- "SELECT fkid, from_tbl "
- "FROM temp.fkey2 "
- "WHERE NOT EXISTS (SELECT 1 "
- "FROM temp.idx WHERE tablename=to_tbl AND fkey2.cols==idx.cols"
- ")", pCallback
- );
- if( rc!=SQLITE_OK ) return rc;
-
- return rc;
-}
-
-#define GENFKEY_ERROR 1
-#define GENFKEY_DROPTRIGGER 2
-#define GENFKEY_CREATETRIGGER 3
-static int genfkey_create_triggers(
- sqlite3 *sdb, /* Connection to read schema from */
- const char *zDb, /* Name of db to read ("main", "temp") */
- void *pCtx, /* Context pointer to pass to xData */
- int (*xData)(void *, int, const char *)
-){
- const char *zSql =
- "SELECT multireplace('"
-
- "-- Triggers for foreign key mapping:\n"
- "--\n"
- "-- /from_readable/ REFERENCES /to_readable/\n"
- "-- on delete /on_delete/\n"
- "-- on update /on_update/\n"
- "--\n"
-
- /* The "BEFORE INSERT ON <referencing>" trigger. This trigger's job is to
- ** throw an exception if the user tries to insert a row into the
- ** referencing table for which there is no corresponding row in
- ** the referenced table.
- */
- "CREATE TRIGGER /name/_insert_referencing BEFORE INSERT ON /tbl/ WHEN \n"
- " /key_notnull/ AND NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, ''constraint failed'');\n"
- "END;\n"
-
- /* The "BEFORE UPDATE ON <referencing>" trigger. This trigger's job
- ** is to throw an exception if the user tries to update a row in the
- ** referencing table causing it to correspond to no row in the
- ** referenced table.
- */
- "CREATE TRIGGER /name/_update_referencing BEFORE\n"
- " UPDATE OF /rkey_list/ ON /tbl/ WHEN \n"
- " /key_notnull/ AND \n"
- " NOT EXISTS (SELECT 1 FROM /ref/ WHERE /cond1/)\n"
- "BEGIN\n"
- " SELECT RAISE(ABORT, ''constraint failed'');\n"
- "END;\n"
-
-
- /* The "BEFORE DELETE ON <referenced>" trigger. This trigger's job
- ** is to detect when a row is deleted from the referenced table to
- ** which rows in the referencing table correspond. The action taken
- ** depends on the value of the 'ON DELETE' clause.
- */
- "CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n"
- " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
- "BEGIN\n"
- " /delete_action/\n"
- "END;\n"
-
- /* The "AFTER UPDATE ON <referenced>" trigger. This trigger's job
- ** is to detect when the key columns of a row in the referenced table
- ** to which one or more rows in the referencing table correspond are
- ** updated. The action taken depends on the value of the 'ON UPDATE'
- ** clause.
- */
- "CREATE TRIGGER /name/_update_referenced AFTER\n"
- " UPDATE OF /fkey_list/ ON /ref/ WHEN \n"
- " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n"
- "BEGIN\n"
- " /update_action/\n"
- "END;\n"
- "'"
-
- /* These are used in the SQL comment written above each set of triggers */
- ", '/from_readable/', from_tbl || '(' || sj(from_col, ', ') || ')'"
- ", '/to_readable/', to_tbl || '(' || sj(to_col, ', ') || ')'"
- ", '/on_delete/', on_delete"
- ", '/on_update/', on_update"
-
- ", '/name/', 'genfkey' || min(rowid)"
- ", '/tbl/', dq(from_tbl)"
- ", '/ref/', dq(to_tbl)"
- ", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')"
-
- ", '/fkey_list/', sj(dq(to_col), ', ')"
- ", '/rkey_list/', sj(dq(from_col), ', ')"
-
- ", '/cond1/', sj(multireplace('new./from/ == /to/'"
- ", '/from/', dq(from_col)"
- ", '/to/', dq(to_col)"
- "), ' AND ')"
- ", '/cond2/', sj(multireplace('old./to/ == /from/'"
- ", '/from/', dq(from_col)"
- ", '/to/', dq(to_col)"
- "), ' AND ')"
-
- ", '/update_action/', CASE on_update "
- "WHEN 'SET NULL' THEN "
- "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
- ", '/setlist/', sj(dq(from_col)||' = NULL',', ')"
- ", '/tbl/', dq(from_tbl)"
- ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
- ")"
- "WHEN 'CASCADE' THEN "
- "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
- ", '/setlist/', sj(dq(from_col)||' = new.'||dq(to_col),', ')"
- ", '/tbl/', dq(from_tbl)"
- ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
- ")"
- "ELSE "
- " 'SELECT RAISE(ABORT, ''constraint failed'');'"
- "END "
-
- ", '/delete_action/', CASE on_delete "
- "WHEN 'SET NULL' THEN "
- "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' "
- ", '/setlist/', sj(dq(from_col)||' = NULL',', ')"
- ", '/tbl/', dq(from_tbl)"
- ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
- ")"
- "WHEN 'CASCADE' THEN "
- "multireplace('DELETE FROM /tbl/ WHERE /where/;' "
- ", '/tbl/', dq(from_tbl)"
- ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')"
- ")"
- "ELSE "
- " 'SELECT RAISE(ABORT, ''constraint failed'');'"
- "END "
-
- ") FROM temp.fkey "
- "GROUP BY from_tbl, fkid"
- ;
-
- int rc;
- const int enc = SQLITE_UTF8;
- sqlite3 *db = 0;
-
- GenfkeyCb cb;
- cb.xData = xData;
- cb.pCtx = pCtx;
-
- UNUSED_PARAMETER(zDb);
-
- /* Open the working database handle. */
- rc = sqlite3_open(":memory:", &db);
- if( rc!=SQLITE_OK ) goto genfkey_exit;
-
- /* Create the special scalar and aggregate functions used by this program. */
- sqlite3_create_function(db, "dq", 1, enc, 0, doublequote, 0, 0);
- sqlite3_create_function(db, "multireplace", -1, enc, db, multireplace, 0, 0);
- sqlite3_create_function(db, "sj", 2, enc, 0, 0, joinStep, joinFinalize);
-
- /* Install the "schema" virtual table module */
- installSchemaModule(db, sdb);
-
- /* Create and populate a temp table with the information required to
- ** build the foreign key triggers. See function populateTempTable()
- ** for details.
- */
- cb.eType = GENFKEY_ERROR;
- rc = populateTempTable(db, &cb);
- if( rc!=SQLITE_OK ) goto genfkey_exit;
-
- /* Unless the --no-drop option was specified, generate DROP TRIGGER
- ** statements to drop any triggers in the database generated by a
- ** previous run of this program.
- */
- cb.eType = GENFKEY_DROPTRIGGER;
- rc = sqlite3_exec(db,
- "SELECT 'DROP TRIGGER main.' || dq(triggername) || ';' FROM triggers"
- ,invokeCallback, (void *)&cb, 0
- );
- if( rc!=SQLITE_OK ) goto genfkey_exit;
-
- /* Run the main query to create the trigger definitions. */
- cb.eType = GENFKEY_CREATETRIGGER;
- rc = sqlite3_exec(db, zSql, invokeCallback, (void *)&cb, 0);
- if( rc!=SQLITE_OK ) goto genfkey_exit;
-
-genfkey_exit:
- sqlite3_close(db);
- return rc;
-}
-
-
-#endif
-/* End genfkey logic. */
-/*************************************************************************/
-/*************************************************************************/
-
/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
@@ -1512,10 +655,6 @@
int i;
struct callback_data *p = (struct callback_data*)pArg;
- if( p->echoOn && p->cnt==0 && p->pStmt){
- printf("%s\n", sqlite3_sql(p->pStmt));
- }
-
switch( p->mode ){
case MODE_Line: {
int w = 5;
@@ -1866,6 +1005,12 @@
continue;
}
+ /* echo the sql statement if echo on */
+ if( pArg->echoOn ){
+ const char *zStmtSql = sqlite3_sql(pStmt);
+ fprintf(pArg->out,"%s\n", zStmtSql ? zStmtSql : zSql);
+ }
+
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
@@ -2068,62 +1213,6 @@
return rc;
}
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
-struct GenfkeyCmd {
- sqlite3 *db; /* Database handle */
- struct callback_data *pCb; /* Callback data */
- int isIgnoreErrors; /* True for --ignore-errors */
- int isExec; /* True for --exec */
- int isNoDrop; /* True for --no-drop */
- int nErr; /* Number of errors seen so far */
-};
-typedef struct GenfkeyCmd GenfkeyCmd;
-
-static int genfkeyParseArgs(GenfkeyCmd *p, char **azArg, int nArg){
- int ii;
- memset(p, 0, sizeof(GenfkeyCmd));
-
- for(ii=0; ii<nArg; ii++){
- int n = strlen30(azArg[ii]);
-
- if( n>2 && n<10 && 0==strncmp(azArg[ii], "--no-drop", n) ){
- p->isNoDrop = 1;
- }else if( n>2 && n<16 && 0==strncmp(azArg[ii], "--ignore-errors", n) ){
- p->isIgnoreErrors = 1;
- }else if( n>2 && n<7 && 0==strncmp(azArg[ii], "--exec", n) ){
- p->isExec = 1;
- }else{
- fprintf(stderr, "unknown option: %s\n", azArg[ii]);
- return -1;
- }
- }
-
- return SQLITE_OK;
-}
-
-static int genfkeyCmdCb(void *pCtx, int eType, const char *z){
- GenfkeyCmd *p = (GenfkeyCmd *)pCtx;
- if( eType==GENFKEY_ERROR && !p->isIgnoreErrors ){
- p->nErr++;
- fprintf(stderr, "%s\n", z);
- }
-
- if( p->nErr==0 && (
- (eType==GENFKEY_CREATETRIGGER)
- || (eType==GENFKEY_DROPTRIGGER && !p->isNoDrop)
- )){
- if( p->isExec ){
- sqlite3_exec(p->db, z, 0, 0, 0);
- }else{
- char *zCol = "sql";
- callback((void *)p->pCb, 1, (char **)&z, (char **)&zCol);
- }
- }
-
- return SQLITE_OK;
-}
-#endif
-
/*
** Text of a help message
*/
@@ -2138,14 +1227,6 @@
".exit Exit this program\n"
".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n"
" With no args, it turns EXPLAIN on.\n"
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
- ".genfkey ?OPTIONS? Options are:\n"
- " --no-drop: Do not drop old fkey triggers.\n"
- " --ignore-errors: Ignore tables with fkey errors\n"
- " --exec: Execute generated SQL immediately\n"
- " See file tool/genfkey.README in the source \n"
- " distribution for further information.\n"
-#endif
".header(s) ON|OFF Turn display of headers on or off\n"
".help Show this message\n"
".import FILE TABLE Import data from FILE into TABLE\n"
@@ -2214,6 +1295,20 @@
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
+ // Begin Android Add
+ #ifndef NO_ANDROID_FUNCS
+ int err = register_localized_collators(db, "en_US", 0);
+ if (err != SQLITE_OK) {
+ fprintf(stderr, "register_localized_collators() failed\n");
+ exit(1);
+ }
+ err = register_android_functions(db, 0);
+ if (err != SQLITE_OK) {
+ fprintf(stderr, "register_android_functions() failed\n");
+ exit(1);
+ }
+ #endif
+ // End Android Add
}
}
@@ -2466,17 +1561,6 @@
}
}else
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY)
- if( c=='g' && strncmp(azArg[0], "genfkey", n)==0 ){
- GenfkeyCmd cmd;
- if( 0==genfkeyParseArgs(&cmd, &azArg[1], nArg-1) ){
- cmd.db = p->db;
- cmd.pCb = p;
- genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb);
- }
- }else
-#endif
-
if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
p->showHeader = booleanValue(azArg[1]);
@@ -3353,6 +2437,7 @@
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
+ sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
}
int main(int argc, char **argv){
@@ -3512,7 +2597,6 @@
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
- return rc;
}else{
open_db(&data);
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
@@ -3559,9 +2643,10 @@
}
}
set_table_name(&data, 0);
- if( db ){
- if( sqlite3_close(db)!=SQLITE_OK ){
- fprintf(stderr,"Error: cannot close database \"%s\"\n", sqlite3_errmsg(db));
+ if( data.db ){
+ if( sqlite3_close(data.db)!=SQLITE_OK ){
+ fprintf(stderr,"Error: cannot close database \"%s\"\n",
+ sqlite3_errmsg(db));
rc++;
}
}
diff --git a/dist/shell.c.orig b/dist/shell.c.orig
new file mode 100644
index 0000000..23099b9
--- /dev/null
+++ b/dist/shell.c.orig
@@ -0,0 +1,2635 @@
+/*
+** 2001 September 15
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains code to implement the "sqlite" command line
+** utility for accessing SQLite databases.
+*/
+#if defined(_WIN32) || defined(WIN32)
+/* This needs to come before any includes for MSVC compiler */
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include "sqlite3.h"
+#include <ctype.h>
+#include <stdarg.h>
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
+# include <signal.h>
+# if !defined(__RTP__) && !defined(_WRS_KERNEL)
+# include <pwd.h>
+# endif
+# include <unistd.h>
+# include <sys/types.h>
+#endif
+
+#ifdef __OS2__
+# include <unistd.h>
+#endif
+
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+# include <readline/readline.h>
+# include <readline/history.h>
+#else
+# define readline(p) local_getline(p,stdin)
+# define add_history(X)
+# define read_history(X)
+# define write_history(X)
+# define stifle_history(X)
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+#define isatty(h) _isatty(h)
+#define access(f,m) _access((f),(m))
+#else
+/* Make sure isatty() has a prototype.
+*/
+extern int isatty();
+#endif
+
+#if defined(_WIN32_WCE)
+/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
+ * thus we always assume that we have a console. That can be
+ * overridden with the -batch command line option.
+ */
+#define isatty(x) 1
+#endif
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* Saved resource information for the beginning of an operation */
+static struct rusage sBegin;
+
+/* True if the timer is enabled */
+static int enableTimer = 0;
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+ if( enableTimer ){
+ getrusage(RUSAGE_SELF, &sBegin);
+ }
+}
+
+/* Return the difference of two time_structs in seconds */
+static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
+ return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
+ (double)(pEnd->tv_sec - pStart->tv_sec);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+ if( enableTimer ){
+ struct rusage sEnd;
+ getrusage(RUSAGE_SELF, &sEnd);
+ printf("CPU Time: user %f sys %f\n",
+ timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
+ timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
+ }
+}
+
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER 1
+
+#elif (defined(_WIN32) || defined(WIN32))
+
+#include <windows.h>
+
+/* Saved resource information for the beginning of an operation */
+static HANDLE hProcess;
+static FILETIME ftKernelBegin;
+static FILETIME ftUserBegin;
+typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
+static GETPROCTIMES getProcessTimesAddr = NULL;
+
+/* True if the timer is enabled */
+static int enableTimer = 0;
+
+/*
+** Check to see if we have timer support. Return 1 if necessary
+** support found (or found previously).
+*/
+static int hasTimer(void){
+ if( getProcessTimesAddr ){
+ return 1;
+ } else {
+ /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
+ ** See if the version we are running on has it, and if it does, save off
+ ** a pointer to it and the current process handle.
+ */
+ hProcess = GetCurrentProcess();
+ if( hProcess ){
+ HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
+ if( NULL != hinstLib ){
+ getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
+ if( NULL != getProcessTimesAddr ){
+ return 1;
+ }
+ FreeLibrary(hinstLib);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+** Begin timing an operation
+*/
+static void beginTimer(void){
+ if( enableTimer && getProcessTimesAddr ){
+ FILETIME ftCreation, ftExit;
+ getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
+ }
+}
+
+/* Return the difference of two FILETIME structs in seconds */
+static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
+ sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
+ sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
+ return (double) ((i64End - i64Start) / 10000000.0);
+}
+
+/*
+** Print the timing results.
+*/
+static void endTimer(void){
+ if( enableTimer && getProcessTimesAddr){
+ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
+ getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
+ printf("CPU Time: user %f sys %f\n",
+ timeDiff(&ftUserBegin, &ftUserEnd),
+ timeDiff(&ftKernelBegin, &ftKernelEnd));
+ }
+}
+
+#define BEGIN_TIMER beginTimer()
+#define END_TIMER endTimer()
+#define HAS_TIMER hasTimer()
+
+#else
+#define BEGIN_TIMER
+#define END_TIMER
+#define HAS_TIMER 0
+#endif
+
+/*
+** Used to prevent warnings about unused parameters
+*/
+#define UNUSED_PARAMETER(x) (void)(x)
+
+/*
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
+*/
+static int bail_on_error = 0;
+
+/*
+** Threat stdin as an interactive input if the following variable
+** is true. Otherwise, assume stdin is connected to a file or pipe.
+*/
+static int stdin_is_interactive = 1;
+
+/*
+** The following is the open SQLite database. We make a pointer
+** to this database a static variable so that it can be accessed
+** by the SIGINT handler to interrupt database processing.
+*/
+static sqlite3 *db = 0;
+
+/*
+** True if an interrupt (Control-C) has been received.
+*/
+static volatile int seenInterrupt = 0;
+
+/*
+** This is the name of our program. It is set in main(), used
+** in a number of other places, mostly for error messages.
+*/
+static char *Argv0;
+
+/*
+** Prompt strings. Initialized in main. Settable with
+** .prompt main continue
+*/
+static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
+static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
+
+/*
+** Write I/O traces to the following stream.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static FILE *iotrace = 0;
+#endif
+
+/*
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields. The result of formatting this string
+** is written to iotrace.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+static void iotracePrintf(const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ if( iotrace==0 ) return;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ fprintf(iotrace, "%s", z);
+ sqlite3_free(z);
+}
+#endif
+
+
+/*
+** Determines if a string is a number of not.
+*/
+static int isNumber(const char *z, int *realnum){
+ if( *z=='-' || *z=='+' ) z++;
+ if( !isdigit(*z) ){
+ return 0;
+ }
+ z++;
+ if( realnum ) *realnum = 0;
+ while( isdigit(*z) ){ z++; }
+ if( *z=='.' ){
+ z++;
+ if( !isdigit(*z) ) return 0;
+ while( isdigit(*z) ){ z++; }
+ if( realnum ) *realnum = 1;
+ }
+ if( *z=='e' || *z=='E' ){
+ z++;
+ if( *z=='+' || *z=='-' ) z++;
+ if( !isdigit(*z) ) return 0;
+ while( isdigit(*z) ){ z++; }
+ if( realnum ) *realnum = 1;
+ }
+ return *z==0;
+}
+
+/*
+** A global char* and an SQL function to access its current value
+** from within an SQL statement. This program used to use the
+** sqlite_exec_printf() API to substitue a string into an SQL statement.
+** The correct way to do this with sqlite3 is to use the bind API, but
+** since the shell is built around the callback paradigm it would be a lot
+** of work. Instead just use this hack, which is quite harmless.
+*/
+static const char *zShellStatic = 0;
+static void shellstaticFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( 0==argc );
+ assert( zShellStatic );
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+ sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
+}
+
+
+/*
+** 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()
+** fails.
+**
+** The interface is like "readline" but no command-line editing
+** is done.
+*/
+static char *local_getline(char *zPrompt, FILE *in){
+ char *zLine;
+ int nLine;
+ int n;
+ int eol;
+
+ if( zPrompt && *zPrompt ){
+ printf("%s",zPrompt);
+ fflush(stdout);
+ }
+ nLine = 100;
+ zLine = malloc( nLine );
+ if( zLine==0 ) return 0;
+ n = 0;
+ eol = 0;
+ while( !eol ){
+ if( n+100>nLine ){
+ nLine = nLine*2 + 100;
+ zLine = realloc(zLine, nLine);
+ if( zLine==0 ) return 0;
+ }
+ if( fgets(&zLine[n], nLine - n, in)==0 ){
+ if( n==0 ){
+ free(zLine);
+ return 0;
+ }
+ zLine[n] = 0;
+ eol = 1;
+ break;
+ }
+ while( zLine[n] ){ n++; }
+ if( n>0 && zLine[n-1]=='\n' ){
+ n--;
+ if( n>0 && zLine[n-1]=='\r' ) n--;
+ zLine[n] = 0;
+ eol = 1;
+ }
+ }
+ zLine = realloc( zLine, n+1 );
+ return zLine;
+}
+
+/*
+** Retrieve a single line of input text.
+**
+** zPrior is a string of prior text retrieved. If not the empty
+** string, then issue a continuation prompt.
+*/
+static char *one_input_line(const char *zPrior, FILE *in){
+ char *zPrompt;
+ char *zResult;
+ if( in!=0 ){
+ return local_getline(0, in);
+ }
+ if( zPrior && zPrior[0] ){
+ zPrompt = continuePrompt;
+ }else{
+ zPrompt = mainPrompt;
+ }
+ zResult = readline(zPrompt);
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+ if( zResult && *zResult ) add_history(zResult);
+#endif
+ return zResult;
+}
+
+struct previous_mode_data {
+ int valid; /* Is there legit data in here? */
+ int mode;
+ int showHeader;
+ int colWidth[100];
+};
+
+/*
+** An pointer to an instance of this structure is passed from
+** the main program to the callback. This is used to communicate
+** state and mode information.
+*/
+struct callback_data {
+ sqlite3 *db; /* The database */
+ int echoOn; /* True to echo input commands */
+ int cnt; /* Number of records displayed so far */
+ FILE *out; /* Write results here */
+ int mode; /* An output mode setting */
+ int writableSchema; /* True if PRAGMA writable_schema=ON */
+ int showHeader; /* True to show column names in List or Column mode */
+ char *zDestTable; /* Name of destination table when MODE_Insert */
+ char separator[20]; /* Separator character for MODE_List */
+ int colWidth[100]; /* Requested width of each column when in column mode*/
+ int actualWidth[100]; /* Actual width of each column */
+ char nullvalue[20]; /* The text to print when a NULL comes back from
+ ** the database */
+ struct previous_mode_data explainPrev;
+ /* Holds the mode information just before
+ ** .explain ON */
+ char outfile[FILENAME_MAX]; /* Filename for *out */
+ const char *zDbFilename; /* name of the database file */
+ sqlite3_stmt *pStmt; /* Current statement if any. */
+ FILE *pLog; /* Write log output here */
+};
+
+/*
+** These are the allowed modes.
+*/
+#define MODE_Line 0 /* One column per line. Blank line between records */
+#define MODE_Column 1 /* One record per line in neat columns */
+#define MODE_List 2 /* One record per line with a separator */
+#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
+#define MODE_Html 4 /* Generate an XHTML table */
+#define MODE_Insert 5 /* Generate SQL "insert" statements */
+#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv 7 /* Quote strings, numbers are plain */
+#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
+
+static const char *modeDescr[] = {
+ "line",
+ "column",
+ "list",
+ "semi",
+ "html",
+ "insert",
+ "tcl",
+ "csv",
+ "explain",
+};
+
+/*
+** Number of elements in an array
+*/
+#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
+
+/*
+** Compute a string length that is limited to what can be stored in
+** lower 30 bits of a 32-bit signed integer.
+*/
+static int strlen30(const char *z){
+ const char *z2 = z;
+ while( *z2 ){ z2++; }
+ return 0x3fffffff & (int)(z2 - z);
+}
+
+/*
+** A callback for the sqlite3_log() interface.
+*/
+static void shellLog(void *pArg, int iErrCode, const char *zMsg){
+ struct callback_data *p = (struct callback_data*)pArg;
+ if( p->pLog==0 ) return;
+ fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
+ fflush(p->pLog);
+}
+
+/*
+** Output the given string as a hex-encoded blob (eg. X'1234' )
+*/
+static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
+ int i;
+ char *zBlob = (char *)pBlob;
+ fprintf(out,"X'");
+ for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]); }
+ fprintf(out,"'");
+}
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+*/
+static void output_quoted_string(FILE *out, const char *z){
+ int i;
+ int nSingle = 0;
+ for(i=0; z[i]; i++){
+ if( z[i]=='\'' ) nSingle++;
+ }
+ if( nSingle==0 ){
+ fprintf(out,"'%s'",z);
+ }else{
+ fprintf(out,"'");
+ while( *z ){
+ for(i=0; z[i] && z[i]!='\''; i++){}
+ if( i==0 ){
+ fprintf(out,"''");
+ z++;
+ }else if( z[i]=='\'' ){
+ fprintf(out,"%.*s''",i,z);
+ z += i+1;
+ }else{
+ fprintf(out,"%s",z);
+ break;
+ }
+ }
+ fprintf(out,"'");
+ }
+}
+
+/*
+** Output the given string as a quoted according to C or TCL quoting rules.
+*/
+static void output_c_string(FILE *out, const char *z){
+ unsigned int c;
+ fputc('"', out);
+ while( (c = *(z++))!=0 ){
+ if( c=='\\' ){
+ fputc(c, out);
+ fputc(c, out);
+ }else if( c=='\t' ){
+ fputc('\\', out);
+ fputc('t', out);
+ }else if( c=='\n' ){
+ fputc('\\', out);
+ fputc('n', out);
+ }else if( c=='\r' ){
+ fputc('\\', out);
+ fputc('r', out);
+ }else if( !isprint(c) ){
+ fprintf(out, "\\%03o", c&0xff);
+ }else{
+ fputc(c, out);
+ }
+ }
+ fputc('"', out);
+}
+
+/*
+** Output the given string with characters that are special to
+** HTML escaped.
+*/
+static void output_html_string(FILE *out, const char *z){
+ int i;
+ while( *z ){
+ for(i=0; z[i]
+ && z[i]!='<'
+ && z[i]!='&'
+ && z[i]!='>'
+ && z[i]!='\"'
+ && z[i]!='\'';
+ i++){}
+ if( i>0 ){
+ fprintf(out,"%.*s",i,z);
+ }
+ if( z[i]=='<' ){
+ fprintf(out,"<");
+ }else if( z[i]=='&' ){
+ fprintf(out,"&");
+ }else if( z[i]=='>' ){
+ fprintf(out,">");
+ }else if( z[i]=='\"' ){
+ fprintf(out,""");
+ }else if( z[i]=='\'' ){
+ fprintf(out,"'");
+ }else{
+ break;
+ }
+ z += i + 1;
+ }
+}
+
+/*
+** If a field contains any character identified by a 1 in the following
+** array, then the string must be quoted for CSV.
+*/
+static const char needCsvQuote[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+/*
+** Output a single term of CSV. Actually, p->separator is used for
+** the separator, which may or may not be a comma. p->nullvalue is
+** the null value. Strings are quoted using ANSI-C rules. Numbers
+** appear outside of quotes.
+*/
+static void output_csv(struct callback_data *p, const char *z, int bSep){
+ FILE *out = p->out;
+ if( z==0 ){
+ fprintf(out,"%s",p->nullvalue);
+ }else{
+ int i;
+ int nSep = strlen30(p->separator);
+ for(i=0; z[i]; i++){
+ if( needCsvQuote[((unsigned char*)z)[i]]
+ || (z[i]==p->separator[0] &&
+ (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
+ i = 0;
+ break;
+ }
+ }
+ if( i==0 ){
+ putc('"', out);
+ for(i=0; z[i]; i++){
+ if( z[i]=='"' ) putc('"', out);
+ putc(z[i], out);
+ }
+ putc('"', out);
+ }else{
+ fprintf(out, "%s", z);
+ }
+ }
+ if( bSep ){
+ fprintf(p->out, "%s", p->separator);
+ }
+}
+
+#ifdef SIGINT
+/*
+** This routine runs when the user presses Ctrl-C
+*/
+static void interrupt_handler(int NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ seenInterrupt = 1;
+ if( db ) sqlite3_interrupt(db);
+}
+#endif
+
+/*
+** This is the callback routine that the shell
+** invokes for each row of a query result.
+*/
+static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
+ int i;
+ struct callback_data *p = (struct callback_data*)pArg;
+
+ switch( p->mode ){
+ case MODE_Line: {
+ int w = 5;
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ int len = strlen30(azCol[i] ? azCol[i] : "");
+ if( len>w ) w = len;
+ }
+ if( p->cnt++>0 ) fprintf(p->out,"\n");
+ for(i=0; i<nArg; i++){
+ fprintf(p->out,"%*s = %s\n", w, azCol[i],
+ azArg[i] ? azArg[i] : p->nullvalue);
+ }
+ break;
+ }
+ case MODE_Explain:
+ case MODE_Column: {
+ if( p->cnt++==0 ){
+ for(i=0; i<nArg; i++){
+ int w, n;
+ if( i<ArraySize(p->colWidth) ){
+ w = p->colWidth[i];
+ }else{
+ w = 0;
+ }
+ if( w<=0 ){
+ w = strlen30(azCol[i] ? azCol[i] : "");
+ if( w<10 ) w = 10;
+ n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
+ if( w<n ) w = n;
+ }
+ if( i<ArraySize(p->actualWidth) ){
+ p->actualWidth[i] = w;
+ }
+ if( p->showHeader ){
+ fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
+ }
+ }
+ if( p->showHeader ){
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ w = p->actualWidth[i];
+ }else{
+ w = 10;
+ }
+ fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
+ "----------------------------------------------------------",
+ i==nArg-1 ? "\n": " ");
+ }
+ }
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ int w;
+ if( i<ArraySize(p->actualWidth) ){
+ w = p->actualWidth[i];
+ }else{
+ w = 10;
+ }
+ if( p->mode==MODE_Explain && azArg[i] &&
+ strlen30(azArg[i])>w ){
+ w = strlen30(azArg[i]);
+ }
+ fprintf(p->out,"%-*.*s%s",w,w,
+ azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
+ }
+ break;
+ }
+ case MODE_Semi:
+ case MODE_List: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
+ }
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ char *z = azArg[i];
+ if( z==0 ) z = p->nullvalue;
+ fprintf(p->out, "%s", z);
+ if( i<nArg-1 ){
+ fprintf(p->out, "%s", p->separator);
+ }else if( p->mode==MODE_Semi ){
+ fprintf(p->out, ";\n");
+ }else{
+ fprintf(p->out, "\n");
+ }
+ }
+ break;
+ }
+ case MODE_Html: {
+ if( p->cnt++==0 && p->showHeader ){
+ fprintf(p->out,"<TR>");
+ for(i=0; i<nArg; i++){
+ fprintf(p->out,"<TH>");
+ output_html_string(p->out, azCol[i]);
+ fprintf(p->out,"</TH>\n");
+ }
+ fprintf(p->out,"</TR>\n");
+ }
+ if( azArg==0 ) break;
+ fprintf(p->out,"<TR>");
+ for(i=0; i<nArg; i++){
+ fprintf(p->out,"<TD>");
+ output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+ fprintf(p->out,"</TD>\n");
+ }
+ fprintf(p->out,"</TR>\n");
+ break;
+ }
+ case MODE_Tcl: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ output_c_string(p->out,azCol[i] ? azCol[i] : "");
+ fprintf(p->out, "%s", p->separator);
+ }
+ fprintf(p->out,"\n");
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
+ fprintf(p->out, "%s", p->separator);
+ }
+ fprintf(p->out,"\n");
+ break;
+ }
+ case MODE_Csv: {
+ if( p->cnt++==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
+ }
+ fprintf(p->out,"\n");
+ }
+ if( azArg==0 ) break;
+ for(i=0; i<nArg; i++){
+ output_csv(p, azArg[i], i<nArg-1);
+ }
+ fprintf(p->out,"\n");
+ break;
+ }
+ case MODE_Insert: {
+ p->cnt++;
+ if( azArg==0 ) break;
+ fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
+ for(i=0; i<nArg; i++){
+ char *zSep = i>0 ? ",": "";
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ fprintf(p->out,"%sNULL",zSep);
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ if( zSep[0] ) fprintf(p->out,"%s",zSep);
+ output_quoted_string(p->out, azArg[i]);
+ }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
+ fprintf(p->out,"%s%s",zSep, azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ if( zSep[0] ) fprintf(p->out,"%s",zSep);
+ output_hex_blob(p->out, pBlob, nBlob);
+ }else if( isNumber(azArg[i], 0) ){
+ fprintf(p->out,"%s%s",zSep, azArg[i]);
+ }else{
+ if( zSep[0] ) fprintf(p->out,"%s",zSep);
+ output_quoted_string(p->out, azArg[i]);
+ }
+ }
+ fprintf(p->out,");\n");
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+** This is the callback routine that the SQLite library
+** invokes for each row of a query result.
+*/
+static int callback(void *pArg, int nArg, char **azArg, char **azCol){
+ /* since we don't have type info, call the shell_callback with a NULL value */
+ return shell_callback(pArg, nArg, azArg, azCol, NULL);
+}
+
+/*
+** Set the destination table field of the callback_data structure to
+** the name of the table given. Escape any quote characters in the
+** table name.
+*/
+static void set_table_name(struct callback_data *p, const char *zName){
+ int i, n;
+ int needQuote;
+ char *z;
+
+ if( p->zDestTable ){
+ free(p->zDestTable);
+ p->zDestTable = 0;
+ }
+ if( zName==0 ) return;
+ needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
+ for(i=n=0; zName[i]; i++, n++){
+ if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
+ needQuote = 1;
+ if( zName[i]=='\'' ) n++;
+ }
+ }
+ if( needQuote ) n += 2;
+ z = p->zDestTable = malloc( n+1 );
+ if( z==0 ){
+ fprintf(stderr,"Error: out of memory\n");
+ exit(1);
+ }
+ n = 0;
+ if( needQuote ) z[n++] = '\'';
+ for(i=0; zName[i]; i++){
+ z[n++] = zName[i];
+ if( zName[i]=='\'' ) z[n++] = '\'';
+ }
+ if( needQuote ) z[n++] = '\'';
+ z[n] = 0;
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static char *appendText(char *zIn, char const *zAppend, char quote){
+ int len;
+ int i;
+ int nAppend = strlen30(zAppend);
+ int nIn = (zIn?strlen30(zIn):0);
+
+ len = nAppend+nIn+1;
+ if( quote ){
+ len += 2;
+ for(i=0; i<nAppend; i++){
+ if( zAppend[i]==quote ) len++;
+ }
+ }
+
+ zIn = (char *)realloc(zIn, len);
+ if( !zIn ){
+ return 0;
+ }
+
+ if( quote ){
+ char *zCsr = &zIn[nIn];
+ *zCsr++ = quote;
+ for(i=0; i<nAppend; i++){
+ *zCsr++ = zAppend[i];
+ if( zAppend[i]==quote ) *zCsr++ = quote;
+ }
+ *zCsr++ = quote;
+ *zCsr++ = '\0';
+ assert( (zCsr-zIn)==len );
+ }else{
+ memcpy(&zIn[nIn], zAppend, nAppend);
+ zIn[len-1] = '\0';
+ }
+
+ return zIn;
+}
+
+
+/*
+** Execute a query statement that has a single result column. Print
+** that result column on a line by itself with a semicolon terminator.
+**
+** This is used, for example, to show the schema of the database by
+** querying the SQLITE_MASTER table.
+*/
+static int run_table_dump_query(
+ FILE *out, /* Send output here */
+ sqlite3 *db, /* Database to query */
+ const char *zSelect, /* SELECT statement to extract content */
+ const char *zFirstRow /* Print before first row, if not NULL */
+){
+ sqlite3_stmt *pSelect;
+ int rc;
+ rc = sqlite3_prepare(db, zSelect, -1, &pSelect, 0);
+ if( rc!=SQLITE_OK || !pSelect ){
+ return rc;
+ }
+ rc = sqlite3_step(pSelect);
+ while( rc==SQLITE_ROW ){
+ if( zFirstRow ){
+ fprintf(out, "%s", zFirstRow);
+ zFirstRow = 0;
+ }
+ fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0));
+ rc = sqlite3_step(pSelect);
+ }
+ return sqlite3_finalize(pSelect);
+}
+
+/*
+** Allocate space and save off current error string.
+*/
+static char *save_err_msg(
+ sqlite3 *db /* Database to query */
+){
+ int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
+ char *zErrMsg = sqlite3_malloc(nErrMsg);
+ if( zErrMsg ){
+ memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
+ }
+ return zErrMsg;
+}
+
+/*
+** Execute a statement or set of statements. Print
+** any result rows/columns depending on the current mode
+** set via the supplied callback.
+**
+** This is very similar to SQLite's built-in sqlite3_exec()
+** function except it takes a slightly different callback
+** and callback data argument.
+*/
+static int shell_exec(
+ sqlite3 *db, /* An open database */
+ const char *zSql, /* SQL to be evaluated */
+ int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
+ /* (not the same as sqlite3_exec) */
+ struct callback_data *pArg, /* Pointer to struct callback_data */
+ char **pzErrMsg /* Error msg written here */
+){
+ sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
+ int rc = SQLITE_OK; /* Return Code */
+ const char *zLeftover; /* Tail of unprocessed SQL */
+
+ if( pzErrMsg ){
+ *pzErrMsg = NULL;
+ }
+
+ while( zSql[0] && (SQLITE_OK == rc) ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
+ if( SQLITE_OK != rc ){
+ if( pzErrMsg ){
+ *pzErrMsg = save_err_msg(db);
+ }
+ }else{
+ if( !pStmt ){
+ /* this happens for a comment or white-space */
+ zSql = zLeftover;
+ while( isspace(zSql[0]) ) zSql++;
+ continue;
+ }
+
+ /* echo the sql statement if echo on */
+ if( pArg->echoOn ){
+ const char *zStmtSql = sqlite3_sql(pStmt);
+ fprintf(pArg->out,"%s\n", zStmtSql ? zStmtSql : zSql);
+ }
+
+ /* perform the first step. this will tell us if we
+ ** have a result set or not and how wide it is.
+ */
+ rc = sqlite3_step(pStmt);
+ /* if we have a result set... */
+ if( SQLITE_ROW == rc ){
+ /* if we have a callback... */
+ if( xCallback ){
+ /* allocate space for col name ptr, value ptr, and type */
+ int nCol = sqlite3_column_count(pStmt);
+ void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
+ if( !pData ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char **azCols = (char **)pData; /* Names of result columns */
+ char **azVals = &azCols[nCol]; /* Results */
+ int *aiTypes = (int *)&azVals[nCol]; /* Result types */
+ int i;
+ assert(sizeof(int) <= sizeof(char *));
+ /* save off ptrs to column names */
+ for(i=0; i<nCol; i++){
+ azCols[i] = (char *)sqlite3_column_name(pStmt, i);
+ }
+ /* save off the prepared statment handle and reset row count */
+ if( pArg ){
+ pArg->pStmt = pStmt;
+ pArg->cnt = 0;
+ }
+ do{
+ /* extract the data and data types */
+ for(i=0; i<nCol; i++){
+ azVals[i] = (char *)sqlite3_column_text(pStmt, i);
+ aiTypes[i] = sqlite3_column_type(pStmt, i);
+ if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
+ rc = SQLITE_NOMEM;
+ break; /* from for */
+ }
+ } /* end for */
+
+ /* if data and types extracted successfully... */
+ if( SQLITE_ROW == rc ){
+ /* call the supplied callback with the result row data */
+ if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
+ rc = SQLITE_ABORT;
+ }else{
+ rc = sqlite3_step(pStmt);
+ }
+ }
+ } while( SQLITE_ROW == rc );
+ sqlite3_free(pData);
+ if( pArg ){
+ pArg->pStmt = NULL;
+ }
+ }
+ }else{
+ do{
+ rc = sqlite3_step(pStmt);
+ } while( rc == SQLITE_ROW );
+ }
+ }
+
+ /* Finalize the statement just executed. If this fails, save a
+ ** copy of the error message. Otherwise, set zSql to point to the
+ ** next statement to execute. */
+ rc = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ){
+ zSql = zLeftover;
+ while( isspace(zSql[0]) ) zSql++;
+ }else if( pzErrMsg ){
+ *pzErrMsg = save_err_msg(db);
+ }
+ }
+ } /* end while */
+
+ return rc;
+}
+
+
+/*
+** This is a different callback routine used for dumping the database.
+** Each row received by this callback consists of a table name,
+** the table type ("index" or "table") and SQL to create the table.
+** This routine should print text sufficient to recreate the table.
+*/
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
+ int rc;
+ const char *zTable;
+ const char *zType;
+ const char *zSql;
+ const char *zPrepStmt = 0;
+ struct callback_data *p = (struct callback_data *)pArg;
+
+ UNUSED_PARAMETER(azCol);
+ if( nArg!=3 ) return 1;
+ zTable = azArg[0];
+ zType = azArg[1];
+ zSql = azArg[2];
+
+ if( strcmp(zTable, "sqlite_sequence")==0 ){
+ zPrepStmt = "DELETE FROM sqlite_sequence;\n";
+ }else if( strcmp(zTable, "sqlite_stat1")==0 ){
+ fprintf(p->out, "ANALYZE sqlite_master;\n");
+ }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+ return 0;
+ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ char *zIns;
+ if( !p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=ON;\n");
+ p->writableSchema = 1;
+ }
+ zIns = sqlite3_mprintf(
+ "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "VALUES('table','%q','%q',0,'%q');",
+ zTable, zTable, zSql);
+ fprintf(p->out, "%s\n", zIns);
+ sqlite3_free(zIns);
+ return 0;
+ }else{
+ fprintf(p->out, "%s;\n", zSql);
+ }
+
+ if( strcmp(zType, "table")==0 ){
+ sqlite3_stmt *pTableInfo = 0;
+ char *zSelect = 0;
+ char *zTableInfo = 0;
+ char *zTmp = 0;
+ int nRow = 0;
+
+ zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
+ zTableInfo = appendText(zTableInfo, zTable, '"');
+ zTableInfo = appendText(zTableInfo, ");", 0);
+
+ rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
+ free(zTableInfo);
+ if( rc!=SQLITE_OK || !pTableInfo ){
+ return 1;
+ }
+
+ zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
+ zTmp = appendText(zTmp, zTable, '"');
+ if( zTmp ){
+ zSelect = appendText(zSelect, zTmp, '\'');
+ }
+ zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
+ rc = sqlite3_step(pTableInfo);
+ while( rc==SQLITE_ROW ){
+ const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
+ zSelect = appendText(zSelect, "quote(", 0);
+ zSelect = appendText(zSelect, zText, '"');
+ rc = sqlite3_step(pTableInfo);
+ if( rc==SQLITE_ROW ){
+ zSelect = appendText(zSelect, ") || ',' || ", 0);
+ }else{
+ zSelect = appendText(zSelect, ") ", 0);
+ }
+ nRow++;
+ }
+ rc = sqlite3_finalize(pTableInfo);
+ if( rc!=SQLITE_OK || nRow==0 ){
+ free(zSelect);
+ return 1;
+ }
+ zSelect = appendText(zSelect, "|| ')' FROM ", 0);
+ zSelect = appendText(zSelect, zTable, '"');
+
+ rc = run_table_dump_query(p->out, p->db, zSelect, zPrepStmt);
+ if( rc==SQLITE_CORRUPT ){
+ zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
+ rc = run_table_dump_query(p->out, p->db, zSelect, 0);
+ }
+ if( zSelect ) free(zSelect);
+ }
+ return 0;
+}
+
+/*
+** Run zQuery. Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
+** If we get a SQLITE_CORRUPT error, rerun the query after appending
+** "ORDER BY rowid DESC" to the end.
+*/
+static int run_schema_dump_query(
+ struct callback_data *p,
+ const char *zQuery,
+ char **pzErrMsg
+){
+ int rc;
+ rc = sqlite3_exec(p->db, zQuery, dump_callback, p, pzErrMsg);
+ if( rc==SQLITE_CORRUPT ){
+ char *zQ2;
+ int len = strlen30(zQuery);
+ if( pzErrMsg ) sqlite3_free(*pzErrMsg);
+ zQ2 = malloc( len+100 );
+ if( zQ2==0 ) return rc;
+ sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
+ rc = sqlite3_exec(p->db, zQ2, dump_callback, p, pzErrMsg);
+ free(zQ2);
+ }
+ return rc;
+}
+
+/*
+** Text of a help message
+*/
+static char zHelp[] =
+ ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
+ ".bail ON|OFF Stop after hitting an error. Default OFF\n"
+ ".databases List names and files of attached databases\n"
+ ".dump ?TABLE? ... Dump the database in an SQL text format\n"
+ " If TABLE specified, only dump tables matching\n"
+ " LIKE pattern TABLE.\n"
+ ".echo ON|OFF Turn command echo on or off\n"
+ ".exit Exit this program\n"
+ ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n"
+ " With no args, it turns EXPLAIN on.\n"
+ ".header(s) ON|OFF Turn display of headers on or off\n"
+ ".help Show this message\n"
+ ".import FILE TABLE Import data from FILE into TABLE\n"
+ ".indices ?TABLE? Show names of all indices\n"
+ " If TABLE specified, only show indices for tables\n"
+ " matching LIKE pattern TABLE.\n"
+#ifdef SQLITE_ENABLE_IOTRACE
+ ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
+#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ ".load FILE ?ENTRY? Load an extension library\n"
+#endif
+ ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
+ ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
+ " csv Comma-separated values\n"
+ " column Left-aligned columns. (See .width)\n"
+ " html HTML <table> code\n"
+ " insert SQL insert statements for TABLE\n"
+ " line One value per line\n"
+ " list Values delimited by .separator string\n"
+ " tabs Tab-separated values\n"
+ " tcl TCL list elements\n"
+ ".nullvalue STRING Print STRING in place of NULL values\n"
+ ".output FILENAME Send output to FILENAME\n"
+ ".output stdout Send output to the screen\n"
+ ".prompt MAIN CONTINUE Replace the standard prompts\n"
+ ".quit Exit this program\n"
+ ".read FILENAME Execute SQL in FILENAME\n"
+ ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
+ ".schema ?TABLE? Show the CREATE statements\n"
+ " If TABLE specified, only show tables matching\n"
+ " LIKE pattern TABLE.\n"
+ ".separator STRING Change separator used by output mode and .import\n"
+ ".show Show the current values for various settings\n"
+ ".tables ?TABLE? List names of tables\n"
+ " If TABLE specified, only list tables matching\n"
+ " LIKE pattern TABLE.\n"
+ ".timeout MS Try opening locked tables for MS milliseconds\n"
+ ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
+;
+
+static char zTimerHelp[] =
+ ".timer ON|OFF Turn the CPU timer measurement on or off\n"
+;
+
+/* Forward reference */
+static int process_input(struct callback_data *p, FILE *in);
+
+/*
+** Make sure the database is open. If it is not, then open it. If
+** the database fails to open, print an error message and exit.
+*/
+static void open_db(struct callback_data *p){
+ if( p->db==0 ){
+ sqlite3_open(p->zDbFilename, &p->db);
+ db = p->db;
+ if( db && sqlite3_errcode(db)==SQLITE_OK ){
+ sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
+ shellstaticFunc, 0, 0);
+ }
+ if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
+ fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
+ p->zDbFilename, sqlite3_errmsg(db));
+ exit(1);
+ }
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ sqlite3_enable_load_extension(p->db, 1);
+#endif
+ }
+}
+
+/*
+** Do C-language style dequoting.
+**
+** \t -> tab
+** \n -> newline
+** \r -> carriage return
+** \NNN -> ascii character NNN in octal
+** \\ -> backslash
+*/
+static void resolve_backslashes(char *z){
+ int i, j;
+ char c;
+ for(i=j=0; (c = z[i])!=0; i++, j++){
+ if( c=='\\' ){
+ c = z[++i];
+ if( c=='n' ){
+ c = '\n';
+ }else if( c=='t' ){
+ c = '\t';
+ }else if( c=='r' ){
+ c = '\r';
+ }else if( c>='0' && c<='7' ){
+ c -= '0';
+ if( z[i+1]>='0' && z[i+1]<='7' ){
+ i++;
+ c = (c<<3) + z[i] - '0';
+ if( z[i+1]>='0' && z[i+1]<='7' ){
+ i++;
+ c = (c<<3) + z[i] - '0';
+ }
+ }
+ }
+ }
+ z[j] = c;
+ }
+ z[j] = 0;
+}
+
+/*
+** Interpret zArg as a boolean value. Return either 0 or 1.
+*/
+static int booleanValue(char *zArg){
+ int val = atoi(zArg);
+ int j;
+ for(j=0; zArg[j]; j++){
+ zArg[j] = (char)tolower(zArg[j]);
+ }
+ if( strcmp(zArg,"on")==0 ){
+ val = 1;
+ }else if( strcmp(zArg,"yes")==0 ){
+ val = 1;
+ }
+ return val;
+}
+
+/*
+** If an input line begins with "." then invoke this routine to
+** process that line.
+**
+** Return 1 on error, 2 to exit, and 0 otherwise.
+*/
+static int do_meta_command(char *zLine, struct callback_data *p){
+ int i = 1;
+ int nArg = 0;
+ int n, c;
+ int rc = 0;
+ char *azArg[50];
+
+ /* Parse the input line into tokens.
+ */
+ while( zLine[i] && nArg<ArraySize(azArg) ){
+ while( isspace((unsigned char)zLine[i]) ){ i++; }
+ if( zLine[i]==0 ) break;
+ if( zLine[i]=='\'' || zLine[i]=='"' ){
+ int delim = zLine[i++];
+ azArg[nArg++] = &zLine[i];
+ while( zLine[i] && zLine[i]!=delim ){ i++; }
+ if( zLine[i]==delim ){
+ zLine[i++] = 0;
+ }
+ if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
+ }else{
+ azArg[nArg++] = &zLine[i];
+ while( zLine[i] && !isspace((unsigned char)zLine[i]) ){ i++; }
+ if( zLine[i] ) zLine[i++] = 0;
+ resolve_backslashes(azArg[nArg-1]);
+ }
+ }
+
+ /* Process the input line.
+ */
+ if( nArg==0 ) return 0; /* no tokens, no error */
+ n = strlen30(azArg[0]);
+ c = azArg[0][0];
+ if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
+ const char *zDestFile;
+ const char *zDb;
+ sqlite3 *pDest;
+ sqlite3_backup *pBackup;
+ if( nArg==2 ){
+ zDestFile = azArg[1];
+ zDb = "main";
+ }else{
+ zDestFile = azArg[2];
+ zDb = azArg[1];
+ }
+ rc = sqlite3_open(zDestFile, &pDest);
+ if( rc!=SQLITE_OK ){
+ fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
+ sqlite3_close(pDest);
+ return 1;
+ }
+ open_db(p);
+ pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
+ if( pBackup==0 ){
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
+ sqlite3_close(pDest);
+ return 1;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = 0;
+ }else{
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
+ rc = 1;
+ }
+ sqlite3_close(pDest);
+ }else
+
+ if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
+ bail_on_error = booleanValue(azArg[1]);
+ }else
+
+ if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
+ struct callback_data data;
+ char *zErrMsg = 0;
+ open_db(p);
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 1;
+ data.mode = MODE_Column;
+ data.colWidth[0] = 3;
+ data.colWidth[1] = 15;
+ data.colWidth[2] = 58;
+ data.cnt = 0;
+ sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
+ if( zErrMsg ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }
+ }else
+
+ if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
+ char *zErrMsg = 0;
+ open_db(p);
+ /* When playing back a "dump", the content might appear in an order
+ ** which causes immediate foreign key constraints to be violated.
+ ** So disable foreign-key constraint enforcement to prevent problems. */
+ fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
+ fprintf(p->out, "BEGIN TRANSACTION;\n");
+ p->writableSchema = 0;
+ sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0);
+ if( nArg==1 ){
+ run_schema_dump_query(p,
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0
+ );
+ run_schema_dump_query(p,
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE name=='sqlite_sequence'", 0
+ );
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
+ );
+ }else{
+ int i;
+ for(i=1; i<nArg; i++){
+ zShellStatic = azArg[i];
+ run_schema_dump_query(p,
+ "SELECT name, type, sql FROM sqlite_master "
+ "WHERE tbl_name LIKE shellstatic() AND type=='table'"
+ " AND sql NOT NULL", 0);
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL"
+ " AND type IN ('index','trigger','view')"
+ " AND tbl_name LIKE shellstatic()", 0
+ );
+ zShellStatic = 0;
+ }
+ }
+ if( p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
+ p->writableSchema = 0;
+ }
+ sqlite3_exec(p->db, "PRAGMA writable_schema=OFF", 0, 0, 0);
+ if( zErrMsg ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ }else{
+ fprintf(p->out, "COMMIT;\n");
+ }
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
+ p->echoOn = booleanValue(azArg[1]);
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){
+ rc = 2;
+ }else
+
+ if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
+ int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
+ if(val == 1) {
+ if(!p->explainPrev.valid) {
+ p->explainPrev.valid = 1;
+ p->explainPrev.mode = p->mode;
+ p->explainPrev.showHeader = p->showHeader;
+ memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
+ }
+ /* We could put this code under the !p->explainValid
+ ** condition so that it does not execute if we are already in
+ ** explain mode. However, always executing it allows us an easy
+ ** was to reset to explain mode in case the user previously
+ ** did an .explain followed by a .width, .mode or .header
+ ** command.
+ */
+ p->mode = MODE_Explain;
+ p->showHeader = 1;
+ memset(p->colWidth,0,ArraySize(p->colWidth));
+ p->colWidth[0] = 4; /* addr */
+ p->colWidth[1] = 13; /* opcode */
+ p->colWidth[2] = 4; /* P1 */
+ p->colWidth[3] = 4; /* P2 */
+ p->colWidth[4] = 4; /* P3 */
+ p->colWidth[5] = 13; /* P4 */
+ p->colWidth[6] = 2; /* P5 */
+ p->colWidth[7] = 13; /* Comment */
+ }else if (p->explainPrev.valid) {
+ p->explainPrev.valid = 0;
+ p->mode = p->explainPrev.mode;
+ p->showHeader = p->explainPrev.showHeader;
+ memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
+ }
+ }else
+
+ if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
+ strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
+ p->showHeader = booleanValue(azArg[1]);
+ }else
+
+ if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+ fprintf(stderr,"%s",zHelp);
+ if( HAS_TIMER ){
+ fprintf(stderr,"%s",zTimerHelp);
+ }
+ }else
+
+ if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
+ char *zTable = azArg[2]; /* Insert data into this table */
+ char *zFile = azArg[1]; /* The file from which to extract data */
+ sqlite3_stmt *pStmt = NULL; /* A statement */
+ int nCol; /* Number of columns in the table */
+ int nByte; /* Number of bytes in an SQL string */
+ int i, j; /* Loop counters */
+ int nSep; /* Number of bytes in p->separator[] */
+ char *zSql; /* An SQL statement */
+ char *zLine; /* A single line of input from the file */
+ char **azCol; /* zLine[] broken up into columns */
+ char *zCommit; /* How to commit changes */
+ FILE *in; /* The input file */
+ int lineno = 0; /* Line number of input file */
+
+ open_db(p);
+ nSep = strlen30(p->separator);
+ if( nSep==0 ){
+ fprintf(stderr, "Error: non-null separator required for import\n");
+ return 1;
+ }
+ zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
+ if( zSql==0 ){
+ fprintf(stderr, "Error: out of memory\n");
+ return 1;
+ }
+ nByte = strlen30(zSql);
+ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ if (pStmt) sqlite3_finalize(pStmt);
+ fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+ return 1;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( nCol==0 ) return 0; /* no columns, no error */
+ zSql = malloc( nByte + 20 + nCol*2 );
+ if( zSql==0 ){
+ fprintf(stderr, "Error: out of memory\n");
+ return 1;
+ }
+ sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable);
+ j = strlen30(zSql);
+ for(i=1; i<nCol; i++){
+ zSql[j++] = ',';
+ zSql[j++] = '?';
+ }
+ zSql[j++] = ')';
+ zSql[j] = 0;
+ rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
+ free(zSql);
+ if( rc ){
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
+ if (pStmt) sqlite3_finalize(pStmt);
+ return 1;
+ }
+ in = fopen(zFile, "rb");
+ if( in==0 ){
+ fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
+ sqlite3_finalize(pStmt);
+ return 1;
+ }
+ azCol = malloc( sizeof(azCol[0])*(nCol+1) );
+ if( azCol==0 ){
+ fprintf(stderr, "Error: out of memory\n");
+ fclose(in);
+ sqlite3_finalize(pStmt);
+ return 1;
+ }
+ sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
+ zCommit = "COMMIT";
+ while( (zLine = local_getline(0, in))!=0 ){
+ char *z;
+ i = 0;
+ lineno++;
+ azCol[0] = zLine;
+ for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
+ if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
+ *z = 0;
+ i++;
+ if( i<nCol ){
+ azCol[i] = &z[nSep];
+ z += nSep-1;
+ }
+ }
+ } /* end for */
+ *z = 0;
+ if( i+1!=nCol ){
+ fprintf(stderr,
+ "Error: %s line %d: expected %d columns of data but found %d\n",
+ zFile, lineno, nCol, i+1);
+ zCommit = "ROLLBACK";
+ free(zLine);
+ rc = 1;
+ break; /* from while */
+ }
+ for(i=0; i<nCol; i++){
+ sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
+ }
+ sqlite3_step(pStmt);
+ rc = sqlite3_reset(pStmt);
+ free(zLine);
+ if( rc!=SQLITE_OK ){
+ fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
+ zCommit = "ROLLBACK";
+ rc = 1;
+ break; /* from while */
+ }
+ } /* end while */
+ free(azCol);
+ fclose(in);
+ sqlite3_finalize(pStmt);
+ sqlite3_exec(p->db, zCommit, 0, 0, 0);
+ }else
+
+ if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
+ struct callback_data data;
+ char *zErrMsg = 0;
+ open_db(p);
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 0;
+ data.mode = MODE_List;
+ if( nArg==1 ){
+ rc = sqlite3_exec(p->db,
+ "SELECT name FROM sqlite_master "
+ "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
+ "UNION ALL "
+ "SELECT name FROM sqlite_temp_master "
+ "WHERE type='index' "
+ "ORDER BY 1",
+ callback, &data, &zErrMsg
+ );
+ }else{
+ zShellStatic = azArg[1];
+ rc = sqlite3_exec(p->db,
+ "SELECT name FROM sqlite_master "
+ "WHERE type='index' AND tbl_name LIKE shellstatic() "
+ "UNION ALL "
+ "SELECT name FROM sqlite_temp_master "
+ "WHERE type='index' AND tbl_name LIKE shellstatic() "
+ "ORDER BY 1",
+ callback, &data, &zErrMsg
+ );
+ zShellStatic = 0;
+ }
+ if( zErrMsg ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }else if( rc != SQLITE_OK ){
+ fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
+ rc = 1;
+ }
+ }else
+
+#ifdef SQLITE_ENABLE_IOTRACE
+ if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+ extern void (*sqlite3IoTrace)(const char*, ...);
+ if( iotrace && iotrace!=stdout ) fclose(iotrace);
+ iotrace = 0;
+ if( nArg<2 ){
+ sqlite3IoTrace = 0;
+ }else if( strcmp(azArg[1], "-")==0 ){
+ sqlite3IoTrace = iotracePrintf;
+ iotrace = stdout;
+ }else{
+ iotrace = fopen(azArg[1], "w");
+ if( iotrace==0 ){
+ fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
+ sqlite3IoTrace = 0;
+ rc = 1;
+ }else{
+ sqlite3IoTrace = iotracePrintf;
+ }
+ }
+ }else
+#endif
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
+ const char *zFile, *zProc;
+ char *zErrMsg = 0;
+ zFile = azArg[1];
+ zProc = nArg>=3 ? azArg[2] : 0;
+ open_db(p);
+ rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
+ if( rc!=SQLITE_OK ){
+ fprintf(stderr, "Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }
+ }else
+#endif
+
+ if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=1 ){
+ const char *zFile = azArg[1];
+ if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
+ fclose(p->pLog);
+ p->pLog = 0;
+ }
+ if( strcmp(zFile,"stdout")==0 ){
+ p->pLog = stdout;
+ }else if( strcmp(zFile, "stderr")==0 ){
+ p->pLog = stderr;
+ }else if( strcmp(zFile, "off")==0 ){
+ p->pLog = 0;
+ }else{
+ p->pLog = fopen(zFile, "w");
+ if( p->pLog==0 ){
+ fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
+ }
+ }
+ }else
+
+ if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
+ int n2 = strlen30(azArg[1]);
+ if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
+ ||
+ (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
+ p->mode = MODE_Line;
+ }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
+ ||
+ (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
+ p->mode = MODE_Column;
+ }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
+ p->mode = MODE_List;
+ }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
+ p->mode = MODE_Html;
+ }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
+ p->mode = MODE_Tcl;
+ }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
+ p->mode = MODE_Csv;
+ sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
+ }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
+ p->mode = MODE_List;
+ sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
+ }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
+ p->mode = MODE_Insert;
+ set_table_name(p, "table");
+ }else {
+ fprintf(stderr,"Error: mode should be one of: "
+ "column csv html insert line list tabs tcl\n");
+ rc = 1;
+ }
+ }else
+
+ if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
+ int n2 = strlen30(azArg[1]);
+ if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
+ p->mode = MODE_Insert;
+ set_table_name(p, azArg[2]);
+ }else {
+ fprintf(stderr, "Error: invalid arguments: "
+ " \"%s\". Enter \".help\" for help\n", azArg[2]);
+ rc = 1;
+ }
+ }else
+
+ if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
+ sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
+ "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
+ }else
+
+ if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
+ if( p->out!=stdout ){
+ fclose(p->out);
+ }
+ if( strcmp(azArg[1],"stdout")==0 ){
+ p->out = stdout;
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
+ }else{
+ p->out = fopen(azArg[1], "wb");
+ if( p->out==0 ){
+ fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
+ p->out = stdout;
+ rc = 1;
+ } else {
+ sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
+ }
+ }
+ }else
+
+ if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
+ if( nArg >= 2) {
+ strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
+ }
+ if( nArg >= 3) {
+ strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
+ }
+ }else
+
+ if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
+ rc = 2;
+ }else
+
+ if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
+ FILE *alt = fopen(azArg[1], "rb");
+ if( alt==0 ){
+ fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
+ rc = 1;
+ }else{
+ rc = process_input(p, alt);
+ fclose(alt);
+ }
+ }else
+
+ if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
+ const char *zSrcFile;
+ const char *zDb;
+ sqlite3 *pSrc;
+ sqlite3_backup *pBackup;
+ int nTimeout = 0;
+
+ if( nArg==2 ){
+ zSrcFile = azArg[1];
+ zDb = "main";
+ }else{
+ zSrcFile = azArg[2];
+ zDb = azArg[1];
+ }
+ rc = sqlite3_open(zSrcFile, &pSrc);
+ if( rc!=SQLITE_OK ){
+ fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
+ sqlite3_close(pSrc);
+ return 1;
+ }
+ open_db(p);
+ pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
+ if( pBackup==0 ){
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_close(pSrc);
+ return 1;
+ }
+ while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
+ || rc==SQLITE_BUSY ){
+ if( rc==SQLITE_BUSY ){
+ if( nTimeout++ >= 3 ) break;
+ sqlite3_sleep(100);
+ }
+ }
+ sqlite3_backup_finish(pBackup);
+ if( rc==SQLITE_DONE ){
+ rc = 0;
+ }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
+ fprintf(stderr, "Error: source database is busy\n");
+ rc = 1;
+ }else{
+ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ rc = 1;
+ }
+ sqlite3_close(pSrc);
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
+ struct callback_data data;
+ char *zErrMsg = 0;
+ open_db(p);
+ memcpy(&data, p, sizeof(data));
+ data.showHeader = 0;
+ data.mode = MODE_Semi;
+ if( nArg>1 ){
+ int i;
+ for(i=0; azArg[1][i]; i++) azArg[1][i] = (char)tolower(azArg[1][i]);
+ if( strcmp(azArg[1],"sqlite_master")==0 ){
+ char *new_argv[2], *new_colv[2];
+ new_argv[0] = "CREATE TABLE sqlite_master (\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")";
+ new_argv[1] = 0;
+ new_colv[0] = "sql";
+ new_colv[1] = 0;
+ callback(&data, 1, new_argv, new_colv);
+ rc = SQLITE_OK;
+ }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+ char *new_argv[2], *new_colv[2];
+ new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+ " type text,\n"
+ " name text,\n"
+ " tbl_name text,\n"
+ " rootpage integer,\n"
+ " sql text\n"
+ ")";
+ new_argv[1] = 0;
+ new_colv[0] = "sql";
+ new_colv[1] = 0;
+ callback(&data, 1, new_argv, new_colv);
+ rc = SQLITE_OK;
+ }else{
+ zShellStatic = azArg[1];
+ rc = sqlite3_exec(p->db,
+ "SELECT sql FROM "
+ " (SELECT sql sql, type type, tbl_name tbl_name, name name"
+ " FROM sqlite_master UNION ALL"
+ " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
+ "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL "
+ "ORDER BY substr(type,2,1), name",
+ callback, &data, &zErrMsg);
+ zShellStatic = 0;
+ }
+ }else{
+ rc = sqlite3_exec(p->db,
+ "SELECT sql FROM "
+ " (SELECT sql sql, type type, tbl_name tbl_name, name name"
+ " FROM sqlite_master UNION ALL"
+ " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
+ "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
+ "ORDER BY substr(type,2,1), name",
+ callback, &data, &zErrMsg
+ );
+ }
+ if( zErrMsg ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }else if( rc != SQLITE_OK ){
+ fprintf(stderr,"Error: querying schema information\n");
+ rc = 1;
+ }else{
+ rc = 0;
+ }
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
+ sqlite3_snprintf(sizeof(p->separator), p->separator,
+ "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
+ }else
+
+ if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
+ int i;
+ fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
+ fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
+ fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
+ fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
+ fprintf(p->out,"%9.9s: ", "nullvalue");
+ output_c_string(p->out, p->nullvalue);
+ fprintf(p->out, "\n");
+ fprintf(p->out,"%9.9s: %s\n","output",
+ strlen30(p->outfile) ? p->outfile : "stdout");
+ fprintf(p->out,"%9.9s: ", "separator");
+ output_c_string(p->out, p->separator);
+ fprintf(p->out, "\n");
+ fprintf(p->out,"%9.9s: ","width");
+ for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+ fprintf(p->out,"%d ",p->colWidth[i]);
+ }
+ fprintf(p->out,"\n");
+ }else
+
+ if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
+ char **azResult;
+ int nRow;
+ char *zErrMsg;
+ open_db(p);
+ if( nArg==1 ){
+ rc = sqlite3_get_table(p->db,
+ "SELECT name FROM sqlite_master "
+ "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
+ "UNION ALL "
+ "SELECT name FROM sqlite_temp_master "
+ "WHERE type IN ('table','view') "
+ "ORDER BY 1",
+ &azResult, &nRow, 0, &zErrMsg
+ );
+ }else{
+ zShellStatic = azArg[1];
+ rc = sqlite3_get_table(p->db,
+ "SELECT name FROM sqlite_master "
+ "WHERE type IN ('table','view') AND name LIKE shellstatic() "
+ "UNION ALL "
+ "SELECT name FROM sqlite_temp_master "
+ "WHERE type IN ('table','view') AND name LIKE shellstatic() "
+ "ORDER BY 1",
+ &azResult, &nRow, 0, &zErrMsg
+ );
+ zShellStatic = 0;
+ }
+ if( zErrMsg ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ rc = 1;
+ }else if( rc != SQLITE_OK ){
+ fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
+ rc = 1;
+ }else{
+ int len, maxlen = 0;
+ int i, j;
+ int nPrintCol, nPrintRow;
+ for(i=1; i<=nRow; i++){
+ if( azResult[i]==0 ) continue;
+ len = strlen30(azResult[i]);
+ if( len>maxlen ) maxlen = len;
+ }
+ nPrintCol = 80/(maxlen+2);
+ if( nPrintCol<1 ) nPrintCol = 1;
+ nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
+ for(i=0; i<nPrintRow; i++){
+ for(j=i+1; j<=nRow; j+=nPrintRow){
+ char *zSp = j<=nPrintRow ? "" : " ";
+ printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
+ }
+ printf("\n");
+ }
+ }
+ sqlite3_free_table(azResult);
+ }else
+
+ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
+ open_db(p);
+ sqlite3_busy_timeout(p->db, atoi(azArg[1]));
+ }else
+
+ if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){
+ enableTimer = booleanValue(azArg[1]);
+ }else
+
+ if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
+ int j;
+ assert( nArg<=ArraySize(azArg) );
+ for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+ p->colWidth[j-1] = atoi(azArg[j]);
+ }
+ }else
+
+ {
+ fprintf(stderr, "Error: unknown command or invalid arguments: "
+ " \"%s\". Enter \".help\" for help\n", azArg[0]);
+ rc = 1;
+ }
+
+ return rc;
+}
+
+/*
+** Return TRUE if a semicolon occurs anywhere in the first N characters
+** of string z[].
+*/
+static int _contains_semicolon(const char *z, int N){
+ int i;
+ for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
+ return 0;
+}
+
+/*
+** Test to see if a line consists entirely of whitespace.
+*/
+static int _all_whitespace(const char *z){
+ for(; *z; z++){
+ if( isspace(*(unsigned char*)z) ) continue;
+ if( *z=='/' && z[1]=='*' ){
+ z += 2;
+ while( *z && (*z!='*' || z[1]!='/') ){ z++; }
+ if( *z==0 ) return 0;
+ z++;
+ continue;
+ }
+ if( *z=='-' && z[1]=='-' ){
+ z += 2;
+ while( *z && *z!='\n' ){ z++; }
+ if( *z==0 ) return 1;
+ continue;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Return TRUE if the line typed in is an SQL command terminator other
+** than a semi-colon. The SQL Server style "go" command is understood
+** as is the Oracle "/".
+*/
+static int _is_command_terminator(const char *zLine){
+ while( isspace(*(unsigned char*)zLine) ){ zLine++; };
+ if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
+ return 1; /* Oracle */
+ }
+ if( tolower(zLine[0])=='g' && tolower(zLine[1])=='o'
+ && _all_whitespace(&zLine[2]) ){
+ return 1; /* SQL Server */
+ }
+ return 0;
+}
+
+/*
+** Return true if zSql is a complete SQL statement. Return false if it
+** ends in the middle of a string literal or C-style comment.
+*/
+static int _is_complete(char *zSql, int nSql){
+ int rc;
+ if( zSql==0 ) return 1;
+ zSql[nSql] = ';';
+ zSql[nSql+1] = 0;
+ rc = sqlite3_complete(zSql);
+ zSql[nSql] = 0;
+ return rc;
+}
+
+/*
+** Read input from *in and process it. If *in==0 then input
+** is interactive - the user is typing it it. Otherwise, input
+** is coming from a file or device. A prompt is issued and history
+** is saved only if input is interactive. An interrupt signal will
+** cause this routine to exit immediately, unless input is interactive.
+**
+** Return the number of errors.
+*/
+static int process_input(struct callback_data *p, FILE *in){
+ char *zLine = 0;
+ char *zSql = 0;
+ int nSql = 0;
+ int nSqlPrior = 0;
+ char *zErrMsg;
+ int rc;
+ int errCnt = 0;
+ int lineno = 0;
+ int startline = 0;
+
+ while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ fflush(p->out);
+ free(zLine);
+ zLine = one_input_line(zSql, in);
+ if( zLine==0 ){
+ break; /* We have reached EOF */
+ }
+ if( seenInterrupt ){
+ if( in!=0 ) break;
+ seenInterrupt = 0;
+ }
+ lineno++;
+ if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
+ if( zLine && zLine[0]=='.' && nSql==0 ){
+ if( p->echoOn ) printf("%s\n", zLine);
+ rc = do_meta_command(zLine, p);
+ if( rc==2 ){ /* exit requested */
+ break;
+ }else if( rc ){
+ errCnt++;
+ }
+ continue;
+ }
+ if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
+ memcpy(zLine,";",2);
+ }
+ nSqlPrior = nSql;
+ if( zSql==0 ){
+ int i;
+ for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){}
+ if( zLine[i]!=0 ){
+ nSql = strlen30(zLine);
+ zSql = malloc( nSql+3 );
+ if( zSql==0 ){
+ fprintf(stderr, "Error: out of memory\n");
+ exit(1);
+ }
+ memcpy(zSql, zLine, nSql+1);
+ startline = lineno;
+ }
+ }else{
+ int len = strlen30(zLine);
+ zSql = realloc( zSql, nSql + len + 4 );
+ if( zSql==0 ){
+ fprintf(stderr,"Error: out of memory\n");
+ exit(1);
+ }
+ zSql[nSql++] = '\n';
+ memcpy(&zSql[nSql], zLine, len+1);
+ nSql += len;
+ }
+ if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
+ && sqlite3_complete(zSql) ){
+ p->cnt = 0;
+ open_db(p);
+ BEGIN_TIMER;
+ rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
+ END_TIMER;
+ if( rc || zErrMsg ){
+ char zPrefix[100];
+ if( in!=0 || !stdin_is_interactive ){
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix,
+ "Error: near line %d:", startline);
+ }else{
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
+ }
+ if( zErrMsg!=0 ){
+ fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
+ sqlite3_free(zErrMsg);
+ zErrMsg = 0;
+ }else{
+ fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
+ }
+ errCnt++;
+ }
+ free(zSql);
+ zSql = 0;
+ nSql = 0;
+ }
+ }
+ if( zSql ){
+ if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
+ free(zSql);
+ }
+ free(zLine);
+ return errCnt;
+}
+
+/*
+** Return a pathname which is the user's home directory. A
+** 0 return indicates an error of some kind. Space to hold the
+** resulting string is obtained from malloc(). The calling
+** function should free the result.
+*/
+static char *find_home_dir(void){
+ char *home_dir = NULL;
+
+#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
+ struct passwd *pwent;
+ uid_t uid = getuid();
+ if( (pwent=getpwuid(uid)) != NULL) {
+ home_dir = pwent->pw_dir;
+ }
+#endif
+
+#if defined(_WIN32_WCE)
+ /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
+ */
+ home_dir = strdup("/");
+#else
+
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+ if (!home_dir) {
+ home_dir = getenv("USERPROFILE");
+ }
+#endif
+
+ if (!home_dir) {
+ home_dir = getenv("HOME");
+ }
+
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+ if (!home_dir) {
+ char *zDrive, *zPath;
+ int n;
+ zDrive = getenv("HOMEDRIVE");
+ zPath = getenv("HOMEPATH");
+ if( zDrive && zPath ){
+ n = strlen30(zDrive) + strlen30(zPath) + 1;
+ home_dir = malloc( n );
+ if( home_dir==0 ) return 0;
+ sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
+ return home_dir;
+ }
+ home_dir = "c:\\";
+ }
+#endif
+
+#endif /* !_WIN32_WCE */
+
+ if( home_dir ){
+ int n = strlen30(home_dir) + 1;
+ char *z = malloc( n );
+ if( z ) memcpy(z, home_dir, n);
+ home_dir = z;
+ }
+
+ return home_dir;
+}
+
+/*
+** Read input from the file given by sqliterc_override. Or if that
+** parameter is NULL, take input from ~/.sqliterc
+**
+** Returns the number of errors.
+*/
+static int process_sqliterc(
+ struct callback_data *p, /* Configuration data */
+ const char *sqliterc_override /* Name of config file. NULL to use default */
+){
+ char *home_dir = NULL;
+ const char *sqliterc = sqliterc_override;
+ char *zBuf = 0;
+ FILE *in = NULL;
+ int nBuf;
+ int rc = 0;
+
+ if (sqliterc == NULL) {
+ home_dir = find_home_dir();
+ if( home_dir==0 ){
+#if !defined(__RTP__) && !defined(_WRS_KERNEL)
+ fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
+#endif
+ return 1;
+ }
+ nBuf = strlen30(home_dir) + 16;
+ zBuf = malloc( nBuf );
+ if( zBuf==0 ){
+ fprintf(stderr,"%s: Error: out of memory\n",Argv0);
+ return 1;
+ }
+ sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
+ free(home_dir);
+ sqliterc = (const char*)zBuf;
+ }
+ in = fopen(sqliterc,"rb");
+ if( in ){
+ if( stdin_is_interactive ){
+ fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
+ }
+ rc = process_input(p,in);
+ fclose(in);
+ }
+ free(zBuf);
+ return rc;
+}
+
+/*
+** Show available command line options
+*/
+static const char zOptions[] =
+ " -help show this message\n"
+ " -init filename read/process named file\n"
+ " -echo print commands before execution\n"
+ " -[no]header turn headers on or off\n"
+ " -bail stop after hitting an error\n"
+ " -interactive force interactive I/O\n"
+ " -batch force batch I/O\n"
+ " -column set output mode to 'column'\n"
+ " -csv set output mode to 'csv'\n"
+ " -html set output mode to HTML\n"
+ " -line set output mode to 'line'\n"
+ " -list set output mode to 'list'\n"
+ " -separator 'x' set output field separator (|)\n"
+ " -nullvalue 'text' set text string for NULL values\n"
+ " -version show SQLite version\n"
+;
+static void usage(int showDetail){
+ fprintf(stderr,
+ "Usage: %s [OPTIONS] FILENAME [SQL]\n"
+ "FILENAME is the name of an SQLite database. A new database is created\n"
+ "if the file does not previously exist.\n", Argv0);
+ if( showDetail ){
+ fprintf(stderr, "OPTIONS include:\n%s", zOptions);
+ }else{
+ fprintf(stderr, "Use the -help option for additional information\n");
+ }
+ exit(1);
+}
+
+/*
+** Initialize the state information in data
+*/
+static void main_init(struct callback_data *data) {
+ memset(data, 0, sizeof(*data));
+ data->mode = MODE_List;
+ memcpy(data->separator,"|", 2);
+ data->showHeader = 0;
+ sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
+ sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
+ sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
+ sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
+}
+
+int main(int argc, char **argv){
+ char *zErrMsg = 0;
+ struct callback_data data;
+ const char *zInitFile = 0;
+ char *zFirstCmd = 0;
+ int i;
+ int rc = 0;
+
+ Argv0 = argv[0];
+ main_init(&data);
+ stdin_is_interactive = isatty(0);
+
+ /* Make sure we have a valid signal handler early, before anything
+ ** else is done.
+ */
+#ifdef SIGINT
+ signal(SIGINT, interrupt_handler);
+#endif
+
+ /* Do an initial pass through the command-line argument to locate
+ ** the name of the database file, the name of the initialization file,
+ ** and the first command to execute.
+ */
+ for(i=1; i<argc-1; i++){
+ char *z;
+ if( argv[i][0]!='-' ) break;
+ z = argv[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
+ i++;
+ }else if( strcmp(argv[i],"-init")==0 ){
+ i++;
+ zInitFile = argv[i];
+ /* Need to check for batch mode here to so we can avoid printing
+ ** informational messages (like from process_sqliterc) before
+ ** we do the actual processing of arguments later in a second pass.
+ */
+ }else if( strcmp(argv[i],"-batch")==0 ){
+ stdin_is_interactive = 0;
+ }
+ }
+ if( i<argc ){
+#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
+ data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
+#else
+ data.zDbFilename = argv[i++];
+#endif
+ }else{
+#ifndef SQLITE_OMIT_MEMORYDB
+ data.zDbFilename = ":memory:";
+#else
+ data.zDbFilename = 0;
+#endif
+ }
+ if( i<argc ){
+ zFirstCmd = argv[i++];
+ }
+ if( i<argc ){
+ fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
+ fprintf(stderr,"Use -help for a list of options.\n");
+ return 1;
+ }
+ data.out = stdout;
+
+#ifdef SQLITE_OMIT_MEMORYDB
+ if( data.zDbFilename==0 ){
+ fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
+ return 1;
+ }
+#endif
+
+ /* Go ahead and open the database file if it already exists. If the
+ ** file does not exist, delay opening it. This prevents empty database
+ ** files from being created if a user mistypes the database name argument
+ ** to the sqlite command-line tool.
+ */
+ if( access(data.zDbFilename, 0)==0 ){
+ open_db(&data);
+ }
+
+ /* Process the initialization file if there is one. If no -init option
+ ** is given on the command line, look for a file named ~/.sqliterc and
+ ** try to process it.
+ */
+ rc = process_sqliterc(&data,zInitFile);
+ if( rc>0 ){
+ return rc;
+ }
+
+ /* Make a second pass through the command-line argument and set
+ ** options. This second pass is delayed until after the initialization
+ ** file is processed so that the command-line arguments will override
+ ** settings in the initialization file.
+ */
+ for(i=1; i<argc && argv[i][0]=='-'; i++){
+ char *z = argv[i];
+ if( z[1]=='-' ){ z++; }
+ if( strcmp(z,"-init")==0 ){
+ i++;
+ }else if( strcmp(z,"-html")==0 ){
+ data.mode = MODE_Html;
+ }else if( strcmp(z,"-list")==0 ){
+ data.mode = MODE_List;
+ }else if( strcmp(z,"-line")==0 ){
+ data.mode = MODE_Line;
+ }else if( strcmp(z,"-column")==0 ){
+ data.mode = MODE_Column;
+ }else if( strcmp(z,"-csv")==0 ){
+ data.mode = MODE_Csv;
+ memcpy(data.separator,",",2);
+ }else if( strcmp(z,"-separator")==0 ){
+ i++;
+ if(i>=argc){
+ fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
+ fprintf(stderr,"Use -help for a list of options.\n");
+ return 1;
+ }
+ sqlite3_snprintf(sizeof(data.separator), data.separator,
+ "%.*s",(int)sizeof(data.separator)-1,argv[i]);
+ }else if( strcmp(z,"-nullvalue")==0 ){
+ i++;
+ if(i>=argc){
+ fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
+ fprintf(stderr,"Use -help for a list of options.\n");
+ return 1;
+ }
+ sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
+ "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
+ }else if( strcmp(z,"-header")==0 ){
+ data.showHeader = 1;
+ }else if( strcmp(z,"-noheader")==0 ){
+ data.showHeader = 0;
+ }else if( strcmp(z,"-echo")==0 ){
+ data.echoOn = 1;
+ }else if( strcmp(z,"-bail")==0 ){
+ bail_on_error = 1;
+ }else if( strcmp(z,"-version")==0 ){
+ printf("%s\n", sqlite3_libversion());
+ return 0;
+ }else if( strcmp(z,"-interactive")==0 ){
+ stdin_is_interactive = 1;
+ }else if( strcmp(z,"-batch")==0 ){
+ stdin_is_interactive = 0;
+ }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
+ usage(1);
+ }else{
+ fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
+ fprintf(stderr,"Use -help for a list of options.\n");
+ return 1;
+ }
+ }
+
+ if( zFirstCmd ){
+ /* Run just the command that follows the database name
+ */
+ if( zFirstCmd[0]=='.' ){
+ rc = do_meta_command(zFirstCmd, &data);
+ }else{
+ open_db(&data);
+ rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
+ if( zErrMsg!=0 ){
+ fprintf(stderr,"Error: %s\n", zErrMsg);
+ return rc!=0 ? rc : 1;
+ }else if( rc!=0 ){
+ fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
+ return rc;
+ }
+ }
+ }else{
+ /* Run commands received from standard input
+ */
+ if( stdin_is_interactive ){
+ char *zHome;
+ char *zHistory = 0;
+ int nHistory;
+ printf(
+ "SQLite version %s\n"
+ "Enter \".help\" for instructions\n"
+ "Enter SQL statements terminated with a \";\"\n",
+ sqlite3_libversion()
+ );
+ zHome = find_home_dir();
+ if( zHome ){
+ nHistory = strlen30(zHome) + 20;
+ if( (zHistory = malloc(nHistory))!=0 ){
+ sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
+ }
+ }
+#if defined(HAVE_READLINE) && HAVE_READLINE==1
+ if( zHistory ) read_history(zHistory);
+#endif
+ rc = process_input(&data, 0);
+ if( zHistory ){
+ stifle_history(100);
+ write_history(zHistory);
+ free(zHistory);
+ }
+ free(zHome);
+ }else{
+ rc = process_input(&data, stdin);
+ }
+ }
+ set_table_name(&data, 0);
+ if( data.db ){
+ if( sqlite3_close(data.db)!=SQLITE_OK ){
+ fprintf(stderr,"Error: cannot close database \"%s\"\n",
+ sqlite3_errmsg(db));
+ rc++;
+ }
+ }
+ return rc;
+}
diff --git a/dist/sqlite3.c b/dist/sqlite3.c
index 076c66a..bbe4d1e 100644
--- a/dist/sqlite3.c
+++ b/dist/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.6.22. By combining all the individual C code files into this
+** version 3.7.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a one translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -25,6 +25,10 @@
#ifndef SQLITE_API
# define SQLITE_API
#endif
+// Begin Android Add
+#define fdatasync fsync
+#undef __APPLE__
+// End Android Add
/************** Begin file sqliteInt.h ***************************************/
/*
** 2001 September 15
@@ -191,6 +195,14 @@
#endif
/*
+** The default number of frames to accumulate in the log file before
+** checkpointing the database in WAL mode.
+*/
+#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
+#endif
+
+/*
** The maximum number of attached databases. This must be between 0
** and 30. The upper bound on 30 is because a 32-bit integer bitmap
** is used internally to track attached databases.
@@ -307,41 +319,43 @@
#include <inttypes.h>
#endif
+/*
+** The number of samples of an index that SQLite takes in order to
+** construct a histogram of the table content when running ANALYZE
+** and with SQLITE_ENABLE_STAT2
+*/
#define SQLITE_INDEX_SAMPLES 10
/*
-** This macro is used to "hide" some ugliness in casting an int
-** value to a ptr value under the MSVC 64-bit compiler. Casting
-** non 64-bit values to ptr types results in a "hard" error with
-** the MSVC 64-bit compiler which this attempts to avoid.
+** 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.
**
-** A simple compiler pragma or casting sequence could not be found
-** to correct this in all situations, so this macro was introduced.
-**
-** It could be argued that the intptr_t type could be used in this
-** case, but that type is not available on all compilers, or
-** requires the #include of specific headers which differs between
-** platforms.
+** 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(__GNUC__)
-# if defined(HAVE_STDINT_H)
-# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
-# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
-# else
-# define SQLITE_INT_TO_PTR(X) ((void*)(X))
-# define SQLITE_PTR_TO_INT(X) ((int)(X))
-# endif
-#else
-# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
-# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
+#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) ((int)(__PTRDIFF_TYPE__)(X))
+#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
+# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
+# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
+#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
+# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
+#else /* Generates a warning - but it always works */
+# define SQLITE_INT_TO_PTR(X) ((void*)(X))
+# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
-
/*
** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
** Older versions of SQLite used an optional THREADSAFE macro.
@@ -371,23 +385,18 @@
**
** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
** SQLITE_MEMDEBUG // Debugging version of system malloc()
-** SQLITE_MEMORY_SIZE // internal allocator #1
-** SQLITE_MMAP_HEAP_SIZE // internal mmap() allocator
-** SQLITE_POW2_MEMORY_SIZE // internal power-of-two allocator
+**
+** (Historical note: There used to be several other options, but we've
+** pared it down to just these two.)
**
** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
** the default.
*/
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
- defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
- defined(SQLITE_POW2_MEMORY_SIZE)>1
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)>1
# error "At most one of the following compile-time configuration options\
- is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG, SQLITE_MEMORY_SIZE,\
- SQLITE_MMAP_HEAP_SIZE, SQLITE_POW2_MEMORY_SIZE"
+ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG"
#endif
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
- defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
- defined(SQLITE_POW2_MEMORY_SIZE)==0
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)==0
# define SQLITE_SYSTEM_MALLOC 1
#endif
@@ -507,6 +516,13 @@
#endif
/*
+** Return true (non-zero) if the input is a integer that is too large
+** to fit in 32-bits. This macro is used inside of various testcase()
+** macros to verify that we have tested SQLite for large-file support.
+*/
+#define IS_BIG_INT(X) (((X)&(i64)0xffffffff)!=0)
+
+/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false. Macro likely() surrounds
** a boolean expression that is usually true. GCC is able to
@@ -631,13 +647,13 @@
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.6.22"
-#define SQLITE_VERSION_NUMBER 3006022
-#define SQLITE_SOURCE_ID "2010-03-22 23:55:10 82dd61fccff3e4c77e060e5734cd4b4e2eeb7c32"
+#define SQLITE_VERSION "3.7.0"
+#define SQLITE_VERSION_NUMBER 3007000
+#define SQLITE_SOURCE_ID "2010-07-07 14:45:41 8eefc287265443ec043bdab629597e79c9d22006"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version
+** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -659,9 +675,9 @@
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function a pointer
-** to a string constant whose value is the same as the [SQLITE_SOURCE_ID]
-** C preprocessor macro.
+** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
+** [SQLITE_SOURCE_ID] C preprocessor macro.
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -671,6 +687,33 @@
SQLITE_API int sqlite3_libversion_number(void);
/*
+** CAPI3REF: Run-Time Library Compilation Options Diagnostics
+**
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
+**
+** ^The sqlite3_compileoption_get() function allows interating
+** over the list of options that were defined at compile time by
+** returning the N-th compile time option string. ^If N is out of range,
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get().
+**
+** ^Support for the diagnostic functions sqlite3_compileoption_used()
+** and sqlite3_compileoption_get() may be omitted by specifing the
+** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
+**
+** See also: SQL functions [sqlite_compileoption_used()] and
+** [sqlite_compileoption_get()] and the [compile_options pragma].
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *sqlite3_compileoption_get(int N);
+#endif
+
+/*
** CAPI3REF: Test To See If The Library Is Threadsafe
**
** ^The sqlite3_threadsafe() function returns zero if and only if
@@ -890,7 +933,7 @@
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
@@ -946,7 +989,12 @@
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
-#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
+#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
+#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
+#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
+#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
+#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -961,6 +1009,7 @@
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
+#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
@@ -993,17 +1042,18 @@
** information is written to disk in the same order as calls
** to xWrite().
*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
@@ -1154,6 +1204,13 @@
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Methods above are valid for version 1 */
+ int (*xShmOpen)(sqlite3_file*);
+ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
+ int (*xShmMap)(sqlite3_file*, int iPage, int pgsz, int, void volatile**);
+ void (*xShmBarrier)(sqlite3_file*);
+ int (*xShmClose)(sqlite3_file*, int deleteFlag);
+ /* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -1171,11 +1228,19 @@
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
+**
+** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
+** layer a hint of how large the database file will grow to be during the
+** current transaction. This hint is not guaranteed to be accurate but it
+** is often close. The underlying VFS might choose to preallocate database
+** file space based on this hint in order to help writes to the database
+** file run faster.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
/*
** CAPI3REF: Mutex Handle
@@ -1307,20 +1372,27 @@
** handled as a fatal error by SQLite, vfs implementations should endeavor
** to prevent this by setting mxPathname to a sufficiently large value.
**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
+** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
+** interfaces are not strictly a part of the filesystem, but they are
** included in the VFS structure for completeness.
** The xRandomness() function attempts to return nBytes bytes
** of good-quality randomness into zOut. The return value is
** the actual number of bytes of randomness obtained.
** The xSleep() method causes the calling thread to sleep for at
** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and time.
-**
+** method returns a Julian Day Number for the current date and time as
+** a floating point value.
+** The xCurrentTimeInt64() method returns, as an integer, the Julian
+** Day Number multipled by 86400000 (the number of milliseconds in
+** a 24-hour day).
+** ^SQLite will use the xCurrentTimeInt64() method to get the current
+** date and time if that method is available (if iVersion is 2 or
+** greater and the function pointer is not NULL) and will fall back
+** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
*/
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
- int iVersion; /* Structure version number */
+ int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@@ -1339,8 +1411,16 @@
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
+ /*
+ ** The methods above are in version 1 of the sqlite_vfs object
+ ** definition. Those that follow are added in version 2 or later
+ */
+ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
+ /*
+ ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
+ ** New fields may be appended in figure versions. The iVersion
+ ** value will increment whenever this happens.
+ */
};
/*
@@ -1361,6 +1441,44 @@
#define SQLITE_ACCESS_READ 2
/*
+** CAPI3REF: Flags for the xShmLock VFS method
+**
+** These integer constants define the various locking operations
+** allowed by the xShmLock method of [sqlite3_io_methods]. The
+** following are the only legal combinations of flags to the
+** xShmLock method:
+**
+** <ul>
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
+** </ul>
+**
+** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
+** was given no the corresponding lock.
+**
+** The xShmLock method can transition between unlocked and SHARED or
+** between unlocked and EXCLUSIVE. It cannot transition between SHARED
+** and EXCLUSIVE.
+*/
+#define SQLITE_SHM_UNLOCK 1
+#define SQLITE_SHM_LOCK 2
+#define SQLITE_SHM_SHARED 4
+#define SQLITE_SHM_EXCLUSIVE 8
+
+/*
+** CAPI3REF: Maximum xShmLock index
+**
+** The xShmLock method on [sqlite3_io_methods] may use values
+** between 0 and this upper bound as its "offset" argument.
+** The SQLite core will never attempt to acquire or release a
+** lock outside of this range
+*/
+#define SQLITE_SHM_NLOCK 8
+
+
+/*
** CAPI3REF: Initialize The SQLite Library
**
** ^The sqlite3_initialize() routine initializes the
@@ -1469,11 +1587,10 @@
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
-** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -1493,11 +1610,10 @@
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
-** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@@ -1579,7 +1695,6 @@
/*
** CAPI3REF: Configuration Options
-** EXPERIMENTAL
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1765,6 +1880,24 @@
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
+** <dt>SQLITE_CONFIG_LOG</dt>
+** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** function with a call signature of void(*)(void*,int,const char*),
+** and a pointer to void. ^If the function pointer is not NULL, it is
+** invoked by [sqlite3_log()] to process each logging event. ^If the
+** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
+** passed through as the first parameter to the application-defined logger
+** function whenever that function is invoked. ^The second parameter to
+** the logger function is a copy of the first parameter to the corresponding
+** [sqlite3_log()] call and is intended to be a [result code] or an
+** [extended result code]. ^The third parameter passed to the logger is
+** log message after formatting via [sqlite3_snprintf()].
+** The SQLite logging interface is not reentrant; the logger function
+** supplied by the application must not invoke any SQLite interface.
+** In a multi-threaded application, the application-defined logger
+** function must be threadsafe. </dd>
+**
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1785,8 +1918,7 @@
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
+** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@@ -2562,7 +2694,6 @@
/*
** CAPI3REF: Tracing And Profiling Functions
-** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2580,7 +2711,7 @@
** the original statement text and an estimate of wall-clock time
** of how long that statement took to run.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
@@ -3373,6 +3504,14 @@
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
+** For all versions of SQLite up to and including 3.6.23.1, it was required
+** after sqlite3_step() returned anything other than [SQLITE_ROW] that
+** [sqlite3_reset()] be called before any subsequent invocation of
+** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
+** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
+** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
+** automatically in this circumstance rather than returning [SQLITE_MISUSE].
+**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@@ -4185,6 +4324,7 @@
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
+#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@@ -4211,6 +4351,25 @@
);
/*
+** Specify the activation key for a SEE database. Unless
+** activated, none of the SEE routines will work.
+*/
+SQLITE_API void sqlite3_activate_see(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+#ifdef SQLITE_ENABLE_CEROD
+/*
+** Specify the activation key for a CEROD database. Unless
+** activated, none of the CEROD routines will work.
+*/
+SQLITE_API void sqlite3_activate_cerod(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+/*
** CAPI3REF: Suspend Execution For A Short Time
**
** ^The sqlite3_sleep() function causes the current thread to suspend execution
@@ -4348,8 +4507,6 @@
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
-** ^The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@@ -4635,8 +4792,6 @@
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -4656,7 +4811,6 @@
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
-** EXPERIMENTAL
**
** This structure, sometimes called a a "virtual table module",
** defines the implementation of a [virtual tables].
@@ -4703,7 +4857,6 @@
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
-** EXPERIMENTAL
**
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the [xBestIndex]
@@ -4785,7 +4938,6 @@
/*
** CAPI3REF: Register A Virtual Table Implementation
-** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -4807,13 +4959,13 @@
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -4824,7 +4976,6 @@
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@@ -4850,7 +5001,6 @@
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@@ -4872,18 +5022,16 @@
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
-** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
-** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -4898,7 +5046,7 @@
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -4908,8 +5056,6 @@
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@@ -5252,7 +5398,6 @@
/*
** CAPI3REF: Mutex Methods Object
-** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@@ -5465,11 +5610,11 @@
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_LAST 16
+#define SQLITE_TESTCTRL_PGHDRSZ 17
+#define SQLITE_TESTCTRL_LAST 17
/*
** CAPI3REF: SQLite Runtime Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about the preformance of SQLite, and optionally to reset various
@@ -5497,12 +5642,11 @@
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
-** EXPERIMENTAL
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
@@ -5589,14 +5733,15 @@
/*
** CAPI3REF: Database Connection Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
-** is the parameter to interrogate. ^Currently, the only allowed value
-** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
-** Additional options will likely appear in future releases of SQLite.
+** is an integer constant, taken from the set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
+** determiness the parameter to interrogate. The set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
+** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
@@ -5605,11 +5750,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
-** EXPERIMENTAL
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@@ -5624,14 +5768,21 @@
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
+**
+** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
+** <dd>^This parameter returns the approximate number of of bytes of heap
+** memory used by all pager caches associated with the database connection.
+** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+** checked out.</dd>)^
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
+#define SQLITE_DBSTATUS_CACHE_USED 1
+#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
-** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
@@ -5653,11 +5804,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
-** EXPERIMENTAL
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
@@ -5675,14 +5825,21 @@
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.</dd>
**
+** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
+** <dd>^This is the number of rows inserted into transient indices that
+** were created automatically in order to help joins run faster.
+** A non-zero value in this counter may indicate an opportunity to
+** improvement performance by adding permanent indices that do not
+** need to be reinitialized each time the statement is run.</dd>
+**
** </dl>
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
+#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
-** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@@ -5697,7 +5854,6 @@
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
-** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
** register an alternative page cache implementation by passing in an
@@ -5839,7 +5995,6 @@
/*
** CAPI3REF: Online Backup Object
-** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@@ -5852,7 +6007,6 @@
/*
** CAPI3REF: Online Backup API.
-** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
@@ -5921,10 +6075,14 @@
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
-** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
-** database was opened read-only or if
-** the destination is an in-memory database with a different page size
-** from the source database.
+** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
+** <ol>
+** <li> the destination database was opened read-only, or
+** <li> the destination database is using write-ahead-log journaling
+** and the destination and source page sizes differ, or
+** <li> The destination database is an in-memory database and the
+** destination and source page sizes differ.
+** </ol>)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
@@ -6040,7 +6198,6 @@
/*
** CAPI3REF: Unlock Notification
-** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -6162,7 +6319,6 @@
/*
** CAPI3REF: String Comparison
-** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
@@ -6173,16 +6329,19 @@
/*
** CAPI3REF: Error Logging Interface
-** EXPERIMENTAL
**
** ^The [sqlite3_log()] interface writes a message into the error log
-** established by the [SQLITE_CONFIG_ERRORLOG] option to [sqlite3_config()].
+** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
+** ^If logging is enabled, the zFormat string and subsequent arguments are
+** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
** nothing to prevent an application from calling sqlite3_log(), doing so
** is considered bad form.
**
+** The zFormat string must not be NULL.
+**
** To avoid deadlocks and other threading problems, the sqlite3_log() routine
** will not use dynamically allocated memory. The log message is stored in
** a fixed-length buffer on the stack. If the log message is longer than
@@ -6192,6 +6351,89 @@
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
+** CAPI3REF: Write-Ahead Log Commit Hook
+**
+** ^The [sqlite3_wal_hook()] function is used to register a callback that
+** will be invoked each time a database connection commits data to a
+** [write-ahead log] (i.e. whenever a transaction is committed in
+** [journal_mode | journal_mode=WAL mode]).
+**
+** ^The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released, so the implementation
+** may read, write or [checkpoint] the database as required.
+**
+** ^The first parameter passed to the callback function when it is invoked
+** is a copy of the third parameter passed to sqlite3_wal_hook() when
+** registering the callback. ^The second is a copy of the database handle.
+** ^The third parameter is the name of the database that was written to -
+** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
+** is the number of pages currently in the write-ahead log file,
+** including those that were just committed.
+**
+** The callback function should normally return [SQLITE_OK]. ^If an error
+** code is returned, that error will propagate back up through the
+** SQLite code base to cause the statement that provoked the callback
+** to report an error, though the commit will have still occurred. If the
+** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
+** that does not correspond to any valid SQLite error code, the results
+** are undefined.
+**
+** A single database handle may have at most a single write-ahead log callback
+** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
+** previously registered write-ahead log callback. ^Note that the
+** [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
+** those overwrite any prior [sqlite3_wal_hook()] settings.
+*/
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3*,
+ int(*)(void *,sqlite3*,const char*,int),
+ void*
+);
+
+/*
+** CAPI3REF: Configure an auto-checkpoint
+**
+** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
+** [sqlite3_wal_hook()] that causes any database on [database connection] D
+** to automatically [checkpoint]
+** after committing a transaction if there are N or
+** more frames in the [write-ahead log] file. ^Passing zero or
+** a negative value as the nFrame parameter disables automatic
+** checkpoints entirely.
+**
+** ^The callback registered by this function replaces any existing callback
+** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
+** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
+** configured by this function.
+**
+** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
+** from SQL.
+**
+** ^Every new [database connection] defaults to having the auto-checkpoint
+** enabled with a threshold of 1000 pages. The use of this interface
+** is only necessary if the default setting is found to be suboptimal
+** for a particular application.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+
+/*
+** CAPI3REF: Checkpoint a database
+**
+** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
+** on [database connection] D to be [checkpointed]. ^If X is NULL or an
+** empty string, then a checkpoint is run on all databases of
+** connection D. ^If the database connection D is not in
+** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+**
+** ^The [wal_checkpoint pragma] can be used to invoke this interface
+** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] can be used to cause this interface to be
+** run whenever the WAL reaches a certain size threshold.
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+
+/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
@@ -6206,11 +6448,6 @@
/************** End of sqlite3.h *********************************************/
-// Begin Android Add
-#define SQLITE_BeginImmediate 0x00200000 /* Default BEGIN to IMMEDIATE */
-#define fdatasync fsync
-#undef __APPLE__
-// End Android Add
/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include hash.h in the middle of sqliteInt.h ******************/
/************** Begin file hash.h ********************************************/
@@ -6487,6 +6724,7 @@
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
+# define float sqlite_int64
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
@@ -6512,20 +6750,6 @@
#endif
/*
-** If the following macro is set to 1, then NULL values are considered
-** distinct when determining whether or not two entries are the same
-** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL,
-** OCELOT, and Firebird all work. The SQL92 spec explicitly says this
-** is the way things are suppose to work.
-**
-** If the following macro is set to 0, the NULLs are indistinct for
-** a UNIQUE index. In this mode, you can only have a single NULL entry
-** for a column declared UNIQUE. This is the way Informix and SQL Server
-** work.
-*/
-#define NULL_DISTINCT_FOR_UNIQUE 1
-
-/*
** The "file format" number is an integer that is incremented whenever
** the VDBE-level file format changes. The following macros define the
** the default file format for new databases and the maximum file format
@@ -6536,6 +6760,10 @@
# define SQLITE_DEFAULT_FILE_FORMAT 1
#endif
+/*
+** Determine whether triggers are recursive by default. This can be
+** changed at run-time using a pragma.
+*/
#ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS
# define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0
#endif
@@ -6780,7 +7008,6 @@
typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec;
-typedef struct RowSet RowSet;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
@@ -6801,6 +7028,7 @@
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
+typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SrcList SrcList;
@@ -6808,9 +7036,9 @@
typedef struct Table Table;
typedef struct TableLock TableLock;
typedef struct Token Token;
+typedef struct Trigger Trigger;
typedef struct TriggerPrg TriggerPrg;
typedef struct TriggerStep TriggerStep;
-typedef struct Trigger Trigger;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct VTable VTable;
typedef struct Walker Walker;
@@ -6908,6 +7136,8 @@
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
+SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
@@ -7011,6 +7241,8 @@
SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
+
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
@@ -7301,83 +7533,83 @@
#define OP_VerifyCookie 37
#define OP_OpenRead 38
#define OP_OpenWrite 39
-#define OP_OpenEphemeral 40
-#define OP_OpenPseudo 41
-#define OP_Close 42
-#define OP_SeekLt 43
-#define OP_SeekLe 44
-#define OP_SeekGe 45
-#define OP_SeekGt 46
-#define OP_Seek 47
-#define OP_NotFound 48
-#define OP_Found 49
-#define OP_IsUnique 50
-#define OP_NotExists 51
-#define OP_Sequence 52
-#define OP_NewRowid 53
-#define OP_Insert 54
-#define OP_InsertInt 55
-#define OP_Delete 56
-#define OP_ResetCount 57
-#define OP_RowKey 58
-#define OP_RowData 59
-#define OP_Rowid 60
-#define OP_NullRow 61
-#define OP_Last 62
-#define OP_Sort 63
-#define OP_Rewind 64
-#define OP_Prev 65
-#define OP_Next 66
-#define OP_IdxInsert 67
-#define OP_IdxDelete 70
-#define OP_IdxRowid 71
-#define OP_IdxLT 72
-#define OP_IdxGE 81
-#define OP_Destroy 92
-#define OP_Clear 95
-#define OP_CreateIndex 96
-#define OP_CreateTable 97
-#define OP_ParseSchema 98
-#define OP_LoadAnalysis 99
-#define OP_DropTable 100
-#define OP_DropIndex 101
-#define OP_DropTrigger 102
-#define OP_IntegrityCk 103
-#define OP_RowSetAdd 104
-#define OP_RowSetRead 105
-#define OP_RowSetTest 106
-#define OP_Program 107
-#define OP_Param 108
-#define OP_FkCounter 109
-#define OP_FkIfZero 110
-#define OP_MemMax 111
-#define OP_IfPos 112
-#define OP_IfNeg 113
-#define OP_IfZero 114
-#define OP_AggStep 115
-#define OP_AggFinal 116
-#define OP_Vacuum 117
-#define OP_IncrVacuum 118
-#define OP_Expire 119
-#define OP_TableLock 120
-#define OP_VBegin 121
-#define OP_VCreate 122
-#define OP_VDestroy 123
-#define OP_VOpen 124
-#define OP_VFilter 125
-#define OP_VColumn 126
-#define OP_VNext 127
-#define OP_VRename 128
-#define OP_VUpdate 129
-#define OP_Pagecount 131
-#define OP_Trace 132
-#define OP_Noop 133
-#define OP_Explain 134
+#define OP_OpenAutoindex 40
+#define OP_OpenEphemeral 41
+#define OP_OpenPseudo 42
+#define OP_Close 43
+#define OP_SeekLt 44
+#define OP_SeekLe 45
+#define OP_SeekGe 46
+#define OP_SeekGt 47
+#define OP_Seek 48
+#define OP_NotFound 49
+#define OP_Found 50
+#define OP_IsUnique 51
+#define OP_NotExists 52
+#define OP_Sequence 53
+#define OP_NewRowid 54
+#define OP_Insert 55
+#define OP_InsertInt 56
+#define OP_Delete 57
+#define OP_ResetCount 58
+#define OP_RowKey 59
+#define OP_RowData 60
+#define OP_Rowid 61
+#define OP_NullRow 62
+#define OP_Last 63
+#define OP_Sort 64
+#define OP_Rewind 65
+#define OP_Prev 66
+#define OP_Next 67
+#define OP_IdxInsert 70
+#define OP_IdxDelete 71
+#define OP_IdxRowid 72
+#define OP_IdxLT 81
+#define OP_IdxGE 92
+#define OP_Destroy 95
+#define OP_Clear 96
+#define OP_CreateIndex 97
+#define OP_CreateTable 98
+#define OP_ParseSchema 99
+#define OP_LoadAnalysis 100
+#define OP_DropTable 101
+#define OP_DropIndex 102
+#define OP_DropTrigger 103
+#define OP_IntegrityCk 104
+#define OP_RowSetAdd 105
+#define OP_RowSetRead 106
+#define OP_RowSetTest 107
+#define OP_Program 108
+#define OP_Param 109
+#define OP_FkCounter 110
+#define OP_FkIfZero 111
+#define OP_MemMax 112
+#define OP_IfPos 113
+#define OP_IfNeg 114
+#define OP_IfZero 115
+#define OP_AggStep 116
+#define OP_AggFinal 117
+#define OP_Checkpoint 118
+#define OP_JournalMode 119
+#define OP_Vacuum 120
+#define OP_IncrVacuum 121
+#define OP_Expire 122
+#define OP_TableLock 123
+#define OP_VBegin 124
+#define OP_VCreate 125
+#define OP_VDestroy 126
+#define OP_VOpen 127
+#define OP_VFilter 128
+#define OP_VColumn 129
+#define OP_VNext 131
+#define OP_VRename 132
+#define OP_VUpdate 133
+#define OP_Pagecount 134
+#define OP_Trace 135
+#define OP_Noop 136
+#define OP_Explain 137
/* The following opcode values are never used */
-#define OP_NotUsed_135 135
-#define OP_NotUsed_136 136
-#define OP_NotUsed_137 137
#define OP_NotUsed_138 138
#define OP_NotUsed_139 139
#define OP_NotUsed_140 140
@@ -7396,22 +7628,22 @@
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\
-/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x24, 0x24,\
+/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
/* 32 */ 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,\
-/* 40 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\
-/* 48 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
-/* 64 */ 0x01, 0x01, 0x01, 0x08, 0x4c, 0x4c, 0x00, 0x02,\
-/* 72 */ 0x01, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\
+/* 48 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00,\
+/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\
+/* 64 */ 0x01, 0x01, 0x01, 0x01, 0x4c, 0x4c, 0x08, 0x00,\
+/* 72 */ 0x02, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
/* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,\
-/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x02, 0x24, 0x02, 0x00,\
-/* 96 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 104 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\
-/* 112 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,\
-/* 128 */ 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
+/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x02,\
+/* 96 */ 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 104 */ 0x00, 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01,\
+/* 112 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
+/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04,}
@@ -7557,14 +7789,15 @@
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
-** Valid values for the second argument to sqlite3PagerJournalMode().
+** Numeric constants that encode the journalmode.
*/
-#define PAGER_JOURNALMODE_QUERY -1
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** The remainder of this file contains the declarations of the functions
@@ -7592,7 +7825,9 @@
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
@@ -7622,9 +7857,16 @@
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
+
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*);
SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -7636,6 +7878,10 @@
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
+#endif
+
/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
@@ -8037,7 +8283,11 @@
** 1GB boundary.
**
*/
-#define PENDING_BYTE sqlite3PendingByte
+#ifdef SQLITE_OMIT_WSD
+# define PENDING_BYTE (0x40000000)
+#else
+# define PENDING_BYTE sqlite3PendingByte
+#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@@ -8063,6 +8313,11 @@
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmOpen(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmClose(sqlite3_file *id, int);
+SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
/*
** Functions for accessing sqlite3_vfs methods
@@ -8079,7 +8334,7 @@
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
** Convenience functions for opening and closing files using
@@ -8214,7 +8469,7 @@
/*
** These macros can be used to test, set, or clear bits in the
-** Db.flags field.
+** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
@@ -8222,7 +8477,7 @@
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
/*
-** Allowed values for the DB.flags field.
+** Allowed values for the DB.pSchema->flags field.
**
** The DB_SchemaLoaded flag is set after the database schema has been
** read into internal hash tables.
@@ -8286,7 +8541,7 @@
};
/*
-** Each database is an instance of the following structure.
+** Each database connection is an instance of the following structure.
**
** The sqlite.lastRowid records the last insert rowid generated by an
** insert statement. Inserts on views do not affect its value. Each
@@ -8356,6 +8611,10 @@
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+#ifndef SQLITE_OMIT_WAL
+ int (*xWalCallback)(void *, sqlite3 *, const char *, int);
+ void *pWalArg;
+#endif
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
@@ -8445,6 +8704,8 @@
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
+#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
/*
** Bits of the sqlite3.flags field that are used by the
@@ -8456,7 +8717,8 @@
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
-#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
+#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
+#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/*
** Possible values for the sqlite.magic field.
@@ -9307,6 +9569,9 @@
** and the next table on the list. The parser builds the list this way.
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
** jointype expresses the join between the table and the previous table.
+**
+** In the colUsed field, the high-order bit (bit 63) is set if the table
+** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -9418,7 +9683,7 @@
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
-#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
+#define WHERE_OMIT_OPEN 0x0010 /* Table cursors are already open */
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
@@ -9441,6 +9706,7 @@
int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
+ double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
@@ -9682,6 +9948,7 @@
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
+ double nQueryLoop; /* Estimated number of iterations of a query */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
@@ -9960,6 +10227,15 @@
/*
+** FTS4 is really an extension for FTS3. It is enabled using the
+** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
+** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
+*/
+#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
+# define SQLITE_ENABLE_FTS3
+#endif
+
+/*
** The ctype.h header is needed for non-ASCII systems. It is also
** needed by FTS3 when FTS3 is included in the amalgamation.
*/
@@ -10048,7 +10324,8 @@
#ifndef SQLITE_MUTEX_OMIT
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void);
SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int);
SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
@@ -10058,7 +10335,11 @@
SQLITE_PRIVATE void sqlite3StatusAdd(int, int);
SQLITE_PRIVATE void sqlite3StatusSet(int, int);
-SQLITE_PRIVATE int sqlite3IsNaN(double);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+SQLITE_PRIVATE int sqlite3IsNaN(double);
+#else
+# define sqlite3IsNaN(X) 0
+#endif
SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
#ifndef SQLITE_OMIT_TRACE
@@ -10176,6 +10457,7 @@
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
+SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
@@ -10202,6 +10484,7 @@
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*);
+SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
@@ -10379,7 +10662,7 @@
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
-SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int);
+SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
#ifdef SQLITE_ENABLE_STAT2
SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *);
#endif
@@ -10391,11 +10674,13 @@
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
+#endif
SQLITE_PRIVATE void sqlite3RootPageMoved(Db*, int, int);
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
-SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3*);
+SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
@@ -10504,6 +10789,9 @@
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
+SQLITE_PRIVATE const char *sqlite3JournalModename(int);
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int);
+SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -10610,7 +10898,46 @@
# define sqlite3VdbeIOTraceSql(X)
#endif
+/*
+** These routines are available for the mem2.c debugging memory allocator
+** only. They are used to verify that different "types" of memory
+** allocations are properly tracked by the system.
+**
+** sqlite3MemdebugSetType() sets the "type" of an allocation to one of
+** the MEMTYPE_* macros defined below. The type must be a bitmask with
+** a single bit set.
+**
+** sqlite3MemdebugHasType() returns true if any of the bits in its second
+** argument match the type set by the previous sqlite3MemdebugSetType().
+** sqlite3MemdebugHasType() is intended for use inside assert() statements.
+** For example:
+**
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+**
+** Perhaps the most important point is the difference between MEMTYPE_HEAP
+** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have
+** been allocated by lookaside, except the allocation was too large or
+** lookaside was already full. It is important to verify that allocations
+** that might have been satisfied by lookaside are not passed back to
+** non-lookaside free() routines. Asserts such as the example above are
+** placed on the non-lookaside free() routines to verify this constraint.
+**
+** All of this is no-op for a production build. It only comes into
+** play when the SQLITE_MEMDEBUG compile-time option is used.
+*/
+#ifdef SQLITE_MEMDEBUG
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8);
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8);
+#else
+# define sqlite3MemdebugSetType(X,Y) /* no-op */
+# define sqlite3MemdebugHasType(X,Y) 1
#endif
+#define MEMTYPE_HEAP 0x01 /* General heap allocations */
+#define MEMTYPE_DB 0x02 /* Associated with a database connection */
+#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
+#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+
+#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
/************** Begin file global.c ******************************************/
@@ -10809,7 +11136,9 @@
** Changing the pending byte during operating results in undefined
** and dileterious behavior.
*/
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+#endif
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
@@ -10820,6 +11149,398 @@
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
/************** End of global.c **********************************************/
+/************** Begin file ctime.c *******************************************/
+/*
+** 2010 February 23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements routines used to report what compile-time options
+** SQLite was built with.
+*/
+
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+
+
+/*
+** 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[] = {
+
+/* 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)
+
+#ifdef SQLITE_32BIT_ROWID
+ "32BIT_ROWID",
+#endif
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+ "4_BYTE_ALIGNED_MALLOC",
+#endif
+#ifdef SQLITE_CASE_SENSITIVE_LIKE
+ "CASE_SENSITIVE_LIKE",
+#endif
+#ifdef SQLITE_CHECK_PAGES
+ "CHECK_PAGES",
+#endif
+#ifdef SQLITE_COVERAGE_TEST
+ "COVERAGE_TEST",
+#endif
+#ifdef SQLITE_DEBUG
+ "DEBUG",
+#endif
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
+#endif
+#ifdef SQLITE_DISABLE_DIRSYNC
+ "DISABLE_DIRSYNC",
+#endif
+#ifdef SQLITE_DISABLE_LFS
+ "DISABLE_LFS",
+#endif
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ "ENABLE_ATOMIC_WRITE",
+#endif
+#ifdef SQLITE_ENABLE_CEROD
+ "ENABLE_CEROD",
+#endif
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ "ENABLE_COLUMN_METADATA",
+#endif
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ "ENABLE_EXPENSIVE_ASSERT",
+#endif
+#ifdef SQLITE_ENABLE_FTS1
+ "ENABLE_FTS1",
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+ "ENABLE_FTS2",
+#endif
+#ifdef SQLITE_ENABLE_FTS3
+ "ENABLE_FTS3",
+#endif
+#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+ "ENABLE_FTS3_PARENTHESIS",
+#endif
+#ifdef SQLITE_ENABLE_FTS4
+ "ENABLE_FTS4",
+#endif
+#ifdef SQLITE_ENABLE_ICU
+ "ENABLE_ICU",
+#endif
+#ifdef SQLITE_ENABLE_IOTRACE
+ "ENABLE_IOTRACE",
+#endif
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+ "ENABLE_LOAD_EXTENSION",
+#endif
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
+#endif
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ "ENABLE_MEMORY_MANAGEMENT",
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS3
+ "ENABLE_MEMSYS3",
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS5
+ "ENABLE_MEMSYS5",
+#endif
+#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+ "ENABLE_OVERSIZE_CELL_CHECK",
+#endif
+#ifdef SQLITE_ENABLE_RTREE
+ "ENABLE_RTREE",
+#endif
+#ifdef SQLITE_ENABLE_STAT2
+ "ENABLE_STAT2",
+#endif
+#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+ "ENABLE_UNLOCK_NOTIFY",
+#endif
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ "ENABLE_UPDATE_DELETE_LIMIT",
+#endif
+#ifdef SQLITE_HAS_CODEC
+ "HAS_CODEC",
+#endif
+#ifdef SQLITE_HAVE_ISNAN
+ "HAVE_ISNAN",
+#endif
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ "HOMEGROWN_RECURSIVE_MUTEX",
+#endif
+#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+ "IGNORE_AFP_LOCK_ERRORS",
+#endif
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+ "IGNORE_FLOCK_LOCK_ERRORS",
+#endif
+#ifdef SQLITE_INT64_TYPE
+ "INT64_TYPE",
+#endif
+#ifdef SQLITE_LOCK_TRACE
+ "LOCK_TRACE",
+#endif
+#ifdef SQLITE_MEMDEBUG
+ "MEMDEBUG",
+#endif
+#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+ "MIXED_ENDIAN_64BIT_FLOAT",
+#endif
+#ifdef SQLITE_NO_SYNC
+ "NO_SYNC",
+#endif
+#ifdef SQLITE_OMIT_ALTERTABLE
+ "OMIT_ALTERTABLE",
+#endif
+#ifdef SQLITE_OMIT_ANALYZE
+ "OMIT_ANALYZE",
+#endif
+#ifdef SQLITE_OMIT_ATTACH
+ "OMIT_ATTACH",
+#endif
+#ifdef SQLITE_OMIT_AUTHORIZATION
+ "OMIT_AUTHORIZATION",
+#endif
+#ifdef SQLITE_OMIT_AUTOINCREMENT
+ "OMIT_AUTOINCREMENT",
+#endif
+#ifdef SQLITE_OMIT_AUTOINIT
+ "OMIT_AUTOINIT",
+#endif
+#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
+ "OMIT_AUTOMATIC_INDEX",
+#endif
+#ifdef SQLITE_OMIT_AUTOVACUUM
+ "OMIT_AUTOVACUUM",
+#endif
+#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
+ "OMIT_BETWEEN_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_BLOB_LITERAL
+ "OMIT_BLOB_LITERAL",
+#endif
+#ifdef SQLITE_OMIT_BTREECOUNT
+ "OMIT_BTREECOUNT",
+#endif
+#ifdef SQLITE_OMIT_BUILTIN_TEST
+ "OMIT_BUILTIN_TEST",
+#endif
+#ifdef SQLITE_OMIT_CAST
+ "OMIT_CAST",
+#endif
+#ifdef SQLITE_OMIT_CHECK
+ "OMIT_CHECK",
+#endif
+/* // redundant
+** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
+** "OMIT_COMPILEOPTION_DIAGS",
+** #endif
+*/
+#ifdef SQLITE_OMIT_COMPLETE
+ "OMIT_COMPLETE",
+#endif
+#ifdef SQLITE_OMIT_COMPOUND_SELECT
+ "OMIT_COMPOUND_SELECT",
+#endif
+#ifdef SQLITE_OMIT_DATETIME_FUNCS
+ "OMIT_DATETIME_FUNCS",
+#endif
+#ifdef SQLITE_OMIT_DECLTYPE
+ "OMIT_DECLTYPE",
+#endif
+#ifdef SQLITE_OMIT_DEPRECATED
+ "OMIT_DEPRECATED",
+#endif
+#ifdef SQLITE_OMIT_DISKIO
+ "OMIT_DISKIO",
+#endif
+#ifdef SQLITE_OMIT_EXPLAIN
+ "OMIT_EXPLAIN",
+#endif
+#ifdef SQLITE_OMIT_FLAG_PRAGMAS
+ "OMIT_FLAG_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ "OMIT_FLOATING_POINT",
+#endif
+#ifdef SQLITE_OMIT_FOREIGN_KEY
+ "OMIT_FOREIGN_KEY",
+#endif
+#ifdef SQLITE_OMIT_GET_TABLE
+ "OMIT_GET_TABLE",
+#endif
+#ifdef SQLITE_OMIT_INCRBLOB
+ "OMIT_INCRBLOB",
+#endif
+#ifdef SQLITE_OMIT_INTEGRITY_CHECK
+ "OMIT_INTEGRITY_CHECK",
+#endif
+#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
+ "OMIT_LIKE_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ "OMIT_LOAD_EXTENSION",
+#endif
+#ifdef SQLITE_OMIT_LOCALTIME
+ "OMIT_LOCALTIME",
+#endif
+#ifdef SQLITE_OMIT_LOOKASIDE
+ "OMIT_LOOKASIDE",
+#endif
+#ifdef SQLITE_OMIT_MEMORYDB
+ "OMIT_MEMORYDB",
+#endif
+#ifdef SQLITE_OMIT_OR_OPTIMIZATION
+ "OMIT_OR_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_PAGER_PRAGMAS
+ "OMIT_PAGER_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_PRAGMA
+ "OMIT_PRAGMA",
+#endif
+#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+ "OMIT_PROGRESS_CALLBACK",
+#endif
+#ifdef SQLITE_OMIT_QUICKBALANCE
+ "OMIT_QUICKBALANCE",
+#endif
+#ifdef SQLITE_OMIT_REINDEX
+ "OMIT_REINDEX",
+#endif
+#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
+ "OMIT_SCHEMA_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+ "OMIT_SCHEMA_VERSION_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ "OMIT_SHARED_CACHE",
+#endif
+#ifdef SQLITE_OMIT_SUBQUERY
+ "OMIT_SUBQUERY",
+#endif
+#ifdef SQLITE_OMIT_TCL_VARIABLE
+ "OMIT_TCL_VARIABLE",
+#endif
+#ifdef SQLITE_OMIT_TEMPDB
+ "OMIT_TEMPDB",
+#endif
+#ifdef SQLITE_OMIT_TRACE
+ "OMIT_TRACE",
+#endif
+#ifdef SQLITE_OMIT_TRIGGER
+ "OMIT_TRIGGER",
+#endif
+#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+ "OMIT_TRUNCATE_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_UTF16
+ "OMIT_UTF16",
+#endif
+#ifdef SQLITE_OMIT_VACUUM
+ "OMIT_VACUUM",
+#endif
+#ifdef SQLITE_OMIT_VIEW
+ "OMIT_VIEW",
+#endif
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ "OMIT_VIRTUALTABLE",
+#endif
+#ifdef SQLITE_OMIT_WAL
+ "OMIT_WAL",
+#endif
+#ifdef SQLITE_OMIT_WSD
+ "OMIT_WSD",
+#endif
+#ifdef SQLITE_OMIT_XFER_OPT
+ "OMIT_XFER_OPT",
+#endif
+#ifdef SQLITE_PERFORMANCE_TRACE
+ "PERFORMANCE_TRACE",
+#endif
+#ifdef SQLITE_PROXY_DEBUG
+ "PROXY_DEBUG",
+#endif
+#ifdef SQLITE_SECURE_DELETE
+ "SECURE_DELETE",
+#endif
+#ifdef SQLITE_SMALL_STACK
+ "SMALL_STACK",
+#endif
+#ifdef SQLITE_SOUNDEX
+ "SOUNDEX",
+#endif
+#ifdef SQLITE_TCL
+ "TCL",
+#endif
+#ifdef SQLITE_TEMP_STORE
+ "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
+#endif
+#ifdef SQLITE_TEST
+ "TEST",
+#endif
+#ifdef SQLITE_THREADSAFE
+ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+#endif
+#ifdef SQLITE_USE_ALLOCA
+ "USE_ALLOCA",
+#endif
+#ifdef SQLITE_ZERO_MALLOC
+ "ZERO_MALLOC"
+#endif
+};
+
+/*
+** 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.
+*/
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
+ int i, n;
+ 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<ArraySize(azCompileOpt); i++){
+ if( (sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0)
+ && ( (azCompileOpt[i][n]==0) || (azCompileOpt[i][n]=='=') ) ) return 1;
+ }
+ return 0;
+}
+
+/*
+** Return the N-th compile-time option string. If N is out of range,
+** return a NULL pointer.
+*/
+SQLITE_API const char *sqlite3_compileoption_get(int N){
+ if( N>=0 && N<ArraySize(azCompileOpt) ){
+ return azCompileOpt[N];
+ }
+ return 0;
+}
+
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+/************** End of ctime.c ***********************************************/
/************** Begin file status.c ******************************************/
/*
** 2008 June 18
@@ -10934,6 +11655,26 @@
}
break;
}
+
+ /*
+ ** Return an approximation for the amount of memory currently used
+ ** by all pagers associated with the given database connection. The
+ ** highwater mark is meaningless and is returned as zero.
+ */
+ case SQLITE_DBSTATUS_CACHE_USED: {
+ int totalUsed = 0;
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ totalUsed += sqlite3PagerMemUsed(pPager);
+ }
+ }
+ *pCurrent = totalUsed;
+ *pHighwater = 0;
+ break;
+ }
default: {
return SQLITE_ERROR;
}
@@ -11256,10 +11997,8 @@
** Set the time to the current time reported by the VFS
*/
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
- double r;
sqlite3 *db = sqlite3_context_db_handle(context);
- sqlite3OsCurrentTime(db->pVfs, &r);
- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
p->validJD = 1;
}
@@ -11980,22 +12719,15 @@
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
sqlite3 *db;
- double rT;
+ sqlite3_int64 iT;
char zBuf[20];
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
db = sqlite3_context_db_handle(context);
- sqlite3OsCurrentTime(db->pVfs, &rT);
-#ifndef SQLITE_OMIT_FLOATING_POINT
- t = 86400.0*(rT - 2440587.5) + 0.5;
-#else
- /* without floating point support, rT will have
- ** already lost fractional day precision.
- */
- t = 86400 * (rT - 2440587) - 43200;
-#endif
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
+ t = iT/1000 - 10000*(sqlite3_int64)21086676;
#ifdef HAVE_GMTIME_R
{
struct tm sNow;
@@ -12034,8 +12766,8 @@
FUNCTION(current_date, 0, 0, 0, cdateFunc ),
#else
STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
- STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d", 0, currentTimeFunc),
- STR_FUNCTION(current_date, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
+ STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
+ STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
int i;
@@ -12084,8 +12816,10 @@
** sqlite3OsLock()
**
*/
-#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
- #define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \
+#if defined(SQLITE_TEST)
+SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
+ #define DO_OS_MALLOC_TEST(x) \
+ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
@@ -12148,6 +12882,27 @@
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+SQLITE_PRIVATE int sqlite3OsShmOpen(sqlite3_file *id){
+ return id->pMethods->xShmOpen(id);
+}
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
+ return id->pMethods->xShmLock(id, offset, n, flags);
+}
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
+ id->pMethods->xShmBarrier(id);
+}
+SQLITE_PRIVATE int sqlite3OsShmClose(sqlite3_file *id, int deleteFlag){
+ return id->pMethods->xShmClose(id, deleteFlag);
+}
+SQLITE_PRIVATE int sqlite3OsShmMap(
+ sqlite3_file *id,
+ int iPage,
+ int pgsz,
+ int isWrite,
+ void volatile **pp
+){
+ return id->pMethods->xShmMap(id, iPage, pgsz, isWrite, pp);
+}
/*
** The next group of routines are convenience wrappers around the
@@ -12162,11 +12917,11 @@
){
int rc;
DO_OS_MALLOC_TEST(0);
- /* 0x7f1f is a mask of SQLITE_OPEN_ flags that are valid to be passed
+ /* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
- rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f1f, pFlagsOut);
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f3f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
@@ -12211,8 +12966,16 @@
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- return pVfs->xCurrentTime(pVfs, pTimeOut);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+ int rc;
+ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
+ rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
+ }else{
+ double r;
+ rc = pVfs->xCurrentTime(pVfs, &r);
+ *pTimeOut = (sqlite3_int64)(r*86400000.0);
+ }
+ return rc;
}
SQLITE_PRIVATE int sqlite3OsOpenMalloc(
@@ -12589,7 +13352,6 @@
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
nByte = ROUND8(nByte);
- p = (sqlite3_int64*)pPrior;
p--;
p = realloc(p, nByte+8 );
if( p ){
@@ -12708,7 +13470,8 @@
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
- short nTitle; /* Bytes of title; includes '\0' */
+ u8 nTitle; /* Bytes of title; includes '\0' */
+ u8 eType; /* Allocation type code */
int iForeGuard; /* Guard word for sanity */
};
@@ -12916,6 +13679,7 @@
}
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
+ pHdr->eType = MEMTYPE_HEAP;
pHdr->nBacktraceSlots = mem.nBacktrace;
pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
@@ -12951,7 +13715,8 @@
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
- assert( sqlite3GlobalConfig.bMemstat || mem.mutex!=0 );
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
+ || mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
@@ -13023,6 +13788,47 @@
}
/*
+** Set the "type" of an allocation.
+*/
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
+ if( p ){
+ struct MemBlockHdr *pHdr;
+ pHdr = sqlite3MemsysGetHeader(p);
+ assert( pHdr->iForeGuard==FOREGUARD );
+ pHdr->eType = eType;
+ }
+}
+
+/*
+** Return TRUE if the mask of type in eType matches the type of the
+** allocation p. Also return true if p==NULL.
+**
+** This routine is designed for use within an assert() statement, to
+** verify the type of an allocation. For example:
+**
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+*/
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
+ int rc = 1;
+ if( p ){
+ struct MemBlockHdr *pHdr;
+ pHdr = sqlite3MemsysGetHeader(p);
+ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
+ assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */
+ if( (pHdr->eType&eType)==0 ){
+ void **pBt;
+ pBt = (void**)pHdr;
+ pBt -= pHdr->nBacktraceSlots;
+ backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr));
+ fprintf(stderr, "\n");
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+
+/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns off backtracing. The number is always rounded
** up to a multiple of 2.
@@ -14423,23 +15229,26 @@
*/
SQLITE_PRIVATE int sqlite3MutexInit(void){
int rc = SQLITE_OK;
- if( sqlite3GlobalConfig.bCoreMutex ){
- if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
- /* If the xMutexAlloc method has not been set, then the user did not
- ** install a mutex implementation via sqlite3_config() prior to
- ** sqlite3_initialize() being called. This block copies pointers to
- ** the default implementation into the sqlite3GlobalConfig structure.
- */
- sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex();
- sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
+ if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
+ /* If the xMutexAlloc method has not been set, then the user did not
+ ** install a mutex implementation via sqlite3_config() prior to
+ ** sqlite3_initialize() being called. This block copies pointers to
+ ** the default implementation into the sqlite3GlobalConfig structure.
+ */
+ sqlite3_mutex_methods const *pFrom;
+ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
- memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
- memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
- sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
- pTo->xMutexAlloc = pFrom->xMutexAlloc;
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pFrom = sqlite3DefaultMutex();
+ }else{
+ pFrom = sqlite3NoopMutex();
}
- rc = sqlite3GlobalConfig.mutex.xMutexInit();
+ memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
+ memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
+ sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
+ pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
+ rc = sqlite3GlobalConfig.mutex.xMutexInit();
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 1;
@@ -14571,25 +15380,30 @@
** called correctly.
*/
+#ifndef SQLITE_MUTEX_OMIT
-#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
+#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/
-static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
-static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
-static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
-static void noopMutexFree(sqlite3_mutex *p){ return; }
-static void noopMutexEnter(sqlite3_mutex *p){ return; }
-static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
-static void noopMutexLeave(sqlite3_mutex *p){ return; }
+static sqlite3_mutex *noopMutexAlloc(int id){
+ UNUSED_PARAMETER(id);
+ return (sqlite3_mutex*)8;
+}
+static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+static int noopMutexTry(sqlite3_mutex *p){
+ UNUSED_PARAMETER(p);
+ return SQLITE_OK;
+}
+static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
noopMutexInit,
noopMutexEnd,
noopMutexAlloc,
@@ -14598,15 +15412,15 @@
noopMutexTry,
noopMutexLeave,
- noopMutexHeld,
- noopMutexNotheld
+ 0,
+ 0,
};
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
+#endif /* !SQLITE_DEBUG */
-#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
+#ifdef SQLITE_DEBUG
/*
** In this implementation, error checking is provided for testing
** and debugging purposes. The mutexes still do not provide any
@@ -14616,19 +15430,21 @@
/*
** The mutex object
*/
-struct sqlite3_mutex {
+typedef struct sqlite3_debug_mutex {
int id; /* The mutex type */
int cnt; /* Number of entries without a matching leave */
-};
+} sqlite3_debug_mutex;
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-static int debugMutexHeld(sqlite3_mutex *p){
+static int debugMutexHeld(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt>0;
}
-static int debugMutexNotheld(sqlite3_mutex *p){
+static int debugMutexNotheld(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt==0;
}
@@ -14644,8 +15460,8 @@
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
- static sqlite3_mutex aStatic[6];
- sqlite3_mutex *pNew = 0;
+ static sqlite3_debug_mutex aStatic[6];
+ sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
@@ -14664,13 +15480,14 @@
break;
}
}
- return pNew;
+ return (sqlite3_mutex*)pNew;
}
/*
** This routine deallocates a previously allocated mutex.
*/
-static void debugMutexFree(sqlite3_mutex *p){
+static void debugMutexFree(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
sqlite3_free(p);
@@ -14687,12 +15504,14 @@
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
-static void debugMutexEnter(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+static void debugMutexEnter(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
}
-static int debugMutexTry(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+static int debugMutexTry(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
return SQLITE_OK;
}
@@ -14703,14 +15522,15 @@
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
-static void debugMutexLeave(sqlite3_mutex *p){
- assert( debugMutexHeld(p) );
+static void debugMutexLeave(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( debugMutexHeld(pX) );
p->cnt--;
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
debugMutexInit,
debugMutexEnd,
debugMutexAlloc,
@@ -14725,7 +15545,18 @@
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */
+#endif /* SQLITE_DEBUG */
+
+/*
+** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
+** is used regardless of the run-time threadsafety setting.
+*/
+#ifdef SQLITE_MUTEX_NOOP
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ return sqlite3NoopMutex();
+}
+#endif /* SQLITE_MUTEX_NOOP */
+#endif /* SQLITE_MUTEX_OMIT */
/************** End of mutex_noop.c ******************************************/
/************** Begin file mutex_os2.c ***************************************/
@@ -14981,8 +15812,8 @@
DosReleaseMutexSem(p->mutex);
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
os2MutexInit,
os2MutexEnd,
os2MutexAlloc,
@@ -15027,23 +15858,33 @@
#include <pthread.h>
+/*
+** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
+** are necessary under two condidtions: (1) Debug builds and (2) using
+** home-grown mutexes. Encapsulate these conditions into a single #define.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
+# define SQLITE_MUTEX_NREF 1
+#else
+# define SQLITE_MUTEX_NREF 0
+#endif
/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
+#if SQLITE_MUTEX_NREF
int id; /* Mutex type */
- int nRef; /* Number of entrances */
- pthread_t owner; /* Thread that is within this mutex */
-#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of entrances */
+ volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
#endif
};
-#ifdef SQLITE_DEBUG
+#if SQLITE_MUTEX_NREF
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
#else
-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0 }
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#endif
/*
@@ -15145,14 +15986,18 @@
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
@@ -15161,7 +16006,9 @@
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(staticMutexes) );
p = &staticMutexes[iType-2];
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
break;
}
}
@@ -15221,9 +16068,11 @@
/* Use the built-in recursive mutexes if they are available.
*/
pthread_mutex_lock(&p->mutex);
+#if SQLITE_MUTEX_NREF
p->owner = pthread_self();
p->nRef++;
#endif
+#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
@@ -15264,8 +16113,10 @@
/* Use the built-in recursive mutexes if they are available.
*/
if( pthread_mutex_trylock(&p->mutex)==0 ){
+#if SQLITE_MUTEX_NREF
p->owner = pthread_self();
p->nRef++;
+#endif
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
@@ -15288,7 +16139,9 @@
*/
static void pthreadMutexLeave(sqlite3_mutex *p){
assert( pthreadMutexHeld(p) );
+#if SQLITE_MUTEX_NREF
p->nRef--;
+#endif
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
@@ -15306,8 +16159,8 @@
#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
pthreadMutexInit,
pthreadMutexEnd,
pthreadMutexAlloc,
@@ -15357,9 +16210,18 @@
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
- int nRef; /* Number of enterances */
- DWORD owner; /* Thread holding this mutex */
+#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of enterances */
+ volatile DWORD owner; /* Thread holding this mutex */
+ int trace; /* True to trace changes */
+#endif
};
+#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
+#ifdef SQLITE_DEBUG
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
+#else
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
+#endif
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
@@ -15403,8 +16265,12 @@
static int winMutexHeld(sqlite3_mutex *p){
return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
+static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
+ return p->nRef==0 || p->owner!=tid;
+}
static int winMutexNotheld(sqlite3_mutex *p){
- return p->nRef==0 || p->owner!=GetCurrentThreadId();
+ DWORD tid = GetCurrentThreadId();
+ return winMutexNotheld2(p, tid);
}
#endif
@@ -15412,7 +16278,14 @@
/*
** Initialize and deinitialize the mutex subsystem.
*/
-static sqlite3_mutex winMutex_staticMutexes[6];
+static sqlite3_mutex winMutex_staticMutexes[6] = {
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER
+};
static int winMutex_isInit = 0;
/* As winMutexInit() and winMutexEnd() are called as part
** of the sqlite3_initialize and sqlite3_shutdown()
@@ -15503,7 +16376,9 @@
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
InitializeCriticalSection(&p->mutex);
}
break;
@@ -15513,7 +16388,9 @@
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
p = &winMutex_staticMutexes[iType-2];
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
break;
}
}
@@ -15546,14 +16423,25 @@
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
+#ifdef SQLITE_DEBUG
+ DWORD tid = GetCurrentThreadId();
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+#endif
EnterCriticalSection(&p->mutex);
- p->owner = GetCurrentThreadId();
+#ifdef SQLITE_DEBUG
+ p->owner = tid;
p->nRef++;
+ if( p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
}
static int winMutexTry(sqlite3_mutex *p){
+#ifndef NDEBUG
+ DWORD tid = GetCurrentThreadId();
+#endif
int rc = SQLITE_BUSY;
- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
/*
** The sqlite3_mutex_try() routine is very rarely used, and when it
** is used it is merely an optimization. So it is OK for it to always
@@ -15567,13 +16455,18 @@
*/
#if 0
if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
- p->owner = GetCurrentThreadId();
+ p->owner = tid;
p->nRef++;
rc = SQLITE_OK;
}
#else
UNUSED_PARAMETER(p);
#endif
+#ifdef SQLITE_DEBUG
+ if( rc==SQLITE_OK && p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
return rc;
}
@@ -15584,15 +16477,23 @@
** is not currently allocated. SQLite will never do either.
*/
static void winMutexLeave(sqlite3_mutex *p){
+#ifndef NDEBUG
+ DWORD tid = GetCurrentThreadId();
assert( p->nRef>0 );
- assert( p->owner==GetCurrentThreadId() );
+ assert( p->owner==tid );
p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+#endif
LeaveCriticalSection(&p->mutex);
+#ifdef SQLITE_DEBUG
+ if( p->trace ){
+ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
winMutexInit,
winMutexEnd,
winMutexAlloc,
@@ -15930,11 +16831,11 @@
assert( n>0 );
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than one scratch allocation per thread
+ /* Verify that no more than two scratch allocation per thread
** is outstanding at one time. (This is only checked in the
** single-threaded case since checking in the multi-threaded case
** would be much more complicated.) */
- assert( scratchAllocOut==0 );
+ assert( scratchAllocOut<=1 );
#endif
if( sqlite3GlobalConfig.szScratch<n ){
@@ -15971,6 +16872,7 @@
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
scratchAllocOut = p!=0;
#endif
@@ -15978,19 +16880,11 @@
}
SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
if( p ){
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than one scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut==1 );
- scratchAllocOut = 0;
-#endif
-
if( sqlite3GlobalConfig.pScratch==0
|| p<sqlite3GlobalConfig.pScratch
|| p>=(void*)mem0.aScratchFree ){
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
@@ -16011,6 +16905,16 @@
mem0.aScratchFree[mem0.nScratchFree++] = i;
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
sqlite3_mutex_leave(mem0.mutex);
+
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+ /* Verify that no more than two scratch allocation per thread
+ ** is outstanding at one time. (This is only checked in the
+ ** single-threaded case since checking in the multi-threaded case
+ ** would be much more complicated.) */
+ assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
+ scratchAllocOut = 0;
+#endif
+
}
}
}
@@ -16031,6 +16935,7 @@
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
@@ -16038,6 +16943,8 @@
if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
+ assert( sqlite3MemdebugHasType(p,
+ db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
}
@@ -16047,6 +16954,7 @@
*/
SQLITE_API void sqlite3_free(void *p){
if( p==0 ) return;
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
@@ -16069,6 +16977,8 @@
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
}else{
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
}
@@ -16101,6 +17011,7 @@
mem0.alarmThreshold ){
sqlite3MallocAlarm(nNew-nOld);
}
+ assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
if( pNew==0 && mem0.alarmCallback ){
sqlite3MallocAlarm(nBytes);
@@ -16198,6 +17109,8 @@
if( !p && db ){
db->mallocFailed = 1;
}
+ sqlite3MemdebugSetType(p,
+ (db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP);
return p;
}
@@ -16223,10 +17136,14 @@
sqlite3DbFree(db, p);
}
}else{
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc(p, n);
if( !pNew ){
db->mallocFailed = 1;
}
+ sqlite3MemdebugSetType(pNew,
+ db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP);
}
}
return pNew;
@@ -16787,7 +17704,9 @@
case etEXP:
case etGENERIC:
realvalue = va_arg(ap,double);
-#ifndef SQLITE_OMIT_FLOATING_POINT
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ length = 0;
+#else
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
if( realvalue<0.0 ){
@@ -16933,7 +17852,7 @@
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif
+#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
case etSIZE:
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -16980,7 +17899,7 @@
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
k = precision;
- for(i=n=0; (ch=escarg[i])!=0 && k!=0; i++, k--){
+ for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
if( ch==q ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
@@ -17274,12 +18193,8 @@
** mutex is held.
*/
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
- StrAccum acc; /* String accumulator */
-#ifdef SQLITE_SMALL_STACK
- char zMsg[150]; /* Complete log message */
-#else
- char zMsg[400]; /* Complete log message */
-#endif
+ StrAccum acc; /* String accumulator */
+ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
acc.useMalloc = 0;
@@ -17832,7 +18747,7 @@
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
i64 startTime; /* Time when query started - used for profiling */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
- int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
+ int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
@@ -17884,7 +18799,11 @@
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
-SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
+#ifdef SQLITE_OMIT_FLOATING_POINT
+# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
+#else
+SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
+#endif
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
@@ -18337,11 +19256,11 @@
**
** NULL is returned if there is an allocation error.
*/
-SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
+SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
Mem m;
memset(&m, 0, sizeof(m));
m.db = db;
- sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+ sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
if( db->mallocFailed ){
sqlite3VdbeMemRelease(&m);
@@ -18349,7 +19268,9 @@
}
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
- return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z);
+ assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
+ assert( m.z || db->mallocFailed );
+ return m.z;
}
/*
@@ -18490,6 +19411,7 @@
}
#endif
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
**
@@ -18534,6 +19456,7 @@
testcase( rc );
return rc;
}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Compute a string length that is limited to what can be stored in
@@ -18711,6 +19634,7 @@
z += incr;
*realnum = 0;
while( sqlite3Isdigit(*z) ){ z += incr; }
+#ifndef SQLITE_OMIT_FLOATING_POINT
if( *z=='.' ){
z += incr;
if( !sqlite3Isdigit(*z) ) return 0;
@@ -18724,6 +19648,7 @@
while( sqlite3Isdigit(*z) ){ z += incr; }
*realnum = 1;
}
+#endif
return *z==0;
}
@@ -18885,6 +19810,9 @@
c = memcmp(zNum,"922337203685477580",18)*10;
if( c==0 ){
c = zNum[18] - '8';
+ testcase( c==(-1) );
+ testcase( c==0 );
+ testcase( c==(+1) );
}
return c;
}
@@ -18921,6 +19849,9 @@
v = v*10 + c - '0';
}
*pNum = neg ? -v : v;
+ testcase( i==18 );
+ testcase( i==19 );
+ testcase( i==20 );
if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranting that it is too large) */
@@ -18964,6 +19895,9 @@
zNum++; /* Skip leading zeros. Ticket #2454 */
}
for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
+ testcase( i==18 );
+ testcase( i==19 );
+ testcase( i==20 );
if( i<19 ){
/* Guaranteed to fit if less than 19 digits */
return 1;
@@ -19004,9 +19938,11 @@
** 1234567890
** 2^31 -> 2147483648
*/
+ testcase( i==10 );
if( i>10 ){
return 0;
}
+ testcase( v-neg==2147483647 );
if( v-neg>2147483647 ){
return 0;
}
@@ -19095,6 +20031,19 @@
}
/*
+** Bitmasks used by sqlite3GetVarint(). These precomputed constants
+** are defined here rather than simply putting the constant expressions
+** inline in order to work around bugs in the RVT compiler.
+**
+** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
+**
+** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
+*/
+#define SLOT_2_0 0x001fc07f
+#define SLOT_4_2_0 0xf01fc07f
+
+
+/*
** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v.
*/
@@ -19121,13 +20070,17 @@
return 2;
}
+ /* Verify that constants are precomputed correctly */
+ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
+ assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
+
p++;
a = a<<14;
a |= *p;
/* a: p0<<14 | p2 (unmasked) */
if (!(a&0x80))
{
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
b &= 0x7f;
b = b<<7;
a |= b;
@@ -19136,14 +20089,14 @@
}
/* CSE1 from below */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
p++;
b = b<<14;
b |= *p;
/* b: p1<<14 | p3 (unmasked) */
if (!(b&0x80))
{
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
/* moved CSE1 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@@ -19157,7 +20110,7 @@
/* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
/* moved CSE1 up */
/* a &= (0x7f<<14)|(0x7f); */
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
s = a;
/* s: p0<<14 | p2 (masked) */
@@ -19190,7 +20143,7 @@
{
/* we can skip this cause it was (effectively) done above in calc'ing s */
/* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
a = a<<7;
a |= b;
s = s>>18;
@@ -19204,8 +20157,8 @@
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
if (!(a&0x80))
{
- a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
- b &= (0x7f<<14)|(0x7f);
+ a &= SLOT_4_2_0;
+ b &= SLOT_2_0;
b = b<<7;
a |= b;
s = s>>11;
@@ -19214,14 +20167,14 @@
}
/* CSE2 from below */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
p++;
b = b<<14;
b |= *p;
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
if (!(b&0x80))
{
- b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
+ b &= SLOT_4_2_0;
/* moved CSE2 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@@ -19238,7 +20191,7 @@
/* moved CSE2 up */
/* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
b = b<<8;
a |= b;
@@ -19358,9 +20311,9 @@
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
- /* Walues between 268435456 and 34359738367 */
- a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
- b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
+ /* Values between 268435456 and 34359738367 */
+ a &= SLOT_4_2_0;
+ b &= SLOT_4_2_0;
b = b<<7;
*v = a | b;
return 5;
@@ -19487,7 +20440,8 @@
}
magic = db->magic;
if( magic!=SQLITE_MAGIC_OPEN ){
- if( !sqlite3SafetyCheckSickOrOk(db) ){
+ if( sqlite3SafetyCheckSickOrOk(db) ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
logBadConnection("unopened");
}
return 0;
@@ -19501,6 +20455,7 @@
if( magic!=SQLITE_MAGIC_SICK &&
magic!=SQLITE_MAGIC_OPEN &&
magic!=SQLITE_MAGIC_BUSY ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
logBadConnection("invalid");
return 0;
}else{
@@ -19832,39 +20787,39 @@
/* 37 */ "VerifyCookie",
/* 38 */ "OpenRead",
/* 39 */ "OpenWrite",
- /* 40 */ "OpenEphemeral",
- /* 41 */ "OpenPseudo",
- /* 42 */ "Close",
- /* 43 */ "SeekLt",
- /* 44 */ "SeekLe",
- /* 45 */ "SeekGe",
- /* 46 */ "SeekGt",
- /* 47 */ "Seek",
- /* 48 */ "NotFound",
- /* 49 */ "Found",
- /* 50 */ "IsUnique",
- /* 51 */ "NotExists",
- /* 52 */ "Sequence",
- /* 53 */ "NewRowid",
- /* 54 */ "Insert",
- /* 55 */ "InsertInt",
- /* 56 */ "Delete",
- /* 57 */ "ResetCount",
- /* 58 */ "RowKey",
- /* 59 */ "RowData",
- /* 60 */ "Rowid",
- /* 61 */ "NullRow",
- /* 62 */ "Last",
- /* 63 */ "Sort",
- /* 64 */ "Rewind",
- /* 65 */ "Prev",
- /* 66 */ "Next",
- /* 67 */ "IdxInsert",
+ /* 40 */ "OpenAutoindex",
+ /* 41 */ "OpenEphemeral",
+ /* 42 */ "OpenPseudo",
+ /* 43 */ "Close",
+ /* 44 */ "SeekLt",
+ /* 45 */ "SeekLe",
+ /* 46 */ "SeekGe",
+ /* 47 */ "SeekGt",
+ /* 48 */ "Seek",
+ /* 49 */ "NotFound",
+ /* 50 */ "Found",
+ /* 51 */ "IsUnique",
+ /* 52 */ "NotExists",
+ /* 53 */ "Sequence",
+ /* 54 */ "NewRowid",
+ /* 55 */ "Insert",
+ /* 56 */ "InsertInt",
+ /* 57 */ "Delete",
+ /* 58 */ "ResetCount",
+ /* 59 */ "RowKey",
+ /* 60 */ "RowData",
+ /* 61 */ "Rowid",
+ /* 62 */ "NullRow",
+ /* 63 */ "Last",
+ /* 64 */ "Sort",
+ /* 65 */ "Rewind",
+ /* 66 */ "Prev",
+ /* 67 */ "Next",
/* 68 */ "Or",
/* 69 */ "And",
- /* 70 */ "IdxDelete",
- /* 71 */ "IdxRowid",
- /* 72 */ "IdxLT",
+ /* 70 */ "IdxInsert",
+ /* 71 */ "IdxDelete",
+ /* 72 */ "IdxRowid",
/* 73 */ "IsNull",
/* 74 */ "NotNull",
/* 75 */ "Ne",
@@ -19873,7 +20828,7 @@
/* 78 */ "Le",
/* 79 */ "Lt",
/* 80 */ "Ge",
- /* 81 */ "IdxGE",
+ /* 81 */ "IdxLT",
/* 82 */ "BitAnd",
/* 83 */ "BitOr",
/* 84 */ "ShiftLeft",
@@ -19884,52 +20839,52 @@
/* 89 */ "Divide",
/* 90 */ "Remainder",
/* 91 */ "Concat",
- /* 92 */ "Destroy",
+ /* 92 */ "IdxGE",
/* 93 */ "BitNot",
/* 94 */ "String8",
- /* 95 */ "Clear",
- /* 96 */ "CreateIndex",
- /* 97 */ "CreateTable",
- /* 98 */ "ParseSchema",
- /* 99 */ "LoadAnalysis",
- /* 100 */ "DropTable",
- /* 101 */ "DropIndex",
- /* 102 */ "DropTrigger",
- /* 103 */ "IntegrityCk",
- /* 104 */ "RowSetAdd",
- /* 105 */ "RowSetRead",
- /* 106 */ "RowSetTest",
- /* 107 */ "Program",
- /* 108 */ "Param",
- /* 109 */ "FkCounter",
- /* 110 */ "FkIfZero",
- /* 111 */ "MemMax",
- /* 112 */ "IfPos",
- /* 113 */ "IfNeg",
- /* 114 */ "IfZero",
- /* 115 */ "AggStep",
- /* 116 */ "AggFinal",
- /* 117 */ "Vacuum",
- /* 118 */ "IncrVacuum",
- /* 119 */ "Expire",
- /* 120 */ "TableLock",
- /* 121 */ "VBegin",
- /* 122 */ "VCreate",
- /* 123 */ "VDestroy",
- /* 124 */ "VOpen",
- /* 125 */ "VFilter",
- /* 126 */ "VColumn",
- /* 127 */ "VNext",
- /* 128 */ "VRename",
- /* 129 */ "VUpdate",
+ /* 95 */ "Destroy",
+ /* 96 */ "Clear",
+ /* 97 */ "CreateIndex",
+ /* 98 */ "CreateTable",
+ /* 99 */ "ParseSchema",
+ /* 100 */ "LoadAnalysis",
+ /* 101 */ "DropTable",
+ /* 102 */ "DropIndex",
+ /* 103 */ "DropTrigger",
+ /* 104 */ "IntegrityCk",
+ /* 105 */ "RowSetAdd",
+ /* 106 */ "RowSetRead",
+ /* 107 */ "RowSetTest",
+ /* 108 */ "Program",
+ /* 109 */ "Param",
+ /* 110 */ "FkCounter",
+ /* 111 */ "FkIfZero",
+ /* 112 */ "MemMax",
+ /* 113 */ "IfPos",
+ /* 114 */ "IfNeg",
+ /* 115 */ "IfZero",
+ /* 116 */ "AggStep",
+ /* 117 */ "AggFinal",
+ /* 118 */ "Checkpoint",
+ /* 119 */ "JournalMode",
+ /* 120 */ "Vacuum",
+ /* 121 */ "IncrVacuum",
+ /* 122 */ "Expire",
+ /* 123 */ "TableLock",
+ /* 124 */ "VBegin",
+ /* 125 */ "VCreate",
+ /* 126 */ "VDestroy",
+ /* 127 */ "VOpen",
+ /* 128 */ "VFilter",
+ /* 129 */ "VColumn",
/* 130 */ "Real",
- /* 131 */ "Pagecount",
- /* 132 */ "Trace",
- /* 133 */ "Noop",
- /* 134 */ "Explain",
- /* 135 */ "NotUsed_135",
- /* 136 */ "NotUsed_136",
- /* 137 */ "NotUsed_137",
+ /* 131 */ "VNext",
+ /* 132 */ "VRename",
+ /* 133 */ "VUpdate",
+ /* 134 */ "Pagecount",
+ /* 135 */ "Trace",
+ /* 136 */ "Noop",
+ /* 137 */ "Explain",
/* 138 */ "NotUsed_138",
/* 139 */ "NotUsed_139",
/* 140 */ "NotUsed_140",
@@ -20034,23 +20989,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -20246,7 +21187,7 @@
APIRET rc = NO_ERROR;
os2File *pFile;
if( id && (pFile = (os2File*)id) != 0 ){
- OSTRACE2( "CLOSE %d\n", pFile->h );
+ OSTRACE(( "CLOSE %d\n", pFile->h ));
rc = DosClose( pFile->h );
pFile->locktype = NO_LOCK;
if( pFile->pathToDel != NULL ){
@@ -20277,7 +21218,7 @@
os2File *pFile = (os2File*)id;
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_READ );
- OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20310,7 +21251,7 @@
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_WRITE );
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20332,7 +21273,7 @@
static int os2Truncate( sqlite3_file *id, i64 nByte ){
APIRET rc = NO_ERROR;
os2File *pFile = (os2File*)id;
- OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
+ OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
rc = DosSetFileSize( pFile->h, nByte );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
@@ -20352,7 +21293,7 @@
*/
static int os2Sync( sqlite3_file *id, int flags ){
os2File *pFile = (os2File*)id;
- OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
#ifdef SQLITE_TEST
if( flags & SQLITE_SYNC_FULL){
sqlite3_fullsync_count++;
@@ -20402,7 +21343,7 @@
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
+ OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
return res;
}
@@ -20420,7 +21361,7 @@
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
+ OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
return res;
}
@@ -20461,14 +21402,14 @@
memset(&LockArea, 0, sizeof(LockArea));
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
- OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
/* If there is already a lock of this type or more restrictive on the
** os2File, do nothing. Don't use the end_lock: exit path, as
** sqlite3_mutex_enter() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
- OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
+ OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
return SQLITE_OK;
}
@@ -20495,7 +21436,7 @@
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
if( res == NO_ERROR ){
gotPendingLock = 1;
- OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
}
}
@@ -20507,7 +21448,7 @@
if( res == NO_ERROR ){
newLocktype = SHARED_LOCK;
}
- OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
}
/* Acquire a RESERVED lock
@@ -20522,7 +21463,7 @@
if( res == NO_ERROR ){
newLocktype = RESERVED_LOCK;
}
- OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
}
/* Acquire a PENDING lock
@@ -20530,7 +21471,8 @@
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
newLocktype = PENDING_LOCK;
gotPendingLock = 0;
- OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
+ OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
+ pFile->h ));
}
/* Acquire an EXCLUSIVE lock
@@ -20538,7 +21480,7 @@
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2( "unreadlock = %d\n", res );
+ OSTRACE(( "unreadlock = %d\n", res ));
LockArea.lOffset = SHARED_FIRST;
LockArea.lRange = SHARED_SIZE;
UnlockArea.lOffset = 0L;
@@ -20547,10 +21489,10 @@
if( res == NO_ERROR ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- OSTRACE2( "OS/2 error-code = %d\n", res );
+ OSTRACE(( "OS/2 error-code = %d\n", res ));
getReadLock(pFile);
}
- OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
}
/* If we are holding a PENDING lock that ought to be released, then
@@ -20563,7 +21505,7 @@
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
+ OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
}
/* Update the state of the lock has held in the file descriptor then
@@ -20572,12 +21514,12 @@
if( res == NO_ERROR ){
rc = SQLITE_OK;
}else{
- OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype );
+ OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype ));
rc = SQLITE_BUSY;
}
pFile->locktype = newLocktype;
- OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -20592,7 +21534,7 @@
assert( pFile!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
r = 1;
- OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
}else{
FILELOCK LockArea,
UnlockArea;
@@ -20604,7 +21546,7 @@
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
+ OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
if( rc == NO_ERROR ){
APIRET rcu = NO_ERROR; /* return code for unlocking */
LockArea.lOffset = 0L;
@@ -20612,10 +21554,10 @@
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
+ OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
}
r = !(rc == NO_ERROR);
- OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
}
*pOut = r;
return SQLITE_OK;
@@ -20643,7 +21585,7 @@
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
LockArea.lOffset = 0L;
@@ -20651,11 +21593,11 @@
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
+ OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
rc = SQLITE_IOERR_UNLOCK;
}
}
@@ -20665,11 +21607,12 @@
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
res = unlockReadLock(pFile);
- OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
+ OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
+ pFile->h, type, locktype, res ));
}
if( type>=PENDING_LOCK ){
LockArea.lOffset = 0L;
@@ -20677,10 +21620,10 @@
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
}
pFile->locktype = locktype;
- OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -20691,7 +21634,8 @@
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = ((os2File*)id)->locktype;
- OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+ OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
+ ((os2File*)id)->h, ((os2File*)id)->locktype ));
return SQLITE_OK;
}
}
@@ -20878,7 +21822,7 @@
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
+ OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
return SQLITE_OK;
}
@@ -20941,30 +21885,30 @@
memset( pFile, 0, sizeof(*pFile) );
- OSTRACE2( "OPEN want %d\n", flags );
+ OSTRACE( "OPEN want %d\n", flags ));
if( flags & SQLITE_OPEN_READWRITE ){
ulOpenMode |= OPEN_ACCESS_READWRITE;
- OSTRACE1( "OPEN read/write\n" );
+ OSTRACE(( "OPEN read/write\n" ));
}else{
ulOpenMode |= OPEN_ACCESS_READONLY;
- OSTRACE1( "OPEN read only\n" );
+ OSTRACE(( "OPEN read only\n" ));
}
if( flags & SQLITE_OPEN_CREATE ){
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
- OSTRACE1( "OPEN open new/create\n" );
+ OSTRACE(( "OPEN open new/create\n" ));
}else{
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
- OSTRACE1( "OPEN open existing\n" );
+ OSTRACE(( "OPEN open existing\n" ));
}
if( flags & SQLITE_OPEN_MAIN_DB ){
ulOpenMode |= OPEN_SHARE_DENYNONE;
- OSTRACE1( "OPEN share read/write\n" );
+ OSTRACE(( "OPEN share read/write\n" ));
}else{
ulOpenMode |= OPEN_SHARE_DENYWRITE;
- OSTRACE1( "OPEN share read only\n" );
+ OSTRACE(( "OPEN share read only\n" ));
}
if( flags & SQLITE_OPEN_DELETEONCLOSE ){
@@ -20974,10 +21918,10 @@
#endif
os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
- OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
+ OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
}else{
pFile->pathToDel = NULL;
- OSTRACE1( "OPEN normal file attribute\n" );
+ OSTRACE(( "OPEN normal file attribute\n" ));
}
/* always open in random access mode for possibly better speed */
@@ -20996,13 +21940,14 @@
(PEAOP2)NULL );
free( zNameCp );
if( rc != NO_ERROR ){
- OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
- rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
+ OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
+ rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
if( pFile->pathToDel )
free( pFile->pathToDel );
pFile->pathToDel = NULL;
if( flags & SQLITE_OPEN_READWRITE ){
- OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
+ OSTRACE(( "OPEN %d Invalid handle\n",
+ ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
return os2Open( pVfs, zName, id,
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
pOutFlags );
@@ -21018,7 +21963,7 @@
pFile->pMethod = &os2IoMethod;
pFile->h = h;
OpenCounter(+1);
- OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
+ OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
return SQLITE_OK;
}
@@ -21035,7 +21980,7 @@
SimulateIOError( return SQLITE_IOERR_DELETE );
rc = DosDelete( (PSZ)zFilenameCp );
free( zFilenameCp );
- OSTRACE2( "DELETE \"%s\"\n", zFilename );
+ OSTRACE(( "DELETE \"%s\"\n", zFilename ));
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
@@ -21056,17 +22001,17 @@
rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
&fsts3ConfigInfo, sizeof(FILESTATUS3) );
free( zFilenameCp );
- OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
- fsts3ConfigInfo.attrFile, flags, rc );
+ OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
+ fsts3ConfigInfo.attrFile, flags, rc ));
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
rc = (rc == NO_ERROR);
- OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
+ OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc));
break;
case SQLITE_ACCESS_READWRITE:
rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
- OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
+ OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc ));
break;
default:
assert( !"Invalid flags argument" );
@@ -21276,7 +22221,7 @@
os2Randomness, /* xRandomness */
os2Sleep, /* xSleep */
os2CurrentTime, /* xCurrentTime */
- os2GetLastError /* xGetLastError */
+ os2GetLastError, /* xGetLastError */
};
sqlite3_vfs_register(&os2Vfs, 1);
initUconvObjects();
@@ -21410,6 +22355,7 @@
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
+#include <sys/mman.h>
#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
@@ -21419,10 +22365,18 @@
# else
# include <sys/file.h>
# include <sys/param.h>
-# include <sys/mount.h>
# endif
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+# include <sys/mount.h>
+#endif
+
+/*
+** Allowed values of unixFile.fsFlags
+*/
+#define SQLITE_FSFLAGS_IS_MSDOS 0x1
+
/*
** If we are to be thread-safe, include the pthreads header and define
** the SQLITE_UNIX_THREADS macro.
@@ -21456,6 +22410,11 @@
*/
#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
+/* Forward references */
+typedef struct unixShm unixShm; /* Connection shared memory */
+typedef struct unixShmNode unixShmNode; /* Shared memory instance */
+typedef struct unixInodeInfo unixInodeInfo; /* An i-node */
+typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */
/*
** Sometimes, after a file handle is closed by SQLite, the file descriptor
@@ -21463,7 +22422,6 @@
** structure are used to store the file descriptor while waiting for an
** opportunity to either close or reuse it.
*/
-typedef struct UnixUnusedFd UnixUnusedFd;
struct UnixUnusedFd {
int fd; /* File descriptor to close */
int flags; /* Flags this file descriptor was opened with */
@@ -21477,24 +22435,25 @@
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
- struct unixOpenCnt *pOpen; /* Info about all open fd's on this inode */
- struct unixLockInfo *pLock; /* Info about locks on this inode */
- int h; /* The file descriptor */
- int dirfd; /* File descriptor for the directory */
- unsigned char locktype; /* The type of lock held on this fd */
- int lastErrno; /* The unix errno from the last I/O error */
- void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
- int fileFlags; /* Miscellanous flags */
+ unixInodeInfo *pInode; /* Info about locks on this inode */
+ int h; /* The file descriptor */
+ int dirfd; /* File descriptor for the directory */
+ unsigned char eFileLock; /* The type of lock held on this fd */
+ int lastErrno; /* The unix errno from last I/O error */
+ void *lockingContext; /* Locking style specific state */
+ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+ int fileFlags; /* Miscellanous flags */
+ const char *zPath; /* Name of the file */
+ unixShm *pShm; /* Shared memory segment information */
#if SQLITE_ENABLE_LOCKING_STYLE
- int openFlags; /* The flags specified at open() */
+ int openFlags; /* The flags specified at open() */
#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* The thread that "owns" this unixFile */
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
+ unsigned fsFlags; /* cached details from statfs() */
#endif
#if OS_VXWORKS
- int isDelete; /* Delete on close if true */
- struct vxworksFileId *pId; /* Unique file ID */
+ int isDelete; /* Delete on close if true */
+ struct vxworksFileId *pId; /* Unique file ID */
#endif
#ifndef NDEBUG
/* The next group of variables are used to track whether or not the
@@ -21559,23 +22518,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -21785,7 +22730,7 @@
/*
** Helper functions to obtain and relinquish the global mutex. The
-** global mutex is used to protect the unixOpenCnt, unixLockInfo and
+** global mutex is used to protect the unixInodeInfo and
** vxworksFileId objects used by this file, all of which may be
** shared by multiple threads.
**
@@ -21816,8 +22761,8 @@
** binaries. This returns the string represetation of the supplied
** integer lock-type.
*/
-static const char *locktypeName(int locktype){
- switch( locktype ){
+static const char *azFileLock(int eFileLock){
+ switch( eFileLock ){
case NO_LOCK: return "NONE";
case SHARED_LOCK: return "SHARED";
case RESERVED_LOCK: return "RESERVED";
@@ -22154,13 +23099,12 @@
**
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
-** released. To work around this problem, each unixFile structure contains
-** a pointer to an unixOpenCnt structure. There is one unixOpenCnt structure
-** per open inode, which means that multiple unixFile can point to a single
-** unixOpenCnt. When an attempt is made to close an unixFile, if there are
+** released. To work around this problem, each unixInodeInfo object
+** maintains a count of the number of pending locks on tha inode.
+** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
-** The unixOpenCnt structure keeps a list of file descriptors that need to
+** The unixInodeInfo structure keeps a list of file descriptors that need to
** be closed and that list is walked (and cleared) when the last lock
** clears.
**
@@ -22175,46 +23119,19 @@
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
** compile-time whether or not thread A can override locks on thread B.
-** We have to do a run-time check to discover the behavior of the
+** One has to do a run-time check to discover the behavior of the
** current process.
**
-** On systems where thread A is unable to modify locks created by
-** thread B, we have to keep track of which thread created each
-** lock. Hence there is an extra field in the key to the unixLockInfo
-** structure to record this information. And on those systems it
-** is illegal to begin a transaction in one thread and finish it
-** in another. For this latter restriction, there is no work-around.
-** It is a limitation of LinuxThreads.
+** SQLite used to support LinuxThreads. But support for LinuxThreads
+** was dropped beginning with version 3.7.0. SQLite will still work with
+** LinuxThreads provided that (1) there is no more than one connection
+** per database file in the same process and (2) database connections
+** do not move across threads.
*/
/*
-** Set or check the unixFile.tid field. This field is set when an unixFile
-** is first opened. All subsequent uses of the unixFile verify that the
-** same thread is operating on the unixFile. Some operating systems do
-** not allow locks to be overridden by other threads and that restriction
-** means that sqlite3* database handles cannot be moved from one thread
-** to another while locks are held.
-**
-** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to
-** another as long as we are running on a system that supports threads
-** overriding each others locks (which is now the most common behavior)
-** or if no locks are held. But the unixFile.pLock field needs to be
-** recomputed because its key includes the thread-id. See the
-** transferOwnership() function below for additional information
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# define SET_THREADID(X) (X)->tid = pthread_self()
-# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
- !pthread_equal((X)->tid, pthread_self()))
-#else
-# define SET_THREADID(X)
-# define CHECK_THREADID(X) 0
-#endif
-
-/*
** An instance of the following structure serves as the key used
-** to locate a particular unixOpenCnt structure given its inode. This
-** is the same as the unixLockKey except that the thread ID is omitted.
+** to locate a particular unixInodeInfo object.
*/
struct unixFileId {
dev_t dev; /* Device number */
@@ -22226,23 +23143,6 @@
};
/*
-** An instance of the following structure serves as the key used
-** to locate a particular unixLockInfo structure given its inode.
-**
-** If threads cannot override each others locks (LinuxThreads), then we
-** set the unixLockKey.tid field to the thread ID. If threads can override
-** each others locks (Posix and NPTL) then tid is always set to zero.
-** tid is omitted if we compile without threading support or on an OS
-** other than linux.
-*/
-struct unixLockKey {
- struct unixFileId fid; /* Unique identifier for the file */
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* Thread ID of lock owner. Zero if not using LinuxThreads */
-#endif
-};
-
-/*
** An instance of the following structure is allocated for each open
** inode. Or, on LinuxThreads, there is one of these structures for
** each inode opened by each thread.
@@ -22251,227 +23151,109 @@
** structure contains a pointer to an instance of this object and this
** object keeps a count of the number of unixFile pointing to it.
*/
-struct unixLockInfo {
- struct unixLockKey lockKey; /* The lookup key */
- int cnt; /* Number of SHARED locks held */
- int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+struct unixInodeInfo {
+ struct unixFileId fileId; /* The lookup key */
+ int nShared; /* Number of SHARED locks held */
+ int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
int nRef; /* Number of pointers to this structure */
- struct unixLockInfo *pNext; /* List of all unixLockInfo objects */
- struct unixLockInfo *pPrev; /* .... doubly linked */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode. This structure keeps track of the number of locks on that
-** inode. If a close is attempted against an inode that is holding
-** locks, the close is deferred until all locks clear by adding the
-** file descriptor to be closed to the pending list.
-**
-** TODO: Consider changing this so that there is only a single file
-** descriptor for each open file, even when it is opened multiple times.
-** The close() system call would only occur when the last database
-** using the file closes.
-*/
-struct unixOpenCnt {
- struct unixFileId fileId; /* The lookup key */
- int nRef; /* Number of pointers to this structure */
- int nLock; /* Number of outstanding locks */
- UnixUnusedFd *pUnused; /* Unused file descriptors to close */
+ unixShmNode *pShmNode; /* Shared memory associated with this inode */
+ int nLock; /* Number of outstanding file locks */
+ UnixUnusedFd *pUnused; /* Unused file descriptors to close */
+ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
+ unixInodeInfo *pPrev; /* .... doubly linked */
+#if defined(SQLITE_ENABLE_LOCKING_STYLE)
+ unsigned long long sharedByte; /* for AFP simulated shared lock */
+#endif
#if OS_VXWORKS
- sem_t *pSem; /* Named POSIX semaphore */
- char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
+ sem_t *pSem; /* Named POSIX semaphore */
+ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
#endif
- struct unixOpenCnt *pNext, *pPrev; /* List of all unixOpenCnt objects */
};
/*
-** Lists of all unixLockInfo and unixOpenCnt objects. These used to be hash
-** tables. But the number of objects is rarely more than a dozen and
-** never exceeds a few thousand. And lookup is not on a critical
-** path so a simple linked list will suffice.
+** A lists of all unixInodeInfo objects.
*/
-static struct unixLockInfo *lockList = 0;
-static struct unixOpenCnt *openList = 0;
+static unixInodeInfo *inodeList = 0;
/*
-** This variable remembers whether or not threads can override each others
-** locks.
+** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** If all such file descriptors are closed without error, the list is
+** cleared and SQLITE_OK returned.
**
-** 0: No. Threads cannot override each others locks. (LinuxThreads)
-** 1: Yes. Threads can override each others locks. (Posix & NLPT)
-** -1: We don't know yet.
-**
-** On some systems, we know at compile-time if threads can override each
-** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
-** will be set appropriately. On other systems, we have to check at
-** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
-** undefined.
-**
-** This variable normally has file scope only. But during testing, we make
-** it a global so that the test code can change its value in order to verify
-** that the right stuff happens in either case.
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# ifndef SQLITE_THREAD_OVERRIDE_LOCK
-# define SQLITE_THREAD_OVERRIDE_LOCK -1
-# endif
-# ifdef SQLITE_TEST
-int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# else
-static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# endif
-#endif
-
-/*
-** This structure holds information passed into individual test
-** threads by the testThreadLockingBehavior() routine.
-*/
-struct threadTestData {
- int fd; /* File to be locked */
- struct flock lock; /* The locking operation */
- int result; /* Result of the locking operation */
-};
-
-#if SQLITE_THREADSAFE && defined(__linux__)
-/*
-** This function is used as the main routine for a thread launched by
-** testThreadLockingBehavior(). It tests whether the shared-lock obtained
-** by the main thread in testThreadLockingBehavior() conflicts with a
-** hypothetical write-lock obtained by this thread on the same file.
-**
-** The write-lock is not actually acquired, as this is not possible if
-** the file is open in read-only mode (see ticket #3472).
+** Otherwise, if an error occurs, then successfully closed file descriptor
+** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
+** not deleted and SQLITE_IOERR_CLOSE returned.
*/
-static void *threadLockingTest(void *pArg){
- struct threadTestData *pData = (struct threadTestData*)pArg;
- pData->result = fcntl(pData->fd, F_GETLK, &pData->lock);
- return pArg;
-}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
-
-
-#if SQLITE_THREADSAFE && defined(__linux__)
-/*
-** This procedure attempts to determine whether or not threads
-** can override each others locks then sets the
-** threadsOverrideEachOthersLocks variable appropriately.
-*/
-static void testThreadLockingBehavior(int fd_orig){
- int fd;
- int rc;
- struct threadTestData d;
- struct flock l;
- pthread_t t;
-
- fd = dup(fd_orig);
- if( fd<0 ) return;
- memset(&l, 0, sizeof(l));
- l.l_type = F_RDLCK;
- l.l_len = 1;
- l.l_start = 0;
- l.l_whence = SEEK_SET;
- rc = fcntl(fd_orig, F_SETLK, &l);
- if( rc!=0 ) return;
- memset(&d, 0, sizeof(d));
- d.fd = fd;
- d.lock = l;
- d.lock.l_type = F_WRLCK;
- if( pthread_create(&t, 0, threadLockingTest, &d)==0 ){
- pthread_join(t, 0);
+static int closePendingFds(unixFile *pFile){
+ int rc = SQLITE_OK;
+ unixInodeInfo *pInode = pFile->pInode;
+ UnixUnusedFd *pError = 0;
+ UnixUnusedFd *p;
+ UnixUnusedFd *pNext;
+ for(p=pInode->pUnused; p; p=pNext){
+ pNext = p->pNext;
+ if( close(p->fd) ){
+ pFile->lastErrno = errno;
+ rc = SQLITE_IOERR_CLOSE;
+ p->pNext = pError;
+ pError = p;
+ }else{
+ sqlite3_free(p);
+ }
}
- close(fd);
- if( d.result!=0 ) return;
- threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK);
+ pInode->pUnused = pError;
+ return rc;
}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
/*
-** Release a unixLockInfo structure previously allocated by findLockInfo().
+** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
*/
-static void releaseLockInfo(struct unixLockInfo *pLock){
+static void releaseInodeInfo(unixFile *pFile){
+ unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
- if( pLock ){
- pLock->nRef--;
- if( pLock->nRef==0 ){
- if( pLock->pPrev ){
- assert( pLock->pPrev->pNext==pLock );
- pLock->pPrev->pNext = pLock->pNext;
+ if( pInode ){
+ pInode->nRef--;
+ if( pInode->nRef==0 ){
+ assert( pInode->pShmNode==0 );
+ closePendingFds(pFile);
+ if( pInode->pPrev ){
+ assert( pInode->pPrev->pNext==pInode );
+ pInode->pPrev->pNext = pInode->pNext;
}else{
- assert( lockList==pLock );
- lockList = pLock->pNext;
+ assert( inodeList==pInode );
+ inodeList = pInode->pNext;
}
- if( pLock->pNext ){
- assert( pLock->pNext->pPrev==pLock );
- pLock->pNext->pPrev = pLock->pPrev;
+ if( pInode->pNext ){
+ assert( pInode->pNext->pPrev==pInode );
+ pInode->pNext->pPrev = pInode->pPrev;
}
- sqlite3_free(pLock);
+ sqlite3_free(pInode);
}
}
}
/*
-** Release a unixOpenCnt structure previously allocated by findLockInfo().
-**
-** The mutex entered using the unixEnterMutex() function must be held
-** when this function is called.
-*/
-static void releaseOpenCnt(struct unixOpenCnt *pOpen){
- assert( unixMutexHeld() );
- if( pOpen ){
- pOpen->nRef--;
- if( pOpen->nRef==0 ){
- if( pOpen->pPrev ){
- assert( pOpen->pPrev->pNext==pOpen );
- pOpen->pPrev->pNext = pOpen->pNext;
- }else{
- assert( openList==pOpen );
- openList = pOpen->pNext;
- }
- if( pOpen->pNext ){
- assert( pOpen->pNext->pPrev==pOpen );
- pOpen->pNext->pPrev = pOpen->pPrev;
- }
-#if SQLITE_THREADSAFE && defined(__linux__)
- assert( !pOpen->pUnused || threadsOverrideEachOthersLocks==0 );
-#endif
-
- /* If pOpen->pUnused is not null, then memory and file-descriptors
- ** are leaked.
- **
- ** This will only happen if, under Linuxthreads, the user has opened
- ** a transaction in one thread, then attempts to close the database
- ** handle from another thread (without first unlocking the db file).
- ** This is a misuse. */
- sqlite3_free(pOpen);
- }
- }
-}
-
-/*
-** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that
-** describes that file descriptor. Create new ones if necessary. The
-** return values might be uninitialized if an error occurs.
+** Given a file descriptor, locate the unixInodeInfo object that
+** describes that file descriptor. Create a new one if necessary. The
+** return value might be uninitialized if an error occurs.
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
**
** Return an appropriate error code.
*/
-static int findLockInfo(
+static int findInodeInfo(
unixFile *pFile, /* Unix file with file desc used in the key */
- struct unixLockInfo **ppLock, /* Return the unixLockInfo structure here */
- struct unixOpenCnt **ppOpen /* Return the unixOpenCnt structure here */
+ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */
){
int rc; /* System call return code */
int fd; /* The file descriptor for pFile */
- struct unixLockKey lockKey; /* Lookup key for the unixLockInfo structure */
- struct unixFileId fileId; /* Lookup key for the unixOpenCnt struct */
+ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */
struct stat statbuf; /* Low-level file information */
- struct unixLockInfo *pLock = 0;/* Candidate unixLockInfo object */
- struct unixOpenCnt *pOpen; /* Candidate unixOpenCnt object */
+ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */
assert( unixMutexHeld() );
@@ -22499,9 +23281,10 @@
** is a race condition such that another thread has already populated
** the first page of the database, no damage is done.
*/
- if( statbuf.st_size==0 ){
+ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
rc = write(fd, "S", 1);
if( rc!=1 ){
+ pFile->lastErrno = errno;
return SQLITE_IOERR;
}
rc = fstat(fd, &statbuf);
@@ -22512,120 +23295,36 @@
}
#endif
- memset(&lockKey, 0, sizeof(lockKey));
- lockKey.fid.dev = statbuf.st_dev;
+ memset(&fileId, 0, sizeof(fileId));
+ fileId.dev = statbuf.st_dev;
#if OS_VXWORKS
- lockKey.fid.pId = pFile->pId;
+ fileId.pId = pFile->pId;
#else
- lockKey.fid.ino = statbuf.st_ino;
+ fileId.ino = statbuf.st_ino;
#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- if( threadsOverrideEachOthersLocks<0 ){
- testThreadLockingBehavior(fd);
+ pInode = inodeList;
+ while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
+ pInode = pInode->pNext;
}
- lockKey.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();
-#endif
- fileId = lockKey.fid;
- if( ppLock!=0 ){
- pLock = lockList;
- while( pLock && memcmp(&lockKey, &pLock->lockKey, sizeof(lockKey)) ){
- pLock = pLock->pNext;
+ if( pInode==0 ){
+ pInode = sqlite3_malloc( sizeof(*pInode) );
+ if( pInode==0 ){
+ return SQLITE_NOMEM;
}
- if( pLock==0 ){
- pLock = sqlite3_malloc( sizeof(*pLock) );
- if( pLock==0 ){
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memcpy(&pLock->lockKey,&lockKey,sizeof(lockKey));
- pLock->nRef = 1;
- pLock->cnt = 0;
- pLock->locktype = 0;
- pLock->pNext = lockList;
- pLock->pPrev = 0;
- if( lockList ) lockList->pPrev = pLock;
- lockList = pLock;
- }else{
- pLock->nRef++;
- }
- *ppLock = pLock;
+ memset(pInode, 0, sizeof(*pInode));
+ memcpy(&pInode->fileId, &fileId, sizeof(fileId));
+ pInode->nRef = 1;
+ pInode->pNext = inodeList;
+ pInode->pPrev = 0;
+ if( inodeList ) inodeList->pPrev = pInode;
+ inodeList = pInode;
+ }else{
+ pInode->nRef++;
}
- if( ppOpen!=0 ){
- pOpen = openList;
- while( pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId)) ){
- pOpen = pOpen->pNext;
- }
- if( pOpen==0 ){
- pOpen = sqlite3_malloc( sizeof(*pOpen) );
- if( pOpen==0 ){
- releaseLockInfo(pLock);
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memset(pOpen, 0, sizeof(*pOpen));
- pOpen->fileId = fileId;
- pOpen->nRef = 1;
- pOpen->pNext = openList;
- if( openList ) openList->pPrev = pOpen;
- openList = pOpen;
- }else{
- pOpen->nRef++;
- }
- *ppOpen = pOpen;
- }
-
-exit_findlockinfo:
- return rc;
+ *ppInode = pInode;
+ return SQLITE_OK;
}
-/*
-** If we are currently in a different thread than the thread that the
-** unixFile argument belongs to, then transfer ownership of the unixFile
-** over to the current thread.
-**
-** A unixFile is only owned by a thread on systems that use LinuxThreads.
-**
-** Ownership transfer is only allowed if the unixFile is currently unlocked.
-** If the unixFile is locked and an ownership is wrong, then return
-** SQLITE_MISUSE. SQLITE_OK is returned if everything works.
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-static int transferOwnership(unixFile *pFile){
- int rc;
- pthread_t hSelf;
- if( threadsOverrideEachOthersLocks ){
- /* Ownership transfers not needed on this system */
- return SQLITE_OK;
- }
- hSelf = pthread_self();
- if( pthread_equal(pFile->tid, hSelf) ){
- /* We are still in the same thread */
- OSTRACE1("No-transfer, same thread\n");
- return SQLITE_OK;
- }
- if( pFile->locktype!=NO_LOCK ){
- /* We cannot change ownership while we are holding a lock! */
- return SQLITE_MISUSE_BKPT;
- }
- OSTRACE4("Transfer ownership of %d from %d to %d\n",
- pFile->h, pFile->tid, hSelf);
- pFile->tid = hSelf;
- if (pFile->pLock != NULL) {
- releaseLockInfo(pFile->pLock);
- rc = findLockInfo(pFile, &pFile->pLock, 0);
- OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
- locktypeName(pFile->locktype),
- locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
- return rc;
- } else {
- return SQLITE_OK;
- }
-}
-#else /* if not SQLITE_THREADSAFE */
- /* On single-threaded builds, ownership transfer is a no-op */
-# define transferOwnership(X) SQLITE_OK
-#endif /* SQLITE_THREADSAFE */
-
/*
** This routine checks if there is a RESERVED lock held on the specified
@@ -22641,10 +23340,10 @@
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
- unixEnterMutex(); /* Because pFile->pLock is shared across threads */
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( pFile->pLock->locktype>SHARED_LOCK ){
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -22668,70 +23367,14 @@
#endif
unixLeaveMutex();
- OSTRACE4("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Perform a file locking operation on a range of bytes in a file.
-** The "op" parameter should be one of F_RDLCK, F_WRLCK, or F_UNLCK.
-** Return 0 on success or -1 for failure. On failure, write the error
-** code into *pErrcode.
-**
-** If the SQLITE_WHOLE_FILE_LOCKING bit is clear, then only lock
-** the range of bytes on the locking page between SHARED_FIRST and
-** SHARED_SIZE. If SQLITE_WHOLE_FILE_LOCKING is set, then lock all
-** bytes from 0 up to but not including PENDING_BYTE, and all bytes
-** that follow SHARED_FIRST.
-**
-** In other words, of SQLITE_WHOLE_FILE_LOCKING if false (the historical
-** default case) then only lock a small range of bytes from SHARED_FIRST
-** through SHARED_FIRST+SHARED_SIZE-1. But if SQLITE_WHOLE_FILE_LOCKING is
-** true then lock every byte in the file except for PENDING_BYTE and
-** RESERVED_BYTE.
-**
-** SQLITE_WHOLE_FILE_LOCKING=true overlaps SQLITE_WHOLE_FILE_LOCKING=false
-** and so the locking schemes are compatible. One type of lock will
-** effectively exclude the other type. The reason for using the
-** SQLITE_WHOLE_FILE_LOCKING=true is that by indicating the full range
-** of bytes to be read or written, we give hints to NFS to help it
-** maintain cache coherency. On the other hand, whole file locking
-** is slower, so we don't want to use it except for NFS.
-*/
-static int rangeLock(unixFile *pFile, int op, int *pErrcode){
- struct flock lock;
- int rc;
- lock.l_type = op;
- lock.l_start = SHARED_FIRST;
- lock.l_whence = SEEK_SET;
- if( (pFile->fileFlags & SQLITE_WHOLE_FILE_LOCKING)==0 ){
- lock.l_len = SHARED_SIZE;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- *pErrcode = errno;
- }else{
- lock.l_len = 0;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- *pErrcode = errno;
- if( NEVER(op==F_UNLCK) || rc!=(-1) ){
- lock.l_start = 0;
- lock.l_len = PENDING_BYTE;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- if( ALWAYS(op!=F_UNLCK) && rc==(-1) ){
- *pErrcode = errno;
- lock.l_type = F_UNLCK;
- lock.l_start = SHARED_FIRST;
- lock.l_len = 0;
- fcntl(pFile->h, F_SETLK, &lock);
- }
- }
- }
- return rc;
-}
-
-/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -22754,7 +23397,7 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int unixLock(sqlite3_file *id, int locktype){
+static int unixLock(sqlite3_file *id, int eFileLock){
/* The following describes the implementation of the various locks and
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
@@ -22795,23 +23438,23 @@
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock = pFile->pLock;
+ unixInodeInfo *pInode = pFile->pInode;
struct flock lock;
int s = 0;
- int tErrno;
+ int tErrno = 0;
assert( pFile );
- OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype),
- locktypeName(pLock->locktype), pLock->cnt , getpid());
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock),
+ azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the end_lock: exit path, as
** unixEnterMutex() hasn't been called yet.
*/
- if( pFile->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (unix)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
@@ -22820,28 +23463,20 @@
** (2) SQLite never explicitly requests a pendig lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+ assert( eFileLock!=PENDING_LOCK );
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
- /* This mutex is needed because pFile->pLock is shared across threads
+ /* This mutex is needed because pFile->pInode is shared across threads
*/
unixEnterMutex();
-
- /* Make sure the current thread owns the pFile.
- */
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
- }
- pLock = pFile->pLock;
+ pInode = pFile->pInode;
/* If some thread using this PID has a lock via a different unixFile*
** handle that precludes the requested lock, return BUSY.
*/
- if( (pFile->locktype!=pLock->locktype &&
- (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
+ if( (pFile->eFileLock!=pInode->eFileLock &&
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
goto end_lock;
@@ -22851,14 +23486,14 @@
** has a SHARED or RESERVED lock, then increment reference counts and
** return SQLITE_OK.
*/
- if( locktype==SHARED_LOCK &&
- (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
- assert( locktype==SHARED_LOCK );
- assert( pFile->locktype==0 );
- assert( pLock->cnt>0 );
- pFile->locktype = SHARED_LOCK;
- pLock->cnt++;
- pFile->pOpen->nLock++;
+ if( eFileLock==SHARED_LOCK &&
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+ assert( eFileLock==SHARED_LOCK );
+ assert( pFile->eFileLock==0 );
+ assert( pInode->nShared>0 );
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nShared++;
+ pInode->nLock++;
goto end_lock;
}
@@ -22869,10 +23504,10 @@
*/
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+ if( eFileLock==SHARED_LOCK
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
- lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
+ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
s = fcntl(pFile->h, F_SETLK, &lock);
if( s==(-1) ){
@@ -22889,13 +23524,16 @@
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- assert( pLock->cnt==0 );
- assert( pLock->locktype==0 );
+ if( eFileLock==SHARED_LOCK ){
+ assert( pInode->nShared==0 );
+ assert( pInode->eFileLock==0 );
/* Now get the read-lock */
- s = rangeLock(pFile, F_RDLCK, &tErrno);
-
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
+ if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
+ tErrno = errno;
+ }
/* Drop the temporary PENDING lock */
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
@@ -22917,11 +23555,11 @@
pFile->lastErrno = tErrno;
}
}else{
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
- pLock->cnt = 1;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
- }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
@@ -22930,21 +23568,22 @@
** assumed that there is a SHARED or greater lock on the file
** already.
*/
- assert( 0!=pFile->locktype );
+ assert( 0!=pFile->eFileLock );
lock.l_type = F_WRLCK;
- switch( locktype ){
+ switch( eFileLock ){
case RESERVED_LOCK:
lock.l_start = RESERVED_BYTE;
- s = fcntl(pFile->h, F_SETLK, &lock);
- tErrno = errno;
break;
case EXCLUSIVE_LOCK:
- s = rangeLock(pFile, F_WRLCK, &tErrno);
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
break;
default:
assert(0);
}
+ s = fcntl(pFile->h, F_SETLK, &lock);
if( s==(-1) ){
+ tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
@@ -22960,8 +23599,8 @@
** write operation (not a hot journal rollback).
*/
if( rc==SQLITE_OK
- && pFile->locktype<=SHARED_LOCK
- && locktype==RESERVED_LOCK
+ && pFile->eFileLock<=SHARED_LOCK
+ && eFileLock==RESERVED_LOCK
){
pFile->transCntrChng = 0;
pFile->dbUpdate = 0;
@@ -22971,47 +23610,17 @@
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- pLock->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
- pLock->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (unix)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
- return rc;
-}
-
-/*
-** Close all file descriptors accumuated in the unixOpenCnt->pUnused list.
-** If all such file descriptors are closed without error, the list is
-** cleared and SQLITE_OK returned.
-**
-** Otherwise, if an error occurs, then successfully closed file descriptor
-** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
-** not deleted and SQLITE_IOERR_CLOSE returned.
-*/
-static int closePendingFds(unixFile *pFile){
- int rc = SQLITE_OK;
- struct unixOpenCnt *pOpen = pFile->pOpen;
- UnixUnusedFd *pError = 0;
- UnixUnusedFd *p;
- UnixUnusedFd *pNext;
- for(p=pOpen->pUnused; p; p=pNext){
- pNext = p->pNext;
- if( close(p->fd) ){
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
- p->pNext = pError;
- pError = p;
- }else{
- sqlite3_free(p);
- }
- }
- pOpen->pUnused = pError;
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
@@ -23020,46 +23629,50 @@
** pUnused list.
*/
static void setPendingFd(unixFile *pFile){
- struct unixOpenCnt *pOpen = pFile->pOpen;
+ unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *p = pFile->pUnused;
- p->pNext = pOpen->pUnused;
- pOpen->pUnused = p;
+ p->pNext = pInode->pUnused;
+ pInode->pUnused = p;
pFile->h = -1;
pFile->pUnused = 0;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
+**
+** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
+** the byte range is divided into 2 parts and the first part is unlocked then
+** set to a read lock, then the other part is simply unlocked. This works
+** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
+** remove the write lock on a region when a read lock is set.
*/
-static int unixUnlock(sqlite3_file *id, int locktype){
- unixFile *pFile = (unixFile*)id; /* The open file */
- struct unixLockInfo *pLock; /* Structure describing current lock state */
- struct flock lock; /* Information passed into fcntl() */
- int rc = SQLITE_OK; /* Return code from this interface */
- int h; /* The underlying file descriptor */
+static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
+ unixFile *pFile = (unixFile*)id;
+ unixInodeInfo *pInode;
+ struct flock lock;
+ int rc = SQLITE_OK;
+ int h;
int tErrno; /* Error code from system call errors */
assert( pFile );
- OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, locktype,
- pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
+ getpid()));
- assert( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
h = pFile->h;
- pLock = pFile->pLock;
- assert( pLock->cnt!=0 );
- if( pFile->locktype>SHARED_LOCK ){
- assert( pLock->locktype==pFile->locktype );
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
@@ -23073,20 +23686,76 @@
** the file has changed and hence might not know to flush their
** cache. The use of a stale cache can lead to database corruption.
*/
+#if 0
assert( pFile->inNormalWrite==0
|| pFile->dbUpdate==0
|| pFile->transCntrChng==1 );
+#endif
pFile->inNormalWrite = 0;
#endif
-
- if( locktype==SHARED_LOCK ){
- if( rangeLock(pFile, F_RDLCK, &tErrno)==(-1) ){
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ /* downgrading to a shared lock on NFS involves clearing the write lock
+ ** before establishing the readlock - to avoid a race condition we downgrade
+ ** the lock in 2 blocks, so that part of the range will be covered by a
+ ** write lock until the rest is covered by a read lock:
+ ** 1: [WWWWW]
+ ** 2: [....W]
+ ** 3: [RRRRW]
+ ** 4: [RRRR.]
+ */
+ if( eFileLock==SHARED_LOCK ){
+ if( handleNFSUnlock ){
+ off_t divSize = SHARED_SIZE - 1;
+
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
}
- goto end_unlock;
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST+divSize;
+ lock.l_len = SHARED_SIZE-divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
+ }else{
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
}
}
lock.l_type = F_UNLCK;
@@ -23094,7 +23763,7 @@
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = SHARED_LOCK;
+ pInode->eFileLock = SHARED_LOCK;
}else{
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
@@ -23104,15 +23773,13 @@
goto end_unlock;
}
}
- if( locktype==NO_LOCK ){
- struct unixOpenCnt *pOpen;
-
+ if( eFileLock==NO_LOCK ){
/* Decrement the shared lock counter. Release the lock using an
** OS call only when all threads in this same process have released
** the lock.
*/
- pLock->cnt--;
- if( pLock->cnt==0 ){
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
@@ -23120,15 +23787,15 @@
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = NO_LOCK;
+ pInode->eFileLock = NO_LOCK;
}else{
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
- pLock->locktype = NO_LOCK;
- pFile->locktype = NO_LOCK;
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
}
}
@@ -23136,10 +23803,9 @@
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
- pOpen = pFile->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
int rc2 = closePendingFds(pFile);
if( rc==SQLITE_OK ){
rc = rc2;
@@ -23149,11 +23815,22 @@
end_unlock:
unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->locktype = locktype;
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
/*
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+** must be either NO_LOCK or SHARED_LOCK.
+**
+** If the locking level of the file descriptor is already at or below
+** the requested locking level, this routine is a no-op.
+*/
+static int unixUnlock(sqlite3_file *id, int eFileLock){
+ return _posixUnlock(id, eFileLock, 0);
+}
+
+/*
** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
** handles, if they are valid, and sets all fields of the unixFile
@@ -23191,7 +23868,7 @@
pFile->pId = 0;
}
#endif
- OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
sqlite3_free(pFile->pUnused);
memset(pFile, 0, sizeof(unixFile));
@@ -23208,16 +23885,15 @@
unixFile *pFile = (unixFile *)id;
unixUnlock(id, NO_LOCK);
unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->nLock ){
+ if( pFile->pInode && pFile->pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->pUnused list. It will be automatically closed
+ ** descriptor to pInode->pUnused list. It will be automatically closed
** when the last lock is cleared.
*/
setPendingFd(pFile);
}
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
rc = closeUnixFile(id);
unixLeaveMutex();
}
@@ -23316,7 +23992,7 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
/* Either this connection or some other connection in the same process
** holds a lock on the file. No need to check further. */
reserved = 1;
@@ -23325,13 +24001,13 @@
const char *zLockFile = (const char*)pFile->lockingContext;
reserved = access(zLockFile, 0)==0;
}
- OSTRACE4("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23357,7 +24033,7 @@
** With dotfile locking, we really only support state (4): EXCLUSIVE.
** But we track the other locking levels internally.
*/
-static int dotlockLock(sqlite3_file *id, int locktype) {
+static int dotlockLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
char *zLockFile = (char *)pFile->lockingContext;
@@ -23367,8 +24043,8 @@
/* If we have any lock, then the lock file already exists. All we have
** to do is adjust our internal record of the lock level.
*/
- if( pFile->locktype > NO_LOCK ){
- pFile->locktype = locktype;
+ if( pFile->eFileLock > NO_LOCK ){
+ pFile->eFileLock = eFileLock;
#if !OS_VXWORKS
/* Always update the timestamp on the old file */
utimes(zLockFile, NULL);
@@ -23397,12 +24073,12 @@
}
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
@@ -23410,30 +24086,30 @@
**
** When the locking level reaches NO_LOCK, delete the lock file.
*/
-static int dotlockUnlock(sqlite3_file *id, int locktype) {
+static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* To downgrade to shared, simply update our internal notion of the
** lock state. No need to mess with the file on disk.
*/
- if( locktype==SHARED_LOCK ){
- pFile->locktype = SHARED_LOCK;
+ if( eFileLock==SHARED_LOCK ){
+ pFile->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
/* To fully unlock the database, delete the lock file */
- assert( locktype==NO_LOCK );
+ assert( eFileLock==NO_LOCK );
if( unlink(zLockFile) ){
int rc = 0;
int tErrno = errno;
@@ -23445,7 +24121,7 @@
}
return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -23498,7 +24174,7 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -23529,7 +24205,7 @@
}
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
@@ -23542,7 +24218,7 @@
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23570,7 +24246,7 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int flockLock(sqlite3_file *id, int locktype) {
+static int flockLock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -23578,8 +24254,8 @@
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23594,10 +24270,10 @@
}
} else {
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
}
- OSTRACE4("LOCK %d %s %s (flock)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
@@ -23608,28 +24284,28 @@
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int flockUnlock(sqlite3_file *id, int locktype) {
+static int flockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23649,7 +24325,7 @@
return r;
} else {
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
}
@@ -23697,13 +24373,13 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
struct stat statBuf;
if( sem_trywait(pSem)==-1 ){
@@ -23713,21 +24389,21 @@
pFile->lastErrno = tErrno;
} else {
/* someone else has the lock when we are in NO_LOCK */
- reserved = (pFile->locktype < SHARED_LOCK);
+ reserved = (pFile->eFileLock < SHARED_LOCK);
}
}else{
/* we could have it if we want it */
sem_post(pSem);
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23755,16 +24431,16 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int semLock(sqlite3_file *id, int locktype) {
+static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
@@ -23776,37 +24452,37 @@
}
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
sem_end_lock:
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int semUnlock(sqlite3_file *id, int locktype) {
+static int semUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
assert( pFile );
assert( pSem );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23819,7 +24495,7 @@
}
return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -23832,8 +24508,7 @@
semUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
unixLeaveMutex();
closeUnixFile(id);
}
@@ -23864,7 +24539,7 @@
*/
typedef struct afpLockingContext afpLockingContext;
struct afpLockingContext {
- unsigned long long sharedByte;
+ int reserved;
const char *dbPath; /* Name of the open file */
};
@@ -23902,15 +24577,15 @@
pb.length = length;
pb.fd = pFile->h;
- OSTRACE6("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
(setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
- offset, length);
+ offset, length));
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
if ( err==-1 ) {
int rc;
int tErrno = errno;
- OSTRACE4("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
- path, tErrno, strerror(tErrno));
+ OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
+ path, tErrno, strerror(tErrno)));
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
rc = SQLITE_BUSY;
#else
@@ -23941,9 +24616,14 @@
assert( pFile );
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ if( context->reserved ){
+ *pResOut = 1;
+ return SQLITE_OK;
+ }
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -23965,14 +24645,15 @@
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved);
+ unixLeaveMutex();
+ OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23995,49 +24676,72 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int afpLock(sqlite3_file *id, int locktype){
+static int afpLock(sqlite3_file *id, int eFileLock){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
+ unixInodeInfo *pInode = pFile->pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
assert( pFile );
- OSTRACE5("LOCK %d %s was %s pid=%d (afp)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype), getpid());
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock),
+ azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the afp_end_lock: exit path, as
** unixEnterMutex() hasn't been called yet.
*/
- if( pFile->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (afp)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
+ ** (1) We never move from unlocked to anything higher than shared lock.
+ ** (2) SQLite never explicitly requests a pendig lock.
+ ** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+ assert( eFileLock!=PENDING_LOCK );
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
- /* This mutex is needed because pFile->pLock is shared across threads
+ /* This mutex is needed because pFile->pInode is shared across threads
*/
unixEnterMutex();
+ pInode = pFile->pInode;
- /* Make sure the current thread owns the pFile.
+ /* If some thread using this PID has a lock via a different unixFile*
+ ** handle that precludes the requested lock, return BUSY.
*/
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
+ if( (pFile->eFileLock!=pInode->eFileLock &&
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
+ ){
+ rc = SQLITE_BUSY;
+ goto afp_end_lock;
+ }
+
+ /* If a SHARED lock is requested, and some thread using this PID already
+ ** has a SHARED or RESERVED lock, then increment reference counts and
+ ** return SQLITE_OK.
+ */
+ if( eFileLock==SHARED_LOCK &&
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+ assert( eFileLock==SHARED_LOCK );
+ assert( pFile->eFileLock==0 );
+ assert( pInode->nShared>0 );
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nShared++;
+ pInode->nLock++;
+ goto afp_end_lock;
}
/* A PENDING lock is needed before acquiring a SHARED lock and before
** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
** be released.
*/
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+ if( eFileLock==SHARED_LOCK
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
int failed;
failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
@@ -24050,16 +24754,20 @@
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- int lk, lrc1, lrc2;
- int lrc1Errno = 0;
+ if( eFileLock==SHARED_LOCK ){
+ int lrc1, lrc2, lrc1Errno;
+ long lk, mask;
+ assert( pInode->nShared==0 );
+ assert( pInode->eFileLock==0 );
+
+ mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
/* Now get the read-lock SHARED_LOCK */
/* note that the quality of the randomness doesn't matter that much */
lk = random();
- context->sharedByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
lrc1 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST+context->sharedByte, 1, 1);
+ SHARED_FIRST+pInode->sharedByte, 1, 1);
if( IS_LOCK_ERROR(lrc1) ){
lrc1Errno = pFile->lastErrno;
}
@@ -24076,34 +24784,42 @@
} else if( lrc1 != SQLITE_OK ) {
rc = lrc1;
} else {
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
+ /* We are trying for an exclusive lock but another thread in this
+ ** same process is still holding a shared lock. */
+ rc = SQLITE_BUSY;
}else{
/* The request was for a RESERVED or EXCLUSIVE lock. It is
** assumed that there is a SHARED or greater lock on the file
** already.
*/
int failed = 0;
- assert( 0!=pFile->locktype );
- if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
+ assert( 0!=pFile->eFileLock );
+ if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) {
/* Acquire a RESERVED lock */
failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
+ if( !failed ){
+ context->reserved = 1;
+ }
}
- if (!failed && locktype == EXCLUSIVE_LOCK) {
+ if (!failed && eFileLock == EXCLUSIVE_LOCK) {
/* Acquire an EXCLUSIVE lock */
/* Remove the shared lock before trying the range. we'll need to
** reestablish the shared lock if we can't get the afpUnlock
*/
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
- context->sharedByte, 1, 0)) ){
+ pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
/* now attemmpt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + context->sharedByte, 1, 1)) ){
+ SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
/* Can't reestablish the shared lock. Sqlite can't deal, this is
** a critical I/O error
*/
@@ -24121,78 +24837,124 @@
}
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
afp_end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (afp)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int afpUnlock(sqlite3_file *id, int locktype) {
+static int afpUnlock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- afpLockingContext *pCtx = (afpLockingContext *) pFile->lockingContext;
+ unixInodeInfo *pInode;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ int skipShared = 0;
+#ifdef SQLITE_TEST
+ int h = pFile->h;
+#endif
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (afp)\n", pFile->h, locktype,
- pFile->locktype, getpid());
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
+ getpid()));
- assert( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
- if( pFile->locktype>SHARED_LOCK ){
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
+ SimulateIOErrorBenign(1);
+ SimulateIOError( h=(-1) )
+ SimulateIOErrorBenign(0);
- if( pFile->locktype==EXCLUSIVE_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
- if( rc==SQLITE_OK && locktype==SHARED_LOCK ){
+#ifndef NDEBUG
+ /* When reducing a lock such that other processes can start
+ ** reading the database file again, make sure that the
+ ** transaction counter was updated if any part of the database
+ ** file changed. If the transaction counter is not updated,
+ ** other connections to the same file might not realize that
+ ** the file has changed and hence might not know to flush their
+ ** cache. The use of a stale cache can lead to database corruption.
+ */
+ assert( pFile->inNormalWrite==0
+ || pFile->dbUpdate==0
+ || pFile->transCntrChng==1 );
+ pFile->inNormalWrite = 0;
+#endif
+
+ if( pFile->eFileLock==EXCLUSIVE_LOCK ){
+ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
/* only re-establish the shared lock if necessary */
- int sharedLockByte = SHARED_FIRST+pCtx->sharedByte;
- rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 1);
+ int sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1);
+ } else {
+ skipShared = 1;
}
}
- if( rc==SQLITE_OK && pFile->locktype>=PENDING_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, PENDING_BYTE, 1, 0);
+ if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
+ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
}
- if( rc==SQLITE_OK && pFile->locktype>=RESERVED_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, RESERVED_BYTE, 1, 0);
+ if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
+ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
+ if( !rc ){
+ context->reserved = 0;
+ }
}
- }else if( locktype==NO_LOCK ){
- /* clear the shared lock */
- int sharedLockByte = SHARED_FIRST+pCtx->sharedByte;
- rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 0);
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
+ pInode->eFileLock = SHARED_LOCK;
+ }
}
+ if( rc==SQLITE_OK && eFileLock==NO_LOCK ){
- if( rc==SQLITE_OK ){
- if( locktype==NO_LOCK ){
- struct unixOpenCnt *pOpen = pFile->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
+ /* Decrement the shared lock counter. Release the lock using an
+ ** OS call only when all threads in this same process have released
+ ** the lock.
+ */
+ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
+ SimulateIOErrorBenign(1);
+ SimulateIOError( h=(-1) )
+ SimulateIOErrorBenign(0);
+ if( !skipShared ){
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
+ }
+ if( !rc ){
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
rc = closePendingFds(pFile);
}
}
}
+
unixLeaveMutex();
- if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- }
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
@@ -24200,24 +24962,25 @@
** Close a file & cleanup AFP specific locking context
*/
static int afpClose(sqlite3_file *id) {
+ int rc = SQLITE_OK;
if( id ){
unixFile *pFile = (unixFile*)id;
afpUnlock(id, NO_LOCK);
unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->nLock ){
+ if( pFile->pInode && pFile->pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->aPending. It will be automatically closed when
+ ** descriptor to pInode->aPending. It will be automatically closed when
** the last lock is cleared.
*/
setPendingFd(pFile);
}
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
sqlite3_free(pFile->lockingContext);
- closeUnixFile(id);
+ rc = closeUnixFile(id);
unixLeaveMutex();
}
- return SQLITE_OK;
+ return rc;
}
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
@@ -24230,6 +24993,29 @@
********************* End of the AFP lock implementation **********************
******************************************************************************/
+/******************************************************************************
+*************************** Begin NFS Locking ********************************/
+
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+/*
+ ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+ ** must be either NO_LOCK or SHARED_LOCK.
+ **
+ ** If the locking level of the file descriptor is already at or below
+ ** the requested locking level, this routine is a no-op.
+ */
+static int nfsUnlock(sqlite3_file *id, int eFileLock){
+ return _posixUnlock(id, eFileLock, 1);
+}
+
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+/*
+** The code above is the NFS lock implementation. The code is specific
+** to MacOSX and does not work on other unix platforms. No alternative
+** is available.
+**
+********************* End of the NFS lock implementation **********************
+******************************************************************************/
/******************************************************************************
**************** Non-locking sqlite3_file methods *****************************
@@ -24256,7 +25042,9 @@
*/
static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
+#endif
TIMER_START;
#if defined(USE_PREAD)
got = pread(id->h, pBuf, cnt, offset);
@@ -24281,7 +25069,7 @@
if( got<0 ){
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -24302,10 +25090,12 @@
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
+#if 0
assert( pFile->pUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
+#endif
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
@@ -24330,7 +25120,9 @@
*/
static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
int got;
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
+#endif
TIMER_START;
#if defined(USE_PREAD)
got = pwrite(id->h, pBuf, cnt, offset);
@@ -24353,7 +25145,7 @@
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -24375,10 +25167,12 @@
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
+#if 0
assert( pFile->pUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
+#endif
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
@@ -24524,6 +25318,11 @@
*/
if( rc ) rc = fsync(fd);
+#elif defined(__APPLE__)
+ /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
+ ** so currently we default to the macro that redefines fdatasync to fsync
+ */
+ rc = fsync(fd);
#else
rc = fdatasync(fd);
#if OS_VXWORKS
@@ -24572,7 +25371,7 @@
SimulateDiskfullError( return SQLITE_FULL );
assert( pFile );
- OSTRACE2("SYNC %-3d\n", pFile->h);
+ OSTRACE(("SYNC %-3d\n", pFile->h));
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
@@ -24581,8 +25380,8 @@
}
if( pFile->dirfd>=0 ){
int err;
- OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
- HAVE_FULLFSYNC, isFullsync);
+ OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
+ HAVE_FULLFSYNC, isFullsync));
#ifndef SQLITE_DISABLE_DIRSYNC
/* The directory sync is only attempted if full_fsync is
** turned off or unavailable. If a full_fsync occurred above,
@@ -24654,7 +25453,7 @@
}
*pSize = buf.st_size;
- /* When opening a zero-size database, the findLockInfo() procedure
+ /* When opening a zero-size database, the findInodeInfo() procedure
** writes a single byte into that file in order to work around a bug
** in the OS-X msdos filesystem. In order to avoid problems with upper
** layers, we need to report this file size as zero even though it is
@@ -24681,13 +25480,21 @@
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
- *(int*)pArg = ((unixFile*)id)->locktype;
+ *(int*)pArg = ((unixFile*)id)->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = ((unixFile*)id)->lastErrno;
return SQLITE_OK;
}
+ case SQLITE_FCNTL_SIZE_HINT: {
+#if 0 /* No performance advantage seen on Linux */
+ sqlite3_int64 szFile = *(sqlite3_int64*)pArg;
+ unixFile *pFile = (unixFile*)id;
+ ftruncate(pFile->h, szFile);
+#endif
+ return SQLITE_OK;
+ }
#ifndef NDEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@@ -24732,6 +25539,562 @@
return 0;
}
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** Object used to represent an shared memory buffer.
+**
+** When multiple threads all reference the same wal-index, each thread
+** has its own unixShm object, but they all point to a single instance
+** of this unixShmNode object. In other words, each wal-index is opened
+** only once per process.
+**
+** Each unixShmNode object is connected to a single unixInodeInfo object.
+** We could coalesce this object into unixInodeInfo, but that would mean
+** every open file that does not use shared memory (in other words, most
+** open files) would have to carry around this extra information. So
+** the unixInodeInfo object contains a pointer to this unixShmNode object
+** and the unixShmNode object is created only when needed.
+**
+** unixMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
+**
+** nRef
+**
+** The following fields are read-only after the object is created:
+**
+** fid
+** zFilename
+**
+** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
+** unixMutexHeld() is true when reading or writing any other field
+** in this structure.
+*/
+struct unixShmNode {
+ unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ char *zFilename; /* Name of the mmapped file */
+ int h; /* Open file descriptor */
+ int szRegion; /* Size of shared-memory regions */
+ int nRegion; /* Size of array apRegion */
+ char **apRegion; /* Array of mapped shared-memory regions */
+ int nRef; /* Number of unixShm objects pointing to this */
+ unixShm *pFirst; /* All unixShm objects pointing to this */
+#ifdef SQLITE_DEBUG
+ u8 exclMask; /* Mask of exclusive locks held */
+ u8 sharedMask; /* Mask of shared locks held */
+ u8 nextShmId; /* Next available unixShm.id value */
+#endif
+};
+
+/*
+** Structure used internally by this VFS to record the state of an
+** open shared memory connection.
+**
+** The following fields are initialized when this object is created and
+** are read-only thereafter:
+**
+** unixShm.pFile
+** unixShm.id
+**
+** All other fields are read/write. The unixShm.pFile->mutex must be held
+** while accessing any read/write fields.
+*/
+struct unixShm {
+ unixShmNode *pShmNode; /* The underlying unixShmNode object */
+ unixShm *pNext; /* Next unixShm with the same unixShmNode */
+ u8 hasMutex; /* True if holding the unixShmNode mutex */
+ u16 sharedMask; /* Mask of shared locks held */
+ u16 exclMask; /* Mask of exclusive locks held */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection within its unixShmNode */
+#endif
+};
+
+/*
+** Constants used for locking
+*/
+#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
+**
+** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
+** otherwise.
+*/
+static int unixShmSystemLock(
+ unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
+ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
+ int ofst, /* First byte of the locking range */
+ int n /* Number of bytes to lock */
+){
+ struct flock f; /* The posix advisory locking structure */
+ int rc = SQLITE_OK; /* Result code form fcntl() */
+
+ /* Access to the unixShmNode object is serialized by the caller */
+ assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
+
+ /* Shared locks never span more than one byte */
+ assert( n==1 || lockType!=F_RDLCK );
+
+ /* Locks are within range */
+ assert( n>=1 && n<SQLITE_SHM_NLOCK );
+
+ /* Initialize the locking parameters */
+ memset(&f, 0, sizeof(f));
+ f.l_type = lockType;
+ f.l_whence = SEEK_SET;
+ f.l_start = ofst;
+ f.l_len = n;
+
+ rc = fcntl(pShmNode->h, F_SETLK, &f);
+ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+
+ /* Update the global lock state and do debug tracing */
+#ifdef SQLITE_DEBUG
+ { u16 mask;
+ OSTRACE(("SHM-LOCK "));
+ mask = (1<<(ofst+n)) - (1<<ofst);
+ if( rc==SQLITE_OK ){
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock %d ok", ofst));
+ pShmNode->exclMask &= ~mask;
+ pShmNode->sharedMask &= ~mask;
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock %d ok", ofst));
+ pShmNode->exclMask &= ~mask;
+ pShmNode->sharedMask |= mask;
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock %d ok", ofst));
+ pShmNode->exclMask |= mask;
+ pShmNode->sharedMask &= ~mask;
+ }
+ }else{
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock %d failed", ofst));
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock failed"));
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock %d failed", ofst));
+ }
+ }
+ OSTRACE((" - afterwards %03x,%03x\n",
+ pShmNode->sharedMask, pShmNode->exclMask));
+ }
+#endif
+
+ return rc;
+}
+
+
+/*
+** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void unixShmPurge(unixFile *pFd){
+ unixShmNode *p = pFd->pInode->pShmNode;
+ assert( unixMutexHeld() );
+ if( p && p->nRef==0 ){
+ int i;
+ assert( p->pInode==pFd->pInode );
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ for(i=0; i<p->nRegion; i++){
+ munmap(p->apRegion[i], p->szRegion);
+ }
+ sqlite3_free(p->apRegion);
+ if( p->h>=0 ) close(p->h);
+ p->pInode->pShmNode = 0;
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Open a shared-memory area associated with open database file fd.
+** This particular implementation uses mmapped files.
+**
+** The file used to implement shared-memory is in the same directory
+** as the open database file and has the same name as the open database
+** file with the "-shm" suffix added. For example, if the database file
+** is "/home/user1/config.db" then the file that is created and mmapped
+** for shared memory will be called "/home/user1/config.db-shm". We
+** experimented with using files in /dev/tmp or an some other tmpfs mount.
+** But if a file in a different directory from the database file is used,
+** then differing access permissions or a chroot() might cause two different
+** processes on the same database to end up using different files for
+** shared memory - meaning that their memory would not really be shared -
+** resulting in database corruption.
+**
+** When opening a new shared-memory file, if no other instances of that
+** file are currently open, in this process or in other processes, then
+** the file must be truncated to zero length or have its header cleared.
+*/
+static int unixShmOpen(
+ sqlite3_file *fd /* The file descriptor of the associated database */
+){
+ struct unixShm *p = 0; /* The connection to be opened */
+ struct unixShmNode *pShmNode = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct unixFile *pDbFd; /* Underlying database file */
+ unixInodeInfo *pInode; /* The inode of fd */
+ char *zShmFilename; /* Name of the file used for SHM */
+ int nShmFilename; /* Size of the SHM filename in bytes */
+
+ /* Allocate space for the new sqlite3_shm object.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ pDbFd = (struct unixFile*)fd;
+ assert( pDbFd->pShm==0 );
+
+ /* Check to see if a unixShmNode object already exists. Reuse an existing
+ ** one if present. Create a new one if necessary.
+ */
+ unixEnterMutex();
+ pInode = pDbFd->pInode;
+ pShmNode = pInode->pShmNode;
+ if( pShmNode==0 ){
+ nShmFilename = 5 + (int)strlen(pDbFd->zPath);
+ pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
+ if( pShmNode==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+ memset(pShmNode, 0, sizeof(*pShmNode));
+ zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
+ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+ pShmNode->h = -1;
+ pDbFd->pInode->pShmNode = pShmNode;
+ pShmNode->pInode = pDbFd->pInode;
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+
+ pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, 0664);
+ if( pShmNode->h<0 ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ rc = SQLITE_OK;
+ if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
+ if( ftruncate(pShmNode->h, 0) ){
+ rc = SQLITE_IOERR_SHMOPEN;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the unixShmNode */
+ p->pShmNode = pShmNode;
+ p->pNext = pShmNode->pFirst;
+#ifdef SQLITE_DEBUG
+ p->id = pShmNode->nextShmId++;
+#endif
+ pShmNode->pFirst = p;
+ pShmNode->nRef++;
+ pDbFd->pShm = p;
+ unixLeaveMutex();
+ return SQLITE_OK;
+
+ /* Jump here on any error */
+shm_open_err:
+ unixShmPurge(pDbFd); /* This call frees pShmNode if required */
+ sqlite3_free(p);
+ unixLeaveMutex();
+ return rc;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int unixShmClose(
+ sqlite3_file *fd, /* The underlying database file */
+ int deleteFlag /* Delete shared-memory if true */
+){
+ unixShm *p; /* The connection to be closed */
+ unixShmNode *pShmNode; /* The underlying shared-memory file */
+ unixShm **pp; /* For looping over sibling connections */
+ unixFile *pDbFd; /* The underlying database file */
+
+ pDbFd = (unixFile*)fd;
+ p = pDbFd->pShm;
+ if( p==0 ) return SQLITE_OK;
+ pShmNode = p->pShmNode;
+
+ assert( pShmNode==pDbFd->pInode->pShmNode );
+ assert( pShmNode->pInode==pDbFd->pInode );
+
+ /* Remove connection p from the set of connections associated
+ ** with pShmNode */
+ sqlite3_mutex_enter(pShmNode->mutex);
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+ *pp = p->pNext;
+
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
+ sqlite3_mutex_leave(pShmNode->mutex);
+
+ /* If pShmNode->nRef has reached 0, then close the underlying
+ ** shared-memory file, too */
+ unixEnterMutex();
+ assert( pShmNode->nRef>0 );
+ pShmNode->nRef--;
+ if( pShmNode->nRef==0 ){
+ if( deleteFlag ) unlink(pShmNode->zFilename);
+ unixShmPurge(pDbFd);
+ }
+ unixLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+**
+** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+** different here than in posix. In xShmLock(), one can go from unlocked
+** to shared and back or from unlocked to exclusive and back. But one may
+** not go from shared to exclusive or from exclusive to shared.
+*/
+static int unixShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int ofst, /* First lock to acquire or release */
+ int n, /* Number of locks to acquire or release */
+ int flags /* What to do with the lock */
+){
+ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
+ unixShm *p = pDbFd->pShm; /* The shared memory being locked */
+ unixShm *pX; /* For looping over all siblings */
+ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
+ int rc = SQLITE_OK; /* Result code */
+ u16 mask; /* Mask of locks to take or release */
+
+ assert( pShmNode==pDbFd->pInode->pShmNode );
+ assert( pShmNode->pInode==pDbFd->pInode );
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ mask = (1<<(ofst+n)) - (1<<ofst);
+ assert( n>1 || mask==(1<<ofst) );
+ sqlite3_mutex_enter(pShmNode->mutex);
+ if( flags & SQLITE_SHM_UNLOCK ){
+ u16 allMask = 0; /* Mask of locks held by siblings */
+
+ /* See if any siblings hold this same lock */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( pX==p ) continue;
+ assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
+ allMask |= pX->sharedMask;
+ }
+
+ /* Unlock the system-level locks */
+ if( (mask & allMask)==0 ){
+ rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ /* Undo the local locks */
+ if( rc==SQLITE_OK ){
+ p->exclMask &= ~mask;
+ p->sharedMask &= ~mask;
+ }
+ }else if( flags & SQLITE_SHM_SHARED ){
+ u16 allShared = 0; /* Union of locks held by connections other than "p" */
+
+ /* Find out which shared locks are already held by sibling connections.
+ ** If any sibling already holds an exclusive lock, go ahead and return
+ ** SQLITE_BUSY.
+ */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( (pX->exclMask & mask)!=0 ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ allShared |= pX->sharedMask;
+ }
+
+ /* Get shared locks at the system level, if necessary */
+ if( rc==SQLITE_OK ){
+ if( (allShared & mask)==0 ){
+ rc = unixShmSystemLock(pShmNode, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ }else{
+ rc = SQLITE_OK;
+ }
+ }
+
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= mask;
+ }
+ }else{
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away.
+ */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also mark the local connection as being locked.
+ */
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ assert( (p->sharedMask & mask)==0 );
+ p->exclMask |= mask;
+ }
+ }
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
+ p->id, getpid(), p->sharedMask, p->exclMask));
+ return rc;
+}
+
+/*
+** Implement a memory barrier or memory fence on shared memory.
+**
+** All loads and stores begun before the barrier must complete before
+** any load or store begun after the barrier.
+*/
+static void unixShmBarrier(
+ sqlite3_file *fd /* Database file holding the shared memory */
+){
+ UNUSED_PARAMETER(fd);
+ unixEnterMutex();
+ unixLeaveMutex();
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
+** bytes in size.
+**
+** If an error occurs, an error code is returned and *pp is set to NULL.
+**
+** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+** region has not been allocated (by any client, including one running in a
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
+** been allocated, it is allocated by this function.
+**
+** If the shared-memory region has already been allocated or is allocated by
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
+** memory and SQLITE_OK returned.
+*/
+static int unixShmMap(
+ sqlite3_file *fd, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int isWrite, /* True to extend file if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+ unixShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_OK;
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+ if( pShmNode->nRegion<=iRegion ){
+ char **apNew; /* New apRegion[] array */
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ struct stat sStat; /* Used by fstat() */
+
+ pShmNode->szRegion = szRegion;
+
+ /* The requested region is not mapped into this processes address space.
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
+ ** large enough to contain the requested region).
+ */
+ if( fstat(pShmNode->h, &sStat) ){
+ rc = SQLITE_IOERR_SHMSIZE;
+ goto shmpage_out;
+ }
+
+ if( sStat.st_size<nByte ){
+ /* The requested memory region does not exist. If isWrite is set to
+ ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
+ **
+ ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
+ ** the requested memory region.
+ */
+ if( !isWrite ) goto shmpage_out;
+ if( ftruncate(pShmNode->h, nByte) ){
+ rc = SQLITE_IOERR_SHMSIZE;
+ goto shmpage_out;
+ }
+ }
+
+ /* Map the requested memory region into this processes address space. */
+ apNew = (char **)sqlite3_realloc(
+ pShmNode->apRegion, (iRegion+1)*sizeof(char *)
+ );
+ if( !apNew ){
+ rc = SQLITE_IOERR_NOMEM;
+ goto shmpage_out;
+ }
+ pShmNode->apRegion = apNew;
+ while(pShmNode->nRegion<=iRegion){
+ void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
+ MAP_SHARED, pShmNode->h, iRegion*szRegion
+ );
+ if( pMem==MAP_FAILED ){
+ rc = SQLITE_IOERR;
+ goto shmpage_out;
+ }
+ pShmNode->apRegion[pShmNode->nRegion] = pMem;
+ pShmNode->nRegion++;
+ }
+ }
+
+shmpage_out:
+ if( pShmNode->nRegion>iRegion ){
+ *pp = pShmNode->apRegion[iRegion];
+ }else{
+ *pp = 0;
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+}
+
+#else
+# define unixShmOpen 0
+# define unixShmLock 0
+# define unixShmMap 0
+# define unixShmBarrier 0
+# define unixShmClose 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
/*
** Here ends the implementation of all sqlite3_file methods.
**
@@ -24772,9 +26135,9 @@
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, CLOSE, LOCK, UNLOCK, CKLOCK) \
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
static const sqlite3_io_methods METHOD = { \
- 1, /* iVersion */ \
+ VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
unixRead, /* xRead */ \
unixWrite, /* xWrite */ \
@@ -24786,7 +26149,12 @@
CKLOCK, /* xCheckReservedLock */ \
unixFileControl, /* xFileControl */ \
unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics /* xDeviceCapabilities */ \
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+ unixShmOpen, /* xShmOpen */ \
+ unixShmLock, /* xShmLock */ \
+ unixShmMap, /* xShmMap */ \
+ unixShmBarrier, /* xShmBarrier */ \
+ unixShmClose /* xShmClose */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@@ -24803,6 +26171,7 @@
IOMETHODS(
posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */
+ 2, /* ShmOpen is enabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@@ -24811,6 +26180,7 @@
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
@@ -24819,6 +26189,7 @@
IOMETHODS(
dotlockIoFinder, /* Finder function name */
dotlockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
dotlockClose, /* xClose method */
dotlockLock, /* xLock method */
dotlockUnlock, /* xUnlock method */
@@ -24829,6 +26200,7 @@
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
flockClose, /* xClose method */
flockLock, /* xLock method */
flockUnlock, /* xUnlock method */
@@ -24840,6 +26212,7 @@
IOMETHODS(
semIoFinder, /* Finder function name */
semIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
semClose, /* xClose method */
semLock, /* xLock method */
semUnlock, /* xUnlock method */
@@ -24851,6 +26224,7 @@
IOMETHODS(
afpIoFinder, /* Finder function name */
afpIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
afpClose, /* xClose method */
afpLock, /* xLock method */
afpUnlock, /* xUnlock method */
@@ -24859,23 +26233,6 @@
#endif
/*
-** The "Whole File Locking" finder returns the same set of methods as
-** the posix locking finder. But it also sets the SQLITE_WHOLE_FILE_LOCKING
-** flag to force the posix advisory locks to cover the whole file instead
-** of just a small span of bytes near the 1GiB boundary. Whole File Locking
-** is useful on NFS-mounted files since it helps NFS to maintain cache
-** coherency. But it is a detriment to other filesystems since it runs
-** slower.
-*/
-static const sqlite3_io_methods *posixWflIoFinderImpl(const char*z, unixFile*p){
- UNUSED_PARAMETER(z);
- p->fileFlags = SQLITE_WHOLE_FILE_LOCKING;
- return &posixIoMethods;
-}
-static const sqlite3_io_methods
- *(*const posixWflIoFinder)(const char*,unixFile *p) = posixWflIoFinderImpl;
-
-/*
** The proxy locking method is a "super-method" in the sense that it
** opens secondary file descriptors for the conch and lock files and
** it uses proxy, dot-file, AFP, and flock() locking methods on those
@@ -24892,6 +26249,7 @@
IOMETHODS(
proxyIoFinder, /* Finder function name */
proxyIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
proxyClose, /* xClose method */
proxyLock, /* xLock method */
proxyUnlock, /* xUnlock method */
@@ -24899,6 +26257,18 @@
)
#endif
+/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+IOMETHODS(
+ nfsIoFinder, /* Finder function name */
+ nfsIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
+ unixClose, /* xClose method */
+ unixLock, /* xLock method */
+ nfsUnlock, /* xUnlock method */
+ unixCheckReservedLock /* xCheckReservedLock method */
+)
+#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
@@ -24919,11 +26289,7 @@
{ "hfs", &posixIoMethods },
{ "ufs", &posixIoMethods },
{ "afpfs", &afpIoMethods },
-#ifdef SQLITE_ENABLE_AFP_LOCKING_SMB
{ "smbfs", &afpIoMethods },
-#else
- { "smbfs", &flockIoMethods },
-#endif
{ "webdav", &nolockIoMethods },
{ 0, 0 }
};
@@ -24956,8 +26322,11 @@
lockInfo.l_whence = SEEK_SET;
lockInfo.l_type = F_RDLCK;
if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
- pNew->fileFlags = SQLITE_WHOLE_FILE_LOCKING;
- return &posixIoMethods;
+ if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
+ return &nfsIoMethods;
+ } else {
+ return &posixIoMethods;
+ }
}else{
return &dotlockIoMethods;
}
@@ -25034,19 +26403,19 @@
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
- assert( pNew->pLock==NULL );
- assert( pNew->pOpen==NULL );
+ assert( pNew->pInode==NULL );
/* Parameter isDelete is only used on vxworks. Express this explicitly
** here to prevent compiler warnings about unused parameters.
*/
UNUSED_PARAMETER(isDelete);
- OSTRACE3("OPEN %-3d %s\n", h, zFilename);
+ OSTRACE(("OPEN %-3d %s\n", h, zFilename));
pNew->h = h;
pNew->dirfd = dirfd;
- SET_THREADID(pNew);
pNew->fileFlags = 0;
+ assert( zFilename==0 || zFilename[0]=='/' ); /* Never a relative pathname */
+ pNew->zPath = zFilename;
#if OS_VXWORKS
pNew->pId = vxworksFindFileId(zFilename);
@@ -25068,12 +26437,16 @@
#endif
}
- if( pLockingStyle == &posixIoMethods ){
+ if( pLockingStyle == &posixIoMethods
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+ || pLockingStyle == &nfsIoMethods
+#endif
+ ){
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
if( rc!=SQLITE_OK ){
- /* If an error occured in findLockInfo(), close the file descriptor
- ** immediately, before releasing the mutex. findLockInfo() may fail
+ /* If an error occured in findInodeInfo(), close the file descriptor
+ ** immediately, before releasing the mutex. findInodeInfo() may fail
** in two scenarios:
**
** (a) A call to fstat() failed.
@@ -25082,7 +26455,7 @@
** Scenario (b) may only occur if the process is holding no other
** file descriptors open on the same file. If there were other file
** descriptors on this file, then no malloc would be required by
- ** findLockInfo(). If this is the case, it is quite safe to close
+ ** findInodeInfo(). If this is the case, it is quite safe to close
** handle h - as it is guaranteed that no posix locks will be released
** by doing so.
**
@@ -25110,9 +26483,15 @@
** according to requirement F11141. So we do not need to make a
** copy of the filename. */
pCtx->dbPath = zFilename;
+ pCtx->reserved = 0;
srandomdev();
unixEnterMutex();
- rc = findLockInfo(pNew, NULL, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pNew->lockingContext);
+ close(h);
+ h = -1;
+ }
unixLeaveMutex();
}
}
@@ -25140,18 +26519,18 @@
** included in the semLockingContext
*/
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
- if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
- char *zSemName = pNew->pOpen->aSemName;
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){
+ char *zSemName = pNew->pInode->aSemName;
int n;
sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
pNew->pId->zCanonicalName);
for( n=1; zSemName[n]; n++ )
if( zSemName[n]=='/' ) zSemName[n] = '_';
- pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
- if( pNew->pOpen->pSem == SEM_FAILED ){
+ pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+ if( pNew->pInode->pSem == SEM_FAILED ){
rc = SQLITE_NOMEM;
- pNew->pOpen->aSemName[0] = '\0';
+ pNew->pInode->aSemName[0] = '\0';
}
}
unixLeaveMutex();
@@ -25161,6 +26540,8 @@
pNew->lastErrno = 0;
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
+ if( h>=0 ) close(h);
+ h = -1;
unlink(zFilename);
isDelete = 0;
}
@@ -25200,7 +26581,7 @@
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
- OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
+ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
}
}
*pFd = fd;
@@ -25208,26 +26589,46 @@
}
/*
-** Create a temporary file name in zBuf. zBuf must be allocated
-** by the calling process and must be big enough to hold at least
-** pVfs->mxPathname bytes.
+** Return the name of a directory in which to put temporary files.
+** If no suitable temporary file directory can be found, return NULL.
*/
-static int getTempname(int nBuf, char *zBuf){
+static const char *unixTempFileDir(void){
static const char *azDirs[] = {
0,
0,
"/var/tmp",
"/usr/tmp",
"/tmp",
- ".",
+ 0 /* List terminator */
};
+ unsigned int i;
+ struct stat buf;
+ const char *zDir = 0;
+
+ azDirs[0] = sqlite3_temp_directory;
+ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
+ if( zDir==0 ) continue;
+ if( stat(zDir, &buf) ) continue;
+ if( !S_ISDIR(buf.st_mode) ) continue;
+ if( access(zDir, 07) ) continue;
+ break;
+ }
+ return zDir;
+}
+
+/*
+** Create a temporary file name in zBuf. zBuf must be allocated
+** by the calling process and must be big enough to hold at least
+** pVfs->mxPathname bytes.
+*/
+static int unixGetTempname(int nBuf, char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
- struct stat buf;
- const char *zDir = ".";
+ const char *zDir;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
@@ -25235,19 +26636,8 @@
*/
SimulateIOError( return SQLITE_IOERR );
- azDirs[0] = sqlite3_temp_directory;
- if (NULL == azDirs[1]) {
- azDirs[1] = getenv("TMPDIR");
- }
-
- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
- if( azDirs[i]==0 ) continue;
- if( stat(azDirs[i], &buf) ) continue;
- if( !S_ISDIR(buf.st_mode) ) continue;
- if( access(azDirs[i], 07) ) continue;
- zDir = azDirs[i];
- break;
- }
+ zDir = unixTempFileDir();
+ if( zDir==0 ) zDir = ".";
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
@@ -25313,17 +26703,17 @@
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a resusable file descriptor are not dire. */
if( 0==stat(zPath, &sStat) ){
- struct unixOpenCnt *pOpen;
+ unixInodeInfo *pInode;
unixEnterMutex();
- pOpen = openList;
- while( pOpen && (pOpen->fileId.dev!=sStat.st_dev
- || pOpen->fileId.ino!=sStat.st_ino) ){
- pOpen = pOpen->pNext;
+ pInode = inodeList;
+ while( pInode && (pInode->fileId.dev!=sStat.st_dev
+ || pInode->fileId.ino!=sStat.st_ino) ){
+ pInode = pInode->pNext;
}
- if( pOpen ){
+ if( pInode ){
UnixUnusedFd **pp;
- for(pp=&pOpen->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
+ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
*pp = pUnused->pNext;
@@ -25377,6 +26767,9 @@
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+#if SQLITE_ENABLE_LOCKING_STYLE
+ int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
+#endif
/* If creating a master or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
@@ -25434,7 +26827,7 @@
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !isOpenDirectory);
- rc = getTempname(MAX_PATHNAME+1, zTmpname);
+ rc = unixGetTempname(MAX_PATHNAME+1, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -25454,7 +26847,7 @@
if( fd<0 ){
mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
fd = open(zName, openFlags, openMode);
- OSTRACE4("OPENX %-3d %s 0%o\n", fd, zName, openFlags);
+ OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
@@ -25510,8 +26903,25 @@
noLock = eType!=SQLITE_OPEN_MAIN_DB;
+
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+ struct statfs fsInfo;
+ if( fstatfs(fd, &fsInfo) == -1 ){
+ ((unixFile*)pFile)->lastErrno = errno;
+ if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
+ close(fd); /* silently leak if fail, in error */
+ return SQLITE_IOERR_ACCESS;
+ }
+ if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
+ }
+#endif
+
+#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
- if( zPath!=NULL && !noLock && pVfs->xOpen ){
+ isAutoProxy = 1;
+#endif
+ if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
int useProxy = 0;
@@ -25543,6 +26953,14 @@
rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
if( rc==SQLITE_OK ){
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
+ if( rc!=SQLITE_OK ){
+ /* Use unixClose to clean up the resources added in fillInUnixFile
+ ** and clear all the structure's references. Specifically,
+ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
+ */
+ unixClose(pFile);
+ return rc;
+ }
}
goto open_finished;
}
@@ -25627,6 +27045,12 @@
assert(!"Invalid flags argument");
}
*pResOut = (access(zPath, amode)==0);
+ if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
+ struct stat buf;
+ if( 0==stat(zPath, &buf) && buf.st_size==0 ){
+ *pResOut = 0;
+ }
+ }
return SQLITE_OK;
}
@@ -25815,35 +27239,49 @@
#endif
/*
+** Find the current time (in Universal Coordinated Time). Write into *piNow
+** the current time and date as a Julian Day number times 86_400_000. In
+** other words, write into *piNow the number of milliseconds since the Julian
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+** proleptic Gregorian calendar.
+**
+** On success, return 0. Return 1 if the time and date cannot be found.
+*/
+static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#if defined(NO_GETTOD)
+ time_t t;
+ time(&t);
+ *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
+#elif OS_VXWORKS
+ struct timespec sNow;
+ clock_gettime(CLOCK_REALTIME, &sNow);
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
+#else
+ struct timeval sNow;
+ gettimeofday(&sNow, 0);
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+#endif
+
+#ifdef SQLITE_TEST
+ if( sqlite3_current_time ){
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
+ }
+#endif
+ UNUSED_PARAMETER(NotUsed);
+ return 0;
+}
+
+/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
-#if defined(SQLITE_OMIT_FLOATING_POINT)
- time_t t;
- time(&t);
- *prNow = (((sqlite3_int64)t)/8640 + 24405875)/10;
-#elif defined(NO_GETTOD)
- time_t t;
- time(&t);
- *prNow = t/86400.0 + 2440587.5;
-#elif OS_VXWORKS
- struct timespec sNow;
- clock_gettime(CLOCK_REALTIME, &sNow);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_nsec/86400000000000.0;
-#else
- struct timeval sNow;
- gettimeofday(&sNow, 0);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
-#endif
-
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
+ sqlite3_int64 i;
UNUSED_PARAMETER(NotUsed);
+ unixCurrentTimeInt64(0, &i);
+ *prNow = i/86400000.0;
return 0;
}
@@ -25861,6 +27299,7 @@
return 0;
}
+
/*
************************ End of sqlite3_vfs methods ***************************
******************************************************************************/
@@ -25970,11 +27409,6 @@
** of the database file for multiple readers and writers on the same
** host (the conch ensures that they all use the same local lock file).
**
-** There is a third file - the host ID file - used as a persistent record
-** of a unique identifier for the host, a 128-byte unique host id file
-** in the path defined by the HOSTIDPATH macro (default value is
-** /Library/Caches/.com.apple.sqliteConchHostId).
-**
** Requesting the lock proxy does not immediately take the conch, it is
** only taken when the first request to lock database file is made.
** This matches the semantics of the traditional locking behavior, where
@@ -26000,10 +27434,6 @@
** Enables the logging of error messages during host id file
** retrieval and creation
**
-** HOSTIDPATH
-**
-** Overrides the default host ID file path location
-**
** LOCKPROXYDIR
**
** Overrides the default directory used for lock proxy files that
@@ -26028,11 +27458,6 @@
*/
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-#ifdef SQLITE_TEST
-/* simulate multiple hosts by creating unique hostid file paths */
-SQLITE_API int sqlite3_hostid_num = 0;
-#endif
-
/*
** The proxyLockingContext has the path and file structures for the remote
** and local proxy files in it
@@ -26044,134 +27469,16 @@
unixFile *lockProxy; /* Open proxy lock file */
char *lockProxyPath; /* Name of the proxy lock file */
char *dbPath; /* Name of the open file */
- int conchHeld; /* True if the conch is currently held */
+ int conchHeld; /* 1 if the conch is held, -1 if lockless */
void *oldLockingContext; /* Original lockingcontext to restore on close */
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
-/* HOSTIDLEN and CONCHLEN both include space for the string
-** terminating nul
+/*
+** The proxy lock file path for the database at dbPath is written into lPath,
+** which must point to valid, writable memory large enough for a maxLen length
+** file path.
*/
-#define HOSTIDLEN 128
-#define CONCHLEN (MAXPATHLEN+HOSTIDLEN+1)
-#ifndef HOSTIDPATH
-# define HOSTIDPATH "/Library/Caches/.com.apple.sqliteConchHostId"
-#endif
-
-/* basically a copy of unixRandomness with different
-** test behavior built in */
-static int proxyGenerateHostID(char *pHostID){
- int pid, fd, len;
- unsigned char *key = (unsigned char *)pHostID;
-
- memset(key, 0, HOSTIDLEN);
- len = 0;
- fd = open("/dev/urandom", O_RDONLY);
- if( fd>=0 ){
- len = read(fd, key, HOSTIDLEN);
- close(fd); /* silently leak the fd if it fails */
- }
- if( len < HOSTIDLEN ){
- time_t t;
- time(&t);
- memcpy(key, &t, sizeof(t));
- pid = getpid();
- memcpy(&key[sizeof(t)], &pid, sizeof(pid));
- }
-
-#ifdef MAKE_PRETTY_HOSTID
- {
- int i;
- /* filter the bytes into printable ascii characters and NUL terminate */
- key[(HOSTIDLEN-1)] = 0x00;
- for( i=0; i<(HOSTIDLEN-1); i++ ){
- unsigned char pa = key[i]&0x7F;
- if( pa<0x20 ){
- key[i] = (key[i]&0x80 == 0x80) ? pa+0x40 : pa+0x20;
- }else if( pa==0x7F ){
- key[i] = (key[i]&0x80 == 0x80) ? pa=0x20 : pa+0x7E;
- }
- }
- }
-#endif
- return SQLITE_OK;
-}
-
-/* writes the host id path to path, path should be an pre-allocated buffer
-** with enough space for a path
-*/
-static void proxyGetHostIDPath(char *path, size_t len){
- strlcpy(path, HOSTIDPATH, len);
-#ifdef SQLITE_TEST
- if( sqlite3_hostid_num>0 ){
- char suffix[2] = "1";
- suffix[0] = suffix[0] + sqlite3_hostid_num;
- strlcat(path, suffix, len);
- }
-#endif
- OSTRACE3("GETHOSTIDPATH %s pid=%d\n", path, getpid());
-}
-
-/* get the host ID from a sqlite hostid file stored in the
-** user-specific tmp directory, create the ID if it's not there already
-*/
-static int proxyGetHostID(char *pHostID, int *pError){
- int fd;
- char path[MAXPATHLEN];
- size_t len;
- int rc=SQLITE_OK;
-
- proxyGetHostIDPath(path, MAXPATHLEN);
- /* try to create the host ID file, if it already exists read the contents */
- fd = open(path, O_CREAT|O_WRONLY|O_EXCL, 0644);
- if( fd<0 ){
- int err=errno;
-
- if( err!=EEXIST ){
-#ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */
- fprintf(stderr, "sqlite error creating host ID file %s: %s\n",
- path, strerror(err));
-#endif
- return SQLITE_PERM;
- }
- /* couldn't create the file, read it instead */
- fd = open(path, O_RDONLY|O_EXCL);
- if( fd<0 ){
-#ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */
- int err = errno;
- fprintf(stderr, "sqlite error opening host ID file %s: %s\n",
- path, strerror(err));
-#endif
- return SQLITE_PERM;
- }
- len = pread(fd, pHostID, HOSTIDLEN, 0);
- if( len<0 ){
- *pError = errno;
- rc = SQLITE_IOERR_READ;
- }else if( len<HOSTIDLEN ){
- *pError = 0;
- rc = SQLITE_IOERR_SHORT_READ;
- }
- close(fd); /* silently leak the fd if it fails */
- OSTRACE3("GETHOSTID read %s pid=%d\n", pHostID, getpid());
- return rc;
- }else{
- /* we're creating the host ID file (use a random string of bytes) */
- proxyGenerateHostID(pHostID);
- len = pwrite(fd, pHostID, HOSTIDLEN, 0);
- if( len<0 ){
- *pError = errno;
- rc = SQLITE_IOERR_WRITE;
- }else if( len<HOSTIDLEN ){
- *pError = 0;
- rc = SQLITE_IOERR_WRITE;
- }
- close(fd); /* silently leak the fd if it fails */
- OSTRACE3("GETHOSTID wrote %s pid=%d\n", pHostID, getpid());
- return rc;
- }
-}
-
static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
int len;
int dbLen;
@@ -26182,21 +27489,12 @@
#else
# ifdef _CS_DARWIN_USER_TEMP_DIR
{
- confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen);
- len = strlcat(lPath, "sqliteplocks", maxLen);
- if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
- /* if mkdir fails, handle as lock file creation failure */
-# ifdef SQLITE_DEBUG
- int err = errno;
- if( err!=EEXIST ){
- fprintf(stderr, "proxyGetLockPath: mkdir(%s,0%o) error %d %s\n", lPath,
- SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err));
- }
-# endif
- }else{
- OSTRACE3("GETLOCKPATH mkdir %s pid=%d\n", lPath, getpid());
+ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
+ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
+ lPath, errno, getpid()));
+ return SQLITE_IOERR_LOCK;
}
-
+ len = strlcat(lPath, "sqliteplocks", maxLen);
}
# else
len = strlcpy(lPath, "/tmp/", maxLen);
@@ -26209,15 +27507,52 @@
/* transform the db path to a unique cache name */
dbLen = (int)strlen(dbPath);
- for( i=0; i<dbLen && (i+len+7)<maxLen; i++){
+ for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
char c = dbPath[i];
lPath[i+len] = (c=='/')?'_':c;
}
lPath[i+len]='\0';
strlcat(lPath, ":auto:", maxLen);
+ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
return SQLITE_OK;
}
+/*
+ ** Creates the lock file and any missing directories in lockPath
+ */
+static int proxyCreateLockPath(const char *lockPath){
+ int i, len;
+ char buf[MAXPATHLEN];
+ int start = 0;
+
+ assert(lockPath!=NULL);
+ /* try to create all the intermediate directories */
+ len = (int)strlen(lockPath);
+ buf[0] = lockPath[0];
+ for( i=1; i<len; i++ ){
+ if( lockPath[i] == '/' && (i - start > 0) ){
+ /* only mkdir if leaf dir != "." or "/" or ".." */
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
+ || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
+ buf[i]='\0';
+ if( mkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
+ int err=errno;
+ if( err!=EEXIST ) {
+ OSTRACE(("CREATELOCKPATH FAILED creating %s, "
+ "'%s' proxy lock path=%s pid=%d\n",
+ buf, strerror(err), lockPath, getpid()));
+ return err;
+ }
+ }
+ }
+ start=i+1;
+ }
+ buf[i] = lockPath[i];
+ }
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
+ return 0;
+}
+
/*
** Create a new VFS file descriptor (stored in memory obtained from
** sqlite3_malloc) and open the file named "path" in the file descriptor.
@@ -26225,29 +27560,25 @@
** The caller is responsible not only for closing the file descriptor
** but also for freeing the memory associated with the file descriptor.
*/
-static int proxyCreateUnixFile(const char *path, unixFile **ppFile) {
+static int proxyCreateUnixFile(
+ const char *path, /* path for the new unixFile */
+ unixFile **ppFile, /* unixFile created and returned by ref */
+ int islockfile /* if non zero missing dirs will be created */
+) {
+ int fd = -1;
+ int dirfd = -1;
unixFile *pNew;
- int flags = SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
int rc = SQLITE_OK;
+ int openFlags = O_RDWR | O_CREAT;
sqlite3_vfs dummyVfs;
+ int terrno = 0;
+ UnixUnusedFd *pUnused = NULL;
- pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile));
- if( !pNew ){
- return SQLITE_NOMEM;
- }
- memset(pNew, 0, sizeof(unixFile));
-
- /* Call unixOpen() to open the proxy file. The flags passed to unixOpen()
- ** suggest that the file being opened is a "main database". This is
- ** necessary as other file types do not necessarily support locking. It
- ** is better to use unixOpen() instead of opening the file directly with
- ** open(), as unixOpen() sets up the various mechanisms required to
- ** make sure a call to close() does not cause the system to discard
- ** POSIX locks prematurely.
- **
- ** It is important that the xOpen member of the VFS object passed to
- ** unixOpen() is NULL. This tells unixOpen() may try to open a proxy-file
- ** for the proxy-file (creating a potential infinite loop).
+ /* 1. first try to open/create the file
+ ** 2. if that fails, and this is a lock file (not-conch), try creating
+ ** the parent directories and then try again.
+ ** 3. if that fails, try to open the file read-only
+ ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file
*/
pUnused = findReusableFd(path, openFlags);
if( pUnused ){
@@ -26294,23 +27625,202 @@
memset(pNew, 0, sizeof(unixFile));
pNew->openFlags = openFlags;
dummyVfs.pAppData = (void*)&autolockIoFinder;
- dummyVfs.xOpen = 0;
- rc = unixOpen(&dummyVfs, path, (sqlite3_file *)pNew, flags, &flags);
- if( rc==SQLITE_OK && (flags&SQLITE_OPEN_READONLY) ){
- pNew->pMethod->xClose((sqlite3_file *)pNew);
- rc = SQLITE_CANTOPEN;
+ pUnused->fd = fd;
+ pUnused->flags = openFlags;
+ pNew->pUnused = pUnused;
+
+ rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
+ if( rc==SQLITE_OK ){
+ *ppFile = pNew;
+ return SQLITE_OK;
}
-
- if( rc!=SQLITE_OK ){
- sqlite3_free(pNew);
- pNew = 0;
- }
-
- *ppFile = pNew;
+end_create_proxy:
+ close(fd); /* silently leak fd if error, we're already in error */
+ sqlite3_free(pNew);
+ sqlite3_free(pUnused);
return rc;
}
-/* takes the conch by taking a shared lock and read the contents conch, if
+#ifdef SQLITE_TEST
+/* simulate multiple hosts by creating unique hostid file paths */
+SQLITE_API int sqlite3_hostid_num = 0;
+#endif
+
+#define PROXY_HOSTIDLEN 16 /* conch file host id length */
+
+/* Not always defined in the headers as it ought to be */
+extern int gethostuuid(uuid_t id, const struct timespec *wait);
+
+/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
+** bytes of writable memory.
+*/
+static int proxyGetHostID(unsigned char *pHostID, int *pError){
+ struct timespec timeout = {1, 0}; /* 1 sec timeout */
+
+ assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
+ memset(pHostID, 0, PROXY_HOSTIDLEN);
+ if( gethostuuid(pHostID, &timeout) ){
+ int err = errno;
+ if( pError ){
+ *pError = err;
+ }
+ return SQLITE_IOERR;
+ }
+#ifdef SQLITE_TEST
+ /* simulate multiple hosts by creating unique hostid file paths */
+ if( sqlite3_hostid_num != 0){
+ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
+ }
+#endif
+
+ return SQLITE_OK;
+}
+
+/* The conch file contains the header, host id and lock file path
+ */
+#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
+#define PROXY_HEADERLEN 1 /* conch file header length */
+#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
+#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
+
+/*
+** Takes an open conch file, copies the contents to a new path and then moves
+** it back. The newly created file's file descriptor is assigned to the
+** conch file structure and finally the original conch file descriptor is
+** closed. Returns zero if successful.
+*/
+static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ unixFile *conchFile = pCtx->conchFile;
+ char tPath[MAXPATHLEN];
+ char buf[PROXY_MAXCONCHLEN];
+ char *cPath = pCtx->conchFilePath;
+ size_t readLen = 0;
+ size_t pathLen = 0;
+ char errmsg[64] = "";
+ int fd = -1;
+ int rc = -1;
+ UNUSED_PARAMETER(myHostID);
+
+ /* create a new path by replace the trailing '-conch' with '-break' */
+ pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
+ if( pathLen>MAXPATHLEN || pathLen<6 ||
+ (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
+ sprintf(errmsg, "path error (len %d)", (int)pathLen);
+ goto end_breaklock;
+ }
+ /* read the conch content */
+ readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
+ if( readLen<PROXY_PATHINDEX ){
+ sprintf(errmsg, "read error (len %d)", (int)readLen);
+ goto end_breaklock;
+ }
+ /* write it out to the temporary break file */
+ fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
+ if( fd<0 ){
+ sprintf(errmsg, "create failed (%d)", errno);
+ goto end_breaklock;
+ }
+ if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
+ sprintf(errmsg, "write failed (%d)", errno);
+ goto end_breaklock;
+ }
+ if( rename(tPath, cPath) ){
+ sprintf(errmsg, "rename failed (%d)", errno);
+ goto end_breaklock;
+ }
+ rc = 0;
+ fprintf(stderr, "broke stale lock on %s\n", cPath);
+ close(conchFile->h);
+ conchFile->h = fd;
+ conchFile->openFlags = O_RDWR | O_CREAT;
+
+end_breaklock:
+ if( rc ){
+ if( fd>=0 ){
+ unlink(tPath);
+ close(fd);
+ }
+ fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
+ }
+ return rc;
+}
+
+/* Take the requested lock on the conch file and break a stale lock if the
+** host id matches.
+*/
+static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ unixFile *conchFile = pCtx->conchFile;
+ int rc = SQLITE_OK;
+ int nTries = 0;
+ struct timespec conchModTime;
+
+ do {
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+ nTries ++;
+ if( rc==SQLITE_BUSY ){
+ /* If the lock failed (busy):
+ * 1st try: get the mod time of the conch, wait 0.5s and try again.
+ * 2nd try: fail if the mod time changed or host id is different, wait
+ * 10 sec and try again
+ * 3rd try: break the lock unless the mod time has changed.
+ */
+ struct stat buf;
+ if( fstat(conchFile->h, &buf) ){
+ pFile->lastErrno = errno;
+ return SQLITE_IOERR_LOCK;
+ }
+
+ if( nTries==1 ){
+ conchModTime = buf.st_mtimespec;
+ usleep(500000); /* wait 0.5 sec and try the lock again*/
+ continue;
+ }
+
+ assert( nTries>1 );
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
+ conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
+ return SQLITE_BUSY;
+ }
+
+ if( nTries==2 ){
+ char tBuf[PROXY_MAXCONCHLEN];
+ int len = pread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
+ if( len<0 ){
+ pFile->lastErrno = errno;
+ return SQLITE_IOERR_LOCK;
+ }
+ if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
+ /* don't break the lock if the host id doesn't match */
+ if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
+ return SQLITE_BUSY;
+ }
+ }else{
+ /* don't break the lock on short read or a version mismatch */
+ return SQLITE_BUSY;
+ }
+ usleep(10000000); /* wait 10 sec and try the lock again */
+ continue;
+ }
+
+ assert( nTries==3 );
+ if( 0==proxyBreakConchLock(pFile, myHostID) ){
+ rc = SQLITE_OK;
+ if( lockType==EXCLUSIVE_LOCK ){
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
+ }
+ if( !rc ){
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+ }
+ }
+ }
+ } while( rc==SQLITE_BUSY && nTries<3 );
+
+ return rc;
+}
+
+/* Takes the conch by taking a shared lock and read the contents conch, if
** lockPath is non-NULL, the host ID and lock file path must match. A NULL
** lockPath means that the lockPath in the conch file will be used if the
** host IDs match, or a new lock path will be generated automatically
@@ -26319,145 +27829,83 @@
static int proxyTakeConch(unixFile *pFile){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- if( pCtx->conchHeld>0 ){
+ if( pCtx->conchHeld!=0 ){
return SQLITE_OK;
}else{
unixFile *conchFile = pCtx->conchFile;
- char testValue[CONCHLEN];
- char conchValue[CONCHLEN];
+ uuid_t myHostID;
+ int pError = 0;
+ char readBuf[PROXY_MAXCONCHLEN];
char lockPath[MAXPATHLEN];
- char *tLockPath = NULL;
+ char *tempLockPath = NULL;
int rc = SQLITE_OK;
- int readRc = SQLITE_OK;
- int syncPerms = 0;
+ int createConch = 0;
+ int hostIdMatch = 0;
+ int readLen = 0;
+ int tryOldLockPath = 0;
+ int forceNewLockPath = 0;
+
+ OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
- OSTRACE4("TAKECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid());
-
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
- if( rc==SQLITE_OK ){
- int pError = 0;
- memset(testValue, 0, CONCHLEN); /* conch is fixed size */
- rc = proxyGetHostID(testValue, &pError);
- if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = pError;
- }
- if( pCtx->lockProxyPath ){
- strlcpy(&testValue[HOSTIDLEN], pCtx->lockProxyPath, MAXPATHLEN);
- }
+ rc = proxyGetHostID(myHostID, &pError);
+ if( (rc&0xff)==SQLITE_IOERR ){
+ pFile->lastErrno = pError;
+ goto end_takeconch;
}
+ rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
if( rc!=SQLITE_OK ){
goto end_takeconch;
}
-
- readRc = unixRead((sqlite3_file *)conchFile, conchValue, CONCHLEN, 0);
- if( readRc!=SQLITE_IOERR_SHORT_READ ){
- if( readRc!=SQLITE_OK ){
- if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = conchFile->lastErrno;
- }
- rc = readRc;
- goto end_takeconch;
- }
- /* if the conch has data compare the contents */
- if( !pCtx->lockProxyPath ){
- /* for auto-named local lock file, just check the host ID and we'll
- ** use the local lock file path that's already in there */
- if( !memcmp(testValue, conchValue, HOSTIDLEN) ){
- tLockPath = (char *)&conchValue[HOSTIDLEN];
- goto end_takeconch;
- }
- }else{
- /* we've got the conch if conchValue matches our path and host ID */
- if( !memcmp(testValue, conchValue, CONCHLEN) ){
- goto end_takeconch;
- }
- }
- }else{
- /* a short read means we're "creating" the conch (even though it could
- ** have been user-intervention), if we acquire the exclusive lock,
- ** we'll try to match the current on-disk permissions of the database
+ /* read the existing conch file */
+ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
+ if( readLen<0 ){
+ /* I/O error: lastErrno set by seekAndRead */
+ pFile->lastErrno = conchFile->lastErrno;
+ rc = SQLITE_IOERR_READ;
+ goto end_takeconch;
+ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
+ readBuf[0]!=(char)PROXY_CONCHVERSION ){
+ /* a short read or version format mismatch means we need to create a new
+ ** conch file.
*/
- syncPerms = 1;
+ createConch = 1;
}
-
- /* either conch was emtpy or didn't match */
- if( !pCtx->lockProxyPath ){
- proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
- tLockPath = lockPath;
- strlcpy(&testValue[HOSTIDLEN], lockPath, MAXPATHLEN);
- }
-
- /* update conch with host and path (this will fail if other process
- ** has a shared lock already) */
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
- if( rc==SQLITE_OK ){
- rc = unixWrite((sqlite3_file *)conchFile, testValue, CONCHLEN, 0);
- if( rc==SQLITE_OK && syncPerms ){
- struct stat buf;
- int err = fstat(pFile->h, &buf);
- if( err==0 ){
- /* try to match the database file permissions, ignore failure */
-#ifndef SQLITE_PROXY_DEBUG
- fchmod(conchFile->h, buf.st_mode);
-#else
- if( fchmod(conchFile->h, buf.st_mode)!=0 ){
- int code = errno;
- fprintf(stderr, "fchmod %o FAILED with %d %s\n",
- buf.st_mode, code, strerror(code));
- } else {
- fprintf(stderr, "fchmod %o SUCCEDED\n",buf.st_mode);
- }
- }else{
- int code = errno;
- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
- err, code, strerror(code));
-#endif
- }
- }
- }
- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
-
-end_takeconch:
- OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h);
- if( rc==SQLITE_OK && pFile->openFlags ){
- if( pFile->h>=0 ){
-#ifdef STRICT_CLOSE_ERROR
- if( close(pFile->h) ){
- pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
- }
-#else
- close(pFile->h); /* silently leak fd if fail */
-#endif
- }
- pFile->h = -1;
- int fd = open(pCtx->dbPath, pFile->openFlags,
- SQLITE_DEFAULT_FILE_PERMISSIONS);
- OSTRACE2("TRANSPROXY: OPEN %d\n", fd);
- if( fd>=0 ){
- pFile->h = fd;
- }else{
- rc=SQLITE_CANTOPEN; /* SQLITE_BUSY? proxyTakeConch called
- during locking */
- }
- }
- if( rc==SQLITE_OK && !pCtx->lockProxy ){
- char *path = tLockPath ? tLockPath : pCtx->lockProxyPath;
- /* ACS: Need to make a copy of path sometimes */
- rc = proxyCreateUnixFile(path, &pCtx->lockProxy);
- }
- if( rc==SQLITE_OK ){
- pCtx->conchHeld = 1;
+ /* if the host id matches and the lock path already exists in the conch
+ ** we'll try to use the path there, if we can't open that path, we'll
+ ** retry with a new auto-generated path
+ */
+ do { /* in case we need to try again for an :auto: named lock file */
- if( tLockPath ){
- pCtx->lockProxyPath = sqlite3DbStrDup(0, tLockPath);
- if( pCtx->lockProxy->pMethod == &afpIoMethods ){
- ((afpLockingContext *)pCtx->lockProxy->lockingContext)->dbPath =
- pCtx->lockProxyPath;
+ if( !createConch && !forceNewLockPath ){
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
+ PROXY_HOSTIDLEN);
+ /* if the conch has data compare the contents */
+ if( !pCtx->lockProxyPath ){
+ /* for auto-named local lock file, just check the host ID and we'll
+ ** use the local lock file path that's already in there
+ */
+ if( hostIdMatch ){
+ size_t pathLen = (readLen - PROXY_PATHINDEX);
+
+ if( pathLen>=MAXPATHLEN ){
+ pathLen=MAXPATHLEN-1;
+ }
+ memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen);
+ lockPath[pathLen] = 0;
+ tempLockPath = lockPath;
+ tryOldLockPath = 1;
+ /* create a copy of the lock path if the conch is taken */
+ goto end_takeconch;
+ }
+ }else if( hostIdMatch
+ && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX],
+ readLen-PROXY_PATHINDEX)
+ ){
+ /* conch host and lock path match */
+ goto end_takeconch;
}
}
->>>>>>> BEGIN MERGE CONFLICT
/* if the conch isn't writable and doesn't match, we can't take it */
if( (conchFile->openFlags&O_RDWR) == 0 ){
@@ -26478,7 +27926,7 @@
*/
futimes(conchFile->h, NULL);
if( hostIdMatch && !createConch ){
- if( conchFile->pLock && conchFile->pLock->cnt>1 ){
+ if( conchFile->pInode && conchFile->pInode->nShared>1 ){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
@@ -26534,7 +27982,7 @@
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
end_takeconch:
- OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h);
+ OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
if( rc==SQLITE_OK && pFile->openFlags ){
if( pFile->h>=0 ){
#ifdef STRICT_CLOSE_ERROR
@@ -26549,7 +27997,7 @@
pFile->h = -1;
int fd = open(pCtx->dbPath, pFile->openFlags,
SQLITE_DEFAULT_FILE_PERMISSIONS);
- OSTRACE2("TRANSPROXY: OPEN %d\n", fd);
+ OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
if( fd>=0 ){
pFile->h = fd;
}else{
@@ -26591,16 +28039,11 @@
} else {
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
}
- OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed");
+ OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
+ rc==SQLITE_OK?"ok":"failed"));
return rc;
- } while (1); /* in case we need to retry the :auto: lock file - we should never get here except via the 'continue' call. */
-============================
- } else {
- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
- }
- OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed");
- return rc;
-<<<<<<< END MERGE CONFLICT
+ } while (1); /* in case we need to retry the :auto: lock file -
+ ** we should never get here except via the 'continue' call. */
}
}
@@ -26608,19 +28051,21 @@
** If pFile holds a lock on a conch file, then release that lock.
*/
static int proxyReleaseConch(unixFile *pFile){
- int rc; /* Subroutine return code */
+ int rc = SQLITE_OK; /* Subroutine return code */
proxyLockingContext *pCtx; /* The locking context for the proxy lock */
unixFile *conchFile; /* Name of the conch file */
pCtx = (proxyLockingContext *)pFile->lockingContext;
conchFile = pCtx->conchFile;
- OSTRACE4("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
+ OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
- getpid());
+ getpid()));
+ if( pCtx->conchHeld>0 ){
+ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
+ }
pCtx->conchHeld = 0;
- rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
- OSTRACE3("RELEASECONCH %d %s\n", conchFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("RELEASECONCH %d %s\n", conchFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -26677,7 +28122,7 @@
char *oldPath = pCtx->lockProxyPath;
int rc = SQLITE_OK;
- if( pFile->locktype!=NO_LOCK ){
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
@@ -26714,8 +28159,8 @@
/* afp style keeps a reference to the db path in the filePath field
** of the struct */
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath);
- }else
+ strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN);
+ } else
#endif
if( pFile->pMethod == &dotlockIoMethods ){
/* dot lock style uses the locking context to store the dot lock
@@ -26725,7 +28170,7 @@
}else{
/* all other styles use the locking context to store the db file path */
assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strcpy(dbPath, (char *)pFile->lockingContext);
+ strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
}
return SQLITE_OK;
}
@@ -26744,7 +28189,7 @@
char *lockPath=NULL;
int rc = SQLITE_OK;
- if( pFile->locktype!=NO_LOCK ){
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
proxyGetDbPathForUnixFile(pFile, dbPath);
@@ -26754,8 +28199,8 @@
lockPath=(char *)path;
}
- OSTRACE4("TRANSPROXY %d for %s pid=%d\n", pFile->h,
- (lockPath ? lockPath : ":auto:"), getpid());
+ OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
+ (lockPath ? lockPath : ":auto:"), getpid()));
pCtx = sqlite3_malloc( sizeof(*pCtx) );
if( pCtx==0 ){
@@ -26765,32 +28210,58 @@
rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
if( rc==SQLITE_OK ){
- rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile);
+ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0);
+ if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){
+ /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
+ ** (c) the file system is read-only, then enable no-locking access.
+ ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
+ ** that openFlags will have only one of O_RDONLY or O_RDWR.
+ */
+ struct statfs fsInfo;
+ struct stat conchInfo;
+ int goLockless = 0;
+
+ if( stat(pCtx->conchFilePath, &conchInfo) == -1 ) {
+ int err = errno;
+ if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
+ goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
+ }
+ }
+ if( goLockless ){
+ pCtx->conchHeld = -1; /* read only FS/ lockless */
+ rc = SQLITE_OK;
+ }
+ }
}
if( rc==SQLITE_OK && lockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
}
if( rc==SQLITE_OK ){
+ pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
+ if( pCtx->dbPath==NULL ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
/* all memory is allocated, proxys are created and assigned,
** switch the locking context and pMethod then return.
*/
- pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
pCtx->oldLockingContext = pFile->lockingContext;
pFile->lockingContext = pCtx;
pCtx->pOldMethod = pFile->pMethod;
pFile->pMethod = &proxyIoMethods;
}else{
if( pCtx->conchFile ){
- rc = pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
- if( rc ) return rc;
+ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
sqlite3_free(pCtx->conchFile);
}
+ sqlite3_free(pCtx->lockProxyPath);
sqlite3_free(pCtx->conchFilePath);
sqlite3_free(pCtx);
}
- OSTRACE3("TRANSPROXY %d %s\n", pFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -26874,14 +28345,18 @@
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
+ }else{ /* conchHeld < 0 is lockless */
+ pResOut=0;
+ }
}
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -26904,34 +28379,42 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int proxyLock(sqlite3_file *id, int locktype) {
+static int proxyLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xLock((sqlite3_file*)proxy, locktype);
- pFile->locktype = proxy->locktype;
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
+ }else{
+ /* conchHeld < 0 is lockless */
+ }
}
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int proxyUnlock(sqlite3_file *id, int locktype) {
+static int proxyUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, locktype);
- pFile->locktype = proxy->locktype;
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
+ }else{
+ /* conchHeld < 0 is lockless */
+ }
}
return rc;
}
@@ -27023,7 +28506,7 @@
** that filesystem time.
*/
#define UNIXVFS(VFSNAME, FINDER) { \
- 1, /* iVersion */ \
+ 2, /* iVersion */ \
sizeof(unixFile), /* szOsFile */ \
MAX_PATHNAME, /* mxPathname */ \
0, /* pNext */ \
@@ -27040,7 +28523,8 @@
unixRandomness, /* xRandomness */ \
unixSleep, /* xSleep */ \
unixCurrentTime, /* xCurrentTime */ \
- unixGetLastError /* xGetLastError */ \
+ unixGetLastError, /* xGetLastError */ \
+ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
}
/*
@@ -27058,7 +28542,6 @@
#endif
UNIXVFS("unix-none", nolockIoFinder ),
UNIXVFS("unix-dotfile", dotlockIoFinder ),
- UNIXVFS("unix-wfl", posixWflIoFinder ),
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
@@ -27070,6 +28553,7 @@
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix-afp", afpIoFinder ),
+ UNIXVFS("unix-nfs", nfsIoFinder ),
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
@@ -27191,23 +28675,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -27393,6 +28863,10 @@
# define FormatMessageW(a,b,c,d,e,f,g) 0
#endif
+/* Forward references */
+typedef struct winShm winShm; /* A connection to shared-memory */
+typedef struct winShmNode winShmNode; /* A region of shared-memory */
+
/*
** WinCE lacks native support for file locking so we have to fake it
** with some code of our own.
@@ -27412,12 +28886,15 @@
*/
typedef struct winFile winFile;
struct winFile {
- const sqlite3_io_methods *pMethod;/* Must be first */
+ const sqlite3_io_methods *pMethod; /*** Must be first ***/
+ sqlite3_vfs *pVfs; /* The VFS used to open this file */
HANDLE h; /* Handle for accessing the file */
unsigned char locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
+ winShm *pShm; /* Instance of shared memory on this file */
+ const char *zPath; /* Full pathname of this file */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
@@ -27945,7 +29422,8 @@
winFile *pFile = (winFile*)id;
assert( id!=0 );
- OSTRACE2("CLOSE %d\n", pFile->h);
+ assert( pFile->pShm==0 );
+ OSTRACE(("CLOSE %d\n", pFile->h));
do{
rc = CloseHandle(pFile->h);
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
@@ -27964,6 +29442,7 @@
free(pFile->zDeleteOnClose);
}
#endif
+ OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
OpenCounter(-1);
return rc ? SQLITE_OK : SQLITE_IOERR;
}
@@ -27995,7 +29474,7 @@
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
@@ -28034,11 +29513,15 @@
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
- return SQLITE_FULL;
+ if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
+ return SQLITE_FULL;
+ }else{
+ return SQLITE_IOERR_WRITE;
+ }
}
assert( amt>0 );
while(
@@ -28051,7 +29534,11 @@
}
if( !rc || amt>(int)wrote ){
pFile->lastErrno = GetLastError();
- return SQLITE_FULL;
+ if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
+ return SQLITE_FULL;
+ }else{
+ return SQLITE_IOERR_WRITE;
+ }
}
return SQLITE_OK;
}
@@ -28062,24 +29549,25 @@
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(nByte & 0xffffffff);
- DWORD rc;
+ DWORD dwRet;
winFile *pFile = (winFile*)id;
DWORD error;
+ int rc = SQLITE_OK;
assert( id!=0 );
- OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
+ OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
+ dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( dwRet==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
- return SQLITE_IOERR_TRUNCATE;
- }
+ rc = SQLITE_IOERR_TRUNCATE;
/* SetEndOfFile will fail if nByte is negative */
- if( !SetEndOfFile(pFile->h) ){
+ }else if( !SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
- return SQLITE_IOERR_TRUNCATE;
+ rc = SQLITE_IOERR_TRUNCATE;
}
- return SQLITE_OK;
+ OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc==SQLITE_OK ? "ok" : "failed"));
+ return rc;
}
#ifdef SQLITE_TEST
@@ -28099,7 +29587,7 @@
winFile *pFile = (winFile*)id;
assert( id!=0 );
- OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
#else
UNUSED_PARAMETER(id);
#endif
@@ -28240,8 +29728,8 @@
DWORD error = NO_ERROR;
assert( id!=0 );
- OSTRACE5("LOCK %d %d was %d(%d)\n",
- pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("LOCK %d %d was %d(%d)\n",
+ pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
@@ -28271,7 +29759,7 @@
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
- OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
+ OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
Sleep(1);
}
gotPendingLock = res;
@@ -28316,13 +29804,13 @@
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2("unreadlock = %d\n", res);
+ OSTRACE(("unreadlock = %d\n", res));
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
error = GetLastError();
- OSTRACE2("error-code = %d\n", error);
+ OSTRACE(("error-code = %d\n", error));
getReadLock(pFile);
}
}
@@ -28340,8 +29828,8 @@
if( res ){
rc = SQLITE_OK;
}else{
- OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype);
+ OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype));
pFile->lastErrno = error;
rc = SQLITE_BUSY;
}
@@ -28361,14 +29849,14 @@
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
}
*pResOut = rc;
return SQLITE_OK;
@@ -28391,8 +29879,8 @@
int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
- pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ pFile->locktype, pFile->sharedLockByte));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
@@ -28428,6 +29916,11 @@
*(int*)pArg = (int)((winFile*)id)->lastErrno;
return SQLITE_OK;
}
+ case SQLITE_FCNTL_SIZE_HINT: {
+ sqlite3_int64 sz = *(sqlite3_int64*)pArg;
+ winTruncate(id, sz);
+ return SQLITE_OK;
+ }
}
return SQLITE_ERROR;
}
@@ -28452,15 +29945,538 @@
*/
static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id);
- return 0;
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
+/****************************************************************************
+********************************* Shared Memory *****************************
+**
+** The next subdivision of code manages the shared-memory primitives.
+*/
+#ifndef SQLITE_OMIT_WAL
+
+/*
+** Helper functions to obtain and relinquish the global mutex. The
+** global mutex is used to protect the winLockInfo objects used by
+** this file, all of which may be shared by multiple threads.
+**
+** Function winShmMutexHeld() is used to assert() that the global mutex
+** is held when required. This function is only used as part of assert()
+** statements. e.g.
+**
+** winShmEnterMutex()
+** assert( winShmMutexHeld() );
+** winEnterLeave()
+*/
+static void winShmEnterMutex(void){
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+static void winShmLeaveMutex(void){
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+#ifdef SQLITE_DEBUG
+static int winShmMutexHeld(void) {
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+#endif
+
+/*
+** Object used to represent a single file opened and mmapped to provide
+** shared memory. When multiple threads all reference the same
+** log-summary, each thread has its own winFile object, but they all
+** point to a single instance of this object. In other words, each
+** log-summary is opened only once per process.
+**
+** winShmMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
+**
+** nRef
+** pNext
+**
+** The following fields are read-only after the object is created:
+**
+** fid
+** zFilename
+**
+** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
+** winShmMutexHeld() is true when reading or writing any other field
+** in this structure.
+**
+** To avoid deadlocks, mutex and mutexBuf are always released in the
+** reverse order that they are acquired. mutexBuf is always acquired
+** first and released last. This invariant is check by asserting
+** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
+** released.
+*/
+struct winShmNode {
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ char *zFilename; /* Name of the file */
+ winFile hFile; /* File handle from winOpen */
+
+ int szRegion; /* Size of shared-memory regions */
+ int nRegion; /* Size of array apRegion */
+ struct ShmRegion {
+ HANDLE hMap; /* File handle from CreateFileMapping */
+ void *pMap;
+ } *aRegion;
+ DWORD lastErrno; /* The Windows errno from the last I/O error */
+
+ int nRef; /* Number of winShm objects pointing to this */
+ winShm *pFirst; /* All winShm objects pointing to this */
+ winShmNode *pNext; /* Next in list of all winShmNode objects */
+#ifdef SQLITE_DEBUG
+ u8 nextShmId; /* Next available winShm.id value */
+#endif
+};
+
+/*
+** A global array of all winShmNode objects.
+**
+** The winShmMutexHeld() must be true while reading or writing this list.
+*/
+static winShmNode *winShmNodeList = 0;
+
+/*
+** Structure used internally by this VFS to record the state of an
+** open shared memory connection.
+**
+** winShm.pFile->mutex must be held while reading or writing the
+** winShm.pNext and winShm.locks[] elements.
+**
+** The winShm.pFile element is initialized when the object is created
+** and is read-only thereafter.
+*/
+struct winShm {
+ winShmNode *pShmNode; /* The underlying winShmNode object */
+ winShm *pNext; /* Next winShm with the same winShmNode */
+ u8 hasMutex; /* True if holding the winShmNode mutex */
+ u8 hasMutexBuf; /* True if holding pFile->mutexBuf */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection with its winShmNode */
+#endif
+};
+
+/*
+** Constants used for locking
+*/
+#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** Apply advisory locks for all n bytes beginning at ofst.
+*/
+#define _SHM_UNLCK 1
+#define _SHM_RDLCK 2
+#define _SHM_WRLCK 3
+static int winShmSystemLock(
+ winShmNode *pFile, /* Apply locks to this open shared-memory segment */
+ int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
+ int ofst, /* Offset to first byte to be locked/unlocked */
+ int nByte /* Number of bytes to lock or unlock */
+){
+ OVERLAPPED ovlp;
+ DWORD dwFlags;
+ int rc = 0; /* Result code form Lock/UnlockFileEx() */
+
+ /* Access to the winShmNode object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+
+ /* Initialize the locking parameters */
+ dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+ if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ /* Find the first bit in lockMask that is set */
+ memset(&ovlp, 0, sizeof(OVERLAPPED));
+ ovlp.Offset = ofst;
+
+ /* Release/Acquire the system-level lock */
+ if( lockType==_SHM_UNLCK ){
+ rc = UnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
+ }else{
+ rc = LockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
+ }
+ if( !rc ){
+ OSTRACE(("SHM-LOCK %d %s ERROR 0x%08lx\n",
+ pFile->hFile.h,
+ lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
+ GetLastError()));
+ }
+ rc = (rc!=0) ? SQLITE_OK : SQLITE_BUSY;
+
+ return rc;
+}
+
+/* Forward references to VFS methods */
+static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
+static int winDelete(sqlite3_vfs *,const char*,int);
+
+/*
+** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
+ winShmNode **pp;
+ winShmNode *p;
+ assert( winShmMutexHeld() );
+ pp = &winShmNodeList;
+ while( (p = *pp)!=0 ){
+ if( p->nRef==0 ){
+ int i;
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ for(i=0; i<p->nRegion; i++){
+ UnmapViewOfFile(p->aRegion[i].pMap);
+ CloseHandle(p->aRegion[i].hMap);
+ }
+ if( p->hFile.h != INVALID_HANDLE_VALUE ) {
+ winClose((sqlite3_file *)&p->hFile);
+ }
+ if( deleteFlag ) winDelete(pVfs, p->zFilename, 0);
+ *pp = p->pNext;
+ sqlite3_free(p->aRegion);
+ sqlite3_free(p);
+ }else{
+ pp = &p->pNext;
+ }
+ }
+}
+
+/*
+** Open a shared-memory area. This particular implementation uses
+** mmapped files.
+**
+** zName is a filename used to identify the shared-memory area. The
+** implementation does not (and perhaps should not) use this name
+** directly, but rather use it as a template for finding an appropriate
+** name for the shared-memory storage. In this implementation, the
+** string "-index" is appended to zName and used as the name of the
+** mmapped file.
+**
+** When opening a new shared-memory file, if no other instances of that
+** file are currently open, in this process or in other processes, then
+** the file must be truncated to zero length or have its header cleared.
+*/
+static int winShmOpen(
+ sqlite3_file *fd /* The file to which to attach shared memory */
+){
+ struct winFile *pDbFd; /* Database to which to attach SHM */
+ struct winShm *p; /* The connection to be opened */
+ struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct winShmNode *pNew; /* Newly allocated winShmNode */
+ int nName; /* Size of zName in bytes */
+
+ pDbFd = (winFile*)fd;
+ assert( pDbFd->pShm==0 ); /* Not previously opened */
+
+ /* Allocate space for the new sqlite3_shm object. Also speculatively
+ ** allocate space for a new winShmNode and filename.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ nName = sqlite3Strlen30(pDbFd->zPath);
+ pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zFilename = (char*)&pNew[1];
+ sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
+
+ /* Look to see if there is an existing winShmNode that can be used.
+ ** If no matching winShmNode currently exists, create a new one.
+ */
+ winShmEnterMutex();
+ for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
+ /* TBD need to come up with better match here. Perhaps
+ ** use FILE_ID_BOTH_DIR_INFO Structure.
+ */
+ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
+ }
+ if( pShmNode ){
+ sqlite3_free(pNew);
+ }else{
+ pShmNode = pNew;
+ pNew = 0;
+ ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
+ pShmNode->pNext = winShmNodeList;
+ winShmNodeList = pShmNode;
+
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+ rc = winOpen(pDbFd->pVfs,
+ pShmNode->zFilename, /* Name of the file (UTF-8) */
+ (sqlite3_file*)&pShmNode->hFile, /* File handle here */
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
+ 0);
+ if( SQLITE_OK!=rc ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
+ if( rc!=SQLITE_OK ){
+ rc = SQLITE_IOERR_SHMOPEN;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the winShmNode */
+ p->pShmNode = pShmNode;
+ p->pNext = pShmNode->pFirst;
+#ifdef SQLITE_DEBUG
+ p->id = pShmNode->nextShmId++;
+#endif
+ pShmNode->pFirst = p;
+ pShmNode->nRef++;
+ pDbFd->pShm = p;
+ winShmLeaveMutex();
+ return SQLITE_OK;
+
+ /* Jump here on any error */
+shm_open_err:
+ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
+ sqlite3_free(p);
+ sqlite3_free(pNew);
+ winShmLeaveMutex();
+ return rc;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int winShmClose(
+ sqlite3_file *fd, /* Database holding shared memory */
+ int deleteFlag /* Delete after closing if true */
+){
+ winFile *pDbFd; /* Database holding shared-memory */
+ winShm *p; /* The connection to be closed */
+ winShmNode *pShmNode; /* The underlying shared-memory file */
+ winShm **pp; /* For looping over sibling connections */
+
+ pDbFd = (winFile*)fd;
+ p = pDbFd->pShm;
+ pShmNode = p->pShmNode;
+
+ /* Remove connection p from the set of connections associated
+ ** with pShmNode */
+ sqlite3_mutex_enter(pShmNode->mutex);
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+ *pp = p->pNext;
+
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
+ sqlite3_mutex_leave(pShmNode->mutex);
+
+ /* If pShmNode->nRef has reached 0, then close the underlying
+ ** shared-memory file, too */
+ winShmEnterMutex();
+ assert( pShmNode->nRef>0 );
+ pShmNode->nRef--;
+ if( pShmNode->nRef==0 ){
+ winShmPurge(pDbFd->pVfs, deleteFlag);
+ }
+ winShmLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
+** bytes in size.
+**
+** If an error occurs, an error code is returned and *pp is set to NULL.
+**
+** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+** region has not been allocated (by any client, including one running in a
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
+** been allocated, it is allocated by this function.
+**
+** If the shared-memory region has already been allocated or is allocated by
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
+** memory and SQLITE_OK returned.
+*/
+static int winShmMap(
+ sqlite3_file *fd, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int isWrite, /* True to extend file if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ winFile *pDbFd = (winFile*)fd;
+ winShm *p = pDbFd->pShm;
+ winShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_OK;
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+ if( pShmNode->nRegion<=iRegion ){
+ struct ShmRegion *apNew; /* New aRegion[] array */
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ sqlite3_int64 sz; /* Current size of wal-index file */
+
+ pShmNode->szRegion = szRegion;
+
+ /* The requested region is not mapped into this processes address space.
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
+ ** large enough to contain the requested region).
+ */
+ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
+ if( rc!=SQLITE_OK ){
+ goto shmpage_out;
+ }
+
+ if( sz<nByte ){
+ /* The requested memory region does not exist. If isWrite is set to
+ ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
+ **
+ ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
+ ** the requested memory region.
+ */
+ if( !isWrite ) goto shmpage_out;
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
+ if( rc!=SQLITE_OK ){
+ goto shmpage_out;
+ }
+ }
+
+ /* Map the requested memory region into this processes address space. */
+ apNew = (struct ShmRegion *)sqlite3_realloc(
+ pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
+ );
+ if( !apNew ){
+ rc = SQLITE_IOERR_NOMEM;
+ goto shmpage_out;
+ }
+ pShmNode->aRegion = apNew;
+
+ while( pShmNode->nRegion<=iRegion ){
+ HANDLE hMap; /* file-mapping handle */
+ void *pMap = 0; /* Mapped memory region */
+
+ hMap = CreateFileMapping(pShmNode->hFile.h,
+ NULL, PAGE_READWRITE, 0, nByte, NULL
+ );
+ if( hMap ){
+ pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ 0, 0, nByte
+ );
+ }
+ if( !pMap ){
+ pShmNode->lastErrno = GetLastError();
+ rc = SQLITE_IOERR;
+ if( hMap ) CloseHandle(hMap);
+ goto shmpage_out;
+ }
+
+ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
+ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
+ pShmNode->nRegion++;
+ }
+ }
+
+shmpage_out:
+ if( pShmNode->nRegion>iRegion ){
+ char *p = (char *)pShmNode->aRegion[iRegion].pMap;
+ *pp = (void *)&p[iRegion*szRegion];
+ }else{
+ *pp = 0;
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+*/
+static int winShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int ofst, /* First lock to acquire or release */
+ int n, /* Number of locks to acquire or release */
+ int flags /* What to do with the lock */
+){
+ winFile *pDbFd = (winFile*)fd;
+ winShm *p = pDbFd->pShm;
+ winShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_PROTOCOL;
+
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ if( flags & SQLITE_SHM_UNLOCK ){
+ rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
+ }else if( flags & SQLITE_SHM_SHARED ){
+ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
+ }else{
+ rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d %s\n",
+ p->id, (int)GetCurrentProcessId(), rc ? "failed" : "ok"));
+ return rc;
+}
+
+/*
+** Implement a memory barrier or memory fence on shared memory.
+**
+** All loads and stores begun before the barrier must complete before
+** any load or store begun after the barrier.
+*/
+static void winShmBarrier(
+ sqlite3_file *fd /* Database holding the shared memory */
+){
+ UNUSED_PARAMETER(fd);
+ /* MemoryBarrier(); // does not work -- do not know why not */
+ winShmEnterMutex();
+ winShmLeaveMutex();
+}
+
+#else
+# define winShmOpen 0
+# define winShmMap 0
+# define winShmLock 0
+# define winShmBarrier 0
+# define winShmClose 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+/*
+***************************** End Shared Memory *****************************
+****************************************************************************/
+
/*
** This vector defines all the methods that can operate on an
** sqlite3_file for win32.
*/
static const sqlite3_io_methods winIoMethod = {
- 1, /* iVersion */
+ 2, /* iVersion */
winClose,
winRead,
winWrite,
@@ -28472,7 +30488,12 @@
winCheckReservedLock,
winFileControl,
winSectorSize,
- winDeviceCharacteristics
+ winDeviceCharacteristics,
+ winShmOpen, /* xShmOpen */
+ winShmLock, /* xShmLock */
+ winShmMap, /* xShmMap */
+ winShmBarrier, /* xShmBarrier */
+ winShmClose /* xShmClose */
};
/***************************************************************************
@@ -28554,7 +30575,7 @@
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- OSTRACE2("TEMP FILENAME: %s\n", zBuf);
+ OSTRACE(("TEMP FILENAME: %s\n", zBuf));
return SQLITE_OK;
}
@@ -28646,6 +30667,8 @@
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
+ pFile->h = INVALID_HANDLE_VALUE;
+
/* If the second argument to this function is NULL, generate a
** temporary file name to use
*/
@@ -28727,6 +30750,9 @@
);
#endif
}
+ OSTRACE(("OPEN %d %s 0x%lx %s\n",
+ h, zName, dwDesiredAccess,
+ h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
free(zConverted);
if( flags & SQLITE_OPEN_READWRITE ){
@@ -28747,6 +30773,9 @@
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
+ pFile->pVfs = pVfs;
+ pFile->pShm = 0;
+ pFile->zPath = zName;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
@@ -28818,7 +30847,10 @@
#endif
}
free(zConverted);
- OSTRACE2("DELETE \"%s\"\n", zFilename);
+ OSTRACE(("DELETE \"%s\" %s\n", zFilename,
+ ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
+ "ok" : "failed" ));
+
return ( (rc == INVALID_FILE_ATTRIBUTES)
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
@@ -28834,13 +30866,38 @@
){
DWORD attr;
int rc = 0;
- void *zConverted = convertUtf8Filename(zFilename);
+ void *zConverted;
UNUSED_PARAMETER(pVfs);
+
+ SimulateIOError( return SQLITE_IOERR_ACCESS; );
+ zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
- attr = GetFileAttributesW((WCHAR*)zConverted);
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+ memset(&sAttrData, 0, sizeof(sAttrData));
+ if( GetFileAttributesExW((WCHAR*)zConverted,
+ GetFileExInfoStandard,
+ &sAttrData) ){
+ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
+ ** as if it does not exist.
+ */
+ if( flags==SQLITE_ACCESS_EXISTS
+ && sAttrData.nFileSizeHigh==0
+ && sAttrData.nFileSizeLow==0 ){
+ attr = INVALID_FILE_ATTRIBUTES;
+ }else{
+ attr = sAttrData.dwFileAttributes;
+ }
+ }else{
+ if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
+ free(zConverted);
+ return SQLITE_IOERR_ACCESS;
+ }else{
+ attr = INVALID_FILE_ATTRIBUTES;
+ }
+ }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
@@ -29111,34 +31168,32 @@
}
/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
+** The following variable, if set to a non-zero value, is interpreted as
+** the number of seconds since 1970 and is used to set the result of
+** sqlite3OsCurrentTime() during testing.
*/
#ifdef SQLITE_TEST
-SQLITE_API int sqlite3_current_time = 0;
+SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
#endif
/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
+** Find the current time (in Universal Coordinated Time). Write into *piNow
+** the current time and date as a Julian Day number times 86_400_000. In
+** other words, write into *piNow the number of milliseconds since the Julian
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+** proleptic Gregorian calendar.
+**
+** On success, return 0. Return 1 if the time and date cannot be found.
*/
-int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
- FILETIME ft;
+static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
- sqlite3_int64 timeW; /* Whole days */
- sqlite3_int64 timeF; /* Fractional Days */
-
- /* Number of 100-nanosecond intervals in a single day */
- static const sqlite3_int64 ntuPerDay =
- 10000000*(sqlite3_int64)86400;
-
- /* Number of 100-nanosecond intervals in half of a day */
- static const sqlite3_int64 ntuPerHalfDay =
- 10000000*(sqlite3_int64)43200;
-
+ FILETIME ft;
+ static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
+#ifdef SQLITE_TEST
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#endif
/* 2^32 - to avoid use of LL and warnings in gcc */
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
@@ -29153,24 +31208,36 @@
#else
GetSystemTimeAsFileTime( &ft );
#endif
- UNUSED_PARAMETER(pVfs);
- timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
- timeF = timeW % ntuPerDay; /* fractional days (100-nanoseconds) */
- timeW = timeW / ntuPerDay; /* whole days */
- timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
- timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
- timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
- timeF = timeF % ntuPerDay; /* compute new fractional days */
- *prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
+
+ *piNow = winFiletimeEpoch +
+ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
+
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
- *prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
+ UNUSED_PARAMETER(pVfs);
return 0;
}
/*
+** Find the current time (in Universal Coordinated Time). Write the
+** current time and date as a Julian Day number into *prNow and
+** return 0. Return 1 if the time and date cannot be found.
+*/
+int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
+ int rc;
+ sqlite3_int64 i;
+ rc = winCurrentTimeInt64(pVfs, &i);
+ if( !rc ){
+ *prNow = i/86400000.0;
+ }
+ return rc;
+}
+
+/*
** The idea is that this function works like a combination of
** GetLastError() and FormatMessage() on windows (or errno and
** strerror_r() on unix). After an error is returned by an OS
@@ -29205,30 +31272,32 @@
return getLastErrorMsg(nBuf, zBuf);
}
+
+
/*
** Initialize and deinitialize the operating system interface.
*/
SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
- 1, /* iVersion */
- sizeof(winFile), /* szOsFile */
- MAX_PATH, /* mxPathname */
- 0, /* pNext */
- "win32", /* zName */
- 0, /* pAppData */
-
- winOpen, /* xOpen */
- winDelete, /* xDelete */
- winAccess, /* xAccess */
- winFullPathname, /* xFullPathname */
- winDlOpen, /* xDlOpen */
- winDlError, /* xDlError */
- winDlSym, /* xDlSym */
- winDlClose, /* xDlClose */
- winRandomness, /* xRandomness */
- winSleep, /* xSleep */
- winCurrentTime, /* xCurrentTime */
- winGetLastError /* xGetLastError */
+ 2, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ MAX_PATH, /* mxPathname */
+ 0, /* pNext */
+ "win32", /* zName */
+ 0, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
};
sqlite3_vfs_register(&winVfs, 1);
@@ -29913,15 +31982,17 @@
if( pPage ){
if( !pPage->pData ){
- memset(pPage, 0, sizeof(PgHdr) + pCache->szExtra);
- pPage->pExtra = (void*)&pPage[1];
- pPage->pData = (void *)&((char *)pPage)[sizeof(PgHdr) + pCache->szExtra];
+ memset(pPage, 0, sizeof(PgHdr));
+ pPage->pData = (void *)&pPage[1];
+ pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
+ memset(pPage->pExtra, 0, pCache->szExtra);
pPage->pCache = pCache;
pPage->pgno = pgno;
}
assert( pPage->pCache==pCache );
assert( pPage->pgno==pgno );
- assert( pPage->pExtra==(void *)&pPage[1] );
+ assert( pPage->pData==(void *)&pPage[1] );
+ assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
if( 0==pPage->nRef ){
pCache->nRef++;
@@ -30060,7 +32131,12 @@
PgHdr *pNext;
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
- if( p->pgno>pgno ){
+ /* This routine never gets call with a positive pgno except right
+ ** after sqlite3PcacheCleanAll(). So if there are dirty pages,
+ ** it must be that pgno==0.
+ */
+ assert( p->pgno>0 );
+ if( ALWAYS(p->pgno>pgno) ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
@@ -30404,6 +32480,7 @@
int sz = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
}
return p;
}
@@ -30421,7 +32498,10 @@
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
}else{
- int iSize = sqlite3MallocSize(p);
+ int iSize;
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ iSize = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3_free(p);
}
@@ -30943,7 +33023,7 @@
** already provided an alternative.
*/
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
- static sqlite3_pcache_methods defaultMethods = {
+ static const sqlite3_pcache_methods defaultMethods = {
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
@@ -31456,6 +33536,198 @@
** another is writing.
*/
#ifndef SQLITE_OMIT_DISKIO
+/************** Include wal.h in the middle of pager.c ***********************/
+/************** Begin file wal.h *********************************************/
+/*
+** 2010 February 1
+**
+** 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 header file defines the interface to the write-ahead logging
+** system. Refer to the comments below and the header comment attached to
+** the implementation of each function in log.c for further details.
+*/
+
+#ifndef _WAL_H_
+#define _WAL_H_
+
+
+#ifdef SQLITE_OMIT_WAL
+# define sqlite3WalOpen(x,y,z) 0
+# define sqlite3WalClose(w,x,y,z) 0
+# define sqlite3WalBeginReadTransaction(y,z) 0
+# define sqlite3WalEndReadTransaction(z)
+# define sqlite3WalRead(v,w,x,y,z) 0
+# define sqlite3WalDbsize(y,z)
+# define sqlite3WalBeginWriteTransaction(y) 0
+# define sqlite3WalEndWriteTransaction(x) 0
+# define sqlite3WalUndo(x,y,z) 0
+# define sqlite3WalSavepoint(y,z)
+# define sqlite3WalSavepointUndo(y,z) 0
+# define sqlite3WalFrames(u,v,w,x,y,z) 0
+# define sqlite3WalCheckpoint(u,v,w,x) 0
+# define sqlite3WalCallback(z) 0
+# define sqlite3WalExclusiveMode(y,z) 0
+#else
+
+#define WAL_SAVEPOINT_NDATA 4
+
+/* Connection to a write-ahead log (WAL) file.
+** There is one object of this type for each pager.
+*/
+typedef struct Wal Wal;
+
+/* Open and close a connection to a write-ahead log. */
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
+SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+
+/* Used by readers to open (lock) and close (unlock) a snapshot. A
+** snapshot is like a read-transaction. It is the state of the database
+** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
+** preserves the current state even if the other threads or processes
+** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
+** transaction and releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
+
+/* Read a page from the write-ahead log, if it is present. */
+SQLITE_PRIVATE int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
+
+/* Return the size of the database as it existed at the beginning
+** of the snapshot */
+SQLITE_PRIVATE void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
+
+/* Obtain or release the WRITER lock. */
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
+
+/* Undo any frames written (but not committed) to the log */
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
+
+/* Return an integer that records the current (uncommitted) write
+** position in the WAL */
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
+
+/* Move the write position of the WAL back to iFrame. Called in
+** response to a ROLLBACK TO command. */
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
+
+/* Write a frame or frames to the log. */
+SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
+
+/* Copy pages from the log to the database file */
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Write-ahead log connection */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of buffer nBuf */
+ u8 *zBuf /* Temporary buffer to use */
+);
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called. If no commits have occurred since
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
+
+/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
+** by the pager layer on the database file.
+*/
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
+
+#endif /* ifndef SQLITE_OMIT_WAL */
+#endif /* _WAL_H_ */
+
+/************** End of wal.h *************************************************/
+/************** Continuing where we left off in pager.c **********************/
+
+/*
+******************** NOTES ON THE DESIGN OF THE PAGER ************************
+**
+** Within this comment block, a page is deemed to have been synced
+** automatically as soon as it is written when PRAGMA synchronous=OFF.
+** Otherwise, the page is not synced until the xSync method of the VFS
+** is called successfully on the file containing the page.
+**
+** Definition: A page of the database file is said to be "overwriteable" if
+** one or more of the following are true about the page:
+**
+** (a) The original content of the page as it was at the beginning of
+** the transaction has been written into the rollback journal and
+** synced.
+**
+** (b) The page was a freelist leaf page at the start of the transaction.
+**
+** (c) The page number is greater than the largest page that existed in
+** the database file at the start of the transaction.
+**
+** (1) A page of the database file is never overwritten unless one of the
+** following are true:
+**
+** (a) The page and all other pages on the same sector are overwriteable.
+**
+** (b) The atomic page write optimization is enabled, and the entire
+** transaction other than the update of the transaction sequence
+** number consists of a single page change.
+**
+** (2) The content of a page written into the rollback journal exactly matches
+** both the content in the database when the rollback journal was written
+** and the content in the database at the beginning of the current
+** transaction.
+**
+** (3) Writes to the database file are an integer multiple of the page size
+** in length and are aligned to a page boundary.
+**
+** (4) Reads from the database file are either aligned on a page boundary and
+** an integer multiple of the page size in length or are taken from the
+** first 100 bytes of the database file.
+**
+** (5) All writes to the database file are synced prior to the rollback journal
+** being deleted, truncated, or zeroed.
+**
+** (6) If a master journal file is used, then all writes to the database file
+** are synced prior to the master journal being deleted.
+**
+** Definition: Two databases (or the same database at two points it time)
+** are said to be "logically equivalent" if they give the same answer to
+** all queries. Note in particular the the content of freelist leaf
+** pages can be changed arbitarily without effecting the logical equivalence
+** of the database.
+**
+** (7) At any time, if any subset, including the empty set and the total set,
+** of the unsynced changes to a rollback journal are removed and the
+** journal is rolled back, the resulting database file will be logical
+** equivalent to the database file at the beginning of the transaction.
+**
+** (8) When a transaction is rolled back, the xTruncate method of the VFS
+** is called to restore the database file to the same size it was at
+** the beginning of the transaction. (In some VFSes, the xTruncate
+** method is a no-op, but that does not change the fact the SQLite will
+** invoke it.)
+**
+** (9) Whenever the database file is modified, at least one bit in the range
+** of bytes from 24 through 39 inclusive will be changed prior to releasing
+** the EXCLUSIVE lock.
+**
+** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less
+** than one billion transactions.
+**
+** (11) A database file is well-formed at the beginning and at the conclusion
+** of every transaction.
+**
+** (12) An EXCLUSIVE lock is held on the database file when writing to
+** the database file.
+**
+** (13) A SHARED lock is held on the database file while reading any
+** content out of the database file.
+*/
/*
** Macros for troubleshooting. Normally turned off
@@ -31575,6 +33847,9 @@
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
Pgno nOrig; /* Original number of pages in file */
Pgno iSubRec; /* Index of first record in sub-journal */
+#ifndef SQLITE_OMIT_WAL
+ u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
+#endif
};
/*
@@ -31633,7 +33908,8 @@
**
** journalStarted
**
-** This flag is set whenever the the main journal is synced.
+** This flag is set whenever the the main journal is opened and
+** initialized
**
** The point of this flag is that it must be set after the
** first journal header in a journal file has been synced to disk.
@@ -31657,9 +33933,15 @@
** master journal name is only written to the journal file the first
** time CommitPhaseOne() is called.
**
-** doNotSync
+** doNotSpill, doNotSyncSpill
**
-** This variable is set and cleared by sqlite3PagerWrite().
+** When enabled, cache spills are prohibited. The doNotSpill variable
+** inhibits all cache spill and doNotSyncSpill inhibits those spills that
+** would require a journal sync. The doNotSyncSpill is set and cleared
+** by sqlite3PagerWrite() in order to prevent a journal sync from happening
+** in between the journalling of two pages on the same sector. The
+** doNotSpill value set to prevent pagerStress() from trying to use
+** the journal during a rollback.
**
** needSync
**
@@ -31703,7 +33985,8 @@
u8 journalStarted; /* True if header of journal is synced */
u8 changeCountDone; /* Set after incrementing the change-counter */
u8 setMaster; /* True if a m-j name has been written to jrnl */
- u8 doNotSync; /* Boolean. While true, do not spill the cache */
+ u8 doNotSpill; /* Do not spill the cache when non-zero */
+ u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
u8 dbSizeValid; /* Set when dbSize is correct */
u8 subjInMemory; /* True to use in-memory sub-journals */
Pgno dbSize; /* Number of pages in the database */
@@ -31719,6 +34002,7 @@
sqlite3_file *sjfd; /* File descriptor for sub-journal */
i64 journalOff; /* Current write offset in the journal file */
i64 journalHdr; /* Byte offset to previous journal header */
+ i64 journalSizeLimit; /* Size limit for persistent journal files */
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
char dbFileVers[16]; /* Changes whenever database file changes */
@@ -31745,9 +34029,12 @@
void *pCodec; /* First argument to xCodec... methods */
#endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
- i64 journalSizeLimit; /* Size limit for persistent journal files */
PCache *pPCache; /* Pointer to page cache object */
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
+#ifndef SQLITE_OMIT_WAL
+ Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
+ char *zWal; /* File name for write-ahead log */
+#endif
};
/*
@@ -32261,6 +34548,7 @@
for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
+ assert( pPager->journalHdr <= pPager->journalOff );
pPager->journalOff += nHeader;
}
@@ -32419,6 +34707,7 @@
}
pPager->setMaster = 1;
assert( isOpen(pPager->jfd) );
+ assert( pPager->journalHdr <= pPager->journalOff );
/* Calculate the length in bytes and the checksum of zMaster */
for(nMaster=0; zMaster[nMaster]; nMaster++){
@@ -32535,6 +34824,22 @@
}
/*
+** Return true if this pager uses a write-ahead log instead of the usual
+** rollback journal. Otherwise false.
+*/
+#ifndef SQLITE_OMIT_WAL
+static int pagerUseWal(Pager *pPager){
+ return (pPager->pWal!=0);
+}
+#else
+# define pagerUseWal(x) 0
+# define pagerRollbackWal(x) 0
+# define pagerWalFrames(v,w,x,y,z) 0
+# define pagerOpenWalIfPresent(z) SQLITE_OK
+# define pagerBeginReadTransaction(z) SQLITE_OK
+#endif
+
+/*
** Unlock the database file. This function is a no-op if the pager
** is in exclusive mode.
**
@@ -32546,25 +34851,43 @@
*/
static void pager_unlock(Pager *pPager){
if( !pPager->exclusiveMode ){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
+ int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
- /* Always close the journal file when dropping the database lock.
- ** Otherwise, another connection with journal_mode=delete might
- ** delete the file out from under us.
+ /* If the operating system support deletion of open files, then
+ ** close the journal file when dropping the database lock. Otherwise
+ ** another connection with journal_mode=delete might delete the file
+ ** out from under us.
*/
- sqlite3OsClose(pPager->jfd);
+ assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+ if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
+ || 1!=(pPager->journalMode & 5)
+ ){
+ sqlite3OsClose(pPager->jfd);
+ }
+
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
releaseAllSavepoints(pPager);
/* If the file is unlocked, somebody else might change it. The
** values stored in Pager.dbSize etc. might become invalid if
- ** this happens. TODO: Really, this doesn't need to be cleared
+ ** this happens. One can argue that this doesn't need to be cleared
** until the change-counter check fails in PagerSharedLock().
+ ** Clearing the page size cache here is being conservative.
*/
pPager->dbSizeValid = 0;
- rc = osUnlock(pPager->fd, NO_LOCK);
+ if( pagerUseWal(pPager) ){
+ sqlite3WalEndReadTransaction(pPager->pWal);
+ }else{
+ rc = osUnlock(pPager->fd, NO_LOCK);
+ }
if( rc ){
pPager->errCode = rc;
}
@@ -32595,7 +34918,7 @@
** to this function.
**
** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL
-** the error becomes persistent. Until the persisten error is cleared,
+** the error becomes persistent. Until the persistent error is cleared,
** subsequent API calls on this Pager will immediately return the same
** error code.
**
@@ -32713,6 +35036,7 @@
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
if( isOpen(pPager->jfd) ){
+ assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
if( sqlite3IsMemJournal(pPager->jfd) ){
@@ -32726,8 +35050,8 @@
}
pPager->journalOff = 0;
pPager->journalStarted = 0;
- }else if( pPager->exclusiveMode
- || pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasMaster);
pager_error(pPager, rc);
@@ -32737,9 +35061,11 @@
/* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to
- ** the database file, it will do so using an in-memory journal. */
+ ** the database file, it will do so using an in-memory journal.
+ */
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
if( !pPager->tempFile ){
@@ -32750,14 +35076,24 @@
#ifdef SQLITE_CHECK_PAGES
sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
#endif
-
- sqlite3PcacheCleanAll(pPager->pPCache);
- sqlite3BitvecDestroy(pPager->pInJournal);
- pPager->pInJournal = 0;
- pPager->nRec = 0;
}
+ sqlite3BitvecDestroy(pPager->pInJournal);
+ pPager->pInJournal = 0;
+ pPager->nRec = 0;
+ sqlite3PcacheCleanAll(pPager->pPCache);
- if( !pPager->exclusiveMode ){
+ if( pagerUseWal(pPager) ){
+ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
+ assert( rc2==SQLITE_OK );
+ pPager->state = PAGER_SHARED;
+
+ /* If the connection was in locking_mode=exclusive mode but is no longer,
+ ** drop the EXCLUSIVE lock held on the database file.
+ */
+ if( !pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, 0) ){
+ rc2 = osUnlock(pPager->fd, SHARED_LOCK);
+ }
+ }else if( !pPager->exclusiveMode ){
rc2 = osUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->changeCountDone = 0;
@@ -32809,6 +35145,21 @@
}
/*
+** Report the current page size and number of reserved bytes back
+** to the codec.
+*/
+#ifdef SQLITE_HAS_CODEC
+static void pagerReportSize(Pager *pPager){
+ if( pPager->xCodecSizeChng ){
+ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+ (int)pPager->nReserve);
+ }
+}
+#else
+# define pagerReportSize(X) /* No-op if we do not support a codec */
+#endif
+
+/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
@@ -32848,11 +35199,10 @@
*/
static int pager_playback_one_page(
Pager *pPager, /* The pager being played back */
- int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
- int isUnsync, /* True if reading from unsynced main journal */
i64 *pOffset, /* Offset of record to playback */
- int isSavepnt, /* True for a savepoint rollback */
- Bitvec *pDone /* Bitvec of pages already played back */
+ Bitvec *pDone, /* Bitvec of pages already played back */
+ int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
+ int isSavepnt /* True for a savepoint rollback */
){
int rc;
PgHdr *pPg; /* An existing page in the cache */
@@ -32860,6 +35210,7 @@
u32 cksum; /* Checksum used for sanity checking */
char *aData; /* Temporary storage for the page */
sqlite3_file *jfd; /* The file descriptor for the journal file */
+ int isSynced; /* True if journal page is synced */
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
@@ -32868,6 +35219,7 @@
aData = pPager->pTmpSpace;
assert( aData ); /* Temp storage must have already been allocated */
+ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
/* Read the page number and page data from the journal or sub-journal
** file. Return an error code to the caller if an IO error occurs.
@@ -32899,12 +35251,21 @@
}
}
+ /* If this page has already been played by before during the current
+ ** rollback, then don't bother to play it back again.
+ */
if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){
return rc;
}
-
assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE );
+ /* When playing back page 1, restore the nReserve setting
+ */
+ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
+ pPager->nReserve = ((u8*)aData)[20];
+ pagerReportSize(pPager);
+ }
+
/* If the pager is in RESERVED state, then there must be a copy of this
** page in the pager cache. In this case just update the pager cache,
** not the database file. The page is left marked dirty in this case.
@@ -32937,18 +35298,28 @@
** is possible to fail a statement on a database that does not yet exist.
** Do not attempt to write if database file has never been opened.
*/
- pPg = pager_lookup(pPager, pgno);
+ if( pagerUseWal(pPager) ){
+ pPg = 0;
+ }else{
+ pPg = pager_lookup(pPager, pgno);
+ }
assert( pPg || !MEMDB );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
(isMainJrnl?"main-journal":"sub-journal")
));
+ if( isMainJrnl ){
+ isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
+ }else{
+ isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC));
+ }
if( (pPager->state>=PAGER_EXCLUSIVE)
- && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC))
&& isOpen(pPager->fd)
- && !isUnsync
+ && isSynced
){
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
+ testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
+ assert( !pagerUseWal(pPager) );
rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
@@ -32976,9 +35347,12 @@
** requiring a journal-sync before it is written.
*/
assert( isSavepnt );
- if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1))!=SQLITE_OK ){
- return rc;
- }
+ assert( pPager->doNotSpill==0 );
+ pPager->doNotSpill++;
+ rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
+ assert( pPager->doNotSpill==1 );
+ pPager->doNotSpill--;
+ if( rc!=SQLITE_OK ) return rc;
pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
}
@@ -32997,7 +35371,8 @@
/* If the contents of this page were just restored from the main
** journal file, then its content must be as they were when the
** transaction was first opened. In this case we can mark the page
- ** as clean, since there will be no need to write it out to the.
+ ** as clean, since there will be no need to write it out to the
+ ** database.
**
** There is one exception to this rule. If the page is being rolled
** back as part of a savepoint (or statement) rollback from an
@@ -33012,6 +35387,7 @@
** segment is synced. If a crash occurs during or following this,
** database corruption may ensue.
*/
+ assert( !pagerUseWal(pPager) );
sqlite3PcacheMakeClean(pPg);
}
#ifdef SQLITE_CHECK_PAGES
@@ -33080,6 +35456,9 @@
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
char *zMasterJournal = 0; /* Contents of master journal file */
i64 nMasterJournal; /* Size of master journal file */
+ char *zJournal; /* Pointer to one journal within MJ file */
+ char *zMasterPtr; /* Space to hold MJ filename from a journal file */
+ int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
/* Allocate space for both the pJournal and pMaster file descriptors.
** If successful, open the master journal file for reading.
@@ -33094,73 +35473,68 @@
}
if( rc!=SQLITE_OK ) goto delmaster_out;
+ /* Load the entire master journal file into space obtained from
+ ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
+ ** sufficient space (in zMasterPtr) to hold the names of master
+ ** journal files extracted from regular rollback-journals.
+ */
rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
+ nMasterPtr = pVfs->mxPathname+1;
+ zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
+ if( !zMasterJournal ){
+ rc = SQLITE_NOMEM;
+ goto delmaster_out;
+ }
+ zMasterPtr = &zMasterJournal[nMasterJournal+1];
+ rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
+ if( rc!=SQLITE_OK ) goto delmaster_out;
+ zMasterJournal[nMasterJournal] = 0;
- if( nMasterJournal>0 ){
- char *zJournal;
- char *zMasterPtr = 0;
- int nMasterPtr = pVfs->mxPathname+1;
-
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal.
- */
- zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
- if( !zMasterJournal ){
- rc = SQLITE_NOMEM;
+ zJournal = zMasterJournal;
+ while( (zJournal-zMasterJournal)<nMasterJournal ){
+ int exists;
+ rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+1];
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- zMasterJournal[nMasterJournal] = 0;
-
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)<nMasterJournal ){
- int exists;
- rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( exists ){
+ /* One of the journals pointed to by the master journal exists.
+ ** Open it and check if it points at the master journal. If
+ ** so, return without deleting the master journal file.
+ */
+ int c;
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- if( exists ){
- /* One of the journals pointed to by the master journal exists.
- ** Open it and check if it points at the master journal. If
- ** so, return without deleting the master journal file.
- */
- int c;
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
- sqlite3OsClose(pJournal);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
-
- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
- if( c ){
- /* We have a match. Do not delete the master journal file. */
- goto delmaster_out;
- }
+ rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+ sqlite3OsClose(pJournal);
+ if( rc!=SQLITE_OK ){
+ goto delmaster_out;
}
- zJournal += (sqlite3Strlen30(zJournal)+1);
+
+ c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
+ if( c ){
+ /* We have a match. Do not delete the master journal file. */
+ goto delmaster_out;
+ }
}
+ zJournal += (sqlite3Strlen30(zJournal)+1);
}
-
+
+ sqlite3OsClose(pMaster);
rc = sqlite3OsDelete(pVfs, zMaster, 0);
delmaster_out:
- if( zMasterJournal ){
- sqlite3_free(zMasterJournal);
- }
+ sqlite3_free(zMasterJournal);
if( pMaster ){
sqlite3OsClose(pMaster);
assert( !isOpen(pJournal) );
+ sqlite3_free(pMaster);
}
- sqlite3_free(pMaster);
return rc;
}
@@ -33344,8 +35718,6 @@
** occurs.
*/
while( 1 ){
- int isUnsync = 0;
-
/* Read the next journal header from the journal file. If there are
** not enough bytes left in the journal file for a complete header, or
** it is corrupted, then a process must of failed while writing it.
@@ -33386,7 +35758,6 @@
if( nRec==0 && !isHot &&
pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
- isUnsync = 1;
}
/* If this is the first header read from the journal, truncate the
@@ -33408,12 +35779,20 @@
pager_reset(pPager);
needPagerReset = 0;
}
- rc = pager_playback_one_page(pPager,1,isUnsync,&pPager->journalOff,0,0);
+ rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
pPager->journalOff = szJ;
break;
+ }else if( rc==SQLITE_IOERR_SHORT_READ ){
+ /* If the journal has been truncated, simply stop reading and
+ ** processing the journal. This might happen if the journal was
+ ** not completely written and synced prior to a crash. In that
+ ** case, the database should have never been written in the
+ ** first place so it is OK to simply abandon the rollback. */
+ rc = SQLITE_OK;
+ goto end_playback;
}else{
/* If we are unable to rollback, quit and return the error
** code. This will cause the pager to enter the error state
@@ -33458,6 +35837,9 @@
if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
+ if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
+ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ }
if( rc==SQLITE_OK ){
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
testcase( rc!=SQLITE_OK );
@@ -33478,6 +35860,262 @@
return rc;
}
+
+/*
+** Read the content for page pPg out of the database file and into
+** pPg->pData. A shared lock or greater must be held on the database
+** file before this function is called.
+**
+** If page 1 is read, then the value of Pager.dbFileVers[] is set to
+** the value read from the database file.
+**
+** If an IO error occurs, then the IO error is returned to the caller.
+** Otherwise, SQLITE_OK is returned.
+*/
+static int readDbPage(PgHdr *pPg){
+ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
+ Pgno pgno = pPg->pgno; /* Page number to read */
+ int rc = SQLITE_OK; /* Return code */
+ int isInWal = 0; /* True if page is in log file */
+ int pgsz = pPager->pageSize; /* Number of bytes to read */
+
+ assert( pPager->state>=PAGER_SHARED && !MEMDB );
+ assert( isOpen(pPager->fd) );
+
+ if( NEVER(!isOpen(pPager->fd)) ){
+ assert( pPager->tempFile );
+ memset(pPg->pData, 0, pPager->pageSize);
+ return SQLITE_OK;
+ }
+
+ if( pagerUseWal(pPager) ){
+ /* Try to pull the page from the write-ahead log. */
+ rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
+ }
+ if( rc==SQLITE_OK && !isInWal ){
+ i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
+ }
+
+ if( pgno==1 ){
+ if( rc ){
+ /* If the read is unsuccessful, set the dbFileVers[] to something
+ ** that will never be a valid file version. dbFileVers[] is a copy
+ ** of bytes 24..39 of the database. Bytes 28..31 should always be
+ ** zero or the size of the database in page. Bytes 32..35 and 35..39
+ ** should be page numbers which are never 0xffffffff. So filling
+ ** pPager->dbFileVers[] with all 0xff bytes should suffice.
+ **
+ ** For an encrypted database, the situation is more complex: bytes
+ ** 24..39 of the database are white noise. But the probability of
+ ** white noising equaling 16 bytes of 0xff is vanishingly small so
+ ** we should still be ok.
+ */
+ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
+ }else{
+ u8 *dbFileVers = &((u8*)pPg->pData)[24];
+ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
+ }
+ }
+ CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
+
+ PAGER_INCR(sqlite3_pager_readdb_count);
+ PAGER_INCR(pPager->nRead);
+ IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
+ PAGERID(pPager), pgno, pager_pagehash(pPg)));
+
+ return rc;
+}
+
+#ifndef SQLITE_OMIT_WAL
+/*
+** This function is invoked once for each page that has already been
+** written into the log file when a WAL transaction is rolled back.
+** Parameter iPg is the page number of said page. The pCtx argument
+** is actually a pointer to the Pager structure.
+**
+** If page iPg is present in the cache, and has no outstanding references,
+** it is discarded. Otherwise, if there are one or more outstanding
+** references, the page content is reloaded from the database. If the
+** attempt to reload content from the database is required and fails,
+** return an SQLite error code. Otherwise, SQLITE_OK.
+*/
+static int pagerUndoCallback(void *pCtx, Pgno iPg){
+ int rc = SQLITE_OK;
+ Pager *pPager = (Pager *)pCtx;
+ PgHdr *pPg;
+
+ pPg = sqlite3PagerLookup(pPager, iPg);
+ if( pPg ){
+ if( sqlite3PcachePageRefcount(pPg)==1 ){
+ sqlite3PcacheDrop(pPg);
+ }else{
+ rc = readDbPage(pPg);
+ if( rc==SQLITE_OK ){
+ pPager->xReiniter(pPg);
+ }
+ sqlite3PagerUnref(pPg);
+ }
+ }
+
+ /* Normally, if a transaction is rolled back, any backup processes are
+ ** updated as data is copied out of the rollback journal and into the
+ ** database. This is not generally possible with a WAL database, as
+ ** rollback involves simply truncating the log file. Therefore, if one
+ ** or more frames have already been written to the log (and therefore
+ ** also copied into the backup databases) as part of this transaction,
+ ** the backups must be restarted.
+ */
+ sqlite3BackupRestart(pPager->pBackup);
+
+ return rc;
+}
+
+/*
+** This function is called to rollback a transaction on a WAL database.
+*/
+static int pagerRollbackWal(Pager *pPager){
+ int rc; /* Return Code */
+ PgHdr *pList; /* List of dirty pages to revert */
+
+ /* For all pages in the cache that are currently dirty or have already
+ ** been written (but not committed) to the log file, do one of the
+ ** following:
+ **
+ ** + Discard the cached page (if refcount==0), or
+ ** + Reload page content from the database (if refcount>0).
+ */
+ pPager->dbSize = pPager->dbOrigSize;
+ rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
+ pList = sqlite3PcacheDirtyList(pPager->pPCache);
+ while( pList && rc==SQLITE_OK ){
+ PgHdr *pNext = pList->pDirty;
+ rc = pagerUndoCallback((void *)pPager, pList->pgno);
+ pList = pNext;
+ }
+
+ return rc;
+}
+
+/*
+** This function is a wrapper around sqlite3WalFrames(). As well as logging
+** the contents of the list of pages headed by pList (connected by pDirty),
+** this function notifies any active backup processes that the pages have
+** changed.
+*/
+static int pagerWalFrames(
+ Pager *pPager, /* Pager object */
+ PgHdr *pList, /* List of frames to log */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Return code */
+
+ assert( pPager->pWal );
+ rc = sqlite3WalFrames(pPager->pWal,
+ pPager->pageSize, pList, nTruncate, isCommit, sync_flags
+ );
+ if( rc==SQLITE_OK && pPager->pBackup ){
+ PgHdr *p;
+ for(p=pList; p; p=p->pDirty){
+ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
+ }
+ }
+ return rc;
+}
+
+/*
+** Begin a read transaction on the WAL.
+**
+** This routine used to be called "pagerOpenSnapshot()" because it essentially
+** makes a snapshot of the database at the current point in time and preserves
+** that snapshot for use by the reader in spite of concurrently changes by
+** other writers or checkpointers.
+*/
+static int pagerBeginReadTransaction(Pager *pPager){
+ int rc; /* Return code */
+ int changed = 0; /* True if cache must be reset */
+
+ assert( pagerUseWal(pPager) );
+
+ /* sqlite3WalEndReadTransaction() was not called for the previous
+ ** transaction in locking_mode=EXCLUSIVE. So call it now. If we
+ ** are in locking_mode=NORMAL and EndRead() was previously called,
+ ** the duplicate call is harmless.
+ */
+ sqlite3WalEndReadTransaction(pPager->pWal);
+
+ rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
+ if( rc==SQLITE_OK ){
+ int dummy;
+ if( changed ){
+ pager_reset(pPager);
+ assert( pPager->errCode || pPager->dbSizeValid==0 );
+ }
+ rc = sqlite3PagerPagecount(pPager, &dummy);
+ }
+ pPager->state = PAGER_SHARED;
+
+ return rc;
+}
+
+/*
+** Check if the *-wal file that corresponds to the database opened by pPager
+** exists if the database is not empy, or verify that the *-wal file does
+** not exist (by deleting it) if the database file is empty.
+**
+** If the database is not empty and the *-wal file exists, open the pager
+** in WAL mode. If the database is empty or if no *-wal file exists and
+** if no error occurs, make sure Pager.journalMode is not set to
+** PAGER_JOURNALMODE_WAL.
+**
+** Return SQLITE_OK or an error code.
+**
+** If the WAL file is opened, also open a snapshot (read transaction).
+**
+** The caller must hold a SHARED lock on the database file to call this
+** function. Because an EXCLUSIVE lock on the db file is required to delete
+** a WAL on a none-empty database, this ensures there is no race condition
+** between the xAccess() below and an xDelete() being executed by some
+** other connection.
+*/
+static int pagerOpenWalIfPresent(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !pPager->tempFile ){
+ int isWal; /* True if WAL file exists */
+ int nPage; /* Size of the database file */
+ assert( pPager->state>=SHARED_LOCK );
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ isWal = 0;
+ }else{
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+ );
+ }
+ if( rc==SQLITE_OK ){
+ if( isWal ){
+ pager_reset(pPager);
+ rc = sqlite3PagerOpenWal(pPager, 0);
+ if( rc==SQLITE_OK ){
+ rc = pagerBeginReadTransaction(pPager);
+ }
+ }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+ pPager->journalMode = PAGER_JOURNALMODE_DELETE;
+ }
+ }
+ }
+ return rc;
+}
+#endif
+
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
** the entire master journal file. The case pSavepoint==NULL occurs when
@@ -33535,12 +36173,17 @@
*/
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
+ if( !pSavepoint && pagerUseWal(pPager) ){
+ return pagerRollbackWal(pPager);
+ }
+
/* Use pPager->journalOff as the effective size of the main rollback
** journal. The actual file might be larger than this in
** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
** past pPager->journalOff is off-limits to us.
*/
szJ = pPager->journalOff;
+ assert( pagerUseWal(pPager)==0 || szJ==0 );
/* Begin by rolling back records from the main journal starting at
** PagerSavepoint.iOffset and continuing to the next journal header.
@@ -33549,11 +36192,11 @@
** will be skipped automatically. Pages are added to pDone as they
** are played back.
*/
- if( pSavepoint ){
+ if( pSavepoint && !pagerUseWal(pPager) ){
iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
pPager->journalOff = pSavepoint->iOffset;
while( rc==SQLITE_OK && pPager->journalOff<iHdrOff ){
- rc = pager_playback_one_page(pPager, 1, 0, &pPager->journalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}else{
@@ -33583,11 +36226,11 @@
nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
}
for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){
- rc = pager_playback_one_page(pPager, 1, 0, &pPager->journalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}
- assert( rc!=SQLITE_OK || pPager->journalOff==szJ );
+ assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
/* Finally, rollback pages from the sub-journal. Page that were
** previously rolled back out of the main journal (and are hence in pDone)
@@ -33596,9 +36239,13 @@
if( pSavepoint ){
u32 ii; /* Loop counter */
i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
+
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
+ }
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
assert( offset==ii*(4+pPager->pageSize) );
- rc = pager_playback_one_page(pPager, 0, 0, &offset, 1, pDone);
+ rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
}
assert( rc!=SQLITE_DONE );
}
@@ -33607,6 +36254,7 @@
if( rc==SQLITE_OK ){
pPager->journalOff = szJ;
}
+
return rc;
}
@@ -33725,21 +36373,6 @@
}
/*
-** Report the current page size and number of reserved bytes back
-** to the codec.
-*/
-#ifdef SQLITE_HAS_CODEC
-static void pagerReportSize(Pager *pPager){
- if( pPager->xCodecSizeChng ){
- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
- (int)pPager->nReserve);
- }
-}
-#else
-# define pagerReportSize(X) /* No-op if we do not support a codec */
-#endif
-
-/*
** Change the page size used by the Pager object. The new page size
** is passed in *pPageSize.
**
@@ -33819,10 +36452,14 @@
** Regardless of mxPage, return the current maximum page count.
*/
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+ int nPage;
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
- sqlite3PagerPagecount(pPager, 0);
+ if( pPager->state!=PAGER_UNLOCK ){
+ sqlite3PagerPagecount(pPager, &nPage);
+ assert( (int)pPager->mxPgno>=nPage );
+ }
return pPager->mxPgno;
}
@@ -33868,6 +36505,13 @@
int rc = SQLITE_OK;
memset(pDest, 0, N);
assert( isOpen(pPager->fd) || pPager->tempFile );
+
+ /* This routine is only called by btree immediately after creating
+ ** the Pager object. There has not been an opportunity to transition
+ ** to WAL mode yet.
+ */
+ assert( !pagerUseWal(pPager) );
+
if( isOpen(pPager->fd) ){
IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
@@ -33894,12 +36538,7 @@
** and *pnPage is set to the number of pages in the database.
*/
SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
- Pgno nPage; /* Value to return via *pnPage */
-
- /* If the pager is already in the error state, return the error code. */
- if( pPager->errCode ){
- return pPager->errCode;
- }
+ Pgno nPage = 0; /* Value to return via *pnPage */
/* Determine the number of pages in the file. Store this in nPage. */
if( pPager->dbSizeValid ){
@@ -33908,15 +36547,23 @@
int rc; /* Error returned by OsFileSize() */
i64 n = 0; /* File size in bytes returned by OsFileSize() */
- assert( isOpen(pPager->fd) || pPager->tempFile );
- if( isOpen(pPager->fd) && (0 != (rc = sqlite3OsFileSize(pPager->fd, &n))) ){
- pager_error(pPager, rc);
- return rc;
+ if( pagerUseWal(pPager) && pPager->state!=PAGER_UNLOCK ){
+ sqlite3WalDbsize(pPager->pWal, &nPage);
}
- if( n>0 && n<pPager->pageSize ){
- nPage = 1;
- }else{
- nPage = (Pgno)(n / pPager->pageSize);
+
+ if( nPage==0 ){
+ assert( isOpen(pPager->fd) || pPager->tempFile );
+ if( isOpen(pPager->fd) ){
+ if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){
+ pager_error(pPager, rc);
+ return rc;
+ }
+ }
+ if( n>0 && n<pPager->pageSize ){
+ nPage = 1;
+ }else{
+ nPage = (Pgno)(n / pPager->pageSize);
+ }
}
if( pPager->state!=PAGER_UNLOCK ){
pPager->dbSize = nPage;
@@ -33934,9 +36581,7 @@
}
/* Set the output variable and return SQLITE_OK */
- if( pnPage ){
- *pnPage = nPage;
- }
+ *pnPage = nPage;
return SQLITE_OK;
}
@@ -34041,6 +36686,32 @@
assertTruncateConstraint(pPager);
}
+
+/*
+** This function is called before attempting a hot-journal rollback. It
+** syncs the journal file to disk, then sets pPager->journalHdr to the
+** size of the journal file so that the pager_playback() routine knows
+** that the entire journal file has been synced.
+**
+** Syncing a hot-journal to disk before attempting to roll it back ensures
+** that if a power-failure occurs during the rollback, the process that
+** attempts rollback following system recovery sees the same journal
+** content as this process.
+**
+** If everything goes as planned, SQLITE_OK is returned. Otherwise,
+** an SQLite error code.
+*/
+static int pagerSyncHotJournal(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !pPager->noSync ){
+ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr);
+ }
+ return rc;
+}
+
/*
** Shutdown the page cache. Free all memory and close all files.
**
@@ -34056,10 +36727,19 @@
** to the caller.
*/
SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
+ u8 *pTmp = (u8 *)pPager->pTmpSpace;
+
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
pPager->errCode = 0;
pPager->exclusiveMode = 0;
+#ifndef SQLITE_OMIT_WAL
+ sqlite3WalClose(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, pTmp
+ );
+ pPager->pWal = 0;
+#endif
pager_reset(pPager);
if( MEMDB ){
pager_unlock(pPager);
@@ -34070,15 +36750,18 @@
** be played back into the database. If a power failure occurs while
** this is happening, the database may become corrupt.
*/
- pPager->journalHdr = -1;
+ if( isOpen(pPager->jfd) ){
+ pPager->errCode = pagerSyncHotJournal(pPager);
+ }
pagerUnlockAndRollback(pPager);
}
sqlite3EndBenignMalloc();
enable_simulated_io_errors();
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
+ sqlite3OsClose(pPager->jfd);
sqlite3OsClose(pPager->fd);
- sqlite3PageFree(pPager->pTmpSpace);
+ sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
#ifdef SQLITE_HAS_CODEC
@@ -34160,7 +36843,7 @@
** mode, then the journal file may at this point actually be larger
** than Pager.journalOff bytes. If the next thing in the journal
** file happens to be a journal-header (written as part of the
- ** previous connections transaction), and a crash or power-failure
+ ** previous connection's transaction), and a crash or power-failure
** occurs after nRec is updated but before this connection writes
** anything else to the journal file (or commits/rolls back its
** transaction), then SQLite may become confused when doing the
@@ -34179,10 +36862,10 @@
*/
i64 iNextHdrOffset;
u8 aMagic[8];
- u8 zHeader[sizeof(aJournalMagic)+4];
+ u8 zHeader[sizeof(aJournalMagic)+4];
- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
- put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
+ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
iNextHdrOffset = journalHdrOffset(pPager);
rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset);
@@ -34214,7 +36897,7 @@
IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr));
rc = sqlite3OsWrite(
pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr
- );
+ );
if( rc!=SQLITE_OK ) return rc;
}
if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
@@ -34232,6 +36915,7 @@
*/
pPager->needSync = 0;
pPager->journalStarted = 1;
+ pPager->journalHdr = pPager->journalOff;
sqlite3PcacheClearSyncFlags(pPager->pPCache);
}
@@ -34270,13 +36954,9 @@
** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
** be obtained, SQLITE_BUSY is returned.
*/
-static int pager_write_pagelist(PgHdr *pList){
- Pager *pPager; /* Pager object */
+static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
int rc; /* Return code */
- if( NEVER(pList==0) ) return SQLITE_OK;
- pPager = pList->pPager;
-
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
** database file. If there is already an EXCLUSIVE lock, the following
** call is a no-op.
@@ -34293,6 +36973,7 @@
** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback.
*/
+ assert( !pagerUseWal(pPager) );
assert( pPager->state>=PAGER_RESERVED );
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
@@ -34305,6 +36986,14 @@
rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
}
+ /* Before the first write, give the VFS a hint of what the final
+ ** file size will be.
+ */
+ if( pPager->dbSize > (pPager->dbOrigSize+1) && isOpen(pPager->fd) ){
+ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
+ sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
+ }
+
while( rc==SQLITE_OK && pList ){
Pgno pgno = pList->pgno;
@@ -34314,9 +37003,7 @@
** any such pages to the file.
**
** Also, do not write out any page that has the PGHDR_DONT_WRITE flag
- ** set (set by sqlite3PagerDontWrite()). Note that if compiled with
- ** SQLITE_SECURE_DELETE the PGHDR_DONT_WRITE bit is never set and so
- ** the second test is always true.
+ ** set (set by sqlite3PagerDontWrite()).
*/
if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
@@ -34360,6 +37047,26 @@
}
/*
+** Ensure that the sub-journal file is open. If it is already open, this
+** function is a no-op.
+**
+** SQLITE_OK is returned if everything goes according to plan. An
+** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
+** fails.
+*/
+static int openSubJournal(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !isOpen(pPager->sjfd) ){
+ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
+ sqlite3MemJournalOpen(pPager->sjfd);
+ }else{
+ rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
+ }
+ }
+ return rc;
+}
+
+/*
** Append a record of the current state of page pPg to the sub-journal.
** It is the callers responsibility to use subjRequiresPage() to check
** that it is really required before calling this function.
@@ -34375,18 +37082,31 @@
static int subjournalPage(PgHdr *pPg){
int rc = SQLITE_OK;
Pager *pPager = pPg->pPager;
- if( isOpen(pPager->sjfd) ){
- void *pData = pPg->pData;
- i64 offset = pPager->nSubRec*(4+pPager->pageSize);
- char *pData2;
+ if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
- PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
-
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
- rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ /* Open the sub-journal, if it has not already been opened */
+ assert( pPager->useJournal );
+ assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
+ assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
+ assert( pagerUseWal(pPager)
+ || pageInJournal(pPg)
+ || pPg->pgno>pPager->dbOrigSize
+ );
+ rc = openSubJournal(pPager);
+
+ /* If the sub-journal was opened successfully (or was already open),
+ ** write the journal record into the file. */
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ void *pData = pPg->pData;
+ i64 offset = pPager->nSubRec*(4+pPager->pageSize);
+ char *pData2;
+
+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
+ rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ }
}
}
if( rc==SQLITE_OK ){
@@ -34397,7 +37117,6 @@
return rc;
}
-
/*
** This function is called by the pcache layer when it has reached some
** soft memory limit. The first argument is a pointer to a Pager object
@@ -34424,74 +37143,83 @@
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
- /* The doNotSync flag is set by the sqlite3PagerWrite() function while it
- ** is journalling a set of two or more database pages that are stored
- ** on the same disk sector. Syncing the journal is not allowed while
- ** this is happening as it is important that all members of such a
- ** set of pages are synced to disk together. So, if the page this function
- ** is trying to make clean will require a journal sync and the doNotSync
- ** flag is set, return without doing anything. The pcache layer will
- ** just have to go ahead and allocate a new page buffer instead of
- ** reusing pPg.
+ /* The doNotSyncSpill flag is set during times when doing a sync of
+ ** journal (and adding a new header) is not allowed. This occurs
+ ** during calls to sqlite3PagerWrite() while trying to journal multiple
+ ** pages belonging to the same sector.
**
- ** Similarly, if the pager has already entered the error state, do not
- ** try to write the contents of pPg to disk.
+ ** The doNotSpill flag inhibits all cache spilling regardless of whether
+ ** or not a sync is required. This is set during a rollback.
+ **
+ ** Spilling is also inhibited when in an error state.
*/
- if( NEVER(pPager->errCode)
- || (pPager->doNotSync && pPg->flags&PGHDR_NEED_SYNC)
- ){
+ if( pPager->errCode ) return SQLITE_OK;
+ if( pPager->doNotSpill ) return SQLITE_OK;
+ if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
return SQLITE_OK;
}
- /* Sync the journal file if required. */
- if( pPg->flags&PGHDR_NEED_SYNC ){
- rc = syncJournal(pPager);
- if( rc==SQLITE_OK && pPager->fullSync &&
- !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
- !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
- ){
- pPager->nRec = 0;
- rc = writeJournalHdr(pPager);
+ pPg->pDirty = 0;
+ if( pagerUseWal(pPager) ){
+ /* Write a single frame for this page to the log. */
+ if( subjRequiresPage(pPg) ){
+ rc = subjournalPage(pPg);
}
- }
-
- /* If the page number of this page is larger than the current size of
- ** the database image, it may need to be written to the sub-journal.
- ** This is because the call to pager_write_pagelist() below will not
- ** actually write data to the file in this case.
- **
- ** Consider the following sequence of events:
- **
- ** BEGIN;
- ** <journal page X>
- ** <modify page X>
- ** SAVEPOINT sp;
- ** <shrink database file to Y pages>
- ** pagerStress(page X)
- ** ROLLBACK TO sp;
- **
- ** If (X>Y), then when pagerStress is called page X will not be written
- ** out to the database file, but will be dropped from the cache. Then,
- ** following the "ROLLBACK TO sp" statement, reading page X will read
- ** data from the database file. This will be the copy of page X as it
- ** was when the transaction started, not as it was when "SAVEPOINT sp"
- ** was executed.
- **
- ** The solution is to write the current data for page X into the
- ** sub-journal file now (if it is not already there), so that it will
- ** be restored to its current value when the "ROLLBACK TO sp" is
- ** executed.
- */
- if( NEVER(
- rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
- ) ){
- rc = subjournalPage(pPg);
- }
-
- /* Write the contents of the page out to the database file. */
- if( rc==SQLITE_OK ){
- pPg->pDirty = 0;
- rc = pager_write_pagelist(pPg);
+ if( rc==SQLITE_OK ){
+ rc = pagerWalFrames(pPager, pPg, 0, 0, 0);
+ }
+ }else{
+
+ /* Sync the journal file if required. */
+ if( pPg->flags&PGHDR_NEED_SYNC ){
+ assert( !pPager->noSync );
+ rc = syncJournal(pPager);
+ if( rc==SQLITE_OK &&
+ !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
+ !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+ ){
+ pPager->nRec = 0;
+ rc = writeJournalHdr(pPager);
+ }
+ }
+
+ /* If the page number of this page is larger than the current size of
+ ** the database image, it may need to be written to the sub-journal.
+ ** This is because the call to pager_write_pagelist() below will not
+ ** actually write data to the file in this case.
+ **
+ ** Consider the following sequence of events:
+ **
+ ** BEGIN;
+ ** <journal page X>
+ ** <modify page X>
+ ** SAVEPOINT sp;
+ ** <shrink database file to Y pages>
+ ** pagerStress(page X)
+ ** ROLLBACK TO sp;
+ **
+ ** If (X>Y), then when pagerStress is called page X will not be written
+ ** out to the database file, but will be dropped from the cache. Then,
+ ** following the "ROLLBACK TO sp" statement, reading page X will read
+ ** data from the database file. This will be the copy of page X as it
+ ** was when the transaction started, not as it was when "SAVEPOINT sp"
+ ** was executed.
+ **
+ ** The solution is to write the current data for page X into the
+ ** sub-journal file now (if it is not already there), so that it will
+ ** be restored to its current value when the "ROLLBACK TO sp" is
+ ** executed.
+ */
+ if( NEVER(
+ rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
+ ) ){
+ rc = subjournalPage(pPg);
+ }
+
+ /* Write the contents of the page out to the database file. */
+ if( rc==SQLITE_OK ){
+ rc = pager_write_pagelist(pPager, pPg);
+ }
}
/* Mark the page as clean. */
@@ -34630,6 +37358,9 @@
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + /* zFilename */
nPathname + 8 + 1 /* zJournal */
+#ifndef SQLITE_OMIT_WAL
+ + nPathname + 4 + 1 /* zWal */
+#endif
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
@@ -34650,7 +37381,16 @@
memcpy(pPager->zFilename, zPathname, nPathname);
memcpy(pPager->zJournal, zPathname, nPathname);
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
- if( pPager->zFilename[0]==0 ) pPager->zJournal[0] = 0;
+ if( pPager->zFilename[0]==0 ){
+ pPager->zJournal[0] = 0;
+ }
+#ifndef SQLITE_OMIT_WAL
+ else{
+ pPager->zWal = &pPager->zJournal[nPathname+8+1];
+ memcpy(pPager->zWal, zPathname, nPathname);
+ memcpy(&pPager->zWal[nPathname], "-wal", 4);
+ }
+#endif
sqlite3_free(zPathname);
}
pPager->pVfs = pVfs;
@@ -34780,6 +37520,7 @@
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
+
*ppPager = pPager;
return SQLITE_OK;
}
@@ -34819,17 +37560,22 @@
*/
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
- int rc; /* Return code */
- int exists; /* True if a journal file is present */
+ int rc = SQLITE_OK; /* Return code */
+ int exists = 1; /* True if a journal file is present */
+ int jrnlOpen = !!isOpen(pPager->jfd);
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
- assert( !isOpen(pPager->jfd) );
assert( pPager->state <= PAGER_SHARED );
+ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+ ));
*pExists = 0;
- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( !jrnlOpen ){
+ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ }
if( rc==SQLITE_OK && exists ){
int locked; /* True if some process holds a RESERVED lock */
@@ -34867,15 +37613,19 @@
** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
- int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ if( !jrnlOpen ){
+ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ }
if( rc==SQLITE_OK ){
u8 first = 0;
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
- sqlite3OsClose(pPager->jfd);
+ if( !jrnlOpen ){
+ sqlite3OsClose(pPager->jfd);
+ }
*pExists = (first!=0);
}else if( rc==SQLITE_CANTOPEN ){
/* If we cannot open the rollback journal file in order to see if
@@ -34899,51 +37649,6 @@
}
/*
-** Read the content for page pPg out of the database file and into
-** pPg->pData. A shared lock or greater must be held on the database
-** file before this function is called.
-**
-** If page 1 is read, then the value of Pager.dbFileVers[] is set to
-** the value read from the database file.
-**
-** If an IO error occurs, then the IO error is returned to the caller.
-** Otherwise, SQLITE_OK is returned.
-*/
-static int readDbPage(PgHdr *pPg){
- Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
- int rc; /* Return code */
- i64 iOffset; /* Byte offset of file to read from */
-
- assert( pPager->state>=PAGER_SHARED && !MEMDB );
- assert( isOpen(pPager->fd) );
-
- if( NEVER(!isOpen(pPager->fd)) ){
- assert( pPager->tempFile );
- memset(pPg->pData, 0, pPager->pageSize);
- return SQLITE_OK;
- }
- iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
- if( rc==SQLITE_IOERR_SHORT_READ ){
- rc = SQLITE_OK;
- }
- if( pgno==1 ){
- u8 *dbFileVers = &((u8*)pPg->pData)[24];
- memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
- }
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
-
- PAGER_INCR(sqlite3_pager_readdb_count);
- PAGER_INCR(pPager->nRead);
- IOTRACE(("PGIN %p %d\n", pPager, pgno));
- PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
-
- return rc;
-}
-
-/*
** This function is called to obtain a shared lock on the database file.
** It is illegal to call sqlite3PagerAcquire() until after this function
** has been successfully called. If a shared-lock is already held when
@@ -34996,7 +37701,9 @@
pager_reset(pPager);
}
- if( pPager->state==PAGER_UNLOCK || isErrorReset ){
+ if( pagerUseWal(pPager) ){
+ rc = pagerBeginReadTransaction(pPager);
+ }else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs * const pVfs = pPager->pVfs;
int isHotJournal = 0;
assert( !MEMDB );
@@ -35079,19 +37786,28 @@
goto failed;
}
- /* TODO: Why are these cleared here? Is it necessary? */
+ /* Reset the journal status fields to indicates that we have no
+ ** rollback journal at this time. */
pPager->journalStarted = 0;
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
+ /* Make sure the journal file has been synced to disk. */
+
/* Playback and delete the journal. Drop the database write
** lock and reacquire the read lock. Purge the cache before
** playing back the hot-journal so that we don't end up with
- ** an inconsistent cache.
+ ** an inconsistent cache. Sync the hot journal before playing
+ ** it back since the process that crashed and left the hot journal
+ ** probably did not sync it and we are required to always sync
+ ** the journal before playing it back.
*/
if( isOpen(pPager->jfd) ){
- rc = pager_playback(pPager, 1);
+ rc = pagerSyncHotJournal(pPager);
+ if( rc==SQLITE_OK ){
+ rc = pager_playback(pPager, 1);
+ }
if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc);
goto failed;
@@ -35119,16 +37835,16 @@
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
+ int nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)];
- sqlite3PagerPagecount(pPager, 0);
+ sqlite3PagerPagecount(pPager, &nPage);
if( pPager->errCode ){
rc = pPager->errCode;
goto failed;
}
- assert( pPager->dbSizeValid );
- if( pPager->dbSize>0 ){
+ if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
@@ -35143,6 +37859,11 @@
}
}
assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
+
+ /* If there is a WAL file in the file-system, open this database in WAL
+ ** mode. Otherwise, the following function call is a no-op.
+ */
+ rc = pagerOpenWalIfPresent(pPager);
}
failed:
@@ -35197,7 +37918,7 @@
** a) When reading a free-list leaf page from the database, and
**
** b) When a savepoint is being rolled back and we need to load
-** a new page into the cache to populate with the data read
+** a new page into the cache to be filled with the data read
** from the savepoint journal.
**
** If noContent is true, then the data returned is zeroed instead of
@@ -35253,7 +37974,7 @@
assert( (*ppPage)->pgno==pgno );
assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
- if( (*ppPage)->pPager ){
+ if( (*ppPage)->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
@@ -35283,8 +38004,8 @@
if( MEMDB || nMax<(int)pgno || noContent || !isOpen(pPager->fd) ){
if( pgno>pPager->mxPgno ){
- rc = SQLITE_FULL;
- goto pager_acquire_err;
+ rc = SQLITE_FULL;
+ goto pager_acquire_err;
}
if( noContent ){
/* Failure to set the bits in the InJournal bit-vectors is benign.
@@ -35369,27 +38090,6 @@
}
/*
-** If the main journal file has already been opened, ensure that the
-** sub-journal file is open too. If the main journal is not open,
-** this function is a no-op.
-**
-** SQLITE_OK is returned if everything goes according to plan.
-** An SQLITE_IOERR_XXX error code is returned if a call to
-** sqlite3OsOpen() fails.
-*/
-static int openSubJournal(Pager *pPager){
- int rc = SQLITE_OK;
- if( isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ){
- if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
- sqlite3MemJournalOpen(pPager->sjfd);
- }else{
- rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
- }
- }
- return rc;
-}
-
-/*
** This function is called at the start of every write transaction.
** There must already be a RESERVED or EXCLUSIVE lock on the database
** file when this routine is called.
@@ -35413,6 +38113,7 @@
*/
static int pager_open_journal(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
+ int nPage; /* Size of database file */
sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
assert( pPager->state>=PAGER_RESERVED );
@@ -35425,13 +38126,10 @@
** an error state. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
- /* TODO: Is it really possible to get here with dbSizeValid==0? If not,
- ** the call to PagerPagecount() can be removed.
- */
testcase( pPager->dbSizeValid==0 );
- sqlite3PagerPagecount(pPager, 0);
-
- pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ pPager->pInJournal = sqlite3BitvecCreate(nPage);
if( pPager->pInJournal==0 ){
return SQLITE_NOMEM;
}
@@ -35473,9 +38171,6 @@
pPager->journalHdr = 0;
rc = writeJournalHdr(pPager);
}
- if( rc==SQLITE_OK && pPager->nSavepoint ){
- rc = openSubJournal(pPager);
- }
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
@@ -35513,53 +38208,77 @@
int rc = SQLITE_OK;
assert( pPager->state!=PAGER_UNLOCK );
pPager->subjInMemory = (u8)subjInMemory;
+
if( pPager->state==PAGER_SHARED ){
assert( pPager->pInJournal==0 );
assert( !MEMDB && !pPager->tempFile );
- /* Obtain a RESERVED lock on the database file. If the exFlag parameter
- ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
- ** busy-handler callback can be used when upgrading to the EXCLUSIVE
- ** lock, but not when obtaining the RESERVED lock.
- */
- rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
- if( rc==SQLITE_OK ){
- pPager->state = PAGER_RESERVED;
- if( exFlag ){
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ if( pagerUseWal(pPager) ){
+ /* If the pager is configured to use locking_mode=exclusive, and an
+ ** exclusive lock on the database is not already held, obtain it now.
+ */
+ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
+ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
+ pPager->state = PAGER_SHARED;
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ sqlite3WalExclusiveMode(pPager->pWal, 1);
+ }
+
+ /* Grab the write lock on the log file. If successful, upgrade to
+ ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
+ ** The busy-handler is not invoked if another connection already
+ ** holds the write-lock. If possible, the upper layer will call it.
+ **
+ ** WAL mode sets Pager.state to PAGER_RESERVED when it has an open
+ ** transaction, but never to PAGER_EXCLUSIVE. This is because in
+ ** PAGER_EXCLUSIVE state the code to roll back savepoint transactions
+ ** may copy data from the sub-journal into the database file as well
+ ** as into the page cache. Which would be incorrect in WAL mode.
+ */
+ rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
+ if( rc==SQLITE_OK ){
+ pPager->dbOrigSize = pPager->dbSize;
+ pPager->state = PAGER_RESERVED;
+ pPager->journalOff = 0;
+ }
+
+ assert( rc!=SQLITE_OK || pPager->state==PAGER_RESERVED );
+ assert( rc==SQLITE_OK || pPager->state==PAGER_SHARED );
+ }else{
+ /* Obtain a RESERVED lock on the database file. If the exFlag parameter
+ ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
+ ** busy-handler callback can be used when upgrading to the EXCLUSIVE
+ ** lock, but not when obtaining the RESERVED lock.
+ */
+ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
+ if( rc==SQLITE_OK ){
+ pPager->state = PAGER_RESERVED;
+ if( exFlag ){
+ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ }
}
}
- /* If the required locks were successfully obtained, open the journal
- ** file and write the first journal-header to it.
+ /* No need to open the journal file at this time. It will be
+ ** opened before it is written to. If we defer opening the journal,
+ ** we might save the work of creating a file if the transaction
+ ** ends up being a no-op.
*/
- if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- rc = pager_open_journal(pPager);
+
+ if( rc!=SQLITE_OK ){
+ assert( !pPager->dbModified );
+ /* Ignore any IO error that occurs within pager_end_transaction(). The
+ ** purpose of this call is to reset the internal state of the pager
+ ** sub-system. It doesn't matter if the journal-file is not properly
+ ** finalized at this point (since it is not a valid journal file anyway).
+ */
+ pager_end_transaction(pPager, 0);
}
- }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){
- /* This happens when the pager was in exclusive-access mode the last
- ** time a (read or write) transaction was successfully concluded
- ** by this connection. Instead of deleting the journal file it was
- ** kept open and either was truncated to 0 bytes or its header was
- ** overwritten with zeros.
- */
- assert( pPager->nRec==0 );
- assert( pPager->dbOrigSize==0 );
- assert( pPager->pInJournal==0 );
- rc = pager_open_journal(pPager);
}
PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
- assert( !isOpen(pPager->jfd) || pPager->journalOff>0 || rc!=SQLITE_OK );
- if( rc!=SQLITE_OK ){
- assert( !pPager->dbModified );
- /* Ignore any IO error that occurs within pager_end_transaction(). The
- ** purpose of this call is to reset the internal state of the pager
- ** sub-system. It doesn't matter if the journal-file is not properly
- ** finalized at this point (since it is not a valid journal file anyway).
- */
- pager_end_transaction(pPager, 0);
- }
return rc;
}
@@ -35580,8 +38299,8 @@
*/
assert( pPager->state>=PAGER_RESERVED );
- /* If an error has been previously detected, we should not be
- ** calling this routine. Repeat the error for robustness.
+ /* If an error has been previously detected, report the same error
+ ** again.
*/
if( NEVER(pPager->errCode) ) return pPager->errCode;
@@ -35598,6 +38317,7 @@
*/
sqlite3PcacheMakeDirty(pPg);
if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){
+ assert( !pagerUseWal(pPager) );
pPager->dbModified = 1;
}else{
@@ -35606,14 +38326,14 @@
** or both.
**
** Higher level routines should have already started a transaction,
- ** which means they have acquired the necessary locks and opened
- ** a rollback journal. Double-check to makes sure this is the case.
+ ** which means they have acquired the necessary locks but the rollback
+ ** journal might not yet be open.
*/
- rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory);
- if( NEVER(rc!=SQLITE_OK) ){
- return rc;
- }
- if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+ assert( pPager->state>=RESERVED_LOCK );
+ if( pPager->pInJournal==0
+ && pPager->journalMode!=PAGER_JOURNALMODE_OFF
+ && !pagerUseWal(pPager)
+ ){
assert( pPager->useJournal );
rc = pager_open_journal(pPager);
if( rc!=SQLITE_OK ) return rc;
@@ -35625,6 +38345,7 @@
** the transaction journal if it is not there already.
*/
if( !pageInJournal(pPg) && isOpen(pPager->jfd) ){
+ assert( !pagerUseWal(pPager) );
if( pPg->pgno<=pPager->dbOrigSize ){
u32 cksum;
char *pData2;
@@ -35633,6 +38354,8 @@
** contains the database locks. The following assert verifies
** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
+
+ assert( pPager->journalHdr <= pPager->journalOff );
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
cksum = pager_cksum(pPager, (u8*)pData2);
rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
@@ -35735,16 +38458,17 @@
if( nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */
- int nPage; /* Number of pages starting at pg1 to journal */
+ int nPage = 0; /* Number of pages starting at pg1 to journal */
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
- /* Set the doNotSync flag to 1. This is because we cannot allow a journal
- ** header to be written between the pages journaled by this function.
+ /* Set the doNotSyncSpill flag to 1. This is because we cannot allow
+ ** a journal header to be written between the pages journaled by
+ ** this function.
*/
assert( !MEMDB );
- assert( pPager->doNotSync==0 );
- pPager->doNotSync = 1;
+ assert( pPager->doNotSyncSpill==0 );
+ pPager->doNotSyncSpill++;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
@@ -35752,17 +38476,19 @@
*/
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
- sqlite3PagerPagecount(pPager, (int *)&nPageCount);
- if( pPg->pgno>nPageCount ){
- nPage = (pPg->pgno - pg1)+1;
- }else if( (pg1+nPagePerSector-1)>nPageCount ){
- nPage = nPageCount+1-pg1;
- }else{
- nPage = nPagePerSector;
+ rc = sqlite3PagerPagecount(pPager, (int *)&nPageCount);
+ if( rc==SQLITE_OK ){
+ if( pPg->pgno>nPageCount ){
+ nPage = (pPg->pgno - pg1)+1;
+ }else if( (pg1+nPagePerSector-1)>nPageCount ){
+ nPage = nPageCount+1-pg1;
+ }else{
+ nPage = nPagePerSector;
+ }
+ assert(nPage>0);
+ assert(pg1<=pPg->pgno);
+ assert((pg1+nPage)>pPg->pgno);
}
- assert(nPage>0);
- assert(pg1<=pPg->pgno);
- assert((pg1+nPage)>pPg->pgno);
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
Pgno pg = pg1+ii;
@@ -35805,8 +38531,8 @@
assert(pPager->needSync);
}
- assert( pPager->doNotSync==1 );
- pPager->doNotSync = 0;
+ assert( pPager->doNotSyncSpill==1 );
+ pPager->doNotSyncSpill--;
}else{
rc = pager_write(pDbPage);
}
@@ -35824,7 +38550,6 @@
}
#endif
-#ifndef SQLITE_SECURE_DELETE
/*
** A call to this routine tells the pager that it is not necessary to
** write the information on page pPg back to the disk, even though
@@ -35850,7 +38575,6 @@
#endif
}
}
-#endif /* !defined(SQLITE_SECURE_DELETE) */
/*
** This routine is called to increment the value of the database file
@@ -35915,11 +38639,20 @@
change_counter++;
put32bits(((char*)pPgHdr->pData)+24, change_counter);
+ /* Also store the SQLite version number in bytes 96..99 and in
+ ** bytes 92..95 store the change counter for which the version number
+ ** is valid. */
+ put32bits(((char*)pPgHdr->pData)+92, change_counter);
+ put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
+
/* If running in direct mode, write the contents of page 1 to the file. */
if( DIRECT_MODE ){
- const void *zBuf = pPgHdr->pData;
+ const void *zBuf;
assert( pPager->dbFileSize>0 );
- rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ }
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
}
@@ -35988,10 +38721,8 @@
/* The dbOrigSize is never set if journal_mode=OFF */
assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF || pPager->dbOrigSize==0 );
- /* If a prior error occurred, this routine should not be called. ROLLBACK
- ** is the appropriate response to an error, not COMMIT. Guard against
- ** coding errors by repeating the prior error. */
- if( NEVER(pPager->errCode) ) return pPager->errCode;
+ /* If a prior error occurred, report that error again. */
+ if( pPager->errCode ) return pPager->errCode;
PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
@@ -36003,129 +38734,143 @@
*/
sqlite3BackupRestart(pPager->pBackup);
}else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){
-
- /* The following block updates the change-counter. Exactly how it
- ** does this depends on whether or not the atomic-update optimization
- ** was enabled at compile time, and if this transaction meets the
- ** runtime criteria to use the operation:
- **
- ** * The file-system supports the atomic-write property for
- ** blocks of size page-size, and
- ** * This commit is not part of a multi-file transaction, and
- ** * Exactly one page has been modified and store in the journal file.
- **
- ** If the optimization was not enabled at compile time, then the
- ** pager_incr_changecounter() function is called to update the change
- ** counter in 'indirect-mode'. If the optimization is compiled in but
- ** is not applicable to this transaction, call sqlite3JournalCreate()
- ** to make sure the journal file has actually been created, then call
- ** pager_incr_changecounter() to update the change-counter in indirect
- ** mode.
- **
- ** Otherwise, if the optimization is both enabled and applicable,
- ** then call pager_incr_changecounter() to update the change-counter
- ** in 'direct' mode. In this case the journal file will never be
- ** created for this transaction.
- */
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
- PgHdr *pPg;
- assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbFileSize
- && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
- ){
- /* Update the db file change counter via the direct-write method. The
- ** following call will modify the in-memory representation of page 1
- ** to include the updated change counter and then write page 1
- ** directly to the database file. Because of the atomic-write
- ** property of the host file-system, this is safe.
- */
- rc = pager_incr_changecounter(pPager, 1);
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 0);
+ if( pagerUseWal(pPager) ){
+ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
+ if( pList ){
+ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
+ (pPager->fullSync ? pPager->sync_flags : 0)
+ );
}
- }
-#else
- rc = pager_incr_changecounter(pPager, 0);
-#endif
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file. This can only happen in auto-vacuum mode.
- **
- ** Before reading the pages with page numbers larger than the
- ** current value of Pager.dbSize, set dbSize back to the value
- ** that it took at the start of the transaction. Otherwise, the
- ** calls to sqlite3PagerGet() return zeroed pages instead of
- ** reading data from the database file.
- **
- ** When journal_mode==OFF the dbOrigSize is always zero, so this
- ** block never runs if journal_mode=OFF.
- */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pPager->dbSize<pPager->dbOrigSize
- && ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
- ){
- Pgno i; /* Iterator variable */
- const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
- const Pgno dbSize = pPager->dbSize; /* Database image size */
- pPager->dbSize = pPager->dbOrigSize;
- for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
- PgHdr *pPage; /* Page to journal */
- rc = sqlite3PagerGet(pPager, i, &pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- rc = sqlite3PagerWrite(pPage);
- sqlite3PagerUnref(pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ if( rc==SQLITE_OK ){
+ sqlite3PcacheCleanAll(pPager->pPCache);
+ }
+ }else{
+ /* The following block updates the change-counter. Exactly how it
+ ** does this depends on whether or not the atomic-update optimization
+ ** was enabled at compile time, and if this transaction meets the
+ ** runtime criteria to use the operation:
+ **
+ ** * The file-system supports the atomic-write property for
+ ** blocks of size page-size, and
+ ** * This commit is not part of a multi-file transaction, and
+ ** * Exactly one page has been modified and store in the journal file.
+ **
+ ** If the optimization was not enabled at compile time, then the
+ ** pager_incr_changecounter() function is called to update the change
+ ** counter in 'indirect-mode'. If the optimization is compiled in but
+ ** is not applicable to this transaction, call sqlite3JournalCreate()
+ ** to make sure the journal file has actually been created, then call
+ ** pager_incr_changecounter() to update the change-counter in indirect
+ ** mode.
+ **
+ ** Otherwise, if the optimization is both enabled and applicable,
+ ** then call pager_incr_changecounter() to update the change-counter
+ ** in 'direct' mode. In this case the journal file will never be
+ ** created for this transaction.
+ */
+ #ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ PgHdr *pPg;
+ assert( isOpen(pPager->jfd)
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ if( !zMaster && isOpen(pPager->jfd)
+ && pPager->journalOff==jrnlBufferSize(pPager)
+ && pPager->dbSize>=pPager->dbFileSize
+ && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
+ ){
+ /* Update the db file change counter via the direct-write method. The
+ ** following call will modify the in-memory representation of page 1
+ ** to include the updated change counter and then write page 1
+ ** directly to the database file. Because of the atomic-write
+ ** property of the host file-system, this is safe.
+ */
+ rc = pager_incr_changecounter(pPager, 1);
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 0);
}
- }
- pPager->dbSize = dbSize;
- }
-#endif
-
- /* Write the master journal name into the journal file. If a master
- ** journal file name has already been written to the journal file,
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
- */
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Sync the journal file. If the atomic-update optimization is being
- ** used, this call will not create the journal file or perform any
- ** real IO.
- */
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Write all dirty pages to the database file. */
- rc = pager_write_pagelist(sqlite3PcacheDirtyList(pPager->pPCache));
- if( rc!=SQLITE_OK ){
- assert( rc!=SQLITE_IOERR_BLOCKED );
- goto commit_phase_one_exit;
- }
- sqlite3PcacheCleanAll(pPager->pPCache);
-
- /* If the file on disk is not the same size as the database image,
- ** then use pager_truncate to grow or shrink the file here.
- */
- if( pPager->dbSize!=pPager->dbFileSize ){
- Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
- assert( pPager->state>=PAGER_EXCLUSIVE );
- rc = pager_truncate(pPager, nNew);
+ }
+ #else
+ rc = pager_incr_changecounter(pPager, 0);
+ #endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* If this transaction has made the database smaller, then all pages
+ ** being discarded by the truncation must be written to the journal
+ ** file. This can only happen in auto-vacuum mode.
+ **
+ ** Before reading the pages with page numbers larger than the
+ ** current value of Pager.dbSize, set dbSize back to the value
+ ** that it took at the start of the transaction. Otherwise, the
+ ** calls to sqlite3PagerGet() return zeroed pages instead of
+ ** reading data from the database file.
+ **
+ ** When journal_mode==OFF the dbOrigSize is always zero, so this
+ ** block never runs if journal_mode=OFF.
+ */
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPager->dbSize<pPager->dbOrigSize
+ && ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
+ ){
+ Pgno i; /* Iterator variable */
+ const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
+ const Pgno dbSize = pPager->dbSize; /* Database image size */
+ pPager->dbSize = pPager->dbOrigSize;
+ for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
+ if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
+ PgHdr *pPage; /* Page to journal */
+ rc = sqlite3PagerGet(pPager, i, &pPage);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ rc = sqlite3PagerWrite(pPage);
+ sqlite3PagerUnref(pPage);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+ }
+ pPager->dbSize = dbSize;
+ }
+ #endif
+
+ /* Write the master journal name into the journal file. If a master
+ ** journal file name has already been written to the journal file,
+ ** or if zMaster is NULL (no master journal), then this call is a no-op.
+ */
+ rc = writeMasterJournal(pPager, zMaster);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* Sync the journal file. If the atomic-update optimization is being
+ ** used, this call will not create the journal file or perform any
+ ** real IO.
+ */
+ rc = syncJournal(pPager);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* Write all dirty pages to the database file. */
+ rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+ if( rc!=SQLITE_OK ){
+ assert( rc!=SQLITE_IOERR_BLOCKED );
+ goto commit_phase_one_exit;
+ }
+ sqlite3PcacheCleanAll(pPager->pPCache);
+
+ /* If the file on disk is not the same size as the database image,
+ ** then use pager_truncate to grow or shrink the file here.
+ */
+ if( pPager->dbSize!=pPager->dbFileSize ){
+ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
+ assert( pPager->state>=PAGER_EXCLUSIVE );
+ rc = pager_truncate(pPager, nNew);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+
+ /* Finally, sync the database file. */
+ if( !pPager->noSync && !noSync ){
+ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ }
+ IOTRACE(("DBSYNC %p\n", pPager))
}
- /* Finally, sync the database file. */
- if( !pPager->noSync && !noSync ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
- }
- IOTRACE(("DBSYNC %p\n", pPager))
-
pPager->state = PAGER_SYNCED;
}
@@ -36158,8 +38903,9 @@
if( NEVER(pPager->errCode) ) return pPager->errCode;
/* This function should not be called if the pager is not in at least
- ** PAGER_RESERVED state. And indeed SQLite never does this. But it is
- ** nice to have this defensive test here anyway.
+ ** PAGER_RESERVED state. **FIXME**: Make it so that this test always
+ ** fails - make it so that we never reach this point if we do not hold
+ ** all necessary locks.
*/
if( NEVER(pPager->state<PAGER_RESERVED) ) return SQLITE_ERROR;
@@ -36177,7 +38923,7 @@
if( pPager->dbModified==0 && pPager->exclusiveMode
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST
){
- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
+ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
return SQLITE_OK;
}
@@ -36210,7 +38956,7 @@
** (i.e. either SQLITE_IOERR or SQLITE_CORRUPT).
**
** * If the pager is in PAGER_RESERVED state, then attempt (1). Whether
-** or not (1) is succussful, also attempt (2). If successful, return
+** or not (1) is successful, also attempt (2). If successful, return
** SQLITE_OK. Otherwise, enter the error state and return the first
** error code encountered.
**
@@ -36233,7 +38979,14 @@
SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
- if( !pPager->dbModified || !isOpen(pPager->jfd) ){
+ if( pagerUseWal(pPager) ){
+ int rc2;
+
+ rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
+ rc2 = pager_end_transaction(pPager, pPager->setMaster);
+ if( rc==SQLITE_OK ) rc = rc2;
+ rc = pager_error(pPager, rc);
+ }else if( !pPager->dbModified || !isOpen(pPager->jfd) ){
rc = pager_end_transaction(pPager, pPager->setMaster);
}else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
@@ -36281,6 +39034,16 @@
}
/*
+** Return the approximate number of bytes of memory currently
+** used by the pager and its associated cache.
+*/
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
+ int perPageSize = pPager->pageSize + pPager->nExtra + 20;
+ return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
+ + sqlite3MallocSize(pPager);
+}
+
+/*
** Return the number of references to the specified page.
*/
SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
@@ -36332,11 +39095,10 @@
if( nSavepoint>nCurrent && pPager->useJournal ){
int ii; /* Iterator variable */
PagerSavepoint *aNew; /* New Pager.aSavepoint array */
+ int nPage; /* Size of database file */
- /* Either there is no active journal or the sub-journal is open or
- ** the journal is always stored in memory */
- assert( pPager->nSavepoint==0 || isOpen(pPager->sjfd) ||
- pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
/* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
** if the allocation fails. Otherwise, zero the new portion in case a
@@ -36350,26 +39112,26 @@
}
memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
pPager->aSavepoint = aNew;
- pPager->nSavepoint = nSavepoint;
/* Populate the PagerSavepoint structures just allocated. */
for(ii=nCurrent; ii<nSavepoint; ii++){
- assert( pPager->dbSizeValid );
- aNew[ii].nOrig = pPager->dbSize;
- if( isOpen(pPager->jfd) && ALWAYS(pPager->journalOff>0) ){
+ aNew[ii].nOrig = nPage;
+ if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
aNew[ii].iOffset = pPager->journalOff;
}else{
aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
}
aNew[ii].iSubRec = pPager->nSubRec;
- aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
+ aNew[ii].pInSavepoint = sqlite3BitvecCreate(nPage);
if( !aNew[ii].pInSavepoint ){
return SQLITE_NOMEM;
}
+ if( pagerUseWal(pPager) ){
+ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+ }
+ pPager->nSavepoint = ii+1;
}
-
- /* Open the sub-journal, if it is not already opened. */
- rc = openSubJournal(pPager);
+ assert( pPager->nSavepoint==nSavepoint );
assertTruncateConstraint(pPager);
}
@@ -36433,6 +39195,7 @@
/* Only truncate if it is an in-memory sub-journal. */
if( sqlite3IsMemJournal(pPager->sjfd) ){
rc = sqlite3OsTruncate(pPager->sjfd, 0);
+ assert( rc==SQLITE_OK );
}
pPager->nSubRec = 0;
}
@@ -36442,7 +39205,7 @@
** not yet been opened. In this case there have been no changes to
** the database file, so the playback operation can be skipped.
*/
- else if( isOpen(pPager->jfd) ){
+ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){
PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
@@ -36494,7 +39257,7 @@
/*
** Set or retrieve the codec for this pager
*/
-static void sqlite3PagerSetCodec(
+SQLITE_PRIVATE void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void (*xCodecSizeChng)(void*,int,int),
@@ -36508,7 +39271,7 @@
pPager->pCodec = pCodec;
pagerReportSize(pPager);
}
-static void *sqlite3PagerGetCodec(Pager *pPager){
+SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
return pPager->pCodec;
}
#endif
@@ -36711,49 +39474,132 @@
}
/*
-** Get/set the journal-mode for this pager. Parameter eMode must be one of:
+** Set the journal-mode for this pager. Parameter eMode must be one of:
**
-** PAGER_JOURNALMODE_QUERY
** PAGER_JOURNALMODE_DELETE
** PAGER_JOURNALMODE_TRUNCATE
** PAGER_JOURNALMODE_PERSIST
** PAGER_JOURNALMODE_OFF
** PAGER_JOURNALMODE_MEMORY
+** PAGER_JOURNALMODE_WAL
**
-** If the parameter is not _QUERY, then the journal_mode is set to the
-** value specified if the change is allowed. The change is disallowed
-** for the following reasons:
+** The journalmode is set to the value specified if the change is allowed.
+** The change may be disallowed for the following reasons:
**
** * An in-memory database can only have its journal_mode set to _OFF
** or _MEMORY.
**
-** * The journal mode may not be changed while a transaction is active.
+** * Temporary databases cannot have _WAL journalmode.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *pPager, int eMode){
- assert( eMode==PAGER_JOURNALMODE_QUERY
- || eMode==PAGER_JOURNALMODE_DELETE
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
+ u8 eOld = pPager->journalMode; /* Prior journalmode */
+
+ /* The eMode parameter is always valid */
+ assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
+ || eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
- assert( PAGER_JOURNALMODE_QUERY<0 );
- if( eMode>=0
- && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY
- || eMode==PAGER_JOURNALMODE_OFF)
- && !pPager->dbModified
- && (!isOpen(pPager->jfd) || 0==pPager->journalOff)
- ){
- if( isOpen(pPager->jfd) ){
+
+ /* Do not allow the journalmode of a TEMP database to be changed to WAL
+ */
+ if( pPager->tempFile && eMode==PAGER_JOURNALMODE_WAL ){
+ assert( eOld!=PAGER_JOURNALMODE_WAL );
+ eMode = eOld;
+ }
+
+ /* Do allow the journalmode of an in-memory database to be set to
+ ** anything other than MEMORY or OFF
+ */
+ if( MEMDB ){
+ assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
+ if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
+ eMode = eOld;
+ }
+ }
+
+ if( eMode!=eOld ){
+ /* When changing between rollback modes, close the journal file prior
+ ** to the change. But when changing from a rollback mode to WAL, keep
+ ** the journal open since there is a rollback-style transaction in play
+ ** used to convert the version numbers in the btree header.
+ */
+ if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
sqlite3OsClose(pPager->jfd);
}
+
+ /* Change the journal mode. */
pPager->journalMode = (u8)eMode;
+
+ /* When transistioning from TRUNCATE or PERSIST to any other journal
+ ** mode except WAL (and we are not in locking_mode=EXCLUSIVE) then
+ ** delete the journal file.
+ */
+ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+ assert( (PAGER_JOURNALMODE_DELETE & 5)==0 );
+ assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 );
+ assert( (PAGER_JOURNALMODE_OFF & 5)==0 );
+ assert( (PAGER_JOURNALMODE_WAL & 5)==5 );
+
+ assert( isOpen(pPager->fd) || pPager->exclusiveMode );
+ if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
+
+ /* In this case we would like to delete the journal file. If it is
+ ** not possible, then that is not a problem. Deleting the journal file
+ ** here is an optimization only.
+ **
+ ** Before deleting the journal file, obtain a RESERVED lock on the
+ ** database file. This ensures that the journal file is not deleted
+ ** while it is in use by some other client.
+ */
+ int rc = SQLITE_OK;
+ int state = pPager->state;
+ if( state<PAGER_SHARED ){
+ rc = sqlite3PagerSharedLock(pPager);
+ }
+ if( pPager->state==PAGER_SHARED ){
+ assert( rc==SQLITE_OK );
+ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
+ }
+ if( rc==SQLITE_OK && state==PAGER_SHARED ){
+ sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
+ }else if( state==PAGER_UNLOCK ){
+ pager_unlock(pPager);
+ }
+ assert( state==pPager->state );
+ }
}
+
+ /* Return the new journal mode */
return (int)pPager->journalMode;
}
/*
+** Return the current journal mode.
+*/
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
+ return (int)pPager->journalMode;
+}
+
+/*
+** Return TRUE if the pager is in a state where it is OK to change the
+** journalmode. Journalmode changes can only happen when the database
+** is unmodified.
+*/
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
+ if( pPager->dbModified ) return 0;
+ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
+ return 1;
+}
+
+/*
** Get/set the size-limit used for persistent journal files.
**
** Setting the size limit to -1 means no limit is enforced.
@@ -36776,9 +39622,2790 @@
return &pPager->pBackup;
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** This function is called when the user invokes "PRAGMA checkpoint".
+*/
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( pPager->pWal ){
+ u8 *zBuf = (u8 *)pPager->pTmpSpace;
+ rc = sqlite3WalCheckpoint(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, zBuf
+ );
+ }
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
+ return sqlite3WalCallback(pPager->pWal);
+}
+
+/*
+** Return true if the underlying VFS for the given pager supports the
+** primitives necessary for write-ahead logging.
+*/
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
+ const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+ return pMethods->iVersion>=2 && pMethods->xShmOpen!=0;
+}
+
+/*
+** The caller must be holding a SHARED lock on the database file to call
+** this function.
+**
+** If the pager passed as the first argument is open on a real database
+** file (not a temp file or an in-memory database), and the WAL file
+** is not already open, make an attempt to open it now. If successful,
+** return SQLITE_OK. If an error occurs or the VFS used by the pager does
+** not support the xShmXXX() methods, return an error code. *pisOpen is
+** not modified in either case.
+**
+** If the pager is open on a temp-file (or in-memory database), or if
+** the WAL file is already open, set *pisOpen to 1 and return SQLITE_OK
+** without doing anything.
+*/
+SQLITE_PRIVATE int sqlite3PagerOpenWal(
+ Pager *pPager, /* Pager object */
+ int *pisOpen /* OUT: Set to true if call is a no-op */
+){
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pPager->state>=PAGER_SHARED );
+ assert( (pisOpen==0 && !pPager->tempFile && !pPager->pWal) || *pisOpen==0 );
+
+ if( !pPager->tempFile && !pPager->pWal ){
+ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
+
+ /* Open the connection to the log file. If this operation fails,
+ ** (e.g. due to malloc() failure), unlock the database file and
+ ** return an error code.
+ */
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal);
+ if( rc==SQLITE_OK ){
+ pPager->journalMode = PAGER_JOURNALMODE_WAL;
+ }
+ }else{
+ *pisOpen = 1;
+ }
+
+ return rc;
+}
+
+/*
+** This function is called to close the connection to the log file prior
+** to switching from WAL to rollback mode.
+**
+** Before closing the log file, this function attempts to take an
+** EXCLUSIVE lock on the database file. If this cannot be obtained, an
+** error (SQLITE_BUSY) is returned and the log connection is not closed.
+** If successful, the EXCLUSIVE lock is not released before returning.
+*/
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+ int rc = SQLITE_OK;
+
+ assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
+
+ /* If the log file is not already open, but does exist in the file-system,
+ ** it may need to be checkpointed before the connection can switch to
+ ** rollback mode. Open it now so this can happen.
+ */
+ if( !pPager->pWal ){
+ int logexists = 0;
+ rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
+ );
+ }
+ if( rc==SQLITE_OK && logexists ){
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
+ pPager->zWal, &pPager->pWal);
+ }
+ }
+
+ /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
+ ** the database file, the log and log-summary files will be deleted.
+ */
+ if( rc==SQLITE_OK && pPager->pWal ){
+ rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3WalClose(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, (u8*)pPager->pTmpSpace
+ );
+ pPager->pWal = 0;
+ }else{
+ /* If we cannot get an EXCLUSIVE lock, downgrade the PENDING lock
+ ** that we did get back to SHARED. */
+ sqlite3OsUnlock(pPager->fd, SQLITE_LOCK_SHARED);
+ }
+ }
+ return rc;
+}
+
+#ifdef SQLITE_HAS_CODEC
+/*
+** This function is called by the wal module when writing page content
+** into the log file.
+**
+** This function returns a pointer to a buffer containing the encrypted
+** page content. If a malloc fails, this function may return NULL.
+*/
+SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+ void *aData = 0;
+ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+ return aData;
+}
+#endif /* SQLITE_HAS_CODEC */
+
+#endif /* !SQLITE_OMIT_WAL */
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
+/************** Begin file wal.c *********************************************/
+/*
+** 2010 February 1
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains the implementation of a write-ahead log (WAL) used in
+** "journal_mode=WAL" mode.
+**
+** WRITE-AHEAD LOG (WAL) FILE FORMAT
+**
+** A WAL file consists of a header followed by zero or more "frames".
+** Each frame records the revised content of a single page from the
+** database file. All changes to the database are recorded by writing
+** frames into the WAL. Transactions commit when a frame is written that
+** contains a commit marker. A single WAL can and usually does record
+** multiple transactions. Periodically, the content of the WAL is
+** transferred back into the database file in an operation called a
+** "checkpoint".
+**
+** A single WAL file can be used multiple times. In other words, the
+** WAL can fill up with frames and then be checkpointed and then new
+** frames can overwrite the old ones. A WAL always grows from beginning
+** toward the end. Checksums and counters attached to each frame are
+** used to determine which frames within the WAL are valid and which
+** are leftovers from prior checkpoints.
+**
+** The WAL header is 32 bytes in size and consists of the following eight
+** big-endian 32-bit unsigned integer values:
+**
+** 0: Magic number. 0x377f0682 or 0x377f0683
+** 4: File format version. Currently 3007000
+** 8: Database page size. Example: 1024
+** 12: Checkpoint sequence number
+** 16: Salt-1, random integer incremented with each checkpoint
+** 20: Salt-2, a different random integer changing with each ckpt
+** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
+** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
+**
+** Immediately following the wal-header are zero or more frames. Each
+** frame consists of a 24-byte frame-header followed by a <page-size> bytes
+** of page data. The frame-header is six big-endian 32-bit unsigned
+** integer values, as follows:
+**
+** 0: Page number.
+** 4: For commit records, the size of the database image in pages
+** after the commit. For all other records, zero.
+** 8: Salt-1 (copied from the header)
+** 12: Salt-2 (copied from the header)
+** 16: Checksum-1.
+** 20: Checksum-2.
+**
+** A frame is considered valid if and only if the following conditions are
+** true:
+**
+** (1) The salt-1 and salt-2 values in the frame-header match
+** salt values in the wal-header
+**
+** (2) The checksum values in the final 8 bytes of the frame-header
+** exactly match the checksum computed consecutively on the
+** WAL header and the first 8 bytes and the content of all frames
+** up to and including the current frame.
+**
+** The checksum is computed using 32-bit big-endian integers if the
+** magic number in the first 4 bytes of the WAL is 0x377f0683 and it
+** is computed using little-endian if the magic number is 0x377f0682.
+** The checksum values are always stored in the frame header in a
+** big-endian format regardless of which byte order is used to compute
+** the checksum. The checksum is computed by interpreting the input as
+** an even number of unsigned 32-bit integers: x[0] through x[N]. The
+** algorithm used for the checksum is as follows:
+**
+** for i from 0 to n-1 step 2:
+** s0 += x[i] + s1;
+** s1 += x[i+1] + s0;
+** endfor
+**
+** Note that s0 and s1 are both weighted checksums using fibonacci weights
+** in reverse order (the largest fibonacci weight occurs on the first element
+** of the sequence being summed.) The s1 value spans all 32-bit
+** terms of the sequence whereas s0 omits the final term.
+**
+** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
+** WAL is transferred into the database, then the database is VFS.xSync-ed.
+** The VFS.xSync operations serve as write barriers - all writes launched
+** before the xSync must complete before any write that launches after the
+** xSync begins.
+**
+** After each checkpoint, the salt-1 value is incremented and the salt-2
+** value is randomized. This prevents old and new frames in the WAL from
+** being considered valid at the same time and being checkpointing together
+** following a crash.
+**
+** READER ALGORITHM
+**
+** To read a page from the database (call it page number P), a reader
+** first checks the WAL to see if it contains page P. If so, then the
+** last valid instance of page P that is a followed by a commit frame
+** or is a commit frame itself becomes the value read. If the WAL
+** contains no copies of page P that are valid and which are a commit
+** frame or are followed by a commit frame, then page P is read from
+** the database file.
+**
+** To start a read transaction, the reader records the index of the last
+** valid frame in the WAL. The reader uses this recorded "mxFrame" value
+** for all subsequent read operations. New transactions can be appended
+** to the WAL, but as long as the reader uses its original mxFrame value
+** and ignores the newly appended content, it will see a consistent snapshot
+** of the database from a single point in time. This technique allows
+** multiple concurrent readers to view different versions of the database
+** content simultaneously.
+**
+** The reader algorithm in the previous paragraphs works correctly, but
+** because frames for page P can appear anywhere within the WAL, the
+** reader has to scan the entire WAL looking for page P frames. If the
+** WAL is large (multiple megabytes is typical) that scan can be slow,
+** and read performance suffers. To overcome this problem, a separate
+** data structure called the wal-index is maintained to expedite the
+** search for frames of a particular page.
+**
+** WAL-INDEX FORMAT
+**
+** Conceptually, the wal-index is shared memory, though VFS implementations
+** might choose to implement the wal-index using a mmapped file. Because
+** the wal-index is shared memory, SQLite does not support journal_mode=WAL
+** on a network filesystem. All users of the database must be able to
+** share memory.
+**
+** The wal-index is transient. After a crash, the wal-index can (and should
+** be) reconstructed from the original WAL file. In fact, the VFS is required
+** to either truncate or zero the header of the wal-index when the last
+** connection to it closes. Because the wal-index is transient, it can
+** use an architecture-specific format; it does not have to be cross-platform.
+** Hence, unlike the database and WAL file formats which store all values
+** as big endian, the wal-index can store multi-byte values in the native
+** byte order of the host computer.
+**
+** The purpose of the wal-index is to answer this question quickly: Given
+** a page number P, return the index of the last frame for page P in the WAL,
+** or return NULL if there are no frames for page P in the WAL.
+**
+** The wal-index consists of a header region, followed by an one or
+** more index blocks.
+**
+** The wal-index header contains the total number of frames within the WAL
+** in the the mxFrame field.
+**
+** Each index block except for the first contains information on
+** HASHTABLE_NPAGE frames. The first index block contains information on
+** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
+** HASHTABLE_NPAGE are selected so that together the wal-index header and
+** first index block are the same size as all other index blocks in the
+** wal-index.
+**
+** Each index block contains two sections, a page-mapping that contains the
+** database page number associated with each wal frame, and a hash-table
+** that allows readers to query an index block for a specific page number.
+** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
+** for the first index block) 32-bit page numbers. The first entry in the
+** first index-block contains the database page number corresponding to the
+** first frame in the WAL file. The first entry in the second index block
+** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
+** the log, and so on.
+**
+** The last index block in a wal-index usually contains less than the full
+** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers,
+** depending on the contents of the WAL file. This does not change the
+** allocated size of the page-mapping array - the page-mapping array merely
+** contains unused entries.
+**
+** Even without using the hash table, the last frame for page P
+** can be found by scanning the page-mapping sections of each index block
+** starting with the last index block and moving toward the first, and
+** within each index block, starting at the end and moving toward the
+** beginning. The first entry that equals P corresponds to the frame
+** holding the content for that page.
+**
+** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
+** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
+** hash table for each page number in the mapping section, so the hash
+** table is never more than half full. The expected number of collisions
+** prior to finding a match is 1. Each entry of the hash table is an
+** 1-based index of an entry in the mapping section of the same
+** index block. Let K be the 1-based index of the largest entry in
+** the mapping section. (For index blocks other than the last, K will
+** always be exactly HASHTABLE_NPAGE (4096) and for the last index block
+** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table
+** contain a value of 0.
+**
+** To look for page P in the hash table, first compute a hash iKey on
+** P as follows:
+**
+** iKey = (P * 383) % HASHTABLE_NSLOT
+**
+** Then start scanning entries of the hash table, starting with iKey
+** (wrapping around to the beginning when the end of the hash table is
+** reached) until an unused hash slot is found. Let the first unused slot
+** be at index iUnused. (iUnused might be less than iKey if there was
+** wrap-around.) Because the hash table is never more than half full,
+** the search is guaranteed to eventually hit an unused entry. Let
+** iMax be the value between iKey and iUnused, closest to iUnused,
+** where aHash[iMax]==P. If there is no iMax entry (if there exists
+** no hash slot such that aHash[i]==p) then page P is not in the
+** current index block. Otherwise the iMax-th mapping entry of the
+** current index block corresponds to the last entry that references
+** page P.
+**
+** A hash search begins with the last index block and moves toward the
+** first index block, looking for entries corresponding to page P. On
+** average, only two or three slots in each index block need to be
+** examined in order to either find the last entry for page P, or to
+** establish that no such entry exists in the block. Each index block
+** holds over 4000 entries. So two or three index blocks are sufficient
+** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10
+** comparisons (on average) suffice to either locate a frame in the
+** WAL or to establish that the frame does not exist in the WAL. This
+** is much faster than scanning the entire 10MB WAL.
+**
+** Note that entries are added in order of increasing K. Hence, one
+** reader might be using some value K0 and a second reader that started
+** at a later time (after additional transactions were added to the WAL
+** and to the wal-index) might be using a different value K1, where K1>K0.
+** Both readers can use the same hash table and mapping section to get
+** the correct result. There may be entries in the hash table with
+** K>K0 but to the first reader, those entries will appear to be unused
+** slots in the hash table and so the first reader will get an answer as
+** if no values greater than K0 had ever been inserted into the hash table
+** in the first place - which is what reader one wants. Meanwhile, the
+** second reader using K1 will see additional values that were inserted
+** later, which is exactly what reader two wants.
+**
+** When a rollback occurs, the value of K is decreased. Hash table entries
+** that correspond to frames greater than the new K value are removed
+** from the hash table at this point.
+*/
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** Trace output macros
+*/
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3WalTrace = 0;
+# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
+#else
+# define WALTRACE(X)
+#endif
+
+/*
+** The maximum (and only) versions of the wal and wal-index formats
+** that may be interpreted by this version of SQLite.
+**
+** If a client begins recovering a WAL file and finds that (a) the checksum
+** values in the wal-header are correct and (b) the version field is not
+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
+**
+** Similarly, if a client successfully reads a wal-index header (i.e. the
+** checksum test is successful) and finds that the version field is not
+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
+** returns SQLITE_CANTOPEN.
+*/
+#define WAL_MAX_VERSION 3007000
+#define WALINDEX_MAX_VERSION 3007000
+
+/*
+** Indices of various locking bytes. WAL_NREADER is the number
+** of available reader locks and should be at least 3.
+*/
+#define WAL_WRITE_LOCK 0
+#define WAL_ALL_BUT_WRITE 1
+#define WAL_CKPT_LOCK 1
+#define WAL_RECOVER_LOCK 2
+#define WAL_READ_LOCK(I) (3+(I))
+#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
+
+
+/* Object declarations */
+typedef struct WalIndexHdr WalIndexHdr;
+typedef struct WalIterator WalIterator;
+typedef struct WalCkptInfo WalCkptInfo;
+
+
+/*
+** The following object holds a copy of the wal-index header content.
+**
+** The actual header in the wal-index consists of two copies of this
+** object.
+*/
+struct WalIndexHdr {
+ u32 iVersion; /* Wal-index version */
+ u32 unused; /* Unused (padding) field */
+ u32 iChange; /* Counter incremented each transaction */
+ u8 isInit; /* 1 when initialized */
+ u8 bigEndCksum; /* True if checksums in WAL are big-endian */
+ u16 szPage; /* Database page size in bytes */
+ u32 mxFrame; /* Index of last valid frame in the WAL */
+ u32 nPage; /* Size of database in pages */
+ u32 aFrameCksum[2]; /* Checksum of last frame in log */
+ u32 aSalt[2]; /* Two salt values copied from WAL header */
+ u32 aCksum[2]; /* Checksum over all prior fields */
+};
+
+/*
+** A copy of the following object occurs in the wal-index immediately
+** following the second copy of the WalIndexHdr. This object stores
+** information used by checkpoint.
+**
+** nBackfill is the number of frames in the WAL that have been written
+** back into the database. (We call the act of moving content from WAL to
+** database "backfilling".) The nBackfill number is never greater than
+** WalIndexHdr.mxFrame. nBackfill can only be increased by threads
+** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
+** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
+** mxFrame back to zero when the WAL is reset.
+**
+** There is one entry in aReadMark[] for each reader lock. If a reader
+** holds read-lock K, then the value in aReadMark[K] is no greater than
+** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
+** for any aReadMark[] means that entry is unused. aReadMark[0] is
+** a special case; its value is never used and it exists as a place-holder
+** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
+** directly from the database.
+**
+** The value of aReadMark[K] may only be changed by a thread that
+** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
+** aReadMark[K] cannot changed while there is a reader is using that mark
+** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
+**
+** The checkpointer may only transfer frames from WAL to database where
+** the frame numbers are less than or equal to every aReadMark[] that is
+** in use (that is, every aReadMark[j] for which there is a corresponding
+** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the
+** largest value and will increase an unused aReadMark[] to mxFrame if there
+** is not already an aReadMark[] equal to mxFrame. The exception to the
+** previous sentence is when nBackfill equals mxFrame (meaning that everything
+** in the WAL has been backfilled into the database) then new readers
+** will choose aReadMark[0] which has value 0 and hence such reader will
+** get all their all content directly from the database file and ignore
+** the WAL.
+**
+** Writers normally append new frames to the end of the WAL. However,
+** if nBackfill equals mxFrame (meaning that all WAL content has been
+** written back into the database) and if no readers are using the WAL
+** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
+** the writer will first "reset" the WAL back to the beginning and start
+** writing new content beginning at frame 1.
+**
+** We assume that 32-bit loads are atomic and so no locks are needed in
+** order to read from any aReadMark[] entries.
+*/
+struct WalCkptInfo {
+ u32 nBackfill; /* Number of WAL frames backfilled into DB */
+ u32 aReadMark[WAL_NREADER]; /* Reader marks */
+};
+#define READMARK_NOT_USED 0xffffffff
+
+
+/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
+** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
+** only support mandatory file-locks, we do not read or write data
+** from the region of the file on which locks are applied.
+*/
+#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
+#define WALINDEX_LOCK_RESERVED 16
+#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
+
+/* Size of header before each frame in wal */
+#define WAL_FRAME_HDRSIZE 24
+
+/* Size of write ahead log header, including checksum. */
+/* #define WAL_HDRSIZE 24 */
+#define WAL_HDRSIZE 32
+
+/* WAL magic value. Either this value, or the same value with the least
+** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
+** big-endian format in the first 4 bytes of a WAL file.
+**
+** If the LSB is set, then the checksums for each frame within the WAL
+** file are calculated by treating all data as an array of 32-bit
+** big-endian words. Otherwise, they are calculated by interpreting
+** all data as 32-bit little-endian words.
+*/
+#define WAL_MAGIC 0x377f0682
+
+/*
+** Return the offset of frame iFrame in the write-ahead log file,
+** assuming a database page size of szPage bytes. The offset returned
+** is to the start of the write-ahead log frame-header.
+*/
+#define walFrameOffset(iFrame, szPage) ( \
+ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
+)
+
+/*
+** An open write-ahead log file is represented by an instance of the
+** following object.
+*/
+struct Wal {
+ sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
+ sqlite3_file *pDbFd; /* File handle for the database file */
+ sqlite3_file *pWalFd; /* File handle for WAL file */
+ u32 iCallback; /* Value to pass to log callback (or 0) */
+ int nWiData; /* Size of array apWiData */
+ volatile u32 **apWiData; /* Pointer to wal-index content in memory */
+ u16 szPage; /* Database page size */
+ i16 readLock; /* Which read lock is being held. -1 for none */
+ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
+ u8 isWIndexOpen; /* True if ShmOpen() called on pDbFd */
+ u8 writeLock; /* True if in a write transaction */
+ u8 ckptLock; /* True if holding a checkpoint lock */
+ WalIndexHdr hdr; /* Wal-index header for current transaction */
+ const char *zWalName; /* Name of WAL file */
+ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_DEBUG
+ u8 lockError; /* True if a locking error has occurred */
+#endif
+};
+
+/*
+** Each page of the wal-index mapping contains a hash-table made up of
+** an array of HASHTABLE_NSLOT elements of the following type.
+*/
+typedef u16 ht_slot;
+
+/*
+** This structure is used to implement an iterator that loops through
+** all frames in the WAL in database page order. Where two or more frames
+** correspond to the same database page, the iterator visits only the
+** frame most recently written to the WAL (in other words, the frame with
+** the largest index).
+**
+** The internals of this structure are only accessed by:
+**
+** walIteratorInit() - Create a new iterator,
+** walIteratorNext() - Step an iterator,
+** walIteratorFree() - Free an iterator.
+**
+** This functionality is used by the checkpoint code (see walCheckpoint()).
+*/
+struct WalIterator {
+ int iPrior; /* Last result returned from the iterator */
+ int nSegment; /* Size of the aSegment[] array */
+ struct WalSegment {
+ int iNext; /* Next slot in aIndex[] not yet returned */
+ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
+ u32 *aPgno; /* Array of page numbers. */
+ int nEntry; /* Max size of aPgno[] and aIndex[] arrays */
+ int iZero; /* Frame number associated with aPgno[0] */
+ } aSegment[1]; /* One for every 32KB page in the WAL */
+};
+
+/*
+** Define the parameters of the hash tables in the wal-index file. There
+** is a hash-table following every HASHTABLE_NPAGE page numbers in the
+** wal-index.
+**
+** Changing any of these constants will alter the wal-index format and
+** create incompatibilities.
+*/
+#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
+#define HASHTABLE_HASH_1 383 /* Should be prime */
+#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
+
+/*
+** The block of page numbers associated with the first hash-table in a
+** wal-index is smaller than usual. This is so that there is a complete
+** hash-table on each aligned 32KB page of the wal-index.
+*/
+#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
+
+/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
+#define WALINDEX_PGSZ ( \
+ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
+)
+
+/*
+** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
+** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
+** numbered from zero.
+**
+** If this call is successful, *ppPage is set to point to the wal-index
+** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
+** then an SQLite error code is returned and *ppPage is set to 0.
+*/
+static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
+ int rc = SQLITE_OK;
+
+ /* Enlarge the pWal->apWiData[] array if required */
+ if( pWal->nWiData<=iPage ){
+ int nByte = sizeof(u32 *)*(iPage+1);
+ volatile u32 **apNew;
+ apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+ if( !apNew ){
+ *ppPage = 0;
+ return SQLITE_NOMEM;
+ }
+ memset((void *)&apNew[pWal->nWiData], 0, sizeof(u32 *)*(iPage+1-pWal->nWiData));
+ pWal->apWiData = apNew;
+ pWal->nWiData = iPage+1;
+ }
+
+ /* Request a pointer to the required page from the VFS */
+ if( pWal->apWiData[iPage]==0 ){
+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
+ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+ );
+ }
+
+ *ppPage = pWal->apWiData[iPage];
+ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
+ return rc;
+}
+
+/*
+** Return a pointer to the WalCkptInfo structure in the wal-index.
+*/
+static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
+}
+
+/*
+** Return a pointer to the WalIndexHdr structure in the wal-index.
+*/
+static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ return (volatile WalIndexHdr*)pWal->apWiData[0];
+}
+
+/*
+** The argument to this macro must be of type u32. On a little-endian
+** architecture, it returns the u32 value that results from interpreting
+** the 4 bytes as a big-endian value. On a big-endian architecture, it
+** returns the value that would be produced by intepreting the 4 bytes
+** of the input value as a little-endian integer.
+*/
+#define BYTESWAP32(x) ( \
+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
+)
+
+/*
+** Generate or extend an 8 byte checksum based on the data in
+** array aByte[] and the initial values of aIn[0] and aIn[1] (or
+** initial values of 0 and 0 if aIn==NULL).
+**
+** The checksum is written back into aOut[] before returning.
+**
+** nByte must be a positive multiple of 8.
+*/
+static void walChecksumBytes(
+ int nativeCksum, /* True for native byte-order, false for non-native */
+ u8 *a, /* Content to be checksummed */
+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
+ const u32 *aIn, /* Initial checksum value input */
+ u32 *aOut /* OUT: Final checksum value output */
+){
+ u32 s1, s2;
+ u32 *aData = (u32 *)a;
+ u32 *aEnd = (u32 *)&a[nByte];
+
+ if( aIn ){
+ s1 = aIn[0];
+ s2 = aIn[1];
+ }else{
+ s1 = s2 = 0;
+ }
+
+ assert( nByte>=8 );
+ assert( (nByte&0x00000007)==0 );
+
+ if( nativeCksum ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ }while( aData<aEnd );
+ }else{
+ do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }
+
+ aOut[0] = s1;
+ aOut[1] = s2;
+}
+
+/*
+** Write the header information in pWal->hdr into the wal-index.
+**
+** The checksum on pWal->hdr is updated before it is written.
+*/
+static void walIndexWriteHdr(Wal *pWal){
+ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
+ const int nCksum = offsetof(WalIndexHdr, aCksum);
+
+ assert( pWal->writeLock );
+ pWal->hdr.isInit = 1;
+ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
+ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+}
+
+/*
+** This function encodes a single frame header and writes it to a buffer
+** supplied by the caller. A frame-header is made up of a series of
+** 4-byte big-endian integers, as follows:
+**
+** 0: Page number.
+** 4: For commit records, the size of the database image in pages
+** after the commit. For all other records, zero.
+** 8: Salt-1 (copied from the wal-header)
+** 12: Salt-2 (copied from the wal-header)
+** 16: Checksum-1.
+** 20: Checksum-2.
+*/
+static void walEncodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 iPage, /* Database page number for frame */
+ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
+ u8 *aData, /* Pointer to page data */
+ u8 *aFrame /* OUT: Write encoded frame here */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ assert( WAL_FRAME_HDRSIZE==24 );
+ sqlite3Put4byte(&aFrame[0], iPage);
+ sqlite3Put4byte(&aFrame[4], nTruncate);
+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+
+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
+}
+
+/*
+** Check to see if the frame with header in aFrame[] and content
+** in aData[] is valid. If it is a valid frame, fill *piPage and
+** *pnTruncate and return true. Return if the frame is not valid.
+*/
+static int walDecodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 *piPage, /* OUT: Database page number for frame */
+ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
+ u8 *aData, /* Pointer to page data (for checksum) */
+ u8 *aFrame /* Frame data */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ u32 pgno; /* Page number of the frame */
+ assert( WAL_FRAME_HDRSIZE==24 );
+
+ /* A frame is only valid if the salt values in the frame-header
+ ** match the salt values in the wal-header.
+ */
+ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if the page number is creater than zero.
+ */
+ pgno = sqlite3Get4byte(&aFrame[0]);
+ if( pgno==0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if a checksum of the first 16 bytes
+ ** of the frame-header, and the frame-data matches
+ ** the checksum in the last 8 bytes of the frame-header.
+ */
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
+ ){
+ /* Checksum failed. */
+ return 0;
+ }
+
+ /* If we reach this point, the frame is valid. Return the page number
+ ** and the new database size.
+ */
+ *piPage = pgno;
+ *pnTruncate = sqlite3Get4byte(&aFrame[4]);
+ return 1;
+}
+
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+/*
+** Names of locks. This routine is used to provide debugging output and is not
+** a part of an ordinary build.
+*/
+static const char *walLockName(int lockIdx){
+ if( lockIdx==WAL_WRITE_LOCK ){
+ return "WRITE-LOCK";
+ }else if( lockIdx==WAL_CKPT_LOCK ){
+ return "CKPT-LOCK";
+ }else if( lockIdx==WAL_RECOVER_LOCK ){
+ return "RECOVER-LOCK";
+ }else{
+ static char zName[15];
+ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+ lockIdx-WAL_READ_LOCK(0));
+ return zName;
+ }
+}
+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+
+
+/*
+** Set or release locks on the WAL. Locks are either shared or exclusive.
+** A lock cannot be moved directly between shared and exclusive - it must go
+** through the unlocked state first.
+**
+** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+*/
+static int walLockShared(Wal *pWal, int lockIdx){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
+ walLockName(lockIdx), rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockShared(Wal *pWal, int lockIdx){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
+}
+static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
+ walLockName(lockIdx), n, rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
+ walLockName(lockIdx), n));
+}
+
+/*
+** Compute a hash on a page number. The resulting hash value must land
+** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
+** the hash to the next value in the event of a collision.
+*/
+static int walHash(u32 iPage){
+ assert( iPage>0 );
+ assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
+ return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
+}
+static int walNextHash(int iPriorHash){
+ return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
+}
+
+/*
+** Return pointers to the hash table and page number array stored on
+** page iHash of the wal-index. The wal-index is broken into 32KB pages
+** numbered starting from 0.
+**
+** Set output variable *paHash to point to the start of the hash table
+** in the wal-index file. Set *piZero to one less than the frame
+** number of the first frame indexed by this hash table. If a
+** slot in the hash table is set to N, it refers to frame number
+** (*piZero+N) in the log.
+**
+** Finally, set *paPgno so that *paPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (*piZero+1).
+*/
+static int walHashGet(
+ Wal *pWal, /* WAL handle */
+ int iHash, /* Find the iHash'th table */
+ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
+ volatile u32 **paPgno, /* OUT: Pointer to page number array */
+ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+){
+ int rc; /* Return code */
+ volatile u32 *aPgno;
+
+ rc = walIndexPage(pWal, iHash, &aPgno);
+ assert( rc==SQLITE_OK || iHash>0 );
+
+ if( rc==SQLITE_OK ){
+ u32 iZero;
+ volatile ht_slot *aHash;
+
+ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+ if( iHash==0 ){
+ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+ iZero = 0;
+ }else{
+ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+ }
+
+ *paPgno = &aPgno[-1];
+ *paHash = aHash;
+ *piZero = iZero;
+ }
+ return rc;
+}
+
+/*
+** Return the number of the wal-index page that contains the hash-table
+** and page-number array that contain entries corresponding to WAL frame
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
+** are numbered starting from 0.
+*/
+static int walFramePage(u32 iFrame){
+ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
+ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
+ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
+ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
+ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
+ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
+ );
+ return iHash;
+}
+
+/*
+** Return the page number associated with frame iFrame in this WAL.
+*/
+static u32 walFramePgno(Wal *pWal, u32 iFrame){
+ int iHash = walFramePage(iFrame);
+ if( iHash==0 ){
+ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
+ }
+ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+}
+
+/*
+** Remove entries from the hash table that point to WAL slots greater
+** than pWal->hdr.mxFrame.
+**
+** This function is called whenever pWal->hdr.mxFrame is decreased due
+** to a rollback or savepoint.
+**
+** At most only the hash table containing pWal->hdr.mxFrame needs to be
+** updated. Any later hash tables will be automatically cleared when
+** pWal->hdr.mxFrame advances to the point where those hash tables are
+** actually needed.
+*/
+static void walCleanupHash(Wal *pWal){
+ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
+ volatile u32 *aPgno = 0; /* Page number array for hash table */
+ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
+ int iLimit = 0; /* Zero values greater than this */
+ int nByte; /* Number of bytes to zero in aPgno[] */
+ int i; /* Used to iterate through aHash[] */
+
+ assert( pWal->writeLock );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+
+ if( pWal->hdr.mxFrame==0 ) return;
+
+ /* Obtain pointers to the hash-table and page-number array containing
+ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
+ ** that the page said hash-table and array reside on is already mapped.
+ */
+ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
+ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
+ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+
+ /* Zero all hash-table entries that correspond to frame numbers greater
+ ** than pWal->hdr.mxFrame.
+ */
+ iLimit = pWal->hdr.mxFrame - iZero;
+ assert( iLimit>0 );
+ for(i=0; i<HASHTABLE_NSLOT; i++){
+ if( aHash[i]>iLimit ){
+ aHash[i] = 0;
+ }
+ }
+
+ /* Zero the entries in the aPgno array that correspond to frames with
+ ** frame numbers greater than pWal->hdr.mxFrame.
+ */
+ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
+ memset((void *)&aPgno[iLimit+1], 0, nByte);
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the every entry in the mapping region is still reachable
+ ** via the hash table even after the cleanup.
+ */
+ if( iLimit ){
+ int i; /* Loop counter */
+ int iKey; /* Hash key */
+ for(i=1; i<=iLimit; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
+ }
+ assert( aHash[iKey]==i );
+ }
+ }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+}
+
+
+/*
+** Set an entry in the wal-index that will map database page number
+** pPage into WAL frame iFrame.
+*/
+static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+ int rc; /* Return code */
+ u32 iZero = 0; /* One less than frame number of aPgno[1] */
+ volatile u32 *aPgno = 0; /* Page number array */
+ volatile ht_slot *aHash = 0; /* Hash table */
+
+ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+
+ /* Assuming the wal-index file was successfully mapped, populate the
+ ** page number array and hash table entry.
+ */
+ if( rc==SQLITE_OK ){
+ int iKey; /* Hash table key */
+ int idx; /* Value to write to hash-table slot */
+ TESTONLY( int nCollide = 0; /* Number of hash collisions */ )
+
+ idx = iFrame - iZero;
+ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
+
+ /* If this is the first entry to be added to this hash-table, zero the
+ ** entire hash table and aPgno[] array before proceding.
+ */
+ if( idx==1 ){
+ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
+ memset((void*)&aPgno[1], 0, nByte);
+ }
+
+ /* If the entry in aPgno[] is already set, then the previous writer
+ ** must have exited unexpectedly in the middle of a transaction (after
+ ** writing one or more dirty pages to the WAL to free up memory).
+ ** Remove the remnants of that writers uncommitted transaction from
+ ** the hash-table before writing any new entries.
+ */
+ if( aPgno[idx] ){
+ walCleanupHash(pWal);
+ assert( !aPgno[idx] );
+ }
+
+ /* Write the aPgno[] array entry and the hash-table slot. */
+ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+ assert( nCollide++ < idx );
+ }
+ aPgno[idx] = iPage;
+ aHash[iKey] = (ht_slot)idx;
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the number of entries in the hash table exactly equals
+ ** the number of entries in the mapping region.
+ */
+ {
+ int i; /* Loop counter */
+ int nEntry = 0; /* Number of entries in the hash table */
+ for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+ assert( nEntry==idx );
+ }
+
+ /* Verify that the every entry in the mapping region is reachable
+ ** via the hash table. This turns out to be a really, really expensive
+ ** thing to check, so only do this occasionally - not on every
+ ** iteration.
+ */
+ if( (idx&0x3ff)==0 ){
+ int i; /* Loop counter */
+ for(i=1; i<=idx; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
+ }
+ assert( aHash[iKey]==i );
+ }
+ }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+ }
+
+
+ return rc;
+}
+
+
+/*
+** Recover the wal-index by reading the write-ahead log file.
+**
+** This routine first tries to establish an exclusive lock on the
+** wal-index to prevent other threads/processes from doing anything
+** with the WAL or wal-index while recovery is running. The
+** WAL_RECOVER_LOCK is also held so that other threads will know
+** that this thread is running recovery. If unable to establish
+** the necessary locks, this routine returns SQLITE_BUSY.
+*/
+static int walIndexRecover(Wal *pWal){
+ int rc; /* Return Code */
+ i64 nSize; /* Size of log file */
+ u32 aFrameCksum[2] = {0, 0};
+ int iLock; /* Lock offset to lock for checkpoint */
+ int nLock; /* Number of locks to hold */
+
+ /* Obtain an exclusive lock on all byte in the locking range not already
+ ** locked by the caller. The caller is guaranteed to have locked the
+ ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
+ ** If successful, the same bytes that are locked here are unlocked before
+ ** this function returns.
+ */
+ assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
+ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
+ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
+ assert( pWal->writeLock );
+ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
+ nLock = SQLITE_SHM_NLOCK - iLock;
+ rc = walLockExclusive(pWal, iLock, nLock);
+ if( rc ){
+ return rc;
+ }
+ WALTRACE(("WAL%p: recovery begin...\n", pWal));
+
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+
+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ if( nSize>WAL_HDRSIZE ){
+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+ int szFrame; /* Number of bytes in buffer aFrame[] */
+ u8 *aData; /* Pointer to data part of aFrame buffer */
+ int iFrame; /* Index of last frame read */
+ i64 iOffset; /* Next offset to read from log file */
+ int szPage; /* Page size according to the log */
+ u32 magic; /* Magic value read from WAL header */
+ u32 version; /* Magic value read from WAL header */
+
+ /* Read in the WAL header. */
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ /* If the database page size is not a power of two, or is greater than
+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
+ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
+ ** WAL file.
+ */
+ magic = sqlite3Get4byte(&aBuf[0]);
+ szPage = sqlite3Get4byte(&aBuf[8]);
+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
+ || szPage&(szPage-1)
+ || szPage>SQLITE_MAX_PAGE_SIZE
+ || szPage<512
+ ){
+ goto finished;
+ }
+ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
+ pWal->szPage = (u16)szPage;
+ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
+ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+
+ /* Verify that the WAL header checksum is correct */
+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
+ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
+ );
+ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+ ){
+ goto finished;
+ }
+
+ /* Verify that the version number on the WAL format is one that
+ ** are able to understand */
+ version = sqlite3Get4byte(&aBuf[4]);
+ if( version!=WAL_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto finished;
+ }
+
+ /* Malloc a buffer to read frames into. */
+ szFrame = szPage + WAL_FRAME_HDRSIZE;
+ aFrame = (u8 *)sqlite3_malloc(szFrame);
+ if( !aFrame ){
+ rc = SQLITE_NOMEM;
+ goto recovery_error;
+ }
+ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
+ /* Read all frames from the log file. */
+ iFrame = 0;
+ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
+ int isValid; /* True if this frame is valid */
+
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+ if( !isValid ) break;
+ rc = walIndexAppend(pWal, ++iFrame, pgno);
+ if( rc!=SQLITE_OK ) break;
+
+ /* If nTruncate is non-zero, this is a commit record. */
+ if( nTruncate ){
+ pWal->hdr.mxFrame = iFrame;
+ pWal->hdr.nPage = nTruncate;
+ pWal->hdr.szPage = (u16)szPage;
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+ }
+
+ sqlite3_free(aFrame);
+ }
+
+finished:
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo;
+ int i;
+ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
+ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
+ walIndexWriteHdr(pWal);
+
+ /* Reset the checkpoint-header. This is safe because this thread is
+ ** currently holding locks that exclude all other readers, writers and
+ ** checkpointers.
+ */
+ pInfo = walCkptInfo(pWal);
+ pInfo->nBackfill = 0;
+ pInfo->aReadMark[0] = 0;
+ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ }
+
+recovery_error:
+ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
+ walUnlockExclusive(pWal, iLock, nLock);
+ return rc;
+}
+
+/*
+** Close an open wal-index.
+*/
+static void walIndexClose(Wal *pWal, int isDelete){
+ if( pWal->isWIndexOpen ){
+ sqlite3OsShmClose(pWal->pDbFd, isDelete);
+ pWal->isWIndexOpen = 0;
+ }
+}
+
+/*
+** Open a connection to the WAL file zWalName. The database file must
+** already be opened on connection pDbFd. The buffer that zWalName points
+** to must remain valid for the lifetime of the returned Wal* handle.
+**
+** A SHARED lock should be held on the database file when this function
+** is called. The purpose of this SHARED lock is to prevent any other
+** client from unlinking the WAL or wal-index file. If another process
+** were to do this just after this client opened one of these files, the
+** system would be badly broken.
+**
+** If the log file is successfully opened, SQLITE_OK is returned and
+** *ppWal is set to point to a new WAL handle. If an error occurs,
+** an SQLite error code is returned and *ppWal is left unmodified.
+*/
+SQLITE_PRIVATE int sqlite3WalOpen(
+ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
+ sqlite3_file *pDbFd, /* The open database file */
+ const char *zWalName, /* Name of the WAL file */
+ Wal **ppWal /* OUT: Allocated Wal handle */
+){
+ int rc; /* Return Code */
+ Wal *pRet; /* Object to allocate and return */
+ int flags; /* Flags passed to OsOpen() */
+
+ assert( zWalName && zWalName[0] );
+ assert( pDbFd );
+
+ /* In the amalgamation, the os_unix.c and os_win.c source files come before
+ ** this source file. Verify that the #defines of the locking byte offsets
+ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+ */
+#ifdef WIN_SHM_BASE
+ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+#ifdef UNIX_SHM_BASE
+ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+
+
+ /* Allocate an instance of struct Wal to return. */
+ *ppWal = 0;
+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
+ if( !pRet ){
+ return SQLITE_NOMEM;
+ }
+
+ pRet->pVfs = pVfs;
+ pRet->pWalFd = (sqlite3_file *)&pRet[1];
+ pRet->pDbFd = pDbFd;
+ pRet->readLock = -1;
+ sqlite3_randomness(8, &pRet->hdr.aSalt);
+ pRet->zWalName = zWalName;
+ rc = sqlite3OsShmOpen(pDbFd);
+
+ /* Open file handle on the write-ahead log file. */
+ if( rc==SQLITE_OK ){
+ pRet->isWIndexOpen = 1;
+ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
+ }
+
+ if( rc!=SQLITE_OK ){
+ walIndexClose(pRet, 0);
+ sqlite3OsClose(pRet->pWalFd);
+ sqlite3_free(pRet);
+ }else{
+ *ppWal = pRet;
+ WALTRACE(("WAL%d: opened\n", pRet));
+ }
+ return rc;
+}
+
+/*
+** Find the smallest page number out of all pages held in the WAL that
+** has not been returned by any prior invocation of this method on the
+** same WalIterator object. Write into *piFrame the frame index where
+** that page was last written into the WAL. Write into *piPage the page
+** number.
+**
+** Return 0 on success. If there are no pages in the WAL with a page
+** number larger than *piPage, then return 1.
+*/
+static int walIteratorNext(
+ WalIterator *p, /* Iterator */
+ u32 *piPage, /* OUT: The page number of the next page */
+ u32 *piFrame /* OUT: Wal frame index of next page */
+){
+ u32 iMin; /* Result pgno must be greater than iMin */
+ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
+ int i; /* For looping through segments */
+
+ iMin = p->iPrior;
+ assert( iMin<0xffffffff );
+ for(i=p->nSegment-1; i>=0; i--){
+ struct WalSegment *pSegment = &p->aSegment[i];
+ while( pSegment->iNext<pSegment->nEntry ){
+ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
+ if( iPg>iMin ){
+ if( iPg<iRet ){
+ iRet = iPg;
+ *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
+ }
+ break;
+ }
+ pSegment->iNext++;
+ }
+ }
+
+ *piPage = p->iPrior = iRet;
+ return (iRet==0xFFFFFFFF);
+}
+
+/*
+** This function merges two sorted lists into a single sorted list.
+*/
+static void walMerge(
+ u32 *aContent, /* Pages in wal */
+ ht_slot *aLeft, /* IN: Left hand input list */
+ int nLeft, /* IN: Elements in array *paLeft */
+ ht_slot **paRight, /* IN/OUT: Right hand input list */
+ int *pnRight, /* IN/OUT: Elements in *paRight */
+ ht_slot *aTmp /* Temporary buffer */
+){
+ int iLeft = 0; /* Current index in aLeft */
+ int iRight = 0; /* Current index in aRight */
+ int iOut = 0; /* Current index in output buffer */
+ int nRight = *pnRight;
+ ht_slot *aRight = *paRight;
+
+ assert( nLeft>0 && nRight>0 );
+ while( iRight<nRight || iLeft<nLeft ){
+ ht_slot logpage;
+ Pgno dbpage;
+
+ if( (iLeft<nLeft)
+ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
+ ){
+ logpage = aLeft[iLeft++];
+ }else{
+ logpage = aRight[iRight++];
+ }
+ dbpage = aContent[logpage];
+
+ aTmp[iOut++] = logpage;
+ if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
+
+ assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
+ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+ }
+
+ *paRight = aLeft;
+ *pnRight = iOut;
+ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
+}
+
+/*
+** Sort the elements in list aList, removing any duplicates.
+*/
+static void walMergesort(
+ u32 *aContent, /* Pages in wal */
+ ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
+ ht_slot *aList, /* IN/OUT: List to sort */
+ int *pnList /* IN/OUT: Number of elements in aList[] */
+){
+ struct Sublist {
+ int nList; /* Number of elements in aList */
+ ht_slot *aList; /* Pointer to sub-list content */
+ };
+
+ const int nList = *pnList; /* Size of input list */
+ int nMerge = 0; /* Number of elements in list aMerge */
+ ht_slot *aMerge = 0; /* List to be merged */
+ int iList; /* Index into input list */
+ int iSub = 0; /* Index into aSub array */
+ struct Sublist aSub[13]; /* Array of sub-lists */
+
+ memset(aSub, 0, sizeof(aSub));
+ assert( nList<=HASHTABLE_NPAGE && nList>0 );
+ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
+
+ for(iList=0; iList<nList; iList++){
+ nMerge = 1;
+ aMerge = &aList[iList];
+ for(iSub=0; iList & (1<<iSub); iSub++){
+ struct Sublist *p = &aSub[iSub];
+ assert( p->aList && p->nList<=(1<<iSub) );
+ assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ aSub[iSub].aList = aMerge;
+ aSub[iSub].nList = nMerge;
+ }
+
+ for(iSub++; iSub<ArraySize(aSub); iSub++){
+ if( nList & (1<<iSub) ){
+ struct Sublist *p = &aSub[iSub];
+ assert( p->nList<=(1<<iSub) );
+ assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ }
+ assert( aMerge==aList );
+ *pnList = nMerge;
+
+#ifdef SQLITE_DEBUG
+ {
+ int i;
+ for(i=1; i<*pnList; i++){
+ assert( aContent[aList[i]] > aContent[aList[i-1]] );
+ }
+ }
+#endif
+}
+
+/*
+** Free an iterator allocated by walIteratorInit().
+*/
+static void walIteratorFree(WalIterator *p){
+ sqlite3ScratchFree(p);
+}
+
+/*
+** Construct a WalInterator object that can be used to loop over all
+** pages in the WAL in ascending order. The caller must hold the checkpoint
+**
+** On success, make *pp point to the newly allocated WalInterator object
+** return SQLITE_OK. Otherwise, return an error code. If this routine
+** returns an error, the value of *pp is undefined.
+**
+** The calling routine should invoke walIteratorFree() to destroy the
+** WalIterator object when it has finished with it.
+*/
+static int walIteratorInit(Wal *pWal, WalIterator **pp){
+ WalIterator *p; /* Return value */
+ int nSegment; /* Number of segments to merge */
+ u32 iLast; /* Last frame in log */
+ int nByte; /* Number of bytes to allocate */
+ int i; /* Iterator variable */
+ ht_slot *aTmp; /* Temp space used by merge-sort */
+ int rc = SQLITE_OK; /* Return Code */
+
+ /* This routine only runs while holding the checkpoint lock. And
+ ** it only runs if there is actually content in the log (mxFrame>0).
+ */
+ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+ iLast = pWal->hdr.mxFrame;
+
+ /* Allocate space for the WalIterator object. */
+ nSegment = walFramePage(iLast) + 1;
+ nByte = sizeof(WalIterator)
+ + (nSegment-1)*sizeof(struct WalSegment)
+ + iLast*sizeof(ht_slot);
+ p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+ if( !p ){
+ return SQLITE_NOMEM;
+ }
+ memset(p, 0, nByte);
+ p->nSegment = nSegment;
+
+ /* Allocate temporary space used by the merge-sort routine. This block
+ ** of memory will be freed before this function returns.
+ */
+ aTmp = (ht_slot *)sqlite3ScratchMalloc(
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
+ if( !aTmp ){
+ rc = SQLITE_NOMEM;
+ }
+
+ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
+ volatile ht_slot *aHash;
+ u32 iZero;
+ volatile u32 *aPgno;
+
+ rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+ if( rc==SQLITE_OK ){
+ int j; /* Counter variable */
+ int nEntry; /* Number of entries in this segment */
+ ht_slot *aIndex; /* Sorted index for this segment */
+
+ aPgno++;
+ nEntry = (int)(((i+1)==nSegment)?(int)(iLast-iZero):(u32 *)aHash-(u32 *)aPgno);
+ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
+ iZero++;
+
+ for(j=0; j<nEntry; j++){
+ aIndex[j] = (ht_slot)j;
+ }
+ walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
+ p->aSegment[i].iZero = iZero;
+ p->aSegment[i].nEntry = nEntry;
+ p->aSegment[i].aIndex = aIndex;
+ p->aSegment[i].aPgno = (u32 *)aPgno;
+ }
+ }
+ sqlite3ScratchFree(aTmp);
+
+ if( rc!=SQLITE_OK ){
+ walIteratorFree(p);
+ }
+ *pp = p;
+ return rc;
+}
+
+/*
+** Copy as much content as we can from the WAL back into the database file
+** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+**
+** The amount of information copies from WAL to database might be limited
+** by active readers. This routine will never overwrite a database page
+** that a concurrent reader might be using.
+**
+** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
+** checkpoints are always run by a background thread or background
+** process, foreground threads will never block on a lengthy fsync call.
+**
+** Fsync is called on the WAL before writing content out of the WAL and
+** into the database. This ensures that if the new content is persistent
+** in the WAL and can be recovered following a power-loss or hard reset.
+**
+** Fsync is also called on the database file if (and only if) the entire
+** WAL content is copied into the database file. This second fsync makes
+** it safe to delete the WAL since the new content will persist in the
+** database file.
+**
+** This routine uses and updates the nBackfill field of the wal-index header.
+** This is the only routine tha will increase the value of nBackfill.
+** (A WAL reset or recovery will revert nBackfill to zero, but not increase
+** its value.)
+**
+** The caller must be holding sufficient locks to ensure that no other
+** checkpoint is running (in any other thread or process) at the same
+** time.
+*/
+static int walCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int sync_flags, /* Flags for OsSync() (or 0) */
+ int nBuf, /* Size of zBuf in bytes */
+ u8 *zBuf /* Temporary buffer to use */
+){
+ int rc; /* Return code */
+ int szPage = pWal->hdr.szPage; /* Database page-size */
+ WalIterator *pIter = 0; /* Wal iterator context */
+ u32 iDbpage = 0; /* Next database page to write */
+ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
+ u32 mxSafeFrame; /* Max frame that can be backfilled */
+ int i; /* Loop counter */
+ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
+
+ if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
+
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( pIter );
+
+ /*** TODO: Move this test out to the caller. Make it an assert() here ***/
+ if( pWal->hdr.szPage!=nBuf ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto walcheckpoint_out;
+ }
+
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+ ** safe to write into the database. Frames beyond mxSafeFrame might
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
+ */
+ mxSafeFrame = pWal->hdr.mxFrame;
+ pInfo = walCkptInfo(pWal);
+ for(i=1; i<WAL_NREADER; i++){
+ u32 y = pInfo->aReadMark[i];
+ if( mxSafeFrame>=y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ }else{
+ goto walcheckpoint_out;
+ }
+ }
+ }
+
+ if( pInfo->nBackfill<mxSafeFrame
+ && (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK
+ ){
+ u32 nBackfill = pInfo->nBackfill;
+
+ /* Sync the WAL to disk */
+ if( sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
+
+ /* Iterate through the contents of the WAL, copying data to the db file. */
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ i64 iOffset;
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame ) continue;
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ iOffset = (iDbpage-1)*(i64)szPage;
+ testcase( IS_BIG_INT(iOffset) );
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ }
+
+ /* If work was actually accomplished... */
+ if( rc==SQLITE_OK ){
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
+ testcase( IS_BIG_INT(szDb) );
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+ if( rc==SQLITE_OK && sync_flags ){
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInfo->nBackfill = mxSafeFrame;
+ }
+ }
+
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }else if( rc==SQLITE_BUSY ){
+ /* Reset the return code so as not to report a checkpoint failure
+ ** just because active readers prevent any backfill.
+ */
+ rc = SQLITE_OK;
+ }
+
+ walcheckpoint_out:
+ walIteratorFree(pIter);
+ return rc;
+}
+
+/*
+** Close a connection to a log file.
+*/
+SQLITE_PRIVATE int sqlite3WalClose(
+ Wal *pWal, /* Wal to close */
+ int sync_flags, /* Flags to pass to OsSync() (or 0) */
+ int nBuf,
+ u8 *zBuf /* Buffer of at least nBuf bytes */
+){
+ int rc = SQLITE_OK;
+ if( pWal ){
+ int isDelete = 0; /* True to unlink wal and wal-index files */
+
+ /* If an EXCLUSIVE lock can be obtained on the database file (using the
+ ** ordinary, rollback-mode locking methods, this guarantees that the
+ ** connection associated with this log file is the only connection to
+ ** the database. In this case checkpoint the database and unlink both
+ ** the wal and wal-index files.
+ **
+ ** The EXCLUSIVE lock is not released before returning.
+ */
+ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ pWal->exclusiveMode = 1;
+ rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ if( rc==SQLITE_OK ){
+ isDelete = 1;
+ }
+ }
+
+ walIndexClose(pWal, isDelete);
+ sqlite3OsClose(pWal->pWalFd);
+ if( isDelete ){
+ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+ }
+ WALTRACE(("WAL%p: closed\n", pWal));
+ sqlite3_free((void *)pWal->apWiData);
+ sqlite3_free(pWal);
+ }
+ return rc;
+}
+
+/*
+** Try to read the wal-index header. Return 0 on success and 1 if
+** there is a problem.
+**
+** The wal-index is in shared memory. Another thread or process might
+** be writing the header at the same time this procedure is trying to
+** read it, which might result in inconsistency. A dirty read is detected
+** by verifying that both copies of the header are the same and also by
+** a checksum on the header.
+**
+** If and only if the read is consistent and the header is different from
+** pWal->hdr, then pWal->hdr is updated to the content of the new header
+** and *pChanged is set to 1.
+**
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
+*/
+static int walIndexTryHdr(Wal *pWal, int *pChanged){
+ u32 aCksum[2]; /* Checksum on the header content */
+ WalIndexHdr h1, h2; /* Two copies of the header content */
+ WalIndexHdr volatile *aHdr; /* Header in shared memory */
+
+ /* The first page of the wal-index must be mapped at this point. */
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+
+ /* Read the header. This might happen currently with a write to the
+ ** same area of shared memory on a different CPU in a SMP,
+ ** meaning it is possible that an inconsistent snapshot is read
+ ** from the file. If this happens, return non-zero.
+ **
+ ** There are two copies of the header at the beginning of the wal-index.
+ ** When reading, read [0] first then [1]. Writes are in the reverse order.
+ ** Memory barriers are used to prevent the compiler or the hardware from
+ ** reordering the reads and writes.
+ */
+ aHdr = walIndexHdr(pWal);
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
+
+ if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+ return 1; /* Dirty read */
+ }
+ if( h1.isInit==0 ){
+ return 1; /* Malformed header - probably all zeros */
+ }
+ walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
+ if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
+ return 1; /* Checksum does not match */
+ }
+
+ if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+ *pChanged = 1;
+ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
+ pWal->szPage = pWal->hdr.szPage;
+ }
+
+ /* The header was successfully read. Return zero. */
+ return 0;
+}
+
+/*
+** Read the wal-index header from the wal-index and into pWal->hdr.
+** If the wal-header appears to be corrupt, try to reconstruct the
+** wal-index from the WAL before returning.
+**
+** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
+** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK.
+** Otherwise an SQLite error code.
+*/
+static int walIndexReadHdr(Wal *pWal, int *pChanged){
+ int rc; /* Return code */
+ int badHdr; /* True if a header read failed */
+ volatile u32 *page0; /* Chunk of wal-index containing header */
+
+ /* Ensure that page 0 of the wal-index (the page that contains the
+ ** wal-index header) is mapped. Return early if an error occurs here.
+ */
+ assert( pChanged );
+ rc = walIndexPage(pWal, 0, &page0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ };
+ assert( page0 || pWal->writeLock==0 );
+
+ /* If the first page of the wal-index has been mapped, try to read the
+ ** wal-index header immediately, without holding any lock. This usually
+ ** works, but may fail if the wal-index header is corrupt or currently
+ ** being modified by another thread or process.
+ */
+ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+
+ /* If the first attempt failed, it might have been due to a race
+ ** with a writer. So get a WRITE lock and try again.
+ */
+ assert( badHdr==0 || pWal->writeLock==0 );
+ if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ pWal->writeLock = 1;
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+ badHdr = walIndexTryHdr(pWal, pChanged);
+ if( badHdr ){
+ /* If the wal-index header is still malformed even while holding
+ ** a WRITE lock, it can only mean that the header is corrupted and
+ ** needs to be reconstructed. So run recovery to do exactly that.
+ */
+ rc = walIndexRecover(pWal);
+ *pChanged = 1;
+ }
+ }
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ }
+
+ /* If the header is read successfully, check the version number to make
+ ** sure the wal-index was not constructed with some future format that
+ ** this version of SQLite cannot understand.
+ */
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+
+ return rc;
+}
+
+/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY (-1)
+
+/*
+** Attempt to start a read transaction. This might fail due to a race or
+** other transient condition. When that happens, it returns WAL_RETRY to
+** indicate to the caller that it is safe to retry immediately.
+**
+** On success return SQLITE_OK. On a permanent failure (such an
+** I/O error or an SQLITE_BUSY because another process is running
+** recovery) return a positive error code.
+**
+** The useWal parameter is true to force the use of the WAL and disable
+** the case where the WAL is bypassed because it has been completely
+** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
+** to make a copy of the wal-index header into pWal->hdr. If the
+** wal-index header has changed, *pChanged is set to 1 (as an indication
+** to the caller that the local paget cache is obsolete and needs to be
+** flushed.) When useWal==1, the wal-index header is assumed to already
+** be loaded and the pChanged parameter is unused.
+**
+** The caller must set the cnt parameter to the number of prior calls to
+** this routine during the current read attempt that returned WAL_RETRY.
+** This routine will start taking more aggressive measures to clear the
+** race conditions after multiple WAL_RETRY returns, and after an excessive
+** number of errors will ultimately return SQLITE_PROTOCOL. The
+** SQLITE_PROTOCOL return indicates that some other process has gone rogue
+** and is not honoring the locking protocol. There is a vanishingly small
+** chance that SQLITE_PROTOCOL could be returned because of a run of really
+** bad luck when there is lots of contention for the wal-index, but that
+** possibility is so small that it can be safely neglected, we believe.
+**
+** On success, this routine obtains a read lock on
+** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
+** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
+** that means the Wal does not hold any read lock. The reader must not
+** access any database page that is modified by a WAL frame up to and
+** including frame number aReadMark[pWal->readLock]. The reader will
+** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
+** Or if pWal->readLock==0, then the reader will ignore the WAL
+** completely and get all content directly from the database file.
+** If the useWal parameter is 1 then the WAL will never be ignored and
+** this routine will always set pWal->readLock>0 on success.
+** When the read transaction is completed, the caller must release the
+** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
+**
+** This routine uses the nBackfill and aReadMark[] fields of the header
+** to select a particular WAL_READ_LOCK() that strives to let the
+** checkpoint process do as much work as possible. This routine might
+** update values of the aReadMark[] array in the header, but if it does
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
+*/
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pWal->readLock<0 ); /* Not currently locked */
+
+ /* Take steps to avoid spinning forever if there is a protocol error. */
+ if( cnt>5 ){
+ if( cnt>100 ) return SQLITE_PROTOCOL;
+ sqlite3OsSleep(pWal->pVfs, 1);
+ }
+
+ if( !useWal ){
+ rc = walIndexReadHdr(pWal, pChanged);
+ if( rc==SQLITE_BUSY ){
+ /* If there is not a recovery running in another thread or process
+ ** then convert BUSY errors to WAL_RETRY. If recovery is known to
+ ** be running, convert BUSY to BUSY_RECOVERY. There is a race here
+ ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
+ ** would be technically correct. But the race is benign since with
+ ** WAL_RETRY this routine will be called again and will probably be
+ ** right on the second iteration.
+ */
+ rc = walLockShared(pWal, WAL_RECOVER_LOCK);
+ if( rc==SQLITE_OK ){
+ walUnlockShared(pWal, WAL_RECOVER_LOCK);
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = SQLITE_BUSY_RECOVERY;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+
+ pInfo = walCkptInfo(pWal);
+ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+ /* The WAL has been completely backfilled (or it is empty).
+ ** and can be safely ignored.
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ if( rc==SQLITE_OK ){
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
+ ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** happening, this is usually correct.
+ **
+ ** However, if frames have been appended to the log (or if the log
+ ** is wrapped and written for that matter) before the READ_LOCK(0)
+ ** is obtained, that is not necessarily true. A checkpointer may
+ ** have started to backfill the appended frames but crashed before
+ ** it finished. Leaving a corrupt image in the database file.
+ */
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ return WAL_RETRY;
+ }
+ pWal->readLock = 0;
+ return SQLITE_OK;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+
+ /* If we get this far, it means that the reader will want to use
+ ** the WAL to get at content from recent commits. The job now is
+ ** to select one of the aReadMark[] entries that is closest to
+ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+ */
+ mxReadMark = 0;
+ mxI = 0;
+ for(i=1; i<WAL_NREADER; i++){
+ u32 thisMark = pInfo->aReadMark[i];
+ if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
+ mxI = i;
+ }
+ }
+ if( mxI==0 ){
+ /* If we get here, it means that all of the aReadMark[] entries between
+ ** 1 and WAL_NREADER-1 are zero. Try to initialize aReadMark[1] to
+ ** be mxFrame, then retry.
+ */
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), 1);
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = WAL_RETRY;
+ }
+ return rc;
+ }else{
+ if( mxReadMark < pWal->hdr.mxFrame ){
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+ }
+
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** This does not guarantee that the copy of the wal-index header is up to
+ ** date before proceeding. That would not be possible without somehow
+ ** blocking writers. It only guarantees that a dangerous checkpoint or
+ ** log-wrap (either of which would require an exclusive lock on
+ ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+ */
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ if( pInfo->aReadMark[mxI]!=mxReadMark
+ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
+ }
+ return rc;
+}
+
+/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time. The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning. The
+** Pager layer will use this to know that is cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc; /* Return code */
+ int cnt = 0; /* Number of TryBeginRead attempts */
+
+ do{
+ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ }while( rc==WAL_RETRY );
+ return rc;
+}
+
+/*
+** Finish with a read transaction. All this does is release the
+** read-lock.
+*/
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+ if( pWal->readLock>=0 ){
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->readLock = -1;
+ }
+}
+
+/*
+** Read a page from the WAL, if it is present in the WAL and if the
+** current read transaction is configured to use the WAL.
+**
+** The *pInWal is set to 1 if the requested page is in the WAL and
+** has been loaded. Or *pInWal is set to 0 if the page was not in
+** the WAL and needs to be read out of the database.
+*/
+SQLITE_PRIVATE int sqlite3WalRead(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ int *pInWal, /* OUT: True if data is read from WAL */
+ int nOut, /* Size of buffer pOut in bytes */
+ u8 *pOut /* Buffer to write page data to */
+){
+ u32 iRead = 0; /* If !=0, WAL frame to return data from */
+ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
+ int iHash; /* Used to loop through N hash tables */
+
+ /* This routine is only be called from within a read transaction. */
+ assert( pWal->readLock>=0 || pWal->lockError );
+
+ /* If the "last page" field of the wal-index header snapshot is 0, then
+ ** no data will be read from the wal under any circumstances. Return early
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
+ ** then the WAL is ignored by the reader so return early, as if the
+ ** WAL were empty.
+ */
+ if( iLast==0 || pWal->readLock==0 ){
+ *pInWal = 0;
+ return SQLITE_OK;
+ }
+
+ /* Search the hash table or tables for an entry matching page number
+ ** pgno. Each iteration of the following for() loop searches one
+ ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
+ **
+ ** This code might run concurrently to the code in walIndexAppend()
+ ** that adds entries to the wal-index (and possibly to this hash
+ ** table). This means the value just read from the hash
+ ** slot (aHash[iKey]) may have been added before or after the
+ ** current read transaction was opened. Values added after the
+ ** read transaction was opened may have been written incorrectly -
+ ** i.e. these slots may contain garbage data. However, we assume
+ ** that any slots written before the current read transaction was
+ ** opened remain unmodified.
+ **
+ ** For the reasons above, the if(...) condition featured in the inner
+ ** loop of the following block is more stringent that would be required
+ ** if we had exclusive access to the hash-table:
+ **
+ ** (aPgno[iFrame]==pgno):
+ ** This condition filters out normal hash-table collisions.
+ **
+ ** (iFrame<=iLast):
+ ** This condition filters out entries that were added to the hash
+ ** table after the current read-transaction had started.
+ */
+ for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+ volatile ht_slot *aHash; /* Pointer to hash table */
+ volatile u32 *aPgno; /* Pointer to array of page numbers */
+ u32 iZero; /* Frame number corresponding to aPgno[0] */
+ int iKey; /* Hash slot index */
+ int rc;
+
+ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+ u32 iFrame = aHash[iKey] + iZero;
+ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+ assert( iFrame>iRead );
+ iRead = iFrame;
+ }
+ }
+ }
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* If expensive assert() statements are available, do a linear search
+ ** of the wal-index file content. Make sure the results agree with the
+ ** result obtained using the hash indexes above. */
+ {
+ u32 iRead2 = 0;
+ u32 iTest;
+ for(iTest=iLast; iTest>0; iTest--){
+ if( walFramePgno(pWal, iTest)==pgno ){
+ iRead2 = iTest;
+ break;
+ }
+ }
+ assert( iRead==iRead2 );
+ }
+#endif
+
+ /* If iRead is non-zero, then it is the log frame number that contains the
+ ** required page. Read and return data from the log file.
+ */
+ if( iRead ){
+ i64 iOffset = walFrameOffset(iRead, pWal->hdr.szPage) + WAL_FRAME_HDRSIZE;
+ *pInWal = 1;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+ return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset);
+ }
+
+ *pInWal = 0;
+ return SQLITE_OK;
+}
+
+
+/*
+** Set *pPgno to the size of the database file (or zero, if unknown).
+*/
+SQLITE_PRIVATE void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno){
+ assert( pWal->readLock>=0 || pWal->lockError );
+ *pPgno = pWal->hdr.nPage;
+}
+
+
+/*
+** This function starts a write transaction on the WAL.
+**
+** A read transaction must have already been started by a prior call
+** to sqlite3WalBeginReadTransaction().
+**
+** If another thread or process has written into the database since
+** the read transaction was started, then it is not possible for this
+** thread to write as doing so would cause a fork. So this routine
+** returns SQLITE_BUSY in that case and no write transaction is started.
+**
+** There can only be a single writer active at a time.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+ int rc;
+
+ /* Cannot start a write transaction without first holding a read
+ ** transaction. */
+ assert( pWal->readLock>=0 );
+
+ /* Only one writer allowed at a time. Get the write lock. Return
+ ** SQLITE_BUSY if unable.
+ */
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ if( rc ){
+ return rc;
+ }
+ pWal->writeLock = 1;
+
+ /* If another connection has written to the database file since the
+ ** time the read transaction on this connection was started, then
+ ** the write is disallowed.
+ */
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ rc = SQLITE_BUSY;
+ }
+
+ return rc;
+}
+
+/*
+** End a write transaction. The commit has already been done. This
+** routine merely releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ return SQLITE_OK;
+}
+
+/*
+** If any data has been written (but not committed) to the log file, this
+** function moves the write-pointer back to the start of the transaction.
+**
+** Additionally, the callback function is invoked for each frame written
+** to the WAL since the start of the transaction. If the callback returns
+** other than SQLITE_OK, it is not invoked again and the error code is
+** returned to the caller.
+**
+** Otherwise, if the callback function does not return an error, this
+** function returns SQLITE_OK.
+*/
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+ int rc = SQLITE_OK;
+ if( pWal->writeLock ){
+ Pgno iMax = pWal->hdr.mxFrame;
+ Pgno iFrame;
+
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
+ */
+ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ for(iFrame=pWal->hdr.mxFrame+1;
+ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+ iFrame++
+ ){
+ /* This call cannot fail. Unless the page for which the page number
+ ** is passed as the second argument is (a) in the cache and
+ ** (b) has an outstanding reference, then xUndo is either a no-op
+ ** (if (a) is false) or simply expels the page from the cache (if (b)
+ ** is false).
+ **
+ ** If the upper layer is doing a rollback, it is guaranteed that there
+ ** are no outstanding references to any page other than page 1. And
+ ** page 1 is never written to the log until the transaction is
+ ** committed. As a result, the call to xUndo may not fail.
+ */
+ assert( walFramePgno(pWal, iFrame)!=1 );
+ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ }
+ walCleanupHash(pWal);
+ }
+ assert( rc==SQLITE_OK );
+ return rc;
+}
+
+/*
+** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
+** values. This function populates the array with values required to
+** "rollback" the write position of the WAL handle back to the current
+** point in the event of a savepoint rollback (via WalSavepointUndo()).
+*/
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
+ assert( pWal->writeLock );
+ aWalData[0] = pWal->hdr.mxFrame;
+ aWalData[1] = pWal->hdr.aFrameCksum[0];
+ aWalData[2] = pWal->hdr.aFrameCksum[1];
+ aWalData[3] = pWal->nCkpt;
+}
+
+/*
+** Move the write position of the WAL back to the point identified by
+** the values in the aWalData[] array. aWalData must point to an array
+** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
+** by a call to WalSavepoint().
+*/
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
+ int rc = SQLITE_OK;
+
+ assert( pWal->writeLock );
+ assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+
+ if( aWalData[3]!=pWal->nCkpt ){
+ /* This savepoint was opened immediately after the write-transaction
+ ** was started. Right after that, the writer decided to wrap around
+ ** to the start of the log. Update the savepoint values to match.
+ */
+ aWalData[0] = 0;
+ aWalData[3] = pWal->nCkpt;
+ }
+
+ if( aWalData[0]<pWal->hdr.mxFrame ){
+ pWal->hdr.mxFrame = aWalData[0];
+ pWal->hdr.aFrameCksum[0] = aWalData[1];
+ pWal->hdr.aFrameCksum[1] = aWalData[2];
+ walCleanupHash(pWal);
+ }
+
+ return rc;
+}
+
+/*
+** This function is called just before writing a set of frames to the log
+** file (see sqlite3WalFrames()). It checks to see if, instead of appending
+** to the current log file, it is possible to overwrite the start of the
+** existing log file with the new frames (i.e. "reset" the log). If so,
+** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
+** unchanged.
+**
+** SQLITE_OK is returned if no error is encountered (regardless of whether
+** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
+** if some error
+*/
+static int walRestartLog(Wal *pWal){
+ int rc = SQLITE_OK;
+ int cnt;
+
+ if( pWal->readLock==0 ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
+ if( pInfo->nBackfill>0 ){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ if( rc==SQLITE_OK ){
+ /* If all readers are using WAL_READ_LOCK(0) (in other words if no
+ ** readers are currently using the WAL), then the transactions
+ ** frames will overwrite the start of the existing log. Update the
+ ** wal-index header to reflect this.
+ **
+ ** In theory it would be Ok to update the cache of the header only
+ ** at this point. But updating the actual wal-index header is also
+ ** safe and means there is no special case for sqlite3WalUndo()
+ ** to handle if this transaction is rolled back.
+ */
+ int i; /* Loop counter */
+ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+ pWal->nCkpt++;
+ pWal->hdr.mxFrame = 0;
+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+ sqlite3_randomness(4, &aSalt[1]);
+ walIndexWriteHdr(pWal);
+ pInfo->nBackfill = 0;
+ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ assert( pInfo->aReadMark[0]==0 );
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ }
+ }
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ pWal->readLock = -1;
+ cnt = 0;
+ do{
+ int notUsed;
+ rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
+ }while( rc==WAL_RETRY );
+ }
+ return rc;
+}
+
+/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+*/
+SQLITE_PRIVATE int sqlite3WalFrames(
+ Wal *pWal, /* Wal handle to write to */
+ int szPage, /* Database page-size in bytes */
+ PgHdr *pList, /* List of dirty pages to write */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Used to catch return codes */
+ u32 iFrame; /* Next frame address */
+ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+ PgHdr *p; /* Iterator to run through pList with. */
+ PgHdr *pLast = 0; /* Last frame in list */
+ int nLast = 0; /* Number of extra copies of last page */
+
+ assert( pList );
+ assert( pWal->writeLock );
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
+ WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+ pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+ }
+#endif
+
+ /* See if it is possible to write these frames into the start of the
+ ** log file, instead of appending to it at pWal->hdr.mxFrame.
+ */
+ if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+ return rc;
+ }
+
+ /* If this is the first frame written into the log, write the WAL
+ ** header to the start of the WAL file. See comments at the top of
+ ** this source file for a description of the WAL header format.
+ */
+ iFrame = pWal->hdr.mxFrame;
+ if( iFrame==0 ){
+ u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
+ u32 aCksum[2]; /* Checksum for wal-header */
+
+ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
+ sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
+ sqlite3Put4byte(&aWalHdr[8], szPage);
+ sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
+ memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+ walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+ sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+ sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+
+ pWal->szPage = (u16)szPage;
+ pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+ pWal->hdr.aFrameCksum[0] = aCksum[0];
+ pWal->hdr.aFrameCksum[1] = aCksum[1];
+
+ rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
+ WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+ assert( pWal->szPage==szPage );
+
+ /* Write the log file. */
+ for(p=pList; p; p=p->pDirty){
+ u32 nDbsize; /* Db-size field for frame header */
+ i64 iOffset; /* Write offset in log file */
+ void *pData;
+
+ iOffset = walFrameOffset(++iFrame, szPage);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+
+ /* Populate and write the frame header */
+ nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
+#else
+ pData = p->pData;
+#endif
+ walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ /* Write the page data */
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset+sizeof(aFrame));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pLast = p;
+ }
+
+ /* Sync the log file if the 'isSync' flag was specified. */
+ if( sync_flags ){
+ i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
+ i64 iOffset = walFrameOffset(iFrame+1, szPage);
+
+ assert( isCommit );
+ assert( iSegment>0 );
+
+ iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
+ while( iOffset<iSegment ){
+ void *pData;
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
+#else
+ pData = pLast->pData;
+#endif
+ walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ iOffset += WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nLast++;
+ iOffset += szPage;
+ }
+
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
+
+ /* Append data to the wal-index. It is not necessary to lock the
+ ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+ ** guarantees that there are no other writers, and no data that may
+ ** be in use by existing readers is being overwritten.
+ */
+ iFrame = pWal->hdr.mxFrame;
+ for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+ iFrame++;
+ rc = walIndexAppend(pWal, iFrame, p->pgno);
+ }
+ while( nLast>0 && rc==SQLITE_OK ){
+ iFrame++;
+ nLast--;
+ rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Update the private copy of the header. */
+ pWal->hdr.szPage = (u16)szPage;
+ pWal->hdr.mxFrame = iFrame;
+ if( isCommit ){
+ pWal->hdr.iChange++;
+ pWal->hdr.nPage = nTruncate;
+ }
+ /* If this is a commit, update the wal-index header too. */
+ if( isCommit ){
+ walIndexWriteHdr(pWal);
+ pWal->iCallback = iFrame;
+ }
+ }
+
+ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+ return rc;
+}
+
+/*
+** This routine is called to implement sqlite3_wal_checkpoint() and
+** related interfaces.
+**
+** Obtain a CHECKPOINT lock and then backfill as much information as
+** we can from WAL into the database.
+*/
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of temporary buffer */
+ u8 *zBuf /* Temporary buffer to use */
+){
+ int rc; /* Return code */
+ int isChanged = 0; /* True if a new wal-index header is loaded */
+
+ assert( pWal->ckptLock==0 );
+
+ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ if( rc ){
+ /* Usually this is SQLITE_BUSY meaning that another thread or process
+ ** is already running a checkpoint, or maybe a recovery. But it might
+ ** also be SQLITE_IOERR. */
+ return rc;
+ }
+ pWal->ckptLock = 1;
+
+ /* Copy data from the log to the database file. */
+ rc = walIndexReadHdr(pWal, &isChanged);
+ if( rc==SQLITE_OK ){
+ rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ }
+ if( isChanged ){
+ /* If a new wal-index header was loaded before the checkpoint was
+ ** performed, then the pager-cache associated with pWal is now
+ ** out of date. So zero the cached wal-index header to ensure that
+ ** next time the pager opens a snapshot on this database it knows that
+ ** the cache needs to be reset.
+ */
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+ }
+
+ /* Release the locks. */
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ pWal->ckptLock = 0;
+ WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+ return rc;
+}
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called. If no commits have occurred since
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+ u32 ret = 0;
+ if( pWal ){
+ ret = pWal->iCallback;
+ pWal->iCallback = 0;
+ }
+ return (int)ret;
+}
+
+/*
+** This function is called to change the WAL subsystem into or out
+** of locking_mode=EXCLUSIVE.
+**
+** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+** into locking_mode=NORMAL. This means that we must acquire a lock
+** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
+** or if the acquisition of the lock fails, then return 0. If the
+** transition out of exclusive-mode is successful, return 1. This
+** operation must occur while the pager is still holding the exclusive
+** lock on the main database file.
+**
+** If op is one, then change from locking_mode=NORMAL into
+** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
+** be released. Return 1 if the transition is made and 0 if the
+** WAL is already in exclusive-locking mode - meaning that this
+** routine is a no-op. The pager must already hold the exclusive lock
+** on the main database file before invoking this operation.
+**
+** If op is negative, then do a dry-run of the op==1 case but do
+** not actually change anything. The pager uses this to see if it
+** should acquire the database exclusive lock prior to invoking
+** the op==1 case.
+*/
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+ int rc;
+ assert( pWal->writeLock==0 );
+
+ /* pWal->readLock is usually set, but might be -1 if there was a
+ ** prior error while attempting to acquire are read-lock. This cannot
+ ** happen if the connection is actually in exclusive mode (as no xShmLock
+ ** locks are taken in this case). Nor should the pager attempt to
+ ** upgrade to exclusive-mode following such an error.
+ */
+ assert( pWal->readLock>=0 || pWal->lockError );
+ assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+
+ if( op==0 ){
+ if( pWal->exclusiveMode ){
+ pWal->exclusiveMode = 0;
+ if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+ pWal->exclusiveMode = 1;
+ }
+ rc = pWal->exclusiveMode==0;
+ }else{
+ /* Already in locking_mode=NORMAL */
+ rc = 0;
+ }
+ }else if( op>0 ){
+ assert( pWal->exclusiveMode==0 );
+ assert( pWal->readLock>=0 );
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->exclusiveMode = 1;
+ rc = 1;
+ }else{
+ rc = pWal->exclusiveMode==0;
+ }
+ return rc;
+}
+
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
+/************** End of wal.c *************************************************/
/************** Begin file btmutex.c *****************************************/
/*
** 2007 August 27
@@ -37207,6 +42834,8 @@
MemPage *pPage1; /* First page of the database */
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
+ u8 secureDelete; /* True if secure_delete is enabled */
+ u8 initiallyEmpty; /* Database is empty at start of transaction */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
@@ -37218,7 +42847,9 @@
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
u8 inTransaction; /* Transaction state */
+ u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
int nTransaction; /* Number of open transactions (read + write) */
+ u32 nPage; /* Number of pages in the database */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
@@ -38299,11 +43930,8 @@
static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
int rc = SQLITE_OK;
if( !pBt->pHasContent ){
- int nPage = 100;
- sqlite3PagerPagecount(pBt->pPager, &nPage);
- /* If sqlite3PagerPagecount() fails there is no harm because the
- ** nPage variable is unchanged from its default value of 100 */
- pBt->pHasContent = sqlite3BitvecCreate((u32)nPage);
+ assert( pgno<=pBt->nPage );
+ pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM;
}
@@ -39030,11 +44658,11 @@
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( size>=0 ); /* Minimum cell size is 4 */
-#ifdef SQLITE_SECURE_DELETE
- /* Overwrite deleted information with zeros when the SECURE_DELETE
- ** option is enabled at compile-time */
- memset(&data[start], 0, size);
-#endif
+ if( pPage->pBt->secureDelete ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[start], 0, size);
+ }
/* Add the space back into the linked list of freeblocks. Note that
** even though the freeblock list was checked by btreeInitPage(),
@@ -39266,9 +44894,9 @@
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
-#ifdef SQLITE_SECURE_DELETE
- memset(&data[hdr], 0, pBt->usableSize - hdr);
-#endif
+ if( pBt->secureDelete ){
+ memset(&data[hdr], 0, pBt->usableSize - hdr);
+ }
data[hdr] = (char)flags;
first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0);
memset(&data[hdr+1], 0, 4);
@@ -39346,13 +44974,13 @@
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
-static Pgno pagerPagecount(BtShared *pBt){
- int nPage = -1;
- int rc;
- assert( pBt->pPage1 );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- assert( rc==SQLITE_OK || nPage==-1 );
- return (Pgno)nPage;
+static Pgno btreePagecount(BtShared *pBt){
+ return pBt->nPage;
+}
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
+ assert( sqlite3BtreeHoldsMutex(p) );
+ assert( ((p->pBt->nPage)&0x8000000)==0 );
+ return (int)btreePagecount(p->pBt);
}
/*
@@ -39369,25 +44997,22 @@
MemPage **ppPage /* Write the page pointer here */
){
int rc;
- TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = btreeGetPage(pBt, pgno, ppPage, 0);
- if( rc==SQLITE_OK ){
- rc = btreeInitPage(*ppPage);
- if( rc!=SQLITE_OK ){
- releasePage(*ppPage);
+ if( pgno>btreePagecount(pBt) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeGetPage(pBt, pgno, ppPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = btreeInitPage(*ppPage);
+ if( rc!=SQLITE_OK ){
+ releasePage(*ppPage);
+ }
}
}
- /* If the requested page number was either 0 or greater than the page
- ** number of the last page in the database, this function should return
- ** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this
- ** is the case. */
- assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK );
testcase( pgno==0 );
- testcase( pgno==iLastPg );
-
+ assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
}
@@ -39588,6 +45213,9 @@
pBt->pCursor = 0;
pBt->pPage1 = 0;
pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
+#ifdef SQLITE_SECURE_DELETE
+ pBt->secureDelete = 1;
+#endif
pBt->pageSize = get2byte(&zDbHeader[16]);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@@ -39944,6 +45572,23 @@
sqlite3BtreeLeave(p);
return n;
}
+
+/*
+** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1,
+** then make no changes. Always return the value of the secureDelete
+** setting after the change.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
+ int b;
+ if( p==0 ) return 0;
+ sqlite3BtreeEnter(p);
+ if( newFlag>=0 ){
+ p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
+ }
+ b = p->pBt->secureDelete;
+ sqlite3BtreeLeave(p);
+ return b;
+}
#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
/*
@@ -40003,9 +45648,11 @@
** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
- int rc;
- MemPage *pPage1;
- int nPage;
+ int rc; /* Result code from subfunctions */
+ MemPage *pPage1; /* Page 1 of the database file */
+ int nPage; /* Number of pages in the database */
+ int nPageFile = 0; /* Number of pages in the database file */
+ int nPageHeader; /* Number of pages in the database according to hdr */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pBt->pPage1==0 );
@@ -40017,10 +45664,14 @@
/* Do some checking to help insure the file we opened really is
** a valid database file.
*/
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK ){
+ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
+ if( (rc = sqlite3PagerPagecount(pBt->pPager, &nPageFile))!=SQLITE_OK ){;
goto page1_init_failed;
- }else if( nPage>0 ){
+ }
+ if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
+ nPage = nPageFile;
+ }
+ if( nPage>0 ){
int pageSize;
int usableSize;
u8 *page1 = pPage1->aData;
@@ -40028,12 +45679,42 @@
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
+
+#ifdef SQLITE_OMIT_WAL
if( page1[18]>1 ){
pBt->readOnly = 1;
}
if( page1[19]>1 ){
goto page1_init_failed;
}
+#else
+ if( page1[18]>2 ){
+ pBt->readOnly = 1;
+ }
+ if( page1[19]>2 ){
+ goto page1_init_failed;
+ }
+
+ /* If the write version is set to 2, this database should be accessed
+ ** in WAL mode. If the log is not already open, open it now. Then
+ ** return SQLITE_OK and return without populating BtShared.pPage1.
+ ** The caller detects this and calls this function again. This is
+ ** required as the version of page 1 currently in the page1 buffer
+ ** may not be the latest version - there may be a newer one in the log
+ ** file.
+ */
+ if( page1[19]==2 && pBt->doNotUseWAL==0 ){
+ int isOpen = 0;
+ rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
+ if( rc!=SQLITE_OK ){
+ goto page1_init_failed;
+ }else if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
+ }
+ rc = SQLITE_NOTADB;
+ }
+#endif
/* The maximum embedded fraction must be exactly 25%. And the minimum
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
@@ -40066,6 +45747,10 @@
pageSize-usableSize);
return rc;
}
+ if( nPageHeader>nPageFile ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto page1_init_failed;
+ }
if( usableSize<480 ){
goto page1_init_failed;
}
@@ -40096,17 +45781,12 @@
pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
+ pBt->nPage = nPage;
return SQLITE_OK;
page1_init_failed:
releasePage(pPage1);
pBt->pPage1 = 0;
- // Begin Android-add
- if (rc == SQLITE_NOTADB) {
- // the file-header is bad. assume that it got corrupted and return "corruption error"
- rc = SQLITE_CORRUPT_BKPT;
- }
- // End Android-add
return rc;
}
@@ -40139,12 +45819,10 @@
MemPage *pP1;
unsigned char *data;
int rc;
- int nPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK || nPage>0 ){
- return rc;
+ if( pBt->nPage>0 ){
+ return SQLITE_OK;
}
pP1 = pBt->pPage1;
assert( pP1!=0 );
@@ -40170,6 +45848,8 @@
put4byte(&data[36 + 4*4], pBt->autoVacuum);
put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
+ pBt->nPage = 1;
+ data[31] = 1;
return SQLITE_OK;
}
@@ -40259,6 +45939,7 @@
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
+ pBt->initiallyEmpty = (u8)(pBt->nPage==0);
do {
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
@@ -40283,7 +45964,7 @@
if( rc!=SQLITE_OK ){
unlockBtreeIfUnused(pBt);
}
- }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
+ }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
if( rc==SQLITE_OK ){
@@ -40538,12 +46219,12 @@
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
Pgno nFreeList; /* Number of pages still on the free-list */
+ int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( iLastPg>nFin );
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
- int rc;
u8 eType;
Pgno iPtrPage;
@@ -40619,7 +46300,7 @@
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
MemPage *pPg;
- int rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
+ rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -40632,6 +46313,7 @@
iLastPg--;
}
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
+ pBt->nPage = iLastPg;
}
return SQLITE_OK;
}
@@ -40654,7 +46336,11 @@
rc = SQLITE_DONE;
}else{
invalidateAllOverflowCache(pBt);
- rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
+ rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+ }
}
sqlite3BtreeLeave(p);
return rc;
@@ -40685,7 +46371,7 @@
int nEntry; /* Number of entries on one ptrmap page */
Pgno nOrig; /* Database size before freeing */
- nOrig = pagerPagecount(pBt);
+ nOrig = btreePagecount(pBt);
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
/* It is not possible to create a database for which the final page
** is either a pointer-map page or the pending-byte page. If one
@@ -40710,11 +46396,12 @@
rc = incrVacuumStep(pBt, nFin, iFree);
}
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
- rc = SQLITE_OK;
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
+ put4byte(&pBt->pPage1->aData[28], nFin);
sqlite3PagerTruncateImage(pBt->pPager, nFin);
+ pBt->nPage = nFin;
}
if( rc!=SQLITE_OK ){
sqlite3PagerRollback(pPager);
@@ -40964,6 +46651,11 @@
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
+ int nPage = get4byte(28+(u8*)pPage1->aData);
+ testcase( nPage==0 );
+ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
+ testcase( pBt->nPage!=nPage );
+ pBt->nPage = nPage;
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -41001,17 +46693,13 @@
assert( pBt->readOnly==0 );
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
- if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
- rc = SQLITE_INTERNAL;
- }else{
- assert( pBt->inTransaction==TRANS_WRITE );
- /* At the pager level, a statement transaction is a savepoint with
- ** an index greater than all savepoints created explicitly using
- ** SQL statements. It is illegal to open, release or rollback any
- ** such savepoints while the statement transaction savepoint is active.
- */
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
- }
+ assert( pBt->inTransaction==TRANS_WRITE );
+ /* At the pager level, a statement transaction is a savepoint with
+ ** an index greater than all savepoints created explicitly using
+ ** SQL statements. It is illegal to open, release or rollback any
+ ** such savepoints while the statement transaction savepoint is active.
+ */
+ rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
sqlite3BtreeLeave(p);
return rc;
}
@@ -41037,7 +46725,12 @@
sqlite3BtreeEnter(p);
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
if( rc==SQLITE_OK ){
+ if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
rc = newDatabase(pBt);
+ pBt->nPage = get4byte(28 + pBt->pPage1->aData);
+ if( pBt->nPage==0 ){
+ sqlite3PagerPagecount(pBt->pPager, (int*)&pBt->nPage);
+ }
}
sqlite3BtreeLeave(p);
}
@@ -41103,7 +46796,7 @@
if( NEVER(wrFlag && pBt->readOnly) ){
return SQLITE_READONLY;
}
- if( iTable==1 && pagerPagecount(pBt)==0 ){
+ if( iTable==1 && btreePagecount(pBt)==0 ){
return SQLITE_EMPTY;
}
@@ -41374,7 +47067,7 @@
iGuess++;
}
- if( iGuess<=pagerPagecount(pBt) ){
+ if( iGuess<=btreePagecount(pBt) ){
rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
next = iGuess;
@@ -41969,7 +47662,6 @@
if( pCur->eState==CURSOR_INVALID ){
assert( pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
- rc = SQLITE_OK;
}else{
assert( pCur->apPage[pCur->iPage]->nCell>0 );
*pRes = 0;
@@ -42406,7 +48098,7 @@
assert( sqlite3_mutex_held(pBt->mutex) );
pPage1 = pBt->pPage1;
- mxPage = pagerPagecount(pBt);
+ mxPage = btreePagecount(pBt);
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -42602,35 +48294,35 @@
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
- int nPage = pagerPagecount(pBt);
- *pPgno = nPage + 1;
-
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
- (*pPgno)++;
- }
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc ) return rc;
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
+ if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){
/* If *pPgno refers to a pointer-map page, allocate two new pages
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
- assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, &pPg, 0);
+ TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
}
if( rc ) return rc;
- (*pPgno)++;
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; }
}
#endif
+ put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
+ *pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, ppPage, 0);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -42693,17 +48385,17 @@
nFree = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], nFree+1);
-#ifdef SQLITE_SECURE_DELETE
- /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
- ** always fully overwrite deleted information with zeros.
- */
- if( (!pPage && (rc = btreeGetPage(pBt, iPage, &pPage, 0)))
- || (rc = sqlite3PagerWrite(pPage->pDbPage))
- ){
- goto freepage_out;
+ if( pBt->secureDelete ){
+ /* If the secure_delete option is enabled, then
+ ** always fully overwrite deleted information with zeros.
+ */
+ if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
+ || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
+ ){
+ goto freepage_out;
+ }
+ memset(pPage->aData, 0, pPage->pBt->pageSize);
}
- memset(pPage->aData, 0, pPage->pBt->pageSize);
-#endif
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
@@ -42754,11 +48446,9 @@
if( rc==SQLITE_OK ){
put4byte(&pTrunk->aData[4], nLeaf+1);
put4byte(&pTrunk->aData[8+nLeaf*4], iPage);
-#ifndef SQLITE_SECURE_DELETE
- if( pPage ){
+ if( pPage && !pBt->secureDelete ){
sqlite3PagerDontWrite(pPage->pDbPage);
}
-#endif
rc = btreeSetHasContent(pBt, iPage);
}
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
@@ -42822,7 +48512,7 @@
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
- if( ovflPgno<2 || ovflPgno>pagerPagecount(pBt) ){
+ if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
/* 0 is not a legal page number and page 1 cannot be an
** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
@@ -42832,7 +48522,25 @@
rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext);
if( rc ) return rc;
}
- rc = freePage2(pBt, pOvfl, ovflPgno);
+
+ if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
+ && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
+ ){
+ /* There is no reason any cursor should have an outstanding reference
+ ** to an overflow page belonging to a cell that is being deleted/updated.
+ ** So if there exists more than one reference to this page, then it
+ ** must not really be an overflow page and the database must be corrupt.
+ ** It is helpful to detect this before calling freePage2(), as
+ ** freePage2() may zero the page contents if secure-delete mode is
+ ** enabled. If this 'overflow' page happens to be a page that the
+ ** caller is iterating through or using in some other way, this
+ ** can be problematic.
+ */
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = freePage2(pBt, pOvfl, ovflPgno);
+ }
+
if( pOvfl ){
sqlite3PagerUnref(pOvfl->pDbPage);
}
@@ -43076,7 +48784,7 @@
Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
int *pRC /* Read and write return code from here */
){
- int idx; /* Where to write new cell content in data[] */
+ int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
int end; /* First byte past the last cell pointer in data[] */
int ins; /* Index in data[] where new cell pointer is inserted */
@@ -43567,10 +49275,17 @@
** In this case, temporarily copy the cell into the aOvflSpace[]
** buffer. It will be copied out again as soon as the aSpace[] buffer
** is allocated. */
-#ifdef SQLITE_SECURE_DELETE
- memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]);
- apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
-#endif
+ if( pBt->secureDelete ){
+ int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
+ if( (iOff+szNew[i])>pBt->usableSize ){
+ rc = SQLITE_CORRUPT_BKPT;
+ memset(apOld, 0, (i+1)*sizeof(MemPage*));
+ goto balance_cleanup;
+ }else{
+ memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]);
+ apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
+ }
+ }
dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc);
}
}
@@ -44629,8 +50344,14 @@
releasePage(pRoot);
return rc;
}
+
+ /* When the new root page was allocated, page 1 was made writable in
+ ** order either to increase the database filesize, or to decrement the
+ ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
+ */
+ assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) );
rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
- if( rc ){
+ if( NEVER(rc) ){
releasePage(pRoot);
return rc;
}
@@ -44670,7 +50391,7 @@
int i;
assert( sqlite3_mutex_held(pBt->mutex) );
- if( pgno>pagerPagecount(pBt) ){
+ if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -45421,7 +51142,7 @@
nRef = sqlite3PagerRefcount(pBt->pPager);
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = pagerPagecount(sCheck.pBt);
+ sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
@@ -45690,6 +51411,42 @@
}
#endif
+/*
+** Set both the "read version" (single byte at byte offset 18) and
+** "write version" (single byte at byte offset 19) fields in the database
+** header to iVersion.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
+ BtShared *pBt = pBtree->pBt;
+ int rc; /* Return code */
+
+ assert( pBtree->inTrans==TRANS_NONE );
+ assert( iVersion==1 || iVersion==2 );
+
+ /* If setting the version fields to 1, do not automatically open the
+ ** WAL connection, even if the version fields are currently set to 2.
+ */
+ pBt->doNotUseWAL = (u8)(iVersion==1);
+
+ rc = sqlite3BtreeBeginTrans(pBtree, 0);
+ if( rc==SQLITE_OK ){
+ u8 *aData = pBt->pPage1->aData;
+ if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
+ rc = sqlite3BtreeBeginTrans(pBtree, 2);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc==SQLITE_OK ){
+ aData[18] = (u8)iVersion;
+ aData[19] = (u8)iVersion;
+ }
+ }
+ }
+ }
+
+ pBt->doNotUseWAL = 0;
+ return rc;
+}
+
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -45909,7 +51666,7 @@
/* Catch the case where the destination is an in-memory database and the
** page sizes of the source and destination differ.
*/
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
+ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
rc = SQLITE_READONLY;
}
@@ -45979,6 +51736,9 @@
*/
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
+ int destMode; /* Destination journal mode */
+ int pgszSrc = 0; /* Source page size */
+ int pgszDest = 0; /* Destination page size */
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
@@ -46019,13 +51779,21 @@
rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
bCloseTrans = 1;
}
+
+ /* Do not allow backup if the destination database is in WAL mode
+ ** and the page sizes are different between source and destination */
+ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
+ pgszDest = sqlite3BtreeGetPageSize(p->pDest);
+ destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
+ if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ rc = SQLITE_READONLY;
+ }
/* Now that there is a read-lock on the source database, query the
** source pager for the number of pages in the database.
*/
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage);
- }
+ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
+ assert( nSrcPage>=0 );
for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
@@ -46056,8 +51824,6 @@
if( rc==SQLITE_DONE
&& (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
){
- const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
- const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
int nDestTruncate;
if( p->pDestDb ){
@@ -46076,18 +51842,20 @@
** journalled by PagerCommitPhaseOne() before they are destroyed
** by the file truncation.
*/
- if( nSrcPagesize<nDestPagesize ){
- int ratio = nDestPagesize/nSrcPagesize;
+ assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
+ assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
+ if( pgszSrc<pgszDest ){
+ int ratio = pgszDest/pgszSrc;
nDestTruncate = (nSrcPage+ratio-1)/ratio;
if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
nDestTruncate--;
}
}else{
- nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
+ nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
- if( nSrcPagesize<nDestPagesize ){
+ if( pgszSrc<pgszDest ){
/* If the source page-size is smaller than the destination page-size,
** two extra things may need to happen:
**
@@ -46097,31 +51865,31 @@
** pending-byte page in the source database may need to be
** copied into the destination database.
*/
- const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
+ const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
assert( pFile );
- assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
+ assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
- && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
+ && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
&& SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
&& SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
){
i64 iOff;
- i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
+ i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
for(
- iOff=PENDING_BYTE+nSrcPagesize;
+ iOff=PENDING_BYTE+pgszSrc;
rc==SQLITE_OK && iOff<iEnd;
- iOff+=nSrcPagesize
+ iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
- const Pgno iSrcPg = (Pgno)((iOff/nSrcPagesize)+1);
+ const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
- rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
+ rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
}
sqlite3PagerUnref(pSrcPg);
}
@@ -46150,6 +51918,9 @@
assert( rc2==SQLITE_OK );
}
+ if( rc==SQLITE_IOERR_NOMEM ){
+ rc = SQLITE_NOMEM;
+ }
p->rc = rc;
}
if( p->pDestDb ){
@@ -46636,6 +52407,10 @@
** before attempting the conversion.
*/
static i64 doubleToInt64(double r){
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ /* When floating-point is omitted, double and int64 are the same thing */
+ return r;
+#else
/*
** Many compilers we encounter do not define constants for the
** minimum and maximum 64-bit integers, or they define them
@@ -46657,6 +52432,7 @@
}else{
return (i64)r;
}
+#endif
}
/*
@@ -46784,21 +52560,26 @@
/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
+**
+** Every effort is made to force the conversion, even if the input
+** is a string that does not look completely like a number. Convert
+** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
- double r1, r2;
- i64 i;
+ int rc;
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- r1 = sqlite3VdbeRealValue(pMem);
- i = doubleToInt64(r1);
- r2 = (double)i;
- if( r1==r2 ){
- sqlite3VdbeMemIntegerify(pMem);
+ rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
+ if( rc ) return rc;
+ rc = sqlite3VdbeMemNulTerminate(pMem);
+ if( rc ) return rc;
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
+ MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->r = r1;
+ pMem->r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
+ sqlite3VdbeIntegerAffinity(pMem);
}
return SQLITE_OK;
}
@@ -46850,6 +52631,7 @@
pMem->type = SQLITE_INTEGER;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type REAL.
@@ -46864,6 +52646,7 @@
pMem->type = SQLITE_FLOAT;
}
}
+#endif
/*
** Delete any previous value and set the value of pMem to be an
@@ -46918,7 +52701,7 @@
sqlite3VdbeMemReleaseExternal(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->xDel = 0;
- if( (pFrom->flags&MEM_Dyn)!=0 || pFrom->z==pFrom->zMalloc ){
+ if( (pFrom->flags&MEM_Static)==0 ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
assert( srcType==MEM_Ephem || srcType==MEM_Static );
pTo->flags |= srcType;
@@ -47324,9 +53107,16 @@
return SQLITE_OK;
}
op = pExpr->op;
- if( op==TK_REGISTER ){
- op = pExpr->op2; /* This only happens with SQLITE_ENABLE_STAT2 */
- }
+
+ /* op can only be TK_REGISTER is we have compiled with SQLITE_ENABLE_STAT2.
+ ** The ifdef here is to enable us to achieve 100% branch test coverage even
+ ** when SQLITE_ENABLE_STAT2 is omitted.
+ */
+#ifdef SQLITE_ENABLE_STAT2
+ if( op==TK_REGISTER ) op = pExpr->op2;
+#else
+ if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+#endif
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
pVal = sqlite3ValueNew(db);
@@ -47489,7 +53279,7 @@
*/
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
- return (p->isPrepareV2 ? p->zSql : 0);
+ return (p && p->isPrepareV2) ? p->zSql : 0;
}
/*
@@ -48166,7 +53956,7 @@
pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
u8 *aSortOrder;
- memcpy(pKeyInfo, zP4, nByte);
+ memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
@@ -48237,9 +54027,12 @@
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
-** is readable and writable, but it has no effect. The return of a dummy
-** opcode allows the call to continue functioning after a OOM fault without
-** having to check to see if the return from this routine is a valid pointer.
+** is readable but not writable, though it is cast to a writable value.
+** The return of a dummy opcode allows the call to continue functioning
+** after a OOM fault without having to check to see if the return from
+** this routine is a valid pointer. But because the dummy.opcode is 0,
+** dummy will never be written to. This is verified by code inspection and
+** by running with Valgrind.
**
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
@@ -48250,17 +54043,19 @@
** check the value of p->nOp-1 before continuing.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
- static VdbeOp dummy;
+ /* C89 specifies that the constant "dummy" will be initialized to all
+ ** zeros, which is correct. MSVC generates a warning, nevertheless. */
+ static const VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->magic==VDBE_MAGIC_INIT );
if( addr<0 ){
#ifdef SQLITE_OMIT_TRACE
- if( p->nOp==0 ) return &dummy;
+ if( p->nOp==0 ) return (VdbeOp*)&dummy;
#endif
addr = p->nOp - 1;
}
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
- return &dummy;
+ return (VdbeOp*)&dummy;
}else{
return &p->aOp[addr];
}
@@ -48373,6 +54168,11 @@
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
+**
+** The prepared statement has to know in advance which Btree objects
+** will be used so that it can acquire mutexes on them all in sorted
+** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
+** in order (and released in reverse order) to avoid deadlocks.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
int mask;
@@ -48872,6 +54672,7 @@
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->iStatement = 0;
+ p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
{
int i;
@@ -49550,15 +55351,27 @@
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
- ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
- ** code to the new value.
+ ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
+ ** current statement error code.
+ **
+ ** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
+ ** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
+ ** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
+ ** the following code.
*/
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
- if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
- p->rc = rc;
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( rc ){
+ assert( eStatementOp==SAVEPOINT_ROLLBACK );
+ if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
+ p->rc = rc;
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
+ invalidateCursorsOnModifiedBtrees(db);
+ sqlite3RollbackAll(db);
+ sqlite3CloseSavepoints(db);
+ db->autoCommit = 1;
}
}
@@ -49760,6 +55573,7 @@
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p->pFree);
+ p->db = 0;
sqlite3DbFree(db, p);
}
@@ -50843,6 +56657,27 @@
}
/*
+** This function is called after a transaction has been committed. It
+** invokes callbacks registered with sqlite3_wal_hook() as required.
+*/
+static int doWalCallbacks(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_WAL
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
**
@@ -50857,21 +56692,23 @@
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
- sqlite3_log(SQLITE_MISUSE,
- "attempt to step a halted statement: [%s]", p->zSql);
- return SQLITE_MISUSE_BKPT;
+ /* We used to require that sqlite3_reset() be called before retrying
+ ** sqlite3_step() after any error. But after 3.6.23, we changed this
+ ** so that sqlite3_reset() would be called automatically instead of
+ ** throwing the error.
+ */
+ sqlite3_reset((sqlite3_stmt*)p);
}
- /* Assert that malloc() has not failed */
+ /* Check that malloc() has not failed. If it has, return early. */
db = p->db;
if( db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
if( p->pc<=0 && p->expired ){
- if( p->rc==SQLITE_OK ){
- p->rc = SQLITE_SCHEMA;
- }
+ p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
goto end_of_step;
}
@@ -50888,9 +56725,7 @@
#ifndef SQLITE_OMIT_TRACE
if( db->xProfile && !db->init.busy ){
- double rNow;
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}
#endif
@@ -50911,16 +56746,20 @@
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
- double rNow;
- u64 elapseTime;
-
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
- elapseTime -= p->startTime;
- db->xProfile(db->pProfileArg, p->zSql, elapseTime);
+ sqlite3_int64 iNow;
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
+ db->xProfile(db->pProfileArg, p->zSql, iNow - p->startTime);
}
#endif
+ if( rc==SQLITE_DONE ){
+ assert( p->rc==SQLITE_OK );
+ p->rc = doWalCallbacks(db);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ }
+ }
+
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
@@ -50970,7 +56809,7 @@
sqlite3_reset(pStmt);
v->expired = 0;
}
- if( rc2!=SQLITE_OK && v->isPrepareV2 && db->pErr ){
+ if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
@@ -52174,17 +58013,30 @@
static void applyNumericAffinity(Mem *pRec){
if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
int realnum;
+ u8 enc = pRec->enc;
sqlite3VdbeMemNulTerminate(pRec);
- if( (pRec->flags&MEM_Str)
- && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
+ if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
i64 value;
- sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
- if( !realnum && sqlite3Atoi64(pRec->z, &value) ){
+ char *zUtf8 = pRec->z;
+#ifndef SQLITE_OMIT_UTF16
+ if( enc!=SQLITE_UTF8 ){
+ assert( pRec->db );
+ zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
+ if( !zUtf8 ) return;
+ }
+#endif
+ if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
pRec->u.i = value;
MemSetTypeFlag(pRec, MEM_Int);
}else{
- sqlite3VdbeMemRealify(pRec);
+ sqlite3AtoF(zUtf8, &pRec->r);
+ MemSetTypeFlag(pRec, MEM_Real);
}
+#ifndef SQLITE_OMIT_UTF16
+ if( enc!=SQLITE_UTF8 ){
+ sqlite3DbFree(pRec->db, zUtf8);
+ }
+#endif
}
}
}
@@ -52491,22 +58343,6 @@
#define CHECK_FOR_INTERRUPT \
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
-#ifdef SQLITE_DEBUG
-static int fileExists(sqlite3 *db, const char *zFile){
- int res = 0;
- int rc = SQLITE_OK;
-#ifdef SQLITE_TEST
- /* If we are currently testing IO errors, then do not call OsAccess() to
- ** test for the presence of zFile. This is because any IO error that
- ** occurs here will not be reported, causing the test to fail.
- */
- extern int sqlite3_io_error_pending;
- if( sqlite3_io_error_pending<=0 )
-#endif
- rc = sqlite3OsAccess(db->pVfs, zFile, SQLITE_ACCESS_EXISTS, &res);
- return (res && rc==SQLITE_OK);
-}
-#endif
#ifndef NDEBUG
/*
@@ -52562,7 +58398,7 @@
SQLITE_PRIVATE int sqlite3VdbeExec(
Vdbe *p /* The VDBE */
){
- int pc; /* The program counter */
+ int pc=0; /* The program counter */
Op *aOp = p->aOp; /* Copy of p->aOp */
Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */
@@ -52597,9 +58433,6 @@
int pcDest;
} aa;
struct OP_Variable_stack_vars {
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
} ab;
struct OP_Move_stack_vars {
@@ -52636,6 +58469,8 @@
struct OP_Ge_stack_vars {
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
+ u16 flags1; /* Copy of initial value of pIn1->flags */
+ u16 flags3; /* Copy of initial value of pIn3->flags */
} ai;
struct OP_Compare_stack_vars {
int n;
@@ -52922,18 +58757,25 @@
struct OP_AggFinal_stack_vars {
Mem *pMem;
} cc;
+ struct OP_JournalMode_stack_vars {
+ Btree *pBt; /* Btree to change journal mode of */
+ Pager *pPager; /* Pager associated with pBt */
+ int eNew; /* New journal mode */
+ int eOld; /* The old journal mode */
+ const char *zFilename; /* Name of database file for pPager */
+ } cd;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
- } cd;
+ } ce;
struct OP_VBegin_stack_vars {
VTable *pVTab;
- } ce;
+ } cf;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
- } cf;
+ } cg;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
@@ -52946,23 +58788,23 @@
int res;
int i;
Mem **apArg;
- } cg;
+ } ch;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
- } ch;
+ } ci;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
- } ci;
+ } cj;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
- } cj;
+ } ck;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
@@ -52971,11 +58813,6 @@
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
- } ck;
- struct OP_Pagecount_stack_vars {
- int p1;
- int nPage;
- Pager *pPager;
} cl;
struct OP_Trace_stack_vars {
char *zTrace;
@@ -53003,9 +58840,7 @@
#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
- if( p->pc==0
- && ((p->db->flags & SQLITE_VdbeListing) || fileExists(db, "vdbe_explain"))
- ){
+ if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
int i;
printf("VDBE Program Listing:\n");
sqlite3VdbePrintSql(p);
@@ -53013,9 +58848,6 @@
sqlite3VdbePrintOp(stdout, i, &aOp[i]);
}
}
- if( fileExists(db, "vdbe_trace") ){
- p->trace = stdout;
- }
sqlite3EndBenignMalloc();
#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){
@@ -53037,13 +58869,6 @@
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
- if( p->trace==0 && pc==0 ){
- sqlite3BeginBenignMalloc();
- if( fileExists(db, "vdbe_sqltrace") ){
- sqlite3VdbePrintSql(p);
- }
- sqlite3EndBenignMalloc();
- }
#endif
@@ -53311,6 +59136,7 @@
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* Opcode: Real * P2 * P4 *
**
** P4 is a pointer to a 64-bit floating point value.
@@ -53322,6 +59148,7 @@
pOut->r = *pOp->p4.pReal;
break;
}
+#endif
/* Opcode: String8 * P2 * P4 *
**
@@ -53398,40 +59225,25 @@
break;
}
-/* Opcode: Variable P1 P2 P3 P4 *
+/* Opcode: Variable P1 P2 * P4 *
**
-** Transfer the values of bound parameters P1..P1+P3-1 into registers
-** P2..P2+P3-1.
+** Transfer the values of bound parameter P1 into register P2
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
-case OP_Variable: {
+case OP_Variable: { /* out2-prerelease */
#if 0 /* local variables moved into u.ab */
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
#endif /* local variables moved into u.ab */
- u.ab.p1 = pOp->p1 - 1;
- u.ab.p2 = pOp->p2;
- u.ab.n = pOp->p3;
- assert( u.ab.p1>=0 && u.ab.p1+u.ab.n<=p->nVar );
- assert( u.ab.p2>=1 && u.ab.p2+u.ab.n-1<=p->nMem );
- assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
-
- while( u.ab.n-- > 0 ){
- u.ab.pVar = &p->aVar[u.ab.p1++];
- if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
- goto too_big;
- }
- pOut = &aMem[u.ab.p2++];
- sqlite3VdbeMemReleaseExternal(pOut);
- pOut->flags = MEM_Null;
- sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
- UPDATE_MAX_BLOBSIZE(pOut);
+ assert( pOp->p1>0 && pOp->p1<=p->nVar );
+ u.ab.pVar = &p->aVar[pOp->p1 - 1];
+ if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
+ goto too_big;
}
+ sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -53732,6 +59544,10 @@
break;
}
}
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ pOut->u.i = u.af.rB;
+ MemSetTypeFlag(pOut, MEM_Int);
+#else
if( sqlite3IsNaN(u.af.rB) ){
goto arithmetic_result_is_null;
}
@@ -53740,6 +59556,7 @@
if( (u.af.flags & MEM_Real)==0 ){
sqlite3VdbeIntegerAffinity(pOut);
}
+#endif
}
break;
@@ -53799,7 +59616,7 @@
for(u.ag.i=0; u.ag.i<u.ag.n; u.ag.i++, u.ag.pArg++){
u.ag.apVal[u.ag.i] = u.ag.pArg;
sqlite3VdbeMemStoreType(u.ag.pArg);
- REGISTER_TRACE(pOp->p2, u.ag.pArg);
+ REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
@@ -53962,6 +59779,7 @@
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* Opcode: RealAffinity P1 * * * *
**
** If register P1 holds an integer convert it to a real value.
@@ -53978,6 +59796,7 @@
}
break;
}
+#endif
#ifndef SQLITE_OMIT_CAST
/* Opcode: ToText P1 * * * *
@@ -54061,7 +59880,7 @@
break;
}
-#ifndef SQLITE_OMIT_CAST
+#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Opcode: ToReal P1 * * * *
**
** Force the value in register P1 to be a floating point number.
@@ -54078,7 +59897,7 @@
}
break;
}
-#endif /* SQLITE_OMIT_CAST */
+#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
/* Opcode: Lt P1 P2 P3 P4 P5
**
@@ -54161,10 +59980,14 @@
#if 0 /* local variables moved into u.ai */
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
+ u16 flags1; /* Copy of initial value of pIn1->flags */
+ u16 flags3; /* Copy of initial value of pIn3->flags */
#endif /* local variables moved into u.ai */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
+ u.ai.flags1 = pIn1->flags;
+ u.ai.flags3 = pIn3->flags;
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
/* One or both operands are NULL */
if( pOp->p5 & SQLITE_NULLEQ ){
@@ -54219,6 +60042,10 @@
}else if( u.ai.res ){
pc = pOp->p2-1;
}
+
+ /* Undo any changes made by applyAffinity() to the input registers. */
+ pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.ai.flags1&MEM_TypeMask);
+ pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.ai.flags3&MEM_TypeMask);
break;
}
@@ -55506,10 +61333,10 @@
**
** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
-** the main database is read-only. The transient or virtual
+** the main database is read-only. The ephemeral
** table is deleted automatically when the cursor is closed.
**
-** P2 is the number of columns in the virtual table.
+** P2 is the number of columns in the ephemeral table.
** The cursor points to a BTree table if P4==0 and to a BTree index
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
@@ -55520,6 +61347,14 @@
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/
+/* Opcode: OpenAutoindex P1 P2 * P4 *
+**
+** This opcode works the same as OP_OpenEphemeral. It has a
+** different name to distinguish its use. Tables created using
+** by this opcode will be used for automatically created transient
+** indices in joins.
+*/
+case OP_OpenAutoindex:
case OP_OpenEphemeral: {
#if 0 /* local variables moved into u.ax */
VdbeCursor *pCx;
@@ -55574,7 +61409,7 @@
** register P2. In other words, cursor P1 becomes an alias for the
** MEM_Blob content contained in register P2.
**
-** A pseudo-table created by this opcode is used to hold the a single
+** A pseudo-table created by this opcode is used to hold a single
** row output from the sorter so that the row can be decomposed into
** individual columns using the OP_Column opcode. The OP_Column opcode
** is the only cursor opcode that works with a pseudo-table.
@@ -56641,14 +62476,13 @@
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bl.pC = p->apCsr[pOp->p1];
assert( u.bl.pC!=0 );
+ u.bl.res = 1;
if( (u.bl.pCrsr = u.bl.pC->pCursor)!=0 ){
rc = sqlite3BtreeFirst(u.bl.pCrsr, &u.bl.res);
u.bl.pC->atFirst = u.bl.res==0 ?1:0;
u.bl.pC->deferredMoveto = 0;
u.bl.pC->cacheStatus = CACHE_STALE;
u.bl.pC->rowidIsValid = 0;
- }else{
- u.bl.res = 1;
}
u.bl.pC->nullRow = (u8)u.bl.res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
@@ -56658,7 +62492,7 @@
break;
}
-/* Opcode: Next P1 P2 * * *
+/* Opcode: Next P1 P2 * * P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
@@ -56667,9 +62501,12 @@
**
** The P1 cursor must be for a real table, not a pseudo-table.
**
+** If P5 is positive and the jump is taken, then event counter
+** number P5-1 in the prepared statement is incremented.
+**
** See also: Prev
*/
-/* Opcode: Prev P1 P2 * * *
+/* Opcode: Prev P1 P2 * * P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
@@ -56677,6 +62514,9 @@
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.
+**
+** If P5 is positive and the jump is taken, then event counter
+** number P5-1 in the prepared statement is incremented.
*/
case OP_Prev: /* jump */
case OP_Next: { /* jump */
@@ -56688,6 +62528,7 @@
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p5<=ArraySize(p->aCounter) );
u.bm.pC = p->apCsr[pOp->p1];
if( u.bm.pC==0 ){
break; /* See ticket #2273 */
@@ -57084,7 +62925,7 @@
u.bu.initData.iDb = pOp->p1;
u.bu.initData.pzErrMsg = &p->zErrMsg;
u.bu.zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
+ "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
db->aDb[u.bu.iDb].zName, u.bu.zMaster, pOp->p4.z);
if( u.bu.zSql==0 ){
rc = SQLITE_NOMEM;
@@ -57673,6 +63514,147 @@
break;
}
+#ifndef SQLITE_OMIT_WAL
+/* Opcode: Checkpoint P1 * * * *
+**
+** Checkpoint database P1. This is a no-op if P1 is not currently in
+** WAL mode.
+*/
+case OP_Checkpoint: {
+ rc = sqlite3Checkpoint(db, pOp->p1);
+ break;
+};
+#endif
+
+#ifndef SQLITE_OMIT_PRAGMA
+/* Opcode: JournalMode P1 P2 P3 * P5
+**
+** Change the journal mode of database P1 to P3. P3 must be one of the
+** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
+** modes (delete, truncate, persist, off and memory), this is a simple
+** operation. No IO is required.
+**
+** If changing into or out of WAL mode the procedure is more complicated.
+**
+** Write a string containing the final journal-mode to register P2.
+**
+** If an attempt to change in to or out of WAL mode fails because another
+** connection also has the same database open, then an SQLITE_BUSY error
+** is raised if P5==0, or of P5!=0 the journal mode changed is skipped
+** without signaling the error.
+*/
+case OP_JournalMode: { /* out2-prerelease */
+#if 0 /* local variables moved into u.cd */
+ Btree *pBt; /* Btree to change journal mode of */
+ Pager *pPager; /* Pager associated with pBt */
+ int eNew; /* New journal mode */
+ int eOld; /* The old journal mode */
+ const char *zFilename; /* Name of database file for pPager */
+#endif /* local variables moved into u.cd */
+
+ u.cd.eNew = pOp->p3;
+ assert( u.cd.eNew==PAGER_JOURNALMODE_DELETE
+ || u.cd.eNew==PAGER_JOURNALMODE_TRUNCATE
+ || u.cd.eNew==PAGER_JOURNALMODE_PERSIST
+ || u.cd.eNew==PAGER_JOURNALMODE_OFF
+ || u.cd.eNew==PAGER_JOURNALMODE_MEMORY
+ || u.cd.eNew==PAGER_JOURNALMODE_WAL
+ || u.cd.eNew==PAGER_JOURNALMODE_QUERY
+ );
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+
+ /* This opcode is used in two places: PRAGMA journal_mode and ATTACH.
+ ** In PRAGMA journal_mode, the sqlite3VdbeUsesBtree() routine is called
+ ** when the statment is prepared and so p->aMutex.nMutex>0. All mutexes
+ ** are already acquired. But when used in ATTACH, sqlite3VdbeUsesBtree()
+ ** is not called when the statement is prepared because it requires the
+ ** iDb index of the database as a parameter, and the database has not
+ ** yet been attached so that index is unavailable. We have to wait
+ ** until runtime (now) to get the mutex on the newly attached database.
+ ** No other mutexes are required by the ATTACH command so this is safe
+ ** to do.
+ */
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 || p->aMutex.nMutex==0 );
+ if( p->aMutex.nMutex==0 ){
+ /* This occurs right after ATTACH. Get a mutex on the newly ATTACHed
+ ** database. */
+ sqlite3VdbeUsesBtree(p, pOp->p1);
+ sqlite3VdbeMutexArrayEnter(p);
+ }
+
+ u.cd.pBt = db->aDb[pOp->p1].pBt;
+ u.cd.pPager = sqlite3BtreePager(u.cd.pBt);
+ u.cd.eOld = sqlite3PagerGetJournalMode(u.cd.pPager);
+ if( u.cd.eNew==PAGER_JOURNALMODE_QUERY ) u.cd.eNew = u.cd.eOld;
+ if( !sqlite3PagerOkToChangeJournalMode(u.cd.pPager) ) u.cd.eNew = u.cd.eOld;
+
+#ifndef SQLITE_OMIT_WAL
+ u.cd.zFilename = sqlite3PagerFilename(u.cd.pPager);
+
+ /* Do not allow a transition to journal_mode=WAL for a database
+ ** in temporary storage or if the VFS does not support xShmOpen.
+ */
+ if( u.cd.eNew==PAGER_JOURNALMODE_WAL
+ && (u.cd.zFilename[0]==0 /* Temp file */
+ || !sqlite3PagerWalSupported(u.cd.pPager)) /* No xShmOpen support */
+ ){
+ u.cd.eNew = u.cd.eOld;
+ }
+
+ if( (u.cd.eNew!=u.cd.eOld)
+ && (u.cd.eOld==PAGER_JOURNALMODE_WAL || u.cd.eNew==PAGER_JOURNALMODE_WAL)
+ ){
+ if( !db->autoCommit || db->activeVdbeCnt>1 ){
+ rc = SQLITE_ERROR;
+ sqlite3SetString(&p->zErrMsg, db,
+ "cannot change %s wal mode from within a transaction",
+ (u.cd.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
+ );
+ break;
+ }else{
+
+ if( u.cd.eOld==PAGER_JOURNALMODE_WAL ){
+ /* If leaving WAL mode, close the log file. If successful, the call
+ ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
+ ** file. An EXCLUSIVE lock may still be held on the database file
+ ** after a successful return.
+ */
+ rc = sqlite3PagerCloseWal(u.cd.pPager);
+ if( rc==SQLITE_OK ){
+ sqlite3PagerSetJournalMode(u.cd.pPager, u.cd.eNew);
+ }
+ }else if( u.cd.eOld==PAGER_JOURNALMODE_MEMORY ){
+ /* Cannot transition directly from MEMORY to WAL. Use mode OFF
+ ** as an intermediate */
+ sqlite3PagerSetJournalMode(u.cd.pPager, PAGER_JOURNALMODE_OFF);
+ }
+
+ /* Open a transaction on the database file. Regardless of the journal
+ ** mode, this transaction always uses a rollback journal.
+ */
+ assert( sqlite3BtreeIsInTrans(u.cd.pBt)==0 );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeSetVersion(u.cd.pBt, (u.cd.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
+ }
+ }
+ }
+#endif /* ifndef SQLITE_OMIT_WAL */
+
+ if( rc ){
+ if( rc==SQLITE_BUSY && pOp->p5!=0 ) rc = SQLITE_OK;
+ u.cd.eNew = u.cd.eOld;
+ }
+ u.cd.eNew = sqlite3PagerSetJournalMode(u.cd.pPager, u.cd.eNew);
+
+ pOut = &aMem[pOp->p2];
+ pOut->flags = MEM_Str|MEM_Static|MEM_Term;
+ pOut->z = (char *)sqlite3JournalModename(u.cd.eNew);
+ pOut->n = sqlite3Strlen30(pOut->z);
+ pOut->enc = SQLITE_UTF8;
+ sqlite3VdbeChangeEncoding(pOut, encoding);
+ break;
+};
+#endif /* SQLITE_OMIT_PRAGMA */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* Opcode: Vacuum * * * * *
@@ -57695,14 +63677,14 @@
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
-#if 0 /* local variables moved into u.cd */
+#if 0 /* local variables moved into u.ce */
Btree *pBt;
-#endif /* local variables moved into u.cd */
+#endif /* local variables moved into u.ce */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (1<<pOp->p1))!=0 );
- u.cd.pBt = db->aDb[pOp->p1].pBt;
- rc = sqlite3BtreeIncrVacuum(u.cd.pBt);
+ u.ce.pBt = db->aDb[pOp->p1].pBt;
+ rc = sqlite3BtreeIncrVacuum(u.ce.pBt);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
@@ -57772,15 +63754,15 @@
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
-#if 0 /* local variables moved into u.ce */
+#if 0 /* local variables moved into u.cf */
VTable *pVTab;
-#endif /* local variables moved into u.ce */
- u.ce.pVTab = pOp->p4.pVtab;
- rc = sqlite3VtabBegin(db, u.ce.pVTab);
- if( u.ce.pVTab ){
+#endif /* local variables moved into u.cf */
+ u.cf.pVTab = pOp->p4.pVtab;
+ rc = sqlite3VtabBegin(db, u.cf.pVTab);
+ if( u.cf.pVTab ){
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ce.pVTab->pVtab->zErrMsg;
- u.ce.pVTab->pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cf.pVTab->pVtab->zErrMsg;
+ u.cf.pVTab->pVtab->zErrMsg = 0;
}
break;
}
@@ -57820,34 +63802,34 @@
** table and stores that cursor in P1.
*/
case OP_VOpen: {
-#if 0 /* local variables moved into u.cf */
+#if 0 /* local variables moved into u.cg */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
-#endif /* local variables moved into u.cf */
+#endif /* local variables moved into u.cg */
- u.cf.pCur = 0;
- u.cf.pVtabCursor = 0;
- u.cf.pVtab = pOp->p4.pVtab->pVtab;
- u.cf.pModule = (sqlite3_module *)u.cf.pVtab->pModule;
- assert(u.cf.pVtab && u.cf.pModule);
- rc = u.cf.pModule->xOpen(u.cf.pVtab, &u.cf.pVtabCursor);
+ u.cg.pCur = 0;
+ u.cg.pVtabCursor = 0;
+ u.cg.pVtab = pOp->p4.pVtab->pVtab;
+ u.cg.pModule = (sqlite3_module *)u.cg.pVtab->pModule;
+ assert(u.cg.pVtab && u.cg.pModule);
+ rc = u.cg.pModule->xOpen(u.cg.pVtab, &u.cg.pVtabCursor);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cf.pVtab->zErrMsg;
- u.cf.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cg.pVtab->zErrMsg;
+ u.cg.pVtab->zErrMsg = 0;
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
- u.cf.pVtabCursor->pVtab = u.cf.pVtab;
+ u.cg.pVtabCursor->pVtab = u.cg.pVtab;
/* Initialise vdbe cursor object */
- u.cf.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
- if( u.cf.pCur ){
- u.cf.pCur->pVtabCursor = u.cf.pVtabCursor;
- u.cf.pCur->pModule = u.cf.pVtabCursor->pVtab->pModule;
+ u.cg.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
+ if( u.cg.pCur ){
+ u.cg.pCur->pVtabCursor = u.cg.pVtabCursor;
+ u.cg.pCur->pModule = u.cg.pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
- u.cf.pModule->xClose(u.cf.pVtabCursor);
+ u.cg.pModule->xClose(u.cg.pVtabCursor);
}
}
break;
@@ -57874,7 +63856,7 @@
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
-#if 0 /* local variables moved into u.cg */
+#if 0 /* local variables moved into u.ch */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@@ -57886,46 +63868,46 @@
int res;
int i;
Mem **apArg;
-#endif /* local variables moved into u.cg */
+#endif /* local variables moved into u.ch */
- u.cg.pQuery = &aMem[pOp->p3];
- u.cg.pArgc = &u.cg.pQuery[1];
- u.cg.pCur = p->apCsr[pOp->p1];
- REGISTER_TRACE(pOp->p3, u.cg.pQuery);
- assert( u.cg.pCur->pVtabCursor );
- u.cg.pVtabCursor = u.cg.pCur->pVtabCursor;
- u.cg.pVtab = u.cg.pVtabCursor->pVtab;
- u.cg.pModule = u.cg.pVtab->pModule;
+ u.ch.pQuery = &aMem[pOp->p3];
+ u.ch.pArgc = &u.ch.pQuery[1];
+ u.ch.pCur = p->apCsr[pOp->p1];
+ REGISTER_TRACE(pOp->p3, u.ch.pQuery);
+ assert( u.ch.pCur->pVtabCursor );
+ u.ch.pVtabCursor = u.ch.pCur->pVtabCursor;
+ u.ch.pVtab = u.ch.pVtabCursor->pVtab;
+ u.ch.pModule = u.ch.pVtab->pModule;
/* Grab the index number and argc parameters */
- assert( (u.cg.pQuery->flags&MEM_Int)!=0 && u.cg.pArgc->flags==MEM_Int );
- u.cg.nArg = (int)u.cg.pArgc->u.i;
- u.cg.iQuery = (int)u.cg.pQuery->u.i;
+ assert( (u.ch.pQuery->flags&MEM_Int)!=0 && u.ch.pArgc->flags==MEM_Int );
+ u.ch.nArg = (int)u.ch.pArgc->u.i;
+ u.ch.iQuery = (int)u.ch.pQuery->u.i;
/* Invoke the xFilter method */
{
- u.cg.res = 0;
- u.cg.apArg = p->apArg;
- for(u.cg.i = 0; u.cg.i<u.cg.nArg; u.cg.i++){
- u.cg.apArg[u.cg.i] = &u.cg.pArgc[u.cg.i+1];
- sqlite3VdbeMemStoreType(u.cg.apArg[u.cg.i]);
+ u.ch.res = 0;
+ u.ch.apArg = p->apArg;
+ for(u.ch.i = 0; u.ch.i<u.ch.nArg; u.ch.i++){
+ u.ch.apArg[u.ch.i] = &u.ch.pArgc[u.ch.i+1];
+ sqlite3VdbeMemStoreType(u.ch.apArg[u.ch.i]);
}
p->inVtabMethod = 1;
- rc = u.cg.pModule->xFilter(u.cg.pVtabCursor, u.cg.iQuery, pOp->p4.z, u.cg.nArg, u.cg.apArg);
+ rc = u.ch.pModule->xFilter(u.ch.pVtabCursor, u.ch.iQuery, pOp->p4.z, u.ch.nArg, u.ch.apArg);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cg.pVtab->zErrMsg;
- u.cg.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.ch.pVtab->zErrMsg;
+ u.ch.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK ){
- u.cg.res = u.cg.pModule->xEof(u.cg.pVtabCursor);
+ u.ch.res = u.ch.pModule->xEof(u.ch.pVtabCursor);
}
- if( u.cg.res ){
+ if( u.ch.res ){
pc = pOp->p2 - 1;
}
}
- u.cg.pCur->nullRow = 0;
+ u.ch.pCur->nullRow = 0;
break;
}
@@ -57939,52 +63921,52 @@
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
-#if 0 /* local variables moved into u.ch */
+#if 0 /* local variables moved into u.ci */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
-#endif /* local variables moved into u.ch */
+#endif /* local variables moved into u.ci */
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.ch.pDest = &aMem[pOp->p3];
+ u.ci.pDest = &aMem[pOp->p3];
if( pCur->nullRow ){
- sqlite3VdbeMemSetNull(u.ch.pDest);
+ sqlite3VdbeMemSetNull(u.ci.pDest);
break;
}
- u.ch.pVtab = pCur->pVtabCursor->pVtab;
- u.ch.pModule = u.ch.pVtab->pModule;
- assert( u.ch.pModule->xColumn );
- memset(&u.ch.sContext, 0, sizeof(u.ch.sContext));
+ u.ci.pVtab = pCur->pVtabCursor->pVtab;
+ u.ci.pModule = u.ci.pVtab->pModule;
+ assert( u.ci.pModule->xColumn );
+ memset(&u.ci.sContext, 0, sizeof(u.ci.sContext));
/* The output cell may already have a buffer allocated. Move
- ** the current contents to u.ch.sContext.s so in case the user-function
+ ** the current contents to u.ci.sContext.s so in case the user-function
** can use the already allocated buffer instead of allocating a
** new one.
*/
- sqlite3VdbeMemMove(&u.ch.sContext.s, u.ch.pDest);
- MemSetTypeFlag(&u.ch.sContext.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.ci.sContext.s, u.ci.pDest);
+ MemSetTypeFlag(&u.ci.sContext.s, MEM_Null);
- rc = u.ch.pModule->xColumn(pCur->pVtabCursor, &u.ch.sContext, pOp->p2);
+ rc = u.ci.pModule->xColumn(pCur->pVtabCursor, &u.ci.sContext, pOp->p2);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ch.pVtab->zErrMsg;
- u.ch.pVtab->zErrMsg = 0;
- if( u.ch.sContext.isError ){
- rc = u.ch.sContext.isError;
+ p->zErrMsg = u.ci.pVtab->zErrMsg;
+ u.ci.pVtab->zErrMsg = 0;
+ if( u.ci.sContext.isError ){
+ rc = u.ci.sContext.isError;
}
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occurred to ensure any
- ** dynamic allocation in u.ch.sContext.s (a Mem struct) is released.
+ ** dynamic allocation in u.ci.sContext.s (a Mem struct) is released.
*/
- sqlite3VdbeChangeEncoding(&u.ch.sContext.s, encoding);
- sqlite3VdbeMemMove(u.ch.pDest, &u.ch.sContext.s);
- REGISTER_TRACE(pOp->p3, u.ch.pDest);
- UPDATE_MAX_BLOBSIZE(u.ch.pDest);
+ sqlite3VdbeChangeEncoding(&u.ci.sContext.s, encoding);
+ sqlite3VdbeMemMove(u.ci.pDest, &u.ci.sContext.s);
+ REGISTER_TRACE(pOp->p3, u.ci.pDest);
+ UPDATE_MAX_BLOBSIZE(u.ci.pDest);
- if( sqlite3VdbeMemTooBig(u.ch.pDest) ){
+ if( sqlite3VdbeMemTooBig(u.ci.pDest) ){
goto too_big;
}
break;
@@ -57999,22 +63981,22 @@
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
-#if 0 /* local variables moved into u.ci */
+#if 0 /* local variables moved into u.cj */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
-#endif /* local variables moved into u.ci */
+#endif /* local variables moved into u.cj */
- u.ci.res = 0;
- u.ci.pCur = p->apCsr[pOp->p1];
- assert( u.ci.pCur->pVtabCursor );
- if( u.ci.pCur->nullRow ){
+ u.cj.res = 0;
+ u.cj.pCur = p->apCsr[pOp->p1];
+ assert( u.cj.pCur->pVtabCursor );
+ if( u.cj.pCur->nullRow ){
break;
}
- u.ci.pVtab = u.ci.pCur->pVtabCursor->pVtab;
- u.ci.pModule = u.ci.pVtab->pModule;
- assert( u.ci.pModule->xNext );
+ u.cj.pVtab = u.cj.pCur->pVtabCursor->pVtab;
+ u.cj.pModule = u.cj.pVtab->pModule;
+ assert( u.cj.pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
@@ -58023,16 +64005,16 @@
** some other method is next invoked on the save virtual table cursor.
*/
p->inVtabMethod = 1;
- rc = u.ci.pModule->xNext(u.ci.pCur->pVtabCursor);
+ rc = u.cj.pModule->xNext(u.cj.pCur->pVtabCursor);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ci.pVtab->zErrMsg;
- u.ci.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cj.pVtab->zErrMsg;
+ u.cj.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK ){
- u.ci.res = u.ci.pModule->xEof(u.ci.pCur->pVtabCursor);
+ u.cj.res = u.cj.pModule->xEof(u.cj.pCur->pVtabCursor);
}
- if( !u.ci.res ){
+ if( !u.cj.res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
@@ -58048,20 +64030,20 @@
** in register P1 is passed as the zName argument to the xRename method.
*/
case OP_VRename: {
-#if 0 /* local variables moved into u.cj */
+#if 0 /* local variables moved into u.ck */
sqlite3_vtab *pVtab;
Mem *pName;
-#endif /* local variables moved into u.cj */
+#endif /* local variables moved into u.ck */
- u.cj.pVtab = pOp->p4.pVtab->pVtab;
- u.cj.pName = &aMem[pOp->p1];
- assert( u.cj.pVtab->pModule->xRename );
- REGISTER_TRACE(pOp->p1, u.cj.pName);
- assert( u.cj.pName->flags & MEM_Str );
- rc = u.cj.pVtab->pModule->xRename(u.cj.pVtab, u.cj.pName->z);
+ u.ck.pVtab = pOp->p4.pVtab->pVtab;
+ u.ck.pName = &aMem[pOp->p1];
+ assert( u.ck.pVtab->pModule->xRename );
+ REGISTER_TRACE(pOp->p1, u.ck.pName);
+ assert( u.ck.pName->flags & MEM_Str );
+ rc = u.ck.pVtab->pModule->xRename(u.ck.pVtab, u.ck.pName->z);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cj.pVtab->zErrMsg;
- u.cj.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.ck.pVtab->zErrMsg;
+ u.ck.pVtab->zErrMsg = 0;
break;
}
@@ -58092,7 +64074,7 @@
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
-#if 0 /* local variables moved into u.ck */
+#if 0 /* local variables moved into u.cl */
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
@@ -58100,27 +64082,27 @@
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
-#endif /* local variables moved into u.ck */
+#endif /* local variables moved into u.cl */
- u.ck.pVtab = pOp->p4.pVtab->pVtab;
- u.ck.pModule = (sqlite3_module *)u.ck.pVtab->pModule;
- u.ck.nArg = pOp->p2;
+ u.cl.pVtab = pOp->p4.pVtab->pVtab;
+ u.cl.pModule = (sqlite3_module *)u.cl.pVtab->pModule;
+ u.cl.nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
- if( ALWAYS(u.ck.pModule->xUpdate) ){
- u.ck.apArg = p->apArg;
- u.ck.pX = &aMem[pOp->p3];
- for(u.ck.i=0; u.ck.i<u.ck.nArg; u.ck.i++){
- sqlite3VdbeMemStoreType(u.ck.pX);
- u.ck.apArg[u.ck.i] = u.ck.pX;
- u.ck.pX++;
+ if( ALWAYS(u.cl.pModule->xUpdate) ){
+ u.cl.apArg = p->apArg;
+ u.cl.pX = &aMem[pOp->p3];
+ for(u.cl.i=0; u.cl.i<u.cl.nArg; u.cl.i++){
+ sqlite3VdbeMemStoreType(u.cl.pX);
+ u.cl.apArg[u.cl.i] = u.cl.pX;
+ u.cl.pX++;
}
- rc = u.ck.pModule->xUpdate(u.ck.pVtab, u.ck.nArg, u.ck.apArg, &u.ck.rowid);
+ rc = u.cl.pModule->xUpdate(u.cl.pVtab, u.cl.nArg, u.cl.apArg, &u.cl.rowid);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ck.pVtab->zErrMsg;
- u.ck.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cl.pVtab->zErrMsg;
+ u.cl.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK && pOp->p1 ){
- assert( u.ck.nArg>1 && u.ck.apArg[0] && (u.ck.apArg[0]->flags&MEM_Null) );
- db->lastRowid = u.ck.rowid;
+ assert( u.cl.nArg>1 && u.cl.apArg[0] && (u.cl.apArg[0]->flags&MEM_Null) );
+ db->lastRowid = u.cl.rowid;
}
p->nChange++;
}
@@ -58134,21 +64116,7 @@
** Write the current number of pages in database P1 to memory cell P2.
*/
case OP_Pagecount: { /* out2-prerelease */
-#if 0 /* local variables moved into u.cl */
- int p1;
- int nPage;
- Pager *pPager;
-#endif /* local variables moved into u.cl */
-
- u.cl.p1 = pOp->p1;
- u.cl.pPager = sqlite3BtreePager(db->aDb[u.cl.p1].pBt);
- rc = sqlite3PagerPagecount(u.cl.pPager, &u.cl.nPage);
- /* OP_Pagecount is always called from within a read transaction. The
- ** page count has already been successfully read and cached. So the
- ** sqlite3PagerPagecount() call above cannot fail. */
- if( ALWAYS(rc==SQLITE_OK) ){
- pOut->u.i = u.cl.nPage;
- }
+ pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
break;
}
#endif
@@ -58194,6 +64162,7 @@
** the same as a no-op. This opcodesnever appears in a real VM program.
*/
default: { /* This is really OP_Noop and OP_Explain */
+ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
break;
}
@@ -58245,7 +64214,9 @@
vdbe_error_halt:
assert( rc );
p->rc = rc;
- sqlite3_log(rc, "prepared statement aborts at %d: [%s]", pc, p->zSql);
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ sqlite3_log(rc, "statement aborts at %d: [%s] %s",
+ pc, p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
rc = SQLITE_ERROR;
@@ -58489,10 +64460,14 @@
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ sqlite3VdbeChangeToNoop(v, 2, 1);
+#else
sqlite3VdbeChangeP1(v, 2, iDb);
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
sqlite3VdbeChangeP3(v, 2, flags);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
+#endif
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
@@ -58863,7 +64838,12 @@
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
- 0 /* xDeviceCharacteristics */
+ 0, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmLock */
+ 0, /* xShmMap */
+ 0, /* xShmBarrier */
+ 0 /* xShmClose */
};
/*
@@ -59113,11 +65093,10 @@
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
-static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
- UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
- assert( 0 ); /*NO_TEST*/
- return SQLITE_OK; /*NO_TEST*/
-} /*NO_TEST*/
+static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return SQLITE_OK;
+}
/*
** Query the size of the file in bytes.
@@ -59131,7 +65110,7 @@
/*
** Table of methods for MemJournal sqlite3_file object.
*/
-static struct sqlite3_io_methods MemJournalMethods = {
+static const struct sqlite3_io_methods MemJournalMethods = {
1, /* iVersion */
memjrnlClose, /* xClose */
memjrnlRead, /* xRead */
@@ -59144,7 +65123,12 @@
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
- 0 /* xDeviceCharacteristics */
+ 0, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmLock */
+ 0, /* xShmMap */
+ 0, /* xShmBarrier */
+ 0 /* xShmClose */
};
/*
@@ -59154,7 +65138,7 @@
MemJournal *p = (MemJournal *)pJfd;
assert( EIGHT_BYTE_ALIGNMENT(p) );
memset(p, 0, sqlite3MemJournalSize());
- p->pMethod = &MemJournalMethods;
+ p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
}
/*
@@ -59667,6 +65651,7 @@
}else{
sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
}
+ pParse->checkSchema = 1;
pTopNC->nErr++;
}
@@ -59713,7 +65698,7 @@
/*
** Allocate and return a pointer to an expression to load the column iCol
-** from datasource iSrc datasource in SrcList pSrc.
+** from datasource iSrc in SrcList pSrc.
*/
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
@@ -59725,6 +65710,8 @@
p->iColumn = -1;
}else{
p->iColumn = (ynVar)iCol;
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
}
ExprSetProperty(p, EP_Resolved);
@@ -60001,7 +65988,7 @@
** result-set entry.
*/
for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprCompare(pEList->a[i].pExpr, pE) ){
+ if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){
return i+1;
}
}
@@ -60761,10 +66748,6 @@
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
(void*)p4, P4_COLLSEQ);
sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
- if( (p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_NONE ){
- sqlite3ExprCacheAffinityChange(pParse, in1, 1);
- sqlite3ExprCacheAffinityChange(pParse, in2, 1);
- }
return addr;
}
@@ -62395,6 +68378,7 @@
return out;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Generate an instruction that will put the floating point
** value described by z[0..n-1] into register iMem.
@@ -62414,6 +68398,7 @@
sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
}
}
+#endif
/*
@@ -62424,7 +68409,8 @@
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
-static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
+static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
+ Vdbe *v = pParse->pVdbe;
if( pExpr->flags & EP_IntValue ){
int i = pExpr->u.iValue;
if( negFlag ) i = -i;
@@ -62440,7 +68426,11 @@
zV = dup8bytes(v, (char*)&value);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
+#else
codeReal(v, z, negFlag, iMem);
+#endif
}
}
}
@@ -62593,6 +68583,27 @@
}
/*
+** Generate code to extract the value of the iCol-th column of a table.
+*/
+SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
+ Vdbe *v, /* The VDBE under construction */
+ Table *pTab, /* The table containing the value */
+ int iTabCur, /* The cursor for this table */
+ int iCol, /* Index of the column to extract */
+ int regOut /* Extract the valud into this register */
+){
+ if( iCol<0 || iCol==pTab->iPKey ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
+ }else{
+ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp3(v, op, iTabCur, iCol, regOut);
+ }
+ if( iCol>=0 ){
+ sqlite3ColumnDefault(v, pTab, iCol, regOut);
+ }
+}
+
+/*
** Generate code that will extract the iColumn-th column from
** table pTab and store the column value in a register. An effort
** is made to store the column value in register iReg, but this is
@@ -62620,13 +68631,7 @@
}
}
assert( v!=0 );
- if( iColumn<0 ){
- sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg);
- }else if( ALWAYS(pTab!=0) ){
- int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
- sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
- sqlite3ColumnDefault(v, pTab, iColumn, iReg);
- }
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
return iReg;
}
@@ -62827,14 +68832,16 @@
break;
}
case TK_INTEGER: {
- codeInteger(v, pExpr, 0, target);
+ codeInteger(pParse, pExpr, 0, target);
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
case TK_FLOAT: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pExpr->u.zToken, 0, target);
break;
}
+#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
@@ -62861,27 +68868,12 @@
}
#endif
case TK_VARIABLE: {
- VdbeOp *pOp;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( pExpr->u.zToken!=0 );
assert( pExpr->u.zToken[0]!=0 );
- if( pExpr->u.zToken[1]==0
- && (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
- && pOp->p1+pOp->p3==pExpr->iColumn
- && pOp->p2+pOp->p3==target
- && pOp->p4.z==0
- ){
- /* If the previous instruction was a copy of the previous unnamed
- ** parameter into the previous register, then simply increment the
- ** repeat count on the prior instruction rather than making a new
- ** instruction.
- */
- pOp->p3++;
- }else{
- sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1);
- if( pExpr->u.zToken[1]!=0 ){
- sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
- }
+ sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
+ if( pExpr->u.zToken[1]!=0 ){
+ sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
}
break;
}
@@ -63004,11 +68996,13 @@
case TK_UMINUS: {
Expr *pLeft = pExpr->pLeft;
assert( pLeft );
- if( pLeft->op==TK_FLOAT ){
+ if( pLeft->op==TK_INTEGER ){
+ codeInteger(pParse, pLeft, 1, target);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ }else if( pLeft->op==TK_FLOAT ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pLeft->u.zToken, 1, target);
- }else if( pLeft->op==TK_INTEGER ){
- codeInteger(v, pLeft, 1, target);
+#endif
}else{
regFree1 = r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
@@ -63256,6 +69250,7 @@
target
));
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* If the column has REAL affinity, it may currently be stored as an
** integer. Use OP_RealAffinity to make sure it is really real. */
if( pExpr->iColumn>=0
@@ -63263,6 +69258,7 @@
){
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
}
+#endif
break;
}
@@ -63928,59 +69924,76 @@
}
/*
-** Do a deep comparison of two expression trees. Return TRUE (non-zero)
-** if they are identical and return FALSE if they differ in any way.
+** Do a deep comparison of two expression trees. Return 0 if the two
+** expressions are completely identical. Return 1 if they differ only
+** by a COLLATE operator at the top level. Return 2 if there are differences
+** other than the top-level COLLATE operator.
**
-** Sometimes this routine will return FALSE even if the two expressions
+** Sometimes this routine will return 2 even if the two expressions
** really are equivalent. If we cannot prove that the expressions are
-** identical, we return FALSE just to be safe. So if this routine
-** returns false, then you do not really know for certain if the two
-** expressions are the same. But if you get a TRUE return, then you
+** identical, we return 2 just to be safe. So if this routine
+** returns 2, then you do not really know for certain if the two
+** expressions are the same. But if you get a 0 or 1 return, then you
** can be sure the expressions are the same. In the places where
-** this routine is used, it does not hurt to get an extra FALSE - that
+** this routine is used, it does not hurt to get an extra 2 - that
** just might result in some slightly slower code. But returning
-** an incorrect TRUE could lead to a malfunction.
+** an incorrect 0 or 1 could lead to a malfunction.
*/
SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){
- int i;
if( pA==0||pB==0 ){
- return pB==pA;
+ return pB==pA ? 0 : 2;
}
assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
- return 0;
+ return 2;
}
- if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
- if( pA->op!=pB->op ) return 0;
- if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
- if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
-
- if( pA->x.pList && pB->x.pList ){
- if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
- for(i=0; i<pA->x.pList->nExpr; i++){
- Expr *pExprA = pA->x.pList->a[i].pExpr;
- Expr *pExprB = pB->x.pList->a[i].pExpr;
- if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
- }
- }else if( pA->x.pList || pB->x.pList ){
- return 0;
- }
-
- if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
+ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
+ if( pA->op!=pB->op ) return 2;
+ if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
+ if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
+ if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
+ if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
if( ExprHasProperty(pA, EP_IntValue) ){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
- return 0;
+ return 2;
}
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){
- if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 0;
+ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){
- return 0;
+ return 2;
}
}
- return 1;
+ if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
+ if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
+ return 0;
}
+/*
+** Compare two ExprList objects. Return 0 if they are identical and
+** non-zero if they differ in any way.
+**
+** This routine might return non-zero for equivalent ExprLists. The
+** only consequence will be disabled optimizations. But this routine
+** must never return 0 if the two ExprList objects are different, or
+** a malfunction will result.
+**
+** Two NULL pointers are considered to be the same. But a NULL pointer
+** always differs from a non-NULL pointer.
+*/
+SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
+ int i;
+ if( pA==0 && pB==0 ) return 0;
+ if( pA==0 || pB==0 ) return 1;
+ if( pA->nExpr!=pB->nExpr ) return 1;
+ for(i=0; i<pA->nExpr; i++){
+ Expr *pExprA = pA->a[i].pExpr;
+ Expr *pExprB = pB->a[i].pExpr;
+ if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
+ if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
+ }
+ return 0;
+}
/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
@@ -64109,7 +70122,7 @@
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
+ if( sqlite3ExprCompare(pItem->pExpr, pExpr)==0 ){
break;
}
}
@@ -64477,17 +70490,23 @@
/*
** Register built-in functions used to help implement ALTER TABLE
*/
-SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3 *db){
- sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0,
- renameTableFunc, 0, 0);
+SQLITE_PRIVATE void sqlite3AlterFunctions(void){
+ static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
+ FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
- sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
- renameTriggerFunc, 0, 0);
+ FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0,
- renameParentFunc, 0, 0);
+ FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
+ };
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
+
+ for(i=0; i<ArraySize(aAlterTableFuncs); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
}
/*
@@ -64631,7 +70650,9 @@
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
-
+ int savedDbFlags; /* Saved value of db->flags */
+
+ savedDbFlags = db->flags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -64640,6 +70661,7 @@
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
+ db->flags |= SQLITE_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -64730,9 +70752,9 @@
** for which the renamed table is the parent table. */
if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
sqlite3NestedParse(pParse,
- "UPDATE sqlite_master SET "
+ "UPDATE \"%w\".%s SET "
"sql = sqlite_rename_parent(sql, %Q, %Q) "
- "WHERE %s;", zTabName, zName, zWhere);
+ "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
sqlite3DbFree(db, zWhere);
}
}
@@ -64807,6 +70829,7 @@
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
+ db->flags = savedDbFlags;
}
@@ -64926,9 +70949,11 @@
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
+ int savedDbFlags = db->flags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
+ db->flags |= SQLITE_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -64937,6 +70962,7 @@
zTab
);
sqlite3DbFree(db, zCol);
+ db->flags = savedDbFlags;
}
/* If the default value of the new column is NULL, then set the file
@@ -65082,7 +71108,7 @@
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
const char *zWhere /* Delete entries associated with this table */
){
- static struct {
+ static const struct {
const char *zName;
const char *zCols;
} aTable[] = {
@@ -65664,12 +71690,16 @@
n = 24;
}
pSample->nByte = (u8)n;
- pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
- if( pSample->u.z ){
- memcpy(pSample->u.z, z, n);
+ if( n < 1){
+ pSample->u.z = 0;
}else{
- db->mallocFailed = 1;
- break;
+ pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
+ if( pSample->u.z ){
+ memcpy(pSample->u.z, z, n);
+ }else{
+ db->mallocFailed = 1;
+ break;
+ }
}
}
}
@@ -65818,7 +71848,7 @@
** or may not be initialised.
*/
rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE,
- db->openFlags | SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_CREATE /* Android Change */,
+ db->openFlags | SQLITE_OPEN_MAIN_DB,
&aNew->pBt);
db->nDb++;
if( rc==SQLITE_CONSTRAINT ){
@@ -65836,7 +71866,10 @@
}
pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
- sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
+ /* journal_mode set by the OP_JournalMode opcode that will following
+ ** the OP_Function opcode that invoked this function. */
+ sqlite3BtreeSecureDelete(aNew->pBt,
+ sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
@@ -65845,7 +71878,7 @@
}
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( rc==SQLITE_OK ){
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
@@ -65979,7 +72012,7 @@
static void codeAttach(
Parse *pParse, /* The parser context */
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
- FuncDef *pFunc, /* FuncDef wrapper for detachFunc() or attachFunc() */
+ FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */
Expr *pAuthArg, /* Expression to pass to authorization callback */
Expr *pFilename, /* Name of database file */
Expr *pDbname, /* Name of the database to use internally */
@@ -66030,6 +72063,17 @@
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
+ if( type==SQLITE_ATTACH ){
+ /* On an attach, also set the journal mode. Note that
+ ** sqlite3VdbeUsesBtree() is not call here since the iDb index
+ ** will be out of range prior to the new database being attached.
+ ** The OP_JournalMode opcode will all sqlite3VdbeUsesBtree() for us.
+ */
+ sqlite3VdbeAddOp3(v, OP_JournalMode, db->nDb, regArgs+3,
+ db->dfltJournalMode);
+ sqlite3VdbeChangeP5(v, 1);
+ }
+
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
@@ -66049,7 +72093,7 @@
** DETACH pDbname
*/
SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
- static FuncDef detach_func = {
+ static const FuncDef detach_func = {
1, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
@@ -66070,7 +72114,7 @@
** ATTACH p AS pDbname KEY pKey
*/
SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
- static FuncDef attach_func = {
+ static const FuncDef attach_func = {
3, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
@@ -66685,7 +72729,7 @@
pParse->isMultiWrite && pParse->mayAbort);
pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0;
- }else if( pParse->rc==SQLITE_OK ){
+ }else{
pParse->rc = SQLITE_ERROR;
}
pParse->nTab = 0;
@@ -69097,6 +75141,7 @@
if( j>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "table %s has no column named %s",
pTab->zName, zColName);
+ pParse->checkSchema = 1;
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
@@ -69865,7 +75910,7 @@
if( zName ){
Vdbe *v = sqlite3GetVdbe(pParse);
#ifndef SQLITE_OMIT_AUTHORIZATION
- static const char *az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
+ static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 );
#endif
if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){
@@ -69884,6 +75929,7 @@
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt==0 && !pParse->explain ){
int rc;
+ Btree *pBt;
static const int flags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
@@ -69891,17 +75937,20 @@
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TEMP_DB;
- rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags,
- &db->aDb[1].pBt);
+ rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
pParse->rc = rc;
return 1;
}
+ db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
- sqlite3PagerJournalMode(sqlite3BtreePager(db->aDb[1].pBt),
- db->dfltJournalMode);
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
+ db->mallocFailed = 1;
+ return 1;
+ }
+ sqlite3PagerSetJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
}
return 0;
}
@@ -70541,14 +76590,19 @@
/* If no match is found, search the built-in functions.
**
+ ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** functions even if a prior app-defined function was found. And give
+ ** priority to built-in functions.
+ **
** Except, if createFlag is true, that means that we are trying to
** install a new function. Whatever FuncDef structure is returned will
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
- if( !createFlag && !pBest ){
+ if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ bestScore = 0;
p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
@@ -71148,9 +77202,7 @@
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld);
for(iCol=0; iCol<pTab->nCol; iCol++){
if( mask==0xffffffff || mask&(1<<iCol) ){
- int iTarget = iOld + iCol + 1;
- sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget);
- sqlite3ColumnDefault(v, pTab, iCol, iTarget);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1);
}
}
@@ -71546,14 +77598,24 @@
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]);
- zBuf = sqlite3_mprintf("%.*f",n,r);
- if( zBuf==0 ){
- sqlite3_result_error_nomem(context);
+ /* If Y==0 and X will fit in a 64-bit int,
+ ** handle the rounding directly,
+ ** otherwise use printf.
+ */
+ if( n==0 && r>=0 && r<LARGEST_INT64-1 ){
+ r = (double)((sqlite_int64)(r+0.5));
+ }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){
+ r = -(double)((sqlite_int64)((-r)+0.5));
}else{
+ zBuf = sqlite3_mprintf("%.*f",n,r);
+ if( zBuf==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
sqlite3AtoF(zBuf, &r);
sqlite3_free(zBuf);
- sqlite3_result_double(context, r);
}
+ sqlite3_result_double(context, r);
}
#endif
@@ -71715,12 +77777,18 @@
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ /* IMP: R-51513-12026 The last_insert_rowid() SQL function is a
+ ** wrapper around the sqlite3_last_insert_rowid() C/C++ interface
+ ** function. */
sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
}
/*
-** Implementation of the changes() SQL function. The return value is the
-** same as the sqlite3_changes() API function.
+** Implementation of the changes() SQL function.
+**
+** IMP: R-62073-11209 The changes() SQL function is a wrapper
+** around the sqlite3_changes() C/C++ function and hence follows the same
+** rules for counting changes.
*/
static void changes(
sqlite3_context *context,
@@ -71743,6 +77811,8 @@
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ /* IMP: R-52756-41993 This function is a wrapper around the
+ ** sqlite3_total_changes() C/C++ interface. */
sqlite3_result_int(context, sqlite3_total_changes(db));
}
@@ -72010,7 +78080,9 @@
sqlite3_value **NotUsed2
){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
+ /* IMP: R-48699-48617 This function is an SQL wrapper around the
+ ** sqlite3_libversion() C-interface. */
+ sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC);
}
/*
@@ -72024,9 +78096,54 @@
sqlite3_value **NotUsed2
){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- sqlite3_result_text(context, SQLITE_SOURCE_ID, -1, SQLITE_STATIC);
+ /* IMP: R-24470-31136 This function is an SQL wrapper around the
+ ** sqlite3_sourceid() C interface. */
+ sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
}
+/*
+** Implementation of the sqlite_compileoption_used() function.
+** The result is an integer that identifies if the compiler option
+** was used to build SQLite.
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+static void compileoptionusedFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zOptName;
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ /* IMP: R-xxxx This function is an SQL wrapper around the
+ ** sqlite3_compileoption_used() C interface. */
+ if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){
+ sqlite3_result_int(context, sqlite3_compileoption_used(zOptName));
+ }
+}
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+/*
+** Implementation of the sqlite_compileoption_get() function.
+** The result is a string that identifies the compiler options
+** used to build SQLite.
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+static void compileoptiongetFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int n;
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ /* IMP: R-xxxx This function is an SQL wrapper around the
+ ** sqlite3_compileoption_get() C interface. */
+ n = sqlite3_value_int(argv[0]);
+ sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC);
+}
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
/* Array for converting from half-bytes (nybbles) into ASCII hex
** digits. */
static const char hexdigits[] = {
@@ -72153,7 +78270,7 @@
if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
}else{
- sqlite3_result_zeroblob(context, (int)n);
+ sqlite3_result_zeroblob(context, (int)n); /* IMP: R-00293-64994 */
}
}
@@ -72621,20 +78738,15 @@
}
/*
-** This function registered all of the above C functions as SQL
-** functions. This should be the only routine in this file with
-** external linkage.
+** This routine does per-connection function registration. Most
+** of the built-in functions above are part of the global function set.
+** This routine only deals with those that are not global.
*/
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
-#ifndef SQLITE_OMIT_ALTERTABLE
- sqlite3AlterFunctions(db);
-#endif
- if( !db->mallocFailed ){
- int rc = sqlite3_overload_function(db, "MATCH", 2);
- assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
- if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
- }
+ int rc = sqlite3_overload_function(db, "MATCH", 2);
+ assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
+ if( rc==SQLITE_NOMEM ){
+ db->mallocFailed = 1;
}
}
@@ -72758,6 +78870,10 @@
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
+ FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
FUNCTION(changes, 0, 0, 0, changes ),
@@ -72798,6 +78914,9 @@
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
+#ifndef SQLITE_OMIT_ALTERTABLE
+ sqlite3AlterFunctions();
+#endif
}
/************** End of func.c ************************************************/
@@ -74723,7 +80842,7 @@
}else{
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
pTabList, 0, pColumn->a[i].zName);
- pParse->nErr++;
+ pParse->checkSchema = 1;
goto insert_cleanup;
}
}
@@ -74842,7 +80961,7 @@
if( pColumn->a[j].idx==i ) break;
}
}
- if( pColumn && j>=pColumn->nId ){
+ if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
}else if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
@@ -75257,19 +81376,33 @@
** the triggers and remove both the table and index b-tree entries.
**
** Otherwise, if there are no triggers or the recursive-triggers
- ** flag is not set, call GenerateRowIndexDelete(). This removes
- ** the index b-tree entries only. The table b-tree entry will be
- ** replaced by the new entry when it is inserted. */
+ ** flag is not set, but the table has one or more indexes, call
+ ** GenerateRowIndexDelete(). This removes the index b-tree entries
+ ** only. The table b-tree entry will be replaced by the new entry
+ ** when it is inserted.
+ **
+ ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
+ ** also invoke MultiWrite() to indicate that this VDBE may require
+ ** statement rollback (if the statement is aborted after the delete
+ ** takes place). Earlier versions called sqlite3MultiWrite() regardless,
+ ** but being more selective here allows statements like:
+ **
+ ** REPLACE INTO t(rowid) VALUES($newrowid)
+ **
+ ** to run without a statement journal if there are no indexes on the
+ ** table.
+ */
Trigger *pTrigger = 0;
if( pParse->db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
- sqlite3MultiWrite(pParse);
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
+ sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(
pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace
);
- }else{
+ }else if( pTab->pIndex ){
+ sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
}
seenReplace = 1;
@@ -75711,7 +81844,7 @@
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
+ if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
@@ -75854,6 +81987,7 @@
int nRetry = 0; /* Number of retry attempts */
int callbackIsInit; /* True if callback data is initialized */
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
if( zSql==0 ) zSql = "";
sqlite3_mutex_enter(db->mutex);
@@ -77123,6 +83257,9 @@
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+ { "automatic_index", SQLITE_AutoIndex },
+#endif
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
@@ -77204,6 +83341,31 @@
}
#endif
+
+/*
+** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
+** defined in pager.h. This function returns the associated lowercase
+** journal-mode name.
+*/
+SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
+ static char * const azModeName[] = {
+ "delete", "persist", "off", "truncate", "memory"
+#ifndef SQLITE_OMIT_WAL
+ , "wal"
+#endif
+ };
+ assert( PAGER_JOURNALMODE_DELETE==0 );
+ assert( PAGER_JOURNALMODE_PERSIST==1 );
+ assert( PAGER_JOURNALMODE_OFF==2 );
+ assert( PAGER_JOURNALMODE_TRUNCATE==3 );
+ assert( PAGER_JOURNALMODE_MEMORY==4 );
+ assert( PAGER_JOURNALMODE_WAL==5 );
+ assert( eMode>=0 && eMode<=ArraySize(azModeName) );
+
+ if( eMode==ArraySize(azModeName) ) return 0;
+ return azModeName[eMode];
+}
+
/*
** Process a pragma statement.
**
@@ -77276,11 +83438,11 @@
** page cache size value and the persistent page cache size value
** stored in the database file.
**
- ** The default cache size is stored in meta-value 2 of page 1 of the
- ** database file. The cache size is actually the absolute value of
- ** this memory location. The sign of meta-value 2 determines the
- ** synchronous setting. A negative value means synchronous is off
- ** and a positive value means synchronous is on.
+ ** Older versions of SQLite would set the default cache size to a
+ ** negative number to indicate synchronous=OFF. These days, synchronous
+ ** is always on by default regardless of the sign of the default cache
+ ** size. But continue to take the absolute value of the default cache
+ ** size of historical compatibility.
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
@@ -77309,10 +83471,6 @@
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
- sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
- addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
- sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
- sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -77368,6 +83526,31 @@
}else
/*
+ ** PRAGMA [database.]secure_delete
+ ** PRAGMA [database.]secure_delete=ON/OFF
+ **
+ ** The first form reports the current setting for the
+ ** secure_delete flag. The second form changes the secure_delete
+ ** flag setting and reports thenew value.
+ */
+ if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
+ Btree *pBt = pDb->pBt;
+ int b = -1;
+ assert( pBt!=0 );
+ if( zRight ){
+ b = getBoolean(zRight);
+ }
+ if( pId2->n==0 && b>=0 ){
+ int ii;
+ for(ii=0; ii<db->nDb; ii++){
+ sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
+ }
+ }
+ b = sqlite3BtreeSecureDelete(pBt, b);
+ returnSingleInt(pParse, "secure_delete", b);
+ }else
+
+ /*
** PRAGMA [database.]page_count
**
** Return the number of pages in the specified database.
@@ -77432,21 +83615,29 @@
/*
** PRAGMA [database.]journal_mode
- ** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
+ ** PRAGMA [database.]journal_mode =
+ ** (delete|persist|off|truncate|memory|wal|off)
*/
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
- int eMode;
- static char * const azModeName[] = {
- "delete", "persist", "off", "truncate", "memory"
- };
+ int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
+
+ if( sqlite3ReadSchema(pParse) ){
+ goto pragma_out;
+ }
+
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
if( zRight==0 ){
eMode = PAGER_JOURNALMODE_QUERY;
}else{
+ const char *zMode;
int n = sqlite3Strlen30(zRight);
- eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
- while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
- eMode--;
+ for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){
+ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
+ }
+ if( !zMode ){
+ eMode = PAGER_JOURNALMODE_QUERY;
}
}
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
@@ -77455,39 +83646,31 @@
** the journal-mode of the main database).
*/
eMode = db->dfltJournalMode;
+ sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
+ sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
}else{
- Pager *pPager;
+ int ii;
+
if( pId2->n==0 ){
- /* This indicates that no database name was specified as part
- ** of the PRAGMA command. In this case the journal-mode must be
- ** set on all attached databases, as well as the main db file.
+ /* When there is no database name before the "journal_mode" keyword
+ ** in the PRAGMA, then the journal-mode will be set on
+ ** all attached databases, as well as the main db file.
**
** Also, the sqlite3.dfltJournalMode variable is set so that
** any subsequently attached databases also use the specified
** journal mode.
*/
- int ii;
- assert(pDb==&db->aDb[0]);
- for(ii=1; ii<db->nDb; ii++){
- if( db->aDb[ii].pBt ){
- pPager = sqlite3BtreePager(db->aDb[ii].pBt);
- sqlite3PagerJournalMode(pPager, eMode);
- }
- }
db->dfltJournalMode = (u8)eMode;
}
- pPager = sqlite3BtreePager(pDb->pBt);
- eMode = sqlite3PagerJournalMode(pPager, eMode);
+
+ for(ii=db->nDb-1; ii>=0; ii--){
+ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
+ sqlite3VdbeUsesBtree(v, ii);
+ sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
+ }
+ }
}
- assert( eMode==PAGER_JOURNALMODE_DELETE
- || eMode==PAGER_JOURNALMODE_TRUNCATE
- || eMode==PAGER_JOURNALMODE_PERSIST
- || eMode==PAGER_JOURNALMODE_OFF
- || eMode==PAGER_JOURNALMODE_MEMORY );
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
- sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
- azModeName[eMode], P4_STATIC);
+
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else
@@ -78285,6 +84468,56 @@
}else
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ /*
+ ** PRAGMA compile_options
+ **
+ ** Return the names of all compile-time options used in this build,
+ ** one option per row.
+ */
+ if( sqlite3StrICmp(zLeft, "compile_options")==0 ){
+ int i = 0;
+ const char *zOpt;
+ sqlite3VdbeSetNumCols(v, 1);
+ pParse->nMem = 1;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "compile_option", SQLITE_STATIC);
+ while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }
+ }else
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+#ifndef SQLITE_OMIT_WAL
+ /*
+ ** PRAGMA [database.]wal_checkpoint
+ **
+ ** Checkpoint the database.
+ */
+ if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){
+ if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ sqlite3VdbeAddOp3(v, OP_Checkpoint, pId2->z?iDb:SQLITE_MAX_ATTACHED, 0, 0);
+ }else
+
+ /*
+ ** PRAGMA wal_autocheckpoint
+ ** PRAGMA wal_autocheckpoint = N
+ **
+ ** Configure a database connection to automatically checkpoint a database
+ ** after accumulating N frames in the log. Or query for the current value
+ ** of N.
+ */
+ if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
+ if( zRight ){
+ int nAuto = atoi(zRight);
+ sqlite3_wal_autocheckpoint(db, nAuto);
+ }
+ returnSingleInt(pParse, "wal_autocheckpoint",
+ db->xWalCallback==sqlite3WalDefaultHook ?
+ SQLITE_PTR_TO_INT(db->pWalArg) : 0);
+ }else
+#endif
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -78319,7 +84552,7 @@
}else
#endif
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){
sqlite3_key(db, zRight, sqlite3Strlen30(zRight));
}else
@@ -78342,17 +84575,15 @@
}
}else
#endif
-#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
+#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
- extern void sqlite3_activate_see(const char*);
sqlite3_activate_see(&zRight[4]);
}
#endif
#ifdef SQLITE_ENABLE_CEROD
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
- extern void sqlite3_activate_cerod(const char*);
sqlite3_activate_cerod(&zRight[6]);
}
#endif
@@ -78455,15 +84686,18 @@
** or executed. All the parser does is build the internal data
** structures that describe the table, index, or view.
*/
- char *zErr;
int rc;
+ sqlite3_stmt *pStmt;
+ TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
+
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
db->init.orphanTrigger = 0;
- rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+ TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
+ rc = db->errCode;
+ assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = 0;
- assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -78471,12 +84705,12 @@
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
- }else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
- corruptSchema(pData, argv[0], zErr);
+ }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
+ corruptSchema(pData, argv[0], sqlite3_errmsg(db));
}
}
- sqlite3DbFree(db, zErr);
}
+ sqlite3_finalize(pStmt);
}else if( argv[0]==0 ){
corruptSchema(pData, 0, 0);
}else{
@@ -78695,7 +84929,7 @@
{
char *zSql;
zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM '%q'.%s",
+ "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
db->aDb[iDb].zName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
@@ -78961,6 +85195,7 @@
sqlite3VtabUnlockList(db);
pParse->db = db;
+ pParse->nQueryLoop = (double)1;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@@ -78982,6 +85217,7 @@
}else{
sqlite3RunParser(pParse, zSql, &zErrMsg);
}
+ assert( 1==(int)pParse->nQueryLoop );
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
@@ -79182,7 +85418,7 @@
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
- zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
+ zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
if( zSql8 ){
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
}
@@ -81766,8 +88002,8 @@
** (14) The subquery does not use OFFSET
**
** (15) The outer query is not part of a compound select or the
-** subquery does not have both an ORDER BY and a LIMIT clause.
-** (See ticket #2339)
+** subquery does not have a LIMIT clause.
+** (See ticket #2339 and ticket [02a8e81d44]).
**
** (16) The outer query is not an aggregate or the subquery does
** not contain ORDER BY. (Ticket #2942) This used to not matter
@@ -81850,7 +88086,7 @@
** and (14). */
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
if( pSub->pOffset ) return 0; /* Restriction (14) */
- if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){
+ if( p->pRightmost && pSub->pLimit ){
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
@@ -82260,6 +88496,7 @@
);
if( !pIdx ){
sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0);
+ pParse->checkSchema = 1;
return SQLITE_ERROR;
}
pFrom->pIndex = pIdx;
@@ -82567,18 +88804,19 @@
struct SrcList_item *pFrom;
assert( p->selFlags & SF_Resolved );
- assert( (p->selFlags & SF_HasTypeInfo)==0 );
- p->selFlags |= SF_HasTypeInfo;
- pParse = pWalker->pParse;
- pTabList = p->pSrc;
- for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
- if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
- /* A sub-query in the FROM clause of a SELECT */
- Select *pSel = pFrom->pSelect;
- assert( pSel );
- while( pSel->pPrior ) pSel = pSel->pPrior;
- selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
+ if( (p->selFlags & SF_HasTypeInfo)==0 ){
+ p->selFlags |= SF_HasTypeInfo;
+ pParse = pWalker->pParse;
+ pTabList = p->pSrc;
+ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ Table *pTab = pFrom->pTab;
+ if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ /* A sub-query in the FROM clause of a SELECT */
+ Select *pSel = pFrom->pSelect;
+ assert( pSel );
+ while( pSel->pPrior ) pSel = pSel->pPrior;
+ selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
+ }
}
}
return WRC_Continue;
@@ -82737,6 +88975,18 @@
sqlite3ExprCacheClear(pParse);
}
}
+
+ /* Before populating the accumulator registers, clear the column cache.
+ ** Otherwise, if any of the required column values are already present
+ ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
+ ** to pC->iMem. But by the time the value is used, the original register
+ ** may have been used, invalidating the underlying buffer holding the
+ ** text or blob value. See ticket [883034dcb5].
+ **
+ ** Another solution would be to change the OP_SCopy used to copy cached
+ ** values to an OP_Copy.
+ */
+ sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
@@ -82945,6 +89195,18 @@
isDistinct = 0;
}
+ /* If there is both a GROUP BY and an ORDER BY clause and they are
+ ** identical, then disable the ORDER BY clause since the GROUP BY
+ ** will cause elements to come out in the correct order. This is
+ ** an optimization - the correct answer should result regardless.
+ ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
+ ** to disable this optimization for testing purposes.
+ */
+ if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
+ && (db->flags & SQLITE_GroupByOrder)==0 ){
+ pOrderBy = 0;
+ }
+
/* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
@@ -83850,7 +90112,8 @@
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
- if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
+ if( db->init.busy==0 && pName2->n==0 && pTab
+ && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
@@ -83978,12 +90241,12 @@
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
- Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
- char *zName; /* Name of trigger */
- sqlite3 *db = pParse->db; /* The database */
- DbFixer sFix;
- int iDb; /* Database containing the trigger */
- Token nameToken; /* Trigger name for error reporting */
+ Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
+ char *zName; /* Name of trigger */
+ sqlite3 *db = pParse->db; /* The database */
+ DbFixer sFix; /* Fixer object */
+ int iDb; /* Database containing the trigger */
+ Token nameToken; /* Trigger name for error reporting */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
@@ -84002,7 +90265,7 @@
goto triggerfinish_cleanup;
}
- /* if we are not initializing, and this trigger is not on a TEMP table,
+ /* if we are not initializing,
** build the sqlite_master entry
*/
if( !db->init.busy ){
@@ -84219,6 +90482,7 @@
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
}
+ pParse->checkSchema = 1;
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger);
@@ -84549,6 +90813,7 @@
pSubParse->pToplevel = pTop;
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
+ pSubParse->nQueryLoop = pParse->nQueryLoop;
v = sqlite3GetVdbe(pSubParse);
if( v ){
@@ -84825,7 +91090,7 @@
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
-*************************************************************************
+sqlite*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
*/
@@ -85028,6 +91293,7 @@
pRowidExpr = pChanges->a[i].pExpr;
}else{
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
+ pParse->checkSchema = 1;
goto update_cleanup;
}
}
@@ -85212,8 +91478,7 @@
);
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
- sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
- sqlite3ColumnDefault(v, pTab, i, regOld+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
}
@@ -85586,7 +91851,8 @@
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
- int nRes;
+ int nRes; /* Bytes of reserved space at the end of each page */
+ int nDb; /* Number of attached databases */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -85600,8 +91866,8 @@
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_xTrace = db->xTrace;
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
- db->flags &= ~SQLITE_ForeignKeys;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
db->xTrace = 0;
pMain = db->aDb[0].pBt;
@@ -85621,15 +91887,18 @@
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
+ nDb = db->nDb;
if( sqlite3TempInMemory(db) ){
zSql = "ATTACH ':memory:' AS vacuum_db;";
}else{
zSql = "ATTACH '' AS vacuum_db;";
}
rc = execSql(db, pzErrMsg, zSql);
+ if( db->nDb>nDb ){
+ pDb = &db->aDb[db->nDb-1];
+ assert( strcmp(pDb->zName,"vacuum_db")==0 );
+ }
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- pDb = &db->aDb[db->nDb-1];
- assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
/* The call to execSql() to attach the temp database has left the file
@@ -85651,6 +91920,12 @@
}
#endif
+ /* Do not attempt to change the page size for a WAL database */
+ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
+ ==PAGER_JOURNALMODE_WAL ){
+ db->nextPagesize = 0;
+ }
+
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
@@ -85787,6 +92062,7 @@
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
db->xTrace = saved_xTrace;
+ sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
@@ -86469,6 +92745,7 @@
}else{
pParse->declareVtab = 1;
pParse->db = db;
+ pParse->nQueryLoop = 1;
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
&& pParse->pNewTable
@@ -86989,6 +93266,7 @@
#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
+#define WHERE_NOT_FULLSCAN 0x000f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
@@ -86998,6 +93276,7 @@
#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
+#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
/*
** Initialize a preallocated WhereClause structure.
@@ -87407,7 +93686,7 @@
}
assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
pColl = sqlite3ExprCollSeq(pParse, pLeft);
- assert( pColl!=0 ); /* Every non-IPK column has a collating sequence */
+ if( pColl==0 ) return 0; /* Happens when LHS has an undefined collation */
if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
/* IMP: R-09003-32046 For the GLOB operator, the column must use the
@@ -87850,7 +94129,7 @@
Expr *pExpr; /* The expression to be analyzed */
Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
Bitmask prereqAll; /* Prerequesites of pExpr */
- Bitmask extraRight = 0; /* */
+ Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
int noCase = 0; /* LIKE/GLOB distinguishes case */
@@ -87922,7 +94201,8 @@
pLeft = pDup->pLeft;
pNew->leftCursor = pLeft->iTable;
pNew->u.leftColumn = pLeft->iColumn;
- pNew->prereqRight = prereqLeft;
+ testcase( (prereqLeft | extraRight) != prereqLeft );
+ pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
pNew->eOperator = operatorMask(pDup->op);
}
@@ -88326,6 +94606,11 @@
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
WhereTerm *pTerm; /* A single term of the WHERE clause */
+ /* No OR-clause optimization allowed if the NOT INDEXED clause is used */
+ if( pSrc->notIndexed ){
+ return;
+ }
+
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR
@@ -88368,8 +94653,9 @@
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
if( pOrderBy!=0 ){
+ WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
+ rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow);
- WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal));
}
/* If the cost of scanning using this OR term for optimization is
@@ -88388,6 +94674,247 @@
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
}
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Return TRUE if the WHERE clause term pTerm is of a form where it
+** could be used with an index to access pSrc, assuming an appropriate
+** index existed.
+*/
+static int termCanDriveIndex(
+ WhereTerm *pTerm, /* WHERE clause term to check */
+ struct SrcList_item *pSrc, /* Table we are trying to access */
+ Bitmask notReady /* Tables in outer loops of the join */
+){
+ char aff;
+ if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
+ if( pTerm->eOperator!=WO_EQ ) return 0;
+ if( (pTerm->prereqRight & notReady)!=0 ) return 0;
+ aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
+ if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
+ return 1;
+}
+#endif
+
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** If the query plan for pSrc specified in pCost is a full table scan
+** and indexing is allows (if there is no NOT INDEXED clause) and it
+** possible to construct a transient index that would perform better
+** than a full table scan even when the cost of constructing the index
+** is taken into account, then alter the query plan to use the
+** transient index.
+*/
+static void bestAutomaticIndex(
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause */
+ struct SrcList_item *pSrc, /* The FROM clause term to search */
+ Bitmask notReady, /* Mask of cursors that are not available */
+ WhereCost *pCost /* Lowest cost query plan */
+){
+ double nTableRow; /* Rows in the input table */
+ double logN; /* log(nTableRow) */
+ double costTempIdx; /* per-query cost of the transient index */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pWCEnd; /* End of pWC->a[] */
+ Table *pTable; /* Table tht might be indexed */
+
+ if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
+ /* Automatic indices are disabled at run-time */
+ return;
+ }
+ if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
+ /* We already have some kind of index in use for this query. */
+ return;
+ }
+ if( pSrc->notIndexed ){
+ /* The NOT INDEXED clause appears in the SQL. */
+ return;
+ }
+
+ assert( pParse->nQueryLoop >= (double)1 );
+ pTable = pSrc->pTab;
+ nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
+ logN = estLog(nTableRow);
+ costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
+ if( costTempIdx>=pCost->rCost ){
+ /* The cost of creating the transient table would be greater than
+ ** doing the full table scan */
+ return;
+ }
+
+ /* Search for any equality comparison term */
+ pWCEnd = &pWC->a[pWC->nTerm];
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
+ pCost->rCost, costTempIdx));
+ pCost->rCost = costTempIdx;
+ pCost->nRow = logN + 1;
+ pCost->plan.wsFlags = WHERE_TEMP_INDEX;
+ pCost->used = pTerm->prereqRight;
+ break;
+ }
+ }
+}
+#else
+# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
+
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Generate code to construct the Index object for an automatic index
+** and to set up the WhereLevel object pLevel so that the code generator
+** makes use of the automatic index.
+*/
+static void constructAutomaticIndex(
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause */
+ struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
+ Bitmask notReady, /* Mask of cursors that are not available */
+ WhereLevel *pLevel /* Write new index here */
+){
+ int nColumn; /* Number of columns in the constructed index */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pWCEnd; /* End of pWC->a[] */
+ int nByte; /* Byte of memory needed for pIdx */
+ Index *pIdx; /* Object describing the transient index */
+ Vdbe *v; /* Prepared statement under construction */
+ int regIsInit; /* Register set by initialization */
+ int addrInit; /* Address of the initialization bypass jump */
+ Table *pTable; /* The table being indexed */
+ KeyInfo *pKeyinfo; /* Key information for the index */
+ int addrTop; /* Top of the index fill loop */
+ int regRecord; /* Register holding an index record */
+ int n; /* Column counter */
+ int i; /* Loop counter */
+ int mxBitCol; /* Maximum column in pSrc->colUsed */
+ CollSeq *pColl; /* Collating sequence to on a column */
+ Bitmask idxCols; /* Bitmap of columns used for indexing */
+ Bitmask extraCols; /* Bitmap of additional columns */
+
+ /* Generate code to skip over the creation and initialization of the
+ ** transient index on 2nd and subsequent iterations of the loop. */
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ regIsInit = ++pParse->nMem;
+ addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
+
+ /* Count the number of columns that will be added to the index
+ ** and used to match WHERE clause constraints */
+ nColumn = 0;
+ pTable = pSrc->pTab;
+ pWCEnd = &pWC->a[pWC->nTerm];
+ idxCols = 0;
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ int iCol = pTerm->u.leftColumn;
+ Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
+ if( (idxCols & cMask)==0 ){
+ nColumn++;
+ idxCols |= cMask;
+ }
+ }
+ }
+ assert( nColumn>0 );
+ pLevel->plan.nEq = nColumn;
+
+ /* Count the number of additional columns needed to create a
+ ** covering index. A "covering index" is an index that contains all
+ ** columns that are needed by the query. With a covering index, the
+ ** original table never needs to be accessed. Automatic indices must
+ ** be a covering index because the index will not be updated if the
+ ** original table changes and the index and table cannot both be used
+ ** if they go out of sync.
+ */
+ extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1)));
+ mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
+ testcase( pTable->nCol==BMS-1 );
+ testcase( pTable->nCol==BMS-2 );
+ for(i=0; i<mxBitCol; i++){
+ if( extraCols & (((Bitmask)1)<<i) ) nColumn++;
+ }
+ if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
+ nColumn += pTable->nCol - BMS + 1;
+ }
+ pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ;
+
+ /* Construct the Index object to describe this index */
+ nByte = sizeof(Index);
+ nByte += nColumn*sizeof(int); /* Index.aiColumn */
+ nByte += nColumn*sizeof(char*); /* Index.azColl */
+ nByte += nColumn; /* Index.aSortOrder */
+ pIdx = sqlite3DbMallocZero(pParse->db, nByte);
+ if( pIdx==0 ) return;
+ pLevel->plan.u.pIdx = pIdx;
+ pIdx->azColl = (char**)&pIdx[1];
+ pIdx->aiColumn = (int*)&pIdx->azColl[nColumn];
+ pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn];
+ pIdx->zName = "auto-index";
+ pIdx->nColumn = nColumn;
+ pIdx->pTable = pTable;
+ n = 0;
+ idxCols = 0;
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ int iCol = pTerm->u.leftColumn;
+ Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
+ if( (idxCols & cMask)==0 ){
+ Expr *pX = pTerm->pExpr;
+ idxCols |= cMask;
+ pIdx->aiColumn[n] = pTerm->u.leftColumn;
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
+ pIdx->azColl[n] = pColl->zName;
+ n++;
+ }
+ }
+ }
+ assert( (u32)n==pLevel->plan.nEq );
+
+ /* Add additional columns needed to make the automatic index into
+ ** a covering index */
+ for(i=0; i<mxBitCol; i++){
+ if( extraCols & (((Bitmask)1)<<i) ){
+ pIdx->aiColumn[n] = i;
+ pIdx->azColl[n] = "BINARY";
+ n++;
+ }
+ }
+ if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
+ for(i=BMS-1; i<pTable->nCol; i++){
+ pIdx->aiColumn[n] = i;
+ pIdx->azColl[n] = "BINARY";
+ n++;
+ }
+ }
+ assert( n==nColumn );
+
+ /* Create the automatic index */
+ pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx);
+ assert( pLevel->iIdxCur>=0 );
+ sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
+ (char*)pKeyinfo, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "for %s", pTable->zName));
+
+ /* Fill the automatic index with content */
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
+ regRecord = sqlite3GetTempReg(pParse);
+ sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
+ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
+ sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
+ sqlite3VdbeJumpHere(v, addrTop);
+ sqlite3ReleaseTempReg(pParse, regRecord);
+
+ /* Jump here when skipping the initialization */
+ sqlite3VdbeJumpHere(v, addrInit);
+}
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allocate and populate an sqlite3_index_info structure. It is the
@@ -88572,6 +95099,7 @@
WhereTerm *pTerm;
int i, j;
int nOrderBy;
+ double rCost;
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -88658,6 +95186,15 @@
}
}
+ /* If there is an ORDER BY clause, and the selected virtual table index
+ ** does not satisfy it, increase the cost of the scan accordingly. This
+ ** matches the processing for non-virtual tables in bestBtreeIndex().
+ */
+ rCost = pIdxInfo->estimatedCost;
+ if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
+ rCost += estLog(rCost)*rCost;
+ }
+
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
** inital value of lowestCost in this loop. If it is, then the
** (cost<lowestCost) test below will never be true.
@@ -88665,10 +95202,10 @@
** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT
** is defined.
*/
- if( (SQLITE_BIG_DBL/((double)2))<pIdxInfo->estimatedCost ){
+ if( (SQLITE_BIG_DBL/((double)2))<rCost ){
pCost->rCost = (SQLITE_BIG_DBL/((double)2));
}else{
- pCost->rCost = pIdxInfo->estimatedCost;
+ pCost->rCost = rCost;
}
pCost->plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
@@ -89069,14 +95606,14 @@
** Set to true if there was at least one "x IN (SELECT ...)" term used
** in determining the value of nInMul.
**
- ** nBound:
+ ** estBound:
** An estimate on the amount of the table that must be searched. A
** value of 100 means the entire table is searched. Range constraints
** might reduce this to a value less than 100 to indicate that only
** a fraction of the table needs searching. In the absence of
** sqlite_stat2 ANALYZE data, a single inequality reduces the search
** space to 1/3rd its original size. So an x>? constraint reduces
- ** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11.
+ ** estBound to 33. Two constraints (x>? AND x<?) reduce estBound to 11.
**
** bSort:
** Boolean. True if there is an ORDER BY clause that will require an
@@ -89098,13 +95635,14 @@
int nEq;
int bInEst = 0;
int nInMul = 1;
- int nBound = 100;
+ int estBound = 100;
+ int nBound = 0; /* Number of range constraints seen */
int bSort = 0;
int bLookup = 0;
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
/* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; nEq++){
- WhereTerm *pTerm; /* A single term of the WHERE clause */
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
@@ -89124,18 +95662,20 @@
used |= pTerm->prereqRight;
}
- /* Determine the value of nBound. */
+ /* Determine the value of estBound. */
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
- whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
+ whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound);
if( pTop ){
+ nBound = 1;
wsFlags |= WHERE_TOP_LIMIT;
used |= pTop->prereqRight;
}
if( pBtm ){
+ nBound++;
wsFlags |= WHERE_BTM_LIMIT;
used |= pBtm->prereqRight;
}
@@ -89166,7 +95706,7 @@
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
- ** seeking to entries in the main table (i.e. if the index is a covering
+ ** using the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
** wsFlags. Otherwise, set the bLookup variable to true. */
if( pIdx && wsFlags ){
@@ -89185,8 +95725,7 @@
}
}
- /**** Begin adding up the cost of using this index (Needs improvements)
- **
+ /*
** Estimate the number of rows of output. For an IN operator,
** do not let the estimate exceed half the rows in the table.
*/
@@ -89205,8 +95744,8 @@
/* Adjust the number of rows and the cost downward to reflect rows
** that are excluded by range constraints.
*/
- nRow = (nRow * (double)nBound) / (double)100;
- cost = (cost * (double)nBound) / (double)100;
+ nRow = (nRow * (double)estBound) / (double)100;
+ cost = (cost * (double)estBound) / (double)100;
/* Add in the estimated cost of sorting the result
*/
@@ -89223,17 +95762,75 @@
}
/**** Cost of using this index has now been computed ****/
+ /* If there are additional constraints on this table that cannot
+ ** be used with the current index, but which might lower the number
+ ** of output rows, adjust the nRow value accordingly. This only
+ ** matters if the current index is the least costly, so do not bother
+ ** with this step if we already know this index will not be chosen.
+ ** Also, never reduce the output row count below 2 using this step.
+ **
+ ** Do not reduce the output row count if pSrc is the only table that
+ ** is notReady; if notReady is a power of two. This will be the case
+ ** when the main sqlite3WhereBegin() loop is scanning for a table with
+ ** and "optimal" index, and on such a scan the output row count
+ ** reduction is not valid because it does not update the "pCost->used"
+ ** bitmap. The notReady bitmap will also be a power of two when we
+ ** are scanning for the last table in a 64-way join. We are willing
+ ** to bypass this optimization in that corner case.
+ */
+ if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
+ int k; /* Loop counter */
+ int nSkipEq = nEq; /* Number of == constraints to skip */
+ int nSkipRange = nBound; /* Number of < constraints to skip */
+ Bitmask thisTab; /* Bitmap for pSrc */
+
+ thisTab = getMask(pWC->pMaskSet, iCur);
+ for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
+ if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
+ if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
+ if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
+ if( nSkipEq ){
+ /* Ignore the first nEq equality matches since the index
+ ** has already accounted for these */
+ nSkipEq--;
+ }else{
+ /* Assume each additional equality match reduces the result
+ ** set size by a factor of 10 */
+ nRow /= 10;
+ }
+ }else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
+ if( nSkipRange ){
+ /* Ignore the first nBound range constraints since the index
+ ** has already accounted for these */
+ nSkipRange--;
+ }else{
+ /* Assume each additional range constraint reduces the result
+ ** set size by a factor of 3 */
+ nRow /= 3;
+ }
+ }else{
+ /* Any other expression lowers the output row count by half */
+ nRow /= 2;
+ }
+ }
+ if( nRow<2 ) nRow = 2;
+ }
+
+
WHERETRACE((
- "tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
- " wsFlags=%d (nRow=%.2f cost=%.2f)\n",
+ "%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
+ " notReady=0x%llx nRow=%.2f cost=%.2f used=0x%llx\n",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
- nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
+ nEq, nInMul, estBound, bSort, bLookup, wsFlags,
+ notReady, nRow, cost, used
));
/* If this index is the best we have seen so far, then record this
** index and its cost in the pCost structure.
*/
- if( (!pIdx || wsFlags) && cost<pCost->rCost ){
+ if( (!pIdx || wsFlags)
+ && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
+ ){
pCost->rCost = cost;
pCost->nRow = nRow;
pCost->used = used;
@@ -89268,10 +95865,12 @@
);
WHERETRACE(("best index is: %s\n",
- (pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
+ ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
+ pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+ bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
pCost->plan.wsFlags |= eqTermMask;
}
@@ -89329,7 +95928,7 @@
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm
- && ALWAYS((pTerm->wtFlags & TERM_CODED)==0)
+ && (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
pTerm->wtFlags |= TERM_CODED;
@@ -89527,7 +96126,9 @@
int k = pIdx->aiColumn[j];
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
if( NEVER(pTerm==0) ) break;
- assert( (pTerm->wtFlags & TERM_CODED)==0 );
+ /* The following true for indices with redundant columns.
+ ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
+ testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
@@ -89741,7 +96342,11 @@
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iCur;
pLevel->p2 = start;
- pLevel->p5 = (pStart==0 && pEnd==0) ?1:0;
+ if( pStart==0 && pEnd==0 ){
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }else{
+ assert( pLevel->p5==0 );
+ }
if( testOp!=OP_Noop ){
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
@@ -89810,7 +96415,8 @@
int iIdxCur; /* The VDBE cursor for the index */
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
- char *zAff;
+ char *zStartAff; /* Affinity for start of range constraint */
+ char *zEndAff; /* Affinity for end of range constraint */
pIdx = pLevel->plan.u.pIdx;
iIdxCur = pLevel->iIdxCur;
@@ -89851,15 +96457,16 @@
** starting at regBase.
*/
regBase = codeAllEqualityTerms(
- pParse, pLevel, pWC, notReady, nExtraReg, &zAff
+ pParse, pLevel, pWC, notReady, nExtraReg, &zStartAff
);
+ zEndAff = sqlite3DbStrDup(pParse->db, zStartAff);
addrNxt = pLevel->addrNxt;
/* If we are doing a reverse order scan on an ascending index, or
** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd).
*/
- if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
+ if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
}
@@ -89877,15 +96484,15 @@
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
- if( zAff ){
- if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
+ if( zStartAff ){
+ if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
/* Since the comparison is to be performed with no conversions
** applied to the operands, set the affinity to apply to pRight to
** SQLITE_AFF_NONE. */
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ zStartAff[nEq] = SQLITE_AFF_NONE;
}
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
+ zStartAff[nEq] = SQLITE_AFF_NONE;
}
}
nConstraint++;
@@ -89895,7 +96502,7 @@
startEq = 0;
start_constraints = 1;
}
- codeApplyAffinity(pParse, regBase, nConstraint, zAff);
+ codeApplyAffinity(pParse, regBase, nConstraint, zStartAff);
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
testcase( op==OP_Rewind );
@@ -89915,21 +96522,22 @@
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
- if( zAff ){
- if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
+ if( zEndAff ){
+ if( sqlite3CompareAffinity(pRight, zEndAff[nEq])==SQLITE_AFF_NONE){
/* Since the comparison is to be performed with no conversions
** applied to the operands, set the affinity to apply to pRight to
** SQLITE_AFF_NONE. */
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ zEndAff[nEq] = SQLITE_AFF_NONE;
}
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zEndAff[nEq]) ){
+ zEndAff[nEq] = SQLITE_AFF_NONE;
}
}
- codeApplyAffinity(pParse, regBase, nEq+1, zAff);
+ codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
nConstraint++;
}
- sqlite3DbFree(pParse->db, zAff);
+ sqlite3DbFree(pParse->db, zStartAff);
+ sqlite3DbFree(pParse->db, zEndAff);
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -90199,7 +96807,7 @@
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
- if( pWInfo ){
+ if( ALWAYS(pWInfo) ){
int i;
for(i=0; i<pWInfo->nLevel; i++){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
@@ -90210,6 +96818,13 @@
}
sqlite3DbFree(db, pInfo);
}
+ if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){
+ Index *pIdx = pWInfo->a[i].plan.u.pIdx;
+ if( pIdx ){
+ sqlite3DbFree(db, pIdx->zColAff);
+ sqlite3DbFree(db, pIdx);
+ }
+ }
}
whereClauseClear(pWInfo->pWC);
sqlite3DbFree(db, pWInfo);
@@ -90329,6 +96944,7 @@
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
+ testcase( pTabList->nSrc==BMS );
if( pTabList->nSrc>BMS ){
sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
return 0;
@@ -90356,6 +96972,8 @@
sizeof(WhereMaskSet)
);
if( db->mallocFailed ){
+ sqlite3DbFree(db, pWInfo);
+ pWInfo = 0;
goto whereBeginError;
}
pWInfo->nLevel = nTabList;
@@ -90364,6 +96982,7 @@
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
+ pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1];
/* Split the WHERE clause into separate subexpressions where each
@@ -90465,20 +97084,25 @@
bestPlan.rCost = SQLITE_BIG_DBL;
/* Loop through the remaining entries in the FROM clause to find the
- ** next nested loop. The FROM clause entries may be iterated through
+ ** next nested loop. The loop tests all FROM clause entries
** either once or twice.
**
- ** The first iteration, which is always performed, searches for the
- ** FROM clause entry that permits the lowest-cost, "optimal" scan. In
+ ** The first test is always performed if there are two or more entries
+ ** remaining and never performed if there is only one FROM clause entry
+ ** to choose from. The first test looks for an "optimal" scan. In
** this context an optimal scan is one that uses the same strategy
** for the given FROM clause entry as would be selected if the entry
** were used as the innermost nested loop. In other words, a table
** is chosen such that the cost of running that table cannot be reduced
- ** by waiting for other tables to run first.
+ ** by waiting for other tables to run first. This "optimal" test works
+ ** by first assuming that the FROM clause is on the inner loop and finding
+ ** its query plan, then checking to see if that query plan uses any
+ ** other FROM clause terms that are notReady. If no notReady terms are
+ ** used then the "optimal" query plan works.
**
- ** The second iteration is only performed if no optimal scan strategies
- ** were found by the first. This iteration is used to search for the
- ** lowest cost scan overall.
+ ** The second loop iteration is only performed if no optimal scan
+ ** strategies were found by the first loop. This 2nd iteration is used to
+ ** search for the lowest cost scan overall.
**
** Previous versions of SQLite performed only the second iteration -
** the next outermost loop was always that with the lowest overall
@@ -90496,9 +97120,8 @@
** algorithm may choose to use t2 for the outer loop, which is a much
** costlier approach.
*/
- for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
- Bitmask mask = (isOptimal ? 0 : notReady);
- assert( (nTabList-iFrom)>1 || isOptimal );
+ for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
+ Bitmask mask; /* Mask of tables not yet ready */
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
@@ -90511,6 +97134,7 @@
if( j==iFrom ) iFrom++;
continue;
}
+ mask = (isOptimal ? m : notReady);
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
assert( pTabItem->pTab );
@@ -90526,8 +97150,11 @@
assert( isOptimal || (sCost.used¬Ready)==0 );
if( (sCost.used¬Ready)==0
- && (j==iFrom || sCost.rCost<bestPlan.rCost)
+ && (bestJ<0 || sCost.rCost<bestPlan.rCost
+ || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
){
+ WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
+ sCost.rCost, sCost.nRow));
bestPlan = sCost;
bestJ = j;
}
@@ -90543,13 +97170,16 @@
}
andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan;
- if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
+ testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
+ testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
+ if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
pLevel->iIdxCur = pParse->nTab++;
}else{
pLevel->iIdxCur = -1;
}
notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
+ if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
/* Check that if the table scanned by this loop iteration had an
** INDEXED BY clause attached to it, that the named index is being
@@ -90596,6 +97226,7 @@
** searching those tables.
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
+ notReady = ~(Bitmask)0;
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
@@ -90608,7 +97239,9 @@
if( pItem->zAlias ){
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
}
- if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
+ }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
zMsg, pLevel->plan.u.pIdx->zName);
}else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -90631,8 +97264,11 @@
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
+ pLevel->iTabCur = pTabItem->iCursor;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
+ /* Do nothing */
+ }else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
@@ -90644,6 +97280,8 @@
&& (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
+ testcase( pTab->nCol==BMS-1 );
+ testcase( pTab->nCol==BMS );
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
Bitmask b = pTabItem->colUsed;
int n = 0;
@@ -90655,7 +97293,11 @@
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
- pLevel->iTabCur = pTabItem->iCursor;
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+ if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
+ constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
+ }else
+#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
Index *pIx = pLevel->plan.u.pIdx;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
@@ -90667,8 +97309,10 @@
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
+ notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
+ if( db->mallocFailed ) goto whereBeginError;
/* Generate the code to do the search. Each iteration of the for
** loop below generates code for a single nested loop of the VM
@@ -90736,7 +97380,10 @@
/* Jump here if malloc fails */
whereBeginError:
- whereInfoFree(db, pWInfo);
+ if( pWInfo ){
+ pParse->nQueryLoop = pWInfo->savedNQueryLoop;
+ whereInfoFree(db, pWInfo);
+ }
return 0;
}
@@ -90806,12 +97453,15 @@
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
- if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
- if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
- if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
+ if( (pTab->tabFlags & TF_Ephemeral)==0
+ && pTab->pSelect==0
+ && (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0
+ ){
+ int ws = pLevel->plan.wsFlags;
+ if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
- if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
}
@@ -90859,6 +97509,7 @@
/* Final cleanup
*/
+ pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
return;
}
@@ -91145,7 +97796,7 @@
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
-#define YY_ACTTAB_COUNT (1543)
+#define YY_ACTTAB_COUNT (1550)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 313, 49, 556, 46, 147, 172, 628, 598, 55, 55,
/* 10 */ 55, 55, 302, 53, 53, 53, 53, 52, 52, 51,
@@ -91295,13 +97946,13 @@
/* 1450 */ 249, 389, 487, 486, 314, 164, 602, 79, 310, 240,
/* 1460 */ 414, 373, 480, 163, 262, 371, 414, 162, 369, 602,
/* 1470 */ 78, 212, 478, 26, 477, 602, 9, 161, 467, 363,
- /* 1480 */ 141, 122, 339, 187, 119, 457, 348, 117, 347, 116,
- /* 1490 */ 115, 114, 448, 112, 182, 320, 22, 433, 19, 432,
- /* 1500 */ 431, 63, 428, 610, 193, 298, 597, 574, 572, 404,
- /* 1510 */ 555, 552, 290, 281, 510, 499, 498, 497, 495, 380,
- /* 1520 */ 356, 460, 256, 250, 345, 447, 306, 5, 570, 550,
- /* 1530 */ 299, 211, 370, 401, 550, 508, 502, 501, 490, 527,
- /* 1540 */ 525, 483, 238,
+ /* 1480 */ 141, 122, 339, 187, 119, 457, 348, 347, 117, 116,
+ /* 1490 */ 115, 112, 114, 448, 182, 22, 320, 433, 432, 431,
+ /* 1500 */ 19, 428, 610, 597, 574, 193, 572, 63, 298, 404,
+ /* 1510 */ 555, 552, 290, 281, 510, 460, 498, 499, 495, 447,
+ /* 1520 */ 356, 497, 256, 380, 306, 570, 5, 250, 345, 238,
+ /* 1530 */ 299, 550, 527, 490, 508, 525, 502, 401, 501, 963,
+ /* 1540 */ 211, 963, 483, 963, 963, 963, 963, 963, 963, 370,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 19, 222, 223, 224, 225, 24, 1, 26, 77, 78,
@@ -91452,18 +98103,18 @@
/* 1450 */ 107, 150, 176, 176, 111, 156, 174, 175, 179, 116,
/* 1460 */ 165, 18, 157, 156, 238, 157, 165, 156, 45, 174,
/* 1470 */ 175, 157, 157, 135, 239, 174, 175, 156, 189, 157,
- /* 1480 */ 68, 189, 139, 219, 22, 199, 157, 192, 18, 192,
- /* 1490 */ 192, 192, 199, 189, 219, 157, 243, 40, 243, 157,
- /* 1500 */ 157, 246, 38, 153, 196, 198, 166, 233, 233, 228,
- /* 1510 */ 177, 177, 209, 177, 182, 177, 166, 177, 166, 178,
- /* 1520 */ 242, 199, 242, 209, 209, 199, 148, 196, 166, 208,
- /* 1530 */ 195, 236, 237, 191, 208, 183, 183, 183, 186, 174,
- /* 1540 */ 174, 186, 92,
+ /* 1480 */ 68, 189, 139, 219, 22, 199, 157, 18, 192, 192,
+ /* 1490 */ 192, 189, 192, 199, 219, 243, 157, 40, 157, 157,
+ /* 1500 */ 243, 38, 153, 166, 233, 196, 233, 246, 198, 228,
+ /* 1510 */ 177, 177, 209, 177, 182, 199, 166, 177, 166, 199,
+ /* 1520 */ 242, 177, 242, 178, 148, 166, 196, 209, 209, 92,
+ /* 1530 */ 195, 208, 174, 186, 183, 174, 183, 191, 183, 253,
+ /* 1540 */ 236, 253, 186, 253, 253, 253, 253, 253, 253, 237,
};
#define YY_SHIFT_USE_DFLT (-90)
#define YY_SHIFT_COUNT (418)
#define YY_SHIFT_MIN (-89)
-#define YY_SHIFT_MAX (1470)
+#define YY_SHIFT_MAX (1469)
static const short yy_shift_ofst[] = {
/* 0 */ 993, 1114, 1343, 1114, 1213, 1213, 90, 90, 0, -19,
/* 10 */ 1213, 1213, 1213, 1213, 1213, 352, 517, 721, 1091, 1213,
@@ -91478,7 +98129,7 @@
/* 100 */ 1017, -69, -69, -69, -69, -1, -1, 58, 138, -44,
/* 110 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
/* 120 */ 517, 517, 517, 517, 517, 517, 202, 579, 517, 517,
- /* 130 */ 517, 517, 517, 382, 885, 1450, -90, -90, -90, 1293,
+ /* 130 */ 517, 517, 517, 382, 885, 1437, -90, -90, -90, 1293,
/* 140 */ 73, 272, 272, 309, 311, 297, 282, 216, 602, 538,
/* 150 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
/* 160 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
@@ -91489,8 +98140,8 @@
/* 210 */ 149, 604, 516, 149, 149, 508, 3, 299, 677, 871,
/* 220 */ 613, 613, 879, 871, 879, 144, 382, 226, 382, 226,
/* 230 */ 564, 226, 613, 226, 226, 404, 625, 625, 382, 426,
- /* 240 */ -89, 801, 1464, 1244, 1244, 1457, 1457, 1244, 1462, 1412,
- /* 250 */ 1188, 1470, 1470, 1470, 1470, 1244, 1188, 1462, 1412, 1412,
+ /* 240 */ -89, 801, 1463, 1244, 1244, 1457, 1457, 1244, 1462, 1412,
+ /* 250 */ 1188, 1469, 1469, 1469, 1469, 1244, 1188, 1462, 1412, 1412,
/* 260 */ 1244, 1443, 1338, 1423, 1244, 1244, 1443, 1244, 1443, 1244,
/* 270 */ 1443, 1414, 1306, 1306, 1306, 1365, 1348, 1348, 1414, 1306,
/* 280 */ 1317, 1306, 1365, 1306, 1306, 1267, 1268, 1267, 1268, 1267,
@@ -91511,7 +98162,7 @@
#define YY_REDUCE_USE_DFLT (-222)
#define YY_REDUCE_COUNT (312)
#define YY_REDUCE_MIN (-221)
-#define YY_REDUCE_MAX (1378)
+#define YY_REDUCE_MAX (1376)
static const short yy_reduce_ofst[] = {
/* 0 */ 310, 994, 1134, 221, 169, 157, 89, 18, 83, 301,
/* 10 */ 377, 316, 312, 16, 295, 238, 249, 391, 1301, 1295,
@@ -91532,13 +98183,13 @@
/* 160 */ 1084, 1066, 1049, 1011, 1010, 1006, 1002, 999, 998, 973,
/* 170 */ 972, 970, 966, 964, 895, 894, 892, 833, 822, 762,
/* 180 */ 761, 229, 811, 804, 803, 389, 688, 808, 807, 737,
- /* 190 */ 460, 464, 572, 584, 1355, 1366, 1365, 1352, 1354, 1353,
- /* 200 */ 1352, 1326, 1335, 1342, 1335, 1335, 1335, 1335, 1335, 1335,
- /* 210 */ 1335, 1295, 1295, 1335, 1335, 1321, 1362, 1331, 1378, 1326,
- /* 220 */ 1315, 1314, 1280, 1322, 1278, 1341, 1352, 1340, 1350, 1338,
- /* 230 */ 1332, 1336, 1303, 1334, 1333, 1281, 1275, 1274, 1340, 1307,
- /* 240 */ 1308, 1350, 1255, 1343, 1342, 1255, 1253, 1338, 1275, 1304,
- /* 250 */ 1293, 1299, 1298, 1297, 1295, 1329, 1286, 1264, 1292, 1289,
+ /* 190 */ 460, 464, 572, 584, 1356, 1361, 1358, 1347, 1355, 1353,
+ /* 200 */ 1351, 1323, 1335, 1346, 1335, 1335, 1335, 1335, 1335, 1335,
+ /* 210 */ 1335, 1312, 1304, 1335, 1335, 1323, 1359, 1330, 1376, 1320,
+ /* 220 */ 1319, 1318, 1280, 1316, 1278, 1345, 1352, 1344, 1350, 1340,
+ /* 230 */ 1332, 1336, 1303, 1334, 1333, 1281, 1273, 1271, 1337, 1310,
+ /* 240 */ 1309, 1349, 1261, 1342, 1341, 1257, 1252, 1339, 1275, 1302,
+ /* 250 */ 1294, 1300, 1298, 1297, 1296, 1329, 1286, 1264, 1292, 1289,
/* 260 */ 1322, 1321, 1235, 1226, 1315, 1314, 1311, 1308, 1307, 1305,
/* 270 */ 1299, 1279, 1277, 1276, 1270, 1258, 1211, 1209, 1250, 1259,
/* 280 */ 1255, 1242, 1243, 1241, 1201, 1200, 1184, 1186, 1182, 1178,
@@ -92958,7 +99609,7 @@
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy328);}
break;
case 13: /* transtype ::= */
-{yygotominor.yy328 = (pParse->db->flags&SQLITE_BeginImmediate) ? TK_IMMEDIATE : TK_DEFERRED;}/* Android Change */
+{yygotominor.yy328 = TK_DEFERRED;}
break;
case 14: /* transtype ::= DEFERRED */
case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
@@ -95405,9 +102056,7 @@
extern "C" {
#endif /* __cplusplus */
-// Begin Android Change
-SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db, const char* registerAs);
-// End Android Change
+SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db, const char* registerAs); // Android Change
#if 0
} /* extern "C" */
@@ -95840,7 +102489,12 @@
** NULL.
*/
case SQLITE_CONFIG_LOG: {
- sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
+ /* MSVC is picky about pulling func ptrs from va lists.
+ ** http://support.microsoft.com/kb/47961
+ ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
+ */
+ typedef void(*LOGFUNC_t)(void*,int,const char*);
+ sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
break;
}
@@ -96227,7 +102881,7 @@
/* SQLITE_NOTFOUND */ 0,
/* SQLITE_FULL */ "database or disk is full",
/* SQLITE_CANTOPEN */ "unable to open database file",
- /* SQLITE_PROTOCOL */ 0,
+ /* SQLITE_PROTOCOL */ "locking protocol",
/* SQLITE_EMPTY */ "table contains no data",
/* SQLITE_SCHEMA */ "database schema has changed",
/* SQLITE_TOOBIG */ "string or blob too big",
@@ -96501,7 +103155,7 @@
char *zFunc8;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
+ zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
@@ -96637,6 +103291,145 @@
return pRet;
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
+** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
+** is greater than sqlite3.pWalArg cast to an integer (the value configured by
+** wal_autocheckpoint()).
+*/
+SQLITE_PRIVATE int sqlite3WalDefaultHook(
+ void *pClientData, /* Argument */
+ sqlite3 *db, /* Connection */
+ const char *zDb, /* Database */
+ int nFrame /* Size of WAL */
+){
+ if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){
+ sqlite3BeginBenignMalloc();
+ sqlite3_wal_checkpoint(db, zDb);
+ sqlite3EndBenignMalloc();
+ }
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OMIT_WAL */
+
+/*
+** Configure an sqlite3_wal_hook() callback to automatically checkpoint
+** a database after committing a transaction if there are nFrame or
+** more frames in the log file. Passing zero or a negative value as the
+** nFrame parameter disables automatic checkpoints entirely.
+**
+** The callback registered by this function replaces any existing callback
+** registered using sqlite3_wal_hook(). Likewise, registering a callback
+** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
+** configured by this function.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
+#ifndef SQLITE_OMIT_WAL
+ if( nFrame>0 ){
+ sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
+ }else{
+ sqlite3_wal_hook(db, 0, 0);
+ }
+#endif
+ return SQLITE_OK;
+}
+
+/*
+** Register a callback to be invoked each time a transaction is written
+** into the write-ahead-log by this database connection.
+*/
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3 *db, /* Attach the hook to this db handle */
+ int(*xCallback)(void *, sqlite3*, const char*, int),
+ void *pArg /* First argument passed to xCallback() */
+){
+#ifndef SQLITE_OMIT_WAL
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pWalArg;
+ db->xWalCallback = xCallback;
+ db->pWalArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return pRet;
+#else
+ return 0;
+#endif
+}
+
+
+/*
+** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
+** to contains a zero-length string, all attached databases are
+** checkpointed.
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
+#ifdef SQLITE_OMIT_WAL
+ return SQLITE_OK;
+#else
+ int rc; /* Return code */
+ int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
+
+ sqlite3_mutex_enter(db->mutex);
+ if( zDb && zDb[0] ){
+ iDb = sqlite3FindDbName(db, zDb);
+ }
+ if( iDb<0 ){
+ rc = SQLITE_ERROR;
+ sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
+ }else{
+ rc = sqlite3Checkpoint(db, iDb);
+ sqlite3Error(db, rc, 0);
+ }
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+#endif
+}
+
+#ifndef SQLITE_OMIT_WAL
+/*
+** Run a checkpoint on database iDb. This is a no-op if database iDb is
+** not currently open in WAL mode.
+**
+** If a transaction is open on the database being checkpointed, this
+** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
+** an error occurs while running the checkpoint, an SQLite error code is
+** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
+**
+** The mutex on database handle db should be held by the caller. The mutex
+** associated with the specific b-tree being checkpointed is taken by
+** this function while the checkpoint is running.
+**
+** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
+** checkpointed. If an error is encountered it is returned immediately -
+** no attempt is made to checkpoint any remaining databases.
+*/
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb){
+ int rc = SQLITE_OK; /* Return code */
+ int i; /* Used to iterate through attached dbs */
+
+ assert( sqlite3_mutex_held(db->mutex) );
+
+ for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
+ if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ if( sqlite3BtreeIsInReadTrans(pBt) ){
+ rc = SQLITE_LOCKED;
+ }else{
+ sqlite3BtreeEnter(pBt);
+ rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+#endif /* SQLITE_OMIT_WAL */
+
/*
** This function returns true if main-memory should be used instead of
** a temporary file for transient pager files and statement journals.
@@ -97059,7 +103852,7 @@
db->autoCommit = 1;
db->nextAutovac = -1;
db->nextPagesize = 0;
- db->flags |= SQLITE_ShortColNames
+ db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
@@ -97150,9 +103943,6 @@
}
#ifdef SQLITE_ENABLE_FTS1
-// Begin Android change
-#error "Do not enable FTS1 on Android as FTS3_BACKWARDS has been in use"
-// End Android add
if( !db->mallocFailed ){
extern int sqlite3Fts1Init(sqlite3*);
rc = sqlite3Fts1Init(db);
@@ -97160,9 +103950,6 @@
#endif
#ifdef SQLITE_ENABLE_FTS2
-// Begin Android change
-#error "Do not enable FTS2 on Android as FTS3_BACKWARDS has been in use"
-// End Android add
if( !db->mallocFailed && rc==SQLITE_OK ){
extern int sqlite3Fts2Init(sqlite3*);
rc = sqlite3Fts2Init(db);
@@ -97218,6 +104005,8 @@
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
+ sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
+
opendb_out:
if( db ){
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
@@ -97345,7 +104134,7 @@
char *zName8;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- zName8 = sqlite3Utf16to8(db, zName, -1);
+ zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
if( zName8 ){
rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
sqlite3DbFree(db, zName8);
@@ -97392,7 +104181,6 @@
}
#endif /* SQLITE_OMIT_UTF16 */
-#ifndef SQLITE_OMIT_GLOBALRECOVER
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -97402,7 +104190,6 @@
return SQLITE_OK;
}
#endif
-#endif
/*
** Test to see whether or not the database connection is in autocommit
@@ -97430,17 +104217,22 @@
SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_CORRUPT,
- "database corruption found by source line %d", lineno);
+ "database corruption at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_CORRUPT;
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_MISUSE, "misuse detected by source line %d", lineno);
+ sqlite3_log(SQLITE_MISUSE,
+ "misuse at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_MISUSE;
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_CANTOPEN, "cannot open file at source line %d", lineno);
+ sqlite3_log(SQLITE_CANTOPEN,
+ "cannot open file at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_CANTOPEN;
}
@@ -97712,9 +104504,13 @@
** dileterious behavior.
*/
case SQLITE_TESTCTRL_PENDING_BYTE: {
- unsigned int newVal = va_arg(ap, unsigned int);
- rc = sqlite3PendingByte;
- if( newVal ) sqlite3PendingByte = newVal;
+ rc = PENDING_BYTE;
+#ifndef SQLITE_OMIT_WSD
+ {
+ unsigned int newVal = va_arg(ap, unsigned int);
+ if( newVal ) sqlite3PendingByte = newVal;
+ }
+#endif
break;
}
@@ -97818,6 +104614,15 @@
}
#endif
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PGHDRSZ)
+ **
+ ** Return the size of a pcache header in bytes.
+ */
+ case SQLITE_TESTCTRL_PGHDRSZ: {
+ rc = sizeof(PgHdr);
+ break;
+ }
+
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -97983,6 +104788,7 @@
if( xNotify==0 ){
removeFromBlockedList(db);
+ db->pBlockingConnection = 0;
db->pUnlockConnection = 0;
db->xUnlockNotify = 0;
db->pUnlockArg = 0;
@@ -98183,9 +104989,6 @@
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* TODO(shess) Consider exporting this comment to an HTML file or the
-** wiki.
-*/
/* The full-text index is stored in a series of b+tree (-like)
** structures called segments which map terms to doclists. The
** structures are like b+trees in layout, but are constructed from the
@@ -98208,30 +105011,40 @@
** 21 bits - BBA
** and so on.
**
-** This is identical to how sqlite encodes varints (see util.c).
+** This is similar in concept to how sqlite encodes "varints" but
+** the encoding is not the same. SQLite varints are big-endian
+** are are limited to 9 bytes in length whereas FTS3 varints are
+** little-endian and can be up to 10 bytes in length (in theory).
+**
+** Example encodings:
+**
+** 1: 0x01
+** 127: 0x7f
+** 128: 0x81 0x00
**
**
**** Document lists ****
** A doclist (document list) holds a docid-sorted list of hits for a
-** given term. Doclists hold docids, and can optionally associate
-** token positions and offsets with docids.
+** given term. Doclists hold docids and associated token positions.
+** A docid is the unique integer identifier for a single document.
+** A position is the index of a word within the document. The first
+** word of the document has a position of 0.
**
-** A DL_POSITIONS_OFFSETS doclist is stored like this:
+** FTS3 used to optionally store character offsets using a compile-time
+** option. But that functionality is no longer supported.
+**
+** A doclist is stored like this:
**
** array {
** varint docid;
** array { (position list for column 0)
-** varint position; (delta from previous position plus POS_BASE)
-** varint startOffset; (delta from previous startOffset)
-** varint endOffset; (delta from startOffset)
+** varint position; (2 more than the delta from previous position)
** }
** array {
** varint POS_COLUMN; (marks start of position list for new column)
** varint column; (index of new column)
** array {
-** varint position; (delta from previous position plus POS_BASE)
-** varint startOffset;(delta from previous startOffset)
-** varint endOffset; (delta from startOffset)
+** varint position; (2 more than the delta from previous position)
** }
** }
** varint POS_END; (marks end of positions for this document.
@@ -98239,19 +105052,32 @@
**
** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream
-** generated by the tokenizer, while an "offset" is a byte offset,
-** both based at 0. Note that POS_END and POS_COLUMN occur in the
-** same logical place as the position element, and act as sentinals
-** ending a position list array.
+** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
+** in the same logical place as the position element, and act as sentinals
+** ending a position list array. POS_END is 0. POS_COLUMN is 1.
+** The positions numbers are not stored literally but rather as two more
+** than the difference from the prior position, or the just the position plus
+** 2 for the first position. Example:
**
-** A DL_POSITIONS doclist omits the startOffset and endOffset
-** information. A DL_DOCIDS doclist omits both the position and
-** offset information, becoming an array of varint-encoded docids.
+** label: A B C D E F G H I J K
+** value: 123 5 9 1 1 14 35 0 234 72 0
**
-** On-disk data is stored as type DL_DEFAULT, so we don't serialize
-** the type. Due to how deletion is implemented in the segmentation
-** system, on-disk doclists MUST store at least positions.
+** The 123 value is the first docid. For column zero in this document
+** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1
+** at D signals the start of a new column; the 1 at E indicates that the
+** new column is column number 1. There are two positions at 12 and 45
+** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The
+** 234 at I is the next docid. It has one position 72 (72-2) and then
+** terminates with the 0 at K.
**
+** A "position-list" is the list of positions for multiple columns for
+** a single docid. A "column-list" is the set of positions for a single
+** column. Hence, a position-list consists of one or more column-lists,
+** a document record consists of a docid followed by a position-list and
+** a doclist consists of one or more document records.
+**
+** A bare doclist omits the position information, becoming an
+** array of varint-encoded docids.
**
**** Segment leaf nodes ****
** Segment leaf nodes store terms and doclists, ordered by term. Leaf
@@ -98766,6 +105592,20 @@
#define FTS3_VARINT_MAX 10
/*
+** The testcase() macro is only used by the amalgamation. If undefined,
+** make it a no-op.
+*/
+#ifndef testcase
+# define testcase(X)
+#endif
+
+/*
+** Terminator values for position-lists and column-lists.
+*/
+#define POS_COLUMN (1) /* Column-list terminator */
+#define POS_END (0) /* Position-list terminator */
+
+/*
** This section provides definitions to allow the
** FTS3 extension to be compiled outside of the
** amalgamation.
@@ -98816,7 +105656,7 @@
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
- sqlite3_stmt *aStmt[18];
+ sqlite3_stmt *aStmt[25];
/* Pointer to string containing the SQL:
**
@@ -98830,6 +105670,8 @@
sqlite3_stmt **aLeavesStmt; /* Array of prepared zSelectLeaves stmts */
int nNodeSize; /* Soft limit for node size */
+ u8 bHasContent; /* True if %_content table exists */
+ u8 bHasDocsize; /* True if %_docsize table exists */
/* The following hash table is used to buffer pending index updates during
** transactions. Variable nPendingData estimates the memory size of the
@@ -98860,8 +105702,8 @@
char *pNextId; /* Pointer into the body of aDoclist */
char *aDoclist; /* List of docids for full-text queries */
int nDoclist; /* Size of buffer at aDoclist */
- int isMatchinfoOk; /* True when aMatchinfo[] matches iPrevId */
- u32 *aMatchinfo;
+ int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
+ u32 *aMatchinfo; /* Information about most recent match */
};
/*
@@ -98967,6 +105809,8 @@
);
SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
@@ -98991,6 +105835,7 @@
SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -99001,10 +105846,7 @@
/* fts3_snippet.c */
SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
-SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context*, Fts3Cursor*,
- const char *, const char *, const char *
-);
-SQLITE_PRIVATE void sqlite3Fts3Snippet2(sqlite3_context *, Fts3Cursor *, const char *,
+SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
const char *, const char *, int, int
);
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
@@ -99074,8 +105916,7 @@
}
/*
-** Return the number of bytes required to store the value passed as the
-** first argument in varint form.
+** Return the number of bytes required to encode v as a varint
*/
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){
int i = 0;
@@ -99124,12 +105965,23 @@
}
}
+/*
+** Read a single varint from the doclist at *pp and advance *pp to point
+** to the first byte past the end of the varint. Add the value of the varint
+** to *pVal.
+*/
static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
sqlite3_int64 iVal;
*pp += sqlite3Fts3GetVarint(*pp, &iVal);
*pVal += iVal;
}
+/*
+** As long as *pp has not reached its end (pEnd), then do the same
+** as fts3GetDeltaVarint(): read a single varint and add it to *pVal.
+** But if we have reached the end of the varint, just set *pp=0 and
+** leave *pVal unchanged.
+*/
static void fts3GetDeltaVarint2(char **pp, char *pEnd, sqlite3_int64 *pVal){
if( *pp>=pEnd ){
*pp = 0;
@@ -99165,29 +106017,46 @@
}
/*
+** Construct one or more SQL statements from the format string given
+** and then evaluate those statements. The success code is writting
+** into *pRc.
+**
+** If *pRc is initially non-zero then this routine is a no-op.
+*/
+static void fts3DbExec(
+ int *pRc, /* Success code */
+ sqlite3 *db, /* Database in which to run SQL */
+ const char *zFormat, /* Format string for SQL */
+ ... /* Arguments to the format string */
+){
+ va_list ap;
+ char *zSql;
+ if( *pRc ) return;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( zSql==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ *pRc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ }
+}
+
+/*
** The xDestroy() virtual table method.
*/
static int fts3DestroyMethod(sqlite3_vtab *pVtab){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
Fts3Table *p = (Fts3Table *)pVtab;
+ sqlite3 *db = p->db;
- /* Create a script to drop the underlying three storage tables. */
- char *zSql = sqlite3_mprintf(
- "DROP TABLE IF EXISTS %Q.'%q_content';"
- "DROP TABLE IF EXISTS %Q.'%q_segments';"
- "DROP TABLE IF EXISTS %Q.'%q_segdir';",
- p->zDb, p->zName, p->zDb, p->zName, p->zDb, p->zName
- );
-
- /* If malloc has failed, set rc to SQLITE_NOMEM. Otherwise, try to
- ** execute the SQL script created above.
- */
- if( zSql ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_free(zSql);
- }else{
- rc = SQLITE_NOMEM;
- }
+ /* Drop the shadow tables */
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName);
/* If everything has worked, invoke fts3DisconnectMethod() to free the
** memory associated with the Fts3Table structure and return SQLITE_OK.
@@ -99234,24 +106103,39 @@
** Create the backing store tables (%_content, %_segments and %_segdir)
** required by the FTS3 table passed as the only argument. This is done
** as part of the vtab xCreate() method.
+**
+** If the p->bHasDocsize boolean is true (indicating that this is an
+** FTS4 table, not an FTS3 table) then also create the %_docsize and
+** %_stat tables required by FTS4.
*/
static int fts3CreateTables(Fts3Table *p){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
char *zContentCols; /* Columns of %_content table */
- char *zSql; /* SQL script to create required tables */
+ sqlite3 *db = p->db; /* The database connection */
/* Create a list of user columns for the content table */
- zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
- for(i=0; zContentCols && i<p->nColumn; i++){
- char *z = p->azColumn[i];
- zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
- }
+ if( p->bHasContent ){
+ zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
+ for(i=0; zContentCols && i<p->nColumn; i++){
+ char *z = p->azColumn[i];
+ zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
+ }
+ if( zContentCols==0 ) rc = SQLITE_NOMEM;
- /* Create the whole SQL script */
- zSql = sqlite3_mprintf(
- "CREATE TABLE %Q.'%q_content'(%s);"
- "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);"
+ /* Create the content table */
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_content'(%s)",
+ p->zDb, p->zName, zContentCols
+ );
+ sqlite3_free(zContentCols);
+ }
+ /* Create other tables */
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
+ p->zDb, p->zName
+ );
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_segdir'("
"level INTEGER,"
"idx INTEGER,"
@@ -99261,30 +106145,64 @@
"root BLOB,"
"PRIMARY KEY(level, idx)"
");",
- p->zDb, p->zName, zContentCols, p->zDb, p->zName, p->zDb, p->zName
+ p->zDb, p->zName
);
-
- /* Unless a malloc() failure has occurred, execute the SQL script to
- ** create the tables used to store data for this FTS3 virtual table.
- */
- if( zContentCols==0 || zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
+ if( p->bHasDocsize ){
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
+ p->zDb, p->zName
+ );
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_stat'(id INTEGER PRIMARY KEY, value BLOB);",
+ p->zDb, p->zName
+ );
}
-
- sqlite3_free(zSql);
- sqlite3_free(zContentCols);
return rc;
}
/*
+** An sqlite3_exec() callback for fts3TableExists.
+*/
+static int fts3TableExistsCallback(void *pArg, int n, char **pp1, char **pp2){
+ UNUSED_PARAMETER(n);
+ UNUSED_PARAMETER(pp1);
+ UNUSED_PARAMETER(pp2);
+ *(int*)pArg = 1;
+ return 1;
+}
+
+/*
+** Determine if a table currently exists in the database.
+*/
+static void fts3TableExists(
+ int *pRc, /* Success code */
+ sqlite3 *db, /* The database connection to test */
+ const char *zDb, /* ATTACHed database within the connection */
+ const char *zName, /* Name of the FTS3 table */
+ const char *zSuffix, /* Shadow table extension */
+ u8 *pResult /* Write results here */
+){
+ int rc = SQLITE_OK;
+ int res = 0;
+ char *zSql;
+ if( *pRc ) return;
+ zSql = sqlite3_mprintf(
+ "SELECT 1 FROM %Q.sqlite_master WHERE name='%q%s'",
+ zDb, zName, zSuffix
+ );
+ rc = sqlite3_exec(db, zSql, fts3TableExistsCallback, &res, 0);
+ sqlite3_free(zSql);
+ *pResult = (u8)(res & 0xff);
+ if( rc!=SQLITE_ABORT ) *pRc = rc;
+}
+
+/*
** This function is the implementation of both the xConnect and xCreate
** methods of the FTS3 virtual table.
**
** The argv[] array contains the following:
**
-** argv[0] -> module name
+** argv[0] -> module name ("fts3" or "fts4")
** argv[1] -> database name
** argv[2] -> table name
** argv[...] -> "column name" and other module argument fields.
@@ -99303,12 +106221,12 @@
int rc; /* Return code */
int i; /* Iterator variable */
int nByte; /* Size of allocation used for *p */
- int iCol;
- int nString = 0;
- int nCol = 0;
- char *zCsr;
- int nDb;
- int nName;
+ int iCol; /* Column index */
+ int nString = 0; /* Bytes required to hold all column names */
+ int nCol = 0; /* Number of columns in the FTS table */
+ char *zCsr; /* Space for holding column names */
+ int nDb; /* Bytes required to hold database name */
+ int nName; /* Bytes required to hold table name */
const char *zTokenizer = 0; /* Name of tokenizer to use */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
@@ -99394,9 +106312,15 @@
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
+ p->bHasContent = 1;
+ p->bHasDocsize = argv[0][3]=='4';
rc = fts3CreateTables(p);
- if( rc!=SQLITE_OK ) goto fts3_init_out;
+ }else{
+ rc = SQLITE_OK;
+ fts3TableExists(&rc, db, argv[1], argv[2], "_content", &p->bHasContent);
+ fts3TableExists(&rc, db, argv[1], argv[2], "_docsize", &p->bHasDocsize);
}
+ if( rc!=SQLITE_OK ) goto fts3_init_out;
rc = fts3DeclareVtab(p);
if( rc!=SQLITE_OK ) goto fts3_init_out;
@@ -99518,12 +106442,6 @@
return SQLITE_OK;
}
-/****************************************************************/
-/****************************************************************/
-/****************************************************************/
-/****************************************************************/
-
-
/*
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
@@ -99538,6 +106456,11 @@
return SQLITE_OK;
}
+/*
+** Position the pCsr->pStmt statement so that it is on the row
+** of the %_content table that contains the last match. Return
+** SQLITE_OK on success.
+*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
if( pCsr->isRequireSeek ){
pCsr->isRequireSeek = 0;
@@ -99564,6 +106487,17 @@
}
}
+/*
+** Advance the cursor to the next row in the %_content table that
+** matches the search criteria. For a MATCH search, this will be
+** the next row that matches. For a full-table scan, this will be
+** simply the next row in the %_content table. For a docid lookup,
+** this routine simply sets the EOF flag.
+**
+** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
+** even if we reach end-of-file. The fts3EofMethod() will be called
+** subsequently to determine whether or not an EOF was hit.
+*/
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
int rc = SQLITE_OK; /* Return code */
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
@@ -99579,7 +106513,7 @@
sqlite3_reset(pCsr->pStmt);
fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
pCsr->isRequireSeek = 1;
- pCsr->isMatchinfoOk = 1;
+ pCsr->isMatchinfoNeeded = 1;
}
return rc;
}
@@ -99697,24 +106631,37 @@
/*
** When this function is called, *ppPoslist is assumed to point to the
-** start of a position-list.
+** start of a position-list. After it returns, *ppPoslist points to the
+** first byte after the position-list.
+**
+** A position list is list of positions (delta encoded) and columns for
+** a single document record of a doclist. So, in other words, this
+** routine advances *ppPoslist so that it points to the next docid in
+** the doclist, or to the first byte past the end of the doclist.
+**
+** If pp is not NULL, then the contents of the position list are copied
+** to *pp. *pp is set to point to the first byte past the last byte copied
+** before this function returns.
*/
static void fts3PoslistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
/* The end of a position list is marked by a zero encoded as an FTS3
- ** varint. A single 0x00 byte. Except, if the 0x00 byte is preceded by
+ ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
** of some other, multi-byte, value.
**
- ** The following block moves pEnd to point to the first byte that is not
+ ** The following while-loop moves pEnd to point to the first byte that is not
** immediately preceded by a byte with the 0x80 bit set. Then increments
** pEnd once more so that it points to the byte immediately following the
** last byte in the position-list.
*/
- while( *pEnd | c ) c = *pEnd++ & 0x80;
- pEnd++;
+ while( *pEnd | c ){
+ c = *pEnd++ & 0x80;
+ testcase( c!=0 && (*pEnd)==0 );
+ }
+ pEnd++; /* Advance past the POS_END terminator byte */
if( pp ){
int n = (int)(pEnd - *ppPoslist);
@@ -99726,12 +106673,34 @@
*ppPoslist = pEnd;
}
+/*
+** When this function is called, *ppPoslist is assumed to point to the
+** start of a column-list. After it returns, *ppPoslist points to the
+** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
+**
+** A column-list is list of delta-encoded positions for a single column
+** within a single document within a doclist.
+**
+** The column-list is terminated either by a POS_COLUMN varint (1) or
+** a POS_END varint (0). This routine leaves *ppPoslist pointing to
+** the POS_COLUMN or POS_END that terminates the column-list.
+**
+** If pp is not NULL, then the contents of the column-list are copied
+** to *pp. *pp is set to point to the first byte past the last byte copied
+** before this function returns. The POS_COLUMN or POS_END terminator
+** is not copied into *pp.
+*/
static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
- /* A column-list is terminated by either a 0x01 or 0x00. */
- while( 0xFE & (*pEnd | c) ) c = *pEnd++ & 0x80;
+ /* A column-list is terminated by either a 0x01 or 0x00 byte that is
+ ** not part of a multi-byte varint.
+ */
+ while( 0xFE & (*pEnd | c) ){
+ c = *pEnd++ & 0x80;
+ testcase( c!=0 && ((*pEnd)&0xfe)==0 );
+ }
if( pp ){
int n = (int)(pEnd - *ppPoslist);
char *p = *pp;
@@ -99743,37 +106712,45 @@
}
/*
-** Value used to signify the end of an offset-list. This is safe because
+** Value used to signify the end of an position-list. This is safe because
** it is not possible to have a document with 2^31 terms.
*/
-#define OFFSET_LIST_END 0x7fffffff
+#define POSITION_LIST_END 0x7fffffff
/*
-** This function is used to help parse offset-lists. When this function is
-** called, *pp may point to the start of the next varint in the offset-list
-** being parsed, or it may point to 1 byte past the end of the offset-list
-** (in which case **pp will be 0x00 or 0x01).
+** This function is used to help parse position-lists. When this function is
+** called, *pp may point to the start of the next varint in the position-list
+** being parsed, or it may point to 1 byte past the end of the position-list
+** (in which case **pp will be a terminator bytes POS_END (0) or
+** (1)).
**
-** If *pp points past the end of the current offset list, set *pi to
-** OFFSET_LIST_END and return. Otherwise, read the next varint from *pp,
+** If *pp points past the end of the current position-list, set *pi to
+** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
** increment the current value of *pi by the value read, and set *pp to
** point to the next value before returning.
+**
+** Before calling this routine *pi must be initialized to the value of
+** the previous position, or zero if we are reading the first position
+** in the position-list. Because positions are delta-encoded, the value
+** of the previous position is needed in order to compute the value of
+** the next position.
*/
static void fts3ReadNextPos(
- char **pp, /* IN/OUT: Pointer into offset-list buffer */
- sqlite3_int64 *pi /* IN/OUT: Value read from offset-list */
+ char **pp, /* IN/OUT: Pointer into position-list buffer */
+ sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
- if( **pp&0xFE ){
+ if( (**pp)&0xFE ){
fts3GetDeltaVarint(pp, pi);
*pi -= 2;
}else{
- *pi = OFFSET_LIST_END;
+ *pi = POSITION_LIST_END;
}
}
/*
-** If parameter iCol is not 0, write an 0x01 byte followed by the value of
-** iCol encoded as a varint to *pp.
+** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by
+** the value of iCol encoded as a varint to *pp. This will start a new
+** column list.
**
** Set *pp to point to the byte just after the last byte written before
** returning (do not modify it if iCol==0). Return the total number of bytes
@@ -99791,7 +106768,11 @@
}
/*
-**
+** Compute the union of two position lists. The output written
+** into *pp contains all positions of both *pp1 and *pp2 in sorted
+** order and with any duplicates removed. All pointers are
+** updated appropriately. The caller is responsible for insuring
+** that there is enough space in *pp to hold the complete output.
*/
static void fts3PoslistMerge(
char **pp, /* Output buffer */
@@ -99803,32 +106784,33 @@
char *p2 = *pp2;
while( *p1 || *p2 ){
- int iCol1;
- int iCol2;
+ int iCol1; /* The current column index in pp1 */
+ int iCol2; /* The current column index in pp2 */
- if( *p1==0x01 ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
- else if( *p1==0x00 ) iCol1 = OFFSET_LIST_END;
+ if( *p1==POS_COLUMN ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
+ else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
else iCol1 = 0;
- if( *p2==0x01 ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
- else if( *p2==0x00 ) iCol2 = OFFSET_LIST_END;
+ if( *p2==POS_COLUMN ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
+ else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
else iCol2 = 0;
if( iCol1==iCol2 ){
- sqlite3_int64 i1 = 0;
- sqlite3_int64 i2 = 0;
+ sqlite3_int64 i1 = 0; /* Last position from pp1 */
+ sqlite3_int64 i2 = 0; /* Last position from pp2 */
sqlite3_int64 iPrev = 0;
int n = fts3PutColNumber(&p, iCol1);
p1 += n;
p2 += n;
- /* At this point, both p1 and p2 point to the start of offset-lists.
- ** An offset-list is a list of non-negative delta-encoded varints, each
- ** incremented by 2 before being stored. Each list is terminated by a 0
- ** or 1 value (0x00 or 0x01). The following block merges the two lists
+ /* At this point, both p1 and p2 point to the start of column-lists
+ ** for the same column (the column with index iCol1 and iCol2).
+ ** A column-list is a list of non-negative delta-encoded varints, each
+ ** incremented by 2 before being stored. Each list is terminated by a
+ ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
** and writes the results to buffer p. p is left pointing to the byte
- ** after the list written. No terminator (0x00 or 0x01) is written to
- ** the output.
+ ** after the list written. No terminator (POS_END or POS_COLUMN) is
+ ** written to the output.
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
@@ -99843,7 +106825,7 @@
}else{
fts3ReadNextPos(&p2, &i2);
}
- }while( i1!=OFFSET_LIST_END || i2!=OFFSET_LIST_END );
+ }while( i1!=POSITION_LIST_END || i2!=POSITION_LIST_END );
}else if( iCol1<iCol2 ){
p1 += fts3PutColNumber(&p, iCol1);
fts3ColumnlistCopy(&p, &p1);
@@ -99853,7 +106835,7 @@
}
}
- *p++ = '\0';
+ *p++ = POS_END;
*pp = p;
*pp1 = p1 + 1;
*pp2 = p2 + 1;
@@ -99876,11 +106858,11 @@
int iCol1 = 0;
int iCol2 = 0;
assert( *p1!=0 && *p2!=0 );
- if( *p1==0x01 ){
+ if( *p1==POS_COLUMN ){
p1++;
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
}
- if( *p2==0x01 ){
+ if( *p2==POS_COLUMN ){
p2++;
p2 += sqlite3Fts3GetVarint32(p2, &iCol2);
}
@@ -99893,11 +106875,12 @@
sqlite3_int64 iPos2 = 0;
if( pp && iCol1 ){
- *p++ = 0x01;
+ *p++ = POS_COLUMN;
p += sqlite3Fts3PutVarint(p, iCol1);
}
- assert( *p1!=0x00 && *p2!=0x00 && *p1!=0x01 && *p2!=0x01 );
+ assert( *p1!=POS_END && *p1!=POS_COLUMN );
+ assert( *p2!=POS_END && *p2!=POS_COLUMN );
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
@@ -100149,6 +107132,7 @@
default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); {
char *aTmp = 0;
char **ppPos = 0;
+
if( mergetype==MERGE_POS_NEAR ){
ppPos = &p;
aTmp = sqlite3_malloc(2*(n1+n2+1));
@@ -100253,9 +107237,9 @@
**
** The returned doclist may be in one of two formats, depending on the
** value of parameter isReqPos. If isReqPos is zero, then the doclist is
-** a sorted list of delta-compressed docids. If isReqPos is non-zero,
-** then the returned list is in the same format as is stored in the
-** database without the found length specifier at the start of on-disk
+** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
+** is non-zero, then the returned list is in the same format as is stored
+** in the database without the found length specifier at the start of on-disk
** doclists.
*/
static int fts3TermSelect(
@@ -100445,9 +107429,79 @@
return rc;
}
+static int fts3NearMerge(
+ int mergetype, /* MERGE_POS_NEAR or MERGE_NEAR */
+ int nNear, /* Parameter to NEAR operator */
+ int nTokenLeft, /* Number of tokens in LHS phrase arg */
+ char *aLeft, /* Doclist for LHS (incl. positions) */
+ int nLeft, /* Size of LHS doclist in bytes */
+ int nTokenRight, /* As nTokenLeft */
+ char *aRight, /* As aLeft */
+ int nRight, /* As nRight */
+ char **paOut, /* OUT: Results of merge (malloced) */
+ int *pnOut /* OUT: Sized of output buffer */
+){
+ char *aOut;
+ int rc;
+
+ assert( mergetype==MERGE_POS_NEAR || MERGE_NEAR );
+
+ aOut = sqlite3_malloc(nLeft+nRight+1);
+ if( aOut==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = fts3DoclistMerge(mergetype, nNear+nTokenRight, nNear+nTokenLeft,
+ aOut, pnOut, aLeft, nLeft, aRight, nRight
+ );
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(aOut);
+ aOut = 0;
+ }
+ }
+
+ *paOut = aOut;
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
+ int rc;
+ if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
+ sqlite3_free(pLeft->aDoclist);
+ sqlite3_free(pRight->aDoclist);
+ pRight->aDoclist = 0;
+ pLeft->aDoclist = 0;
+ rc = SQLITE_OK;
+ }else{
+ char *aOut;
+ int nOut;
+
+ rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
+ pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
+ pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
+ &aOut, &nOut
+ );
+ if( rc!=SQLITE_OK ) return rc;
+ sqlite3_free(pRight->aDoclist);
+ pRight->aDoclist = aOut;
+ pRight->nDoclist = nOut;
+
+ rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
+ pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
+ pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
+ &aOut, &nOut
+ );
+ sqlite3_free(pLeft->aDoclist);
+ pLeft->aDoclist = aOut;
+ pLeft->nDoclist = nOut;
+ }
+ return rc;
+}
+
/*
** Evaluate the full-text expression pExpr against fts3 table pTab. Store
-** the resulting doclist in *paOut and *pnOut.
+** the resulting doclist in *paOut and *pnOut. This routine mallocs for
+** the space needed to store the output. The caller is responsible for
+** freeing the space when it has finished.
*/
static int evalFts3Expr(
Fts3Table *p, /* Virtual table handle */
@@ -100489,9 +107543,6 @@
Fts3Expr *pLeft;
Fts3Expr *pRight;
int mergetype = isReqPos ? MERGE_POS_NEAR : MERGE_NEAR;
- int nParam1;
- int nParam2;
- char *aBuffer;
if( pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR ){
mergetype = MERGE_POS_NEAR;
@@ -100504,17 +107555,11 @@
assert( pRight->eType==FTSQUERY_PHRASE );
assert( pLeft->eType==FTSQUERY_PHRASE );
- nParam1 = pExpr->nNear+1;
- nParam2 = nParam1+pLeft->pPhrase->nToken+pRight->pPhrase->nToken-2;
- aBuffer = sqlite3_malloc(nLeft+nRight+1);
- rc = fts3DoclistMerge(mergetype, nParam1, nParam2, aBuffer,
- pnOut, aLeft, nLeft, aRight, nRight
+ rc = fts3NearMerge(mergetype, pExpr->nNear,
+ pLeft->pPhrase->nToken, aLeft, nLeft,
+ pRight->pPhrase->nToken, aRight, nRight,
+ paOut, pnOut
);
- if( rc!=SQLITE_OK ){
- sqlite3_free(aBuffer);
- }else{
- *paOut = aBuffer;
- }
sqlite3_free(aLeft);
break;
}
@@ -100629,7 +107674,13 @@
rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn,
iCol, zQuery, -1, &pCsr->pExpr
);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_ERROR ){
+ p->base.zErrMsg = sqlite3_mprintf("malformed MATCH expression: [%s]",
+ zQuery);
+ }
+ return rc;
+ }
rc = evalFts3Expr(p, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
pCsr->pNextId = pCsr->aDoclist;
@@ -100765,7 +107816,7 @@
/*
** After ExprLoadDoclist() (see above) has been called, this function is
-** used to iterate through the position lists that make up the doclist
+** used to iterate/search through the position lists that make up the doclist
** stored in pExpr->aDoclist.
*/
SQLITE_PRIVATE char *sqlite3Fts3FindPositions(
@@ -100782,7 +107833,9 @@
while( pCsr<pEnd ){
if( pExpr->iCurrent<iDocid ){
fts3PoslistCopy(0, &pCsr);
- fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
+ if( pCsr<pEnd ){
+ fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
+ }
pExpr->pCurrent = pCsr;
}else{
if( pExpr->iCurrent==iDocid ){
@@ -100800,7 +107853,7 @@
pCsr++;
pCsr += sqlite3Fts3GetVarint32(pCsr, &iThis);
}
- if( iCol==iThis ) return pCsr;
+ if( iCol==iThis && (*pCsr&0xFE) ) return pCsr;
}
return 0;
}
@@ -100852,45 +107905,8 @@
const char *zStart = "<b>";
const char *zEnd = "</b>";
const char *zEllipsis = "<b>...</b>";
-
- /* There must be at least one argument passed to this function (otherwise
- ** the non-overloaded version would have been called instead of this one).
- */
- assert( nVal>=1 );
-
- if( nVal>4 ){
- sqlite3_result_error(pContext,
- "wrong number of arguments to function snippet()", -1);
- return;
- }
- if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
-
- switch( nVal ){
- case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
- case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
- case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
- }
- if( !zEllipsis || !zEnd || !zStart ){
- sqlite3_result_error_nomem(pContext);
- }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){
- sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis);
- }
-}
-
-/*
-** Implementation of the snippet2() function for FTS3
-*/
-static void fts3Snippet2Func(
- sqlite3_context *pContext, /* SQLite function call context */
- int nVal, /* Size of apVal[] array */
- sqlite3_value **apVal /* Array of arguments */
-){
- Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */
- const char *zStart = "<b>";
- const char *zEnd = "</b>";
- const char *zEllipsis = "<b>...</b>";
int iCol = -1;
- int nToken = 10;
+ int nToken = 15; /* Default number of tokens in snippet */
/* There must be at least one argument passed to this function (otherwise
** the non-overloaded version would have been called instead of this one).
@@ -100914,7 +107930,7 @@
if( !zEllipsis || !zEnd || !zStart ){
sqlite3_result_error_nomem(pContext);
}else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){
- sqlite3Fts3Snippet2(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken);
+ sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken);
}
}
@@ -101015,7 +108031,6 @@
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aOverload[] = {
{ "snippet", fts3SnippetFunc },
- { "snippet2", fts3Snippet2Func },
{ "offsets", fts3OffsetsFunc },
{ "optimize", fts3OptimizeFunc },
{ "matchinfo", fts3MatchinfoFunc },
@@ -101044,22 +108059,35 @@
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
- Fts3Table *p = (Fts3Table *)pVtab;
- int rc = SQLITE_NOMEM; /* Return Code */
- char *zSql; /* SQL script to run to rename tables */
+ Fts3Table *p = (Fts3Table *)pVtab;
+ sqlite3 *db; /* Database connection */
+ int rc; /* Return Code */
- zSql = sqlite3_mprintf(
- "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';"
- "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';"
- "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';"
- , p->zDb, p->zName, zName
- , p->zDb, p->zName, zName
- , p->zDb, p->zName, zName
+ db = p->db;
+ rc = SQLITE_OK;
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
+ p->zDb, p->zName, zName
);
- if( zSql ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_free(zSql);
+ if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
+ if( p->bHasDocsize ){
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
+ p->zDb, p->zName, zName
+ );
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';",
+ p->zDb, p->zName, zName
+ );
}
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';",
+ p->zDb, p->zName, zName
+ );
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
+ p->zDb, p->zName, zName
+ );
return rc;
}
@@ -101118,10 +108146,7 @@
** SQLite. If fts3 is built as a dynamically loadable extension, this
** function is called by the sqlite3_extension_init() entry point.
*/
-// Begin Android change
-SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db, const char* registerAs){
-// End Android change
-
+SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db, const char* registerAs){ // Android Change
int rc = SQLITE_OK;
Fts3Hash *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0;
@@ -101168,17 +108193,22 @@
if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
- && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet2", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
){
- // Begin Android change
- /* Also register as fts1 and fts2 */
- return sqlite3_create_module_v2(
+ rc = sqlite3_create_module_v2(
+ // Begin Android change
+ // Also register as fts1 and fts2
db, registerAs, &fts3Module, (void *)pHash, hashDestroy
- // End Android change
+ // End Android change
);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module_v2(
+ db, "fts4", &fts3Module, (void *)pHash, 0
+ );
+ }
+ return rc;
}
/* An error has occurred. Delete the hash table and return the error code. */
@@ -103108,9 +110138,11 @@
if( c->iOffset>iStartOffset ){
int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){
+ char *pNew;
c->nAllocated = n+20;
- c->zToken = sqlite3_realloc(c->zToken, c->nAllocated);
- if( c->zToken==NULL ) return SQLITE_NOMEM;
+ pNew = sqlite3_realloc(c->zToken, c->nAllocated);
+ if( !pNew ) return SQLITE_NOMEM;
+ c->zToken = pNew;
}
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
*pzToken = c->zToken;
@@ -103821,9 +110853,11 @@
if( c->iOffset>iStartOffset ){
int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){
+ char *pNew;
c->nTokenAllocated = n+20;
- c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated);
- if( c->pToken==NULL ) return SQLITE_NOMEM;
+ pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
+ if( !pNew ) return SQLITE_NOMEM;
+ c->pToken = pNew;
}
for(i=0; i<n; i++){
/* TODO(shess) This needs expansion to handle UTF-8
@@ -104007,19 +111041,26 @@
#define SQL_DELETE_ALL_CONTENT 2
#define SQL_DELETE_ALL_SEGMENTS 3
#define SQL_DELETE_ALL_SEGDIR 4
-#define SQL_SELECT_CONTENT_BY_ROWID 5
-#define SQL_NEXT_SEGMENT_INDEX 6
-#define SQL_INSERT_SEGMENTS 7
-#define SQL_NEXT_SEGMENTS_ID 8
-#define SQL_INSERT_SEGDIR 9
-#define SQL_SELECT_LEVEL 10
-#define SQL_SELECT_ALL_LEVEL 11
-#define SQL_SELECT_LEVEL_COUNT 12
-#define SQL_SELECT_SEGDIR_COUNT_MAX 13
-#define SQL_DELETE_SEGDIR_BY_LEVEL 14
-#define SQL_DELETE_SEGMENTS_RANGE 15
-#define SQL_CONTENT_INSERT 16
-#define SQL_GET_BLOCK 17
+#define SQL_DELETE_ALL_DOCSIZE 5
+#define SQL_DELETE_ALL_STAT 6
+#define SQL_SELECT_CONTENT_BY_ROWID 7
+#define SQL_NEXT_SEGMENT_INDEX 8
+#define SQL_INSERT_SEGMENTS 9
+#define SQL_NEXT_SEGMENTS_ID 10
+#define SQL_INSERT_SEGDIR 11
+#define SQL_SELECT_LEVEL 12
+#define SQL_SELECT_ALL_LEVEL 13
+#define SQL_SELECT_LEVEL_COUNT 14
+#define SQL_SELECT_SEGDIR_COUNT_MAX 15
+#define SQL_DELETE_SEGDIR_BY_LEVEL 16
+#define SQL_DELETE_SEGMENTS_RANGE 17
+#define SQL_CONTENT_INSERT 18
+#define SQL_GET_BLOCK 19
+#define SQL_DELETE_DOCSIZE 20
+#define SQL_REPLACE_DOCSIZE 21
+#define SQL_SELECT_DOCSIZE 22
+#define SQL_SELECT_DOCTOTAL 23
+#define SQL_REPLACE_DOCTOTAL 24
/*
** This function is used to obtain an SQLite prepared statement handle
@@ -104044,25 +111085,32 @@
/* 2 */ "DELETE FROM %Q.'%q_content'",
/* 3 */ "DELETE FROM %Q.'%q_segments'",
/* 4 */ "DELETE FROM %Q.'%q_segdir'",
-/* 5 */ "SELECT * FROM %Q.'%q_content' WHERE rowid=?",
-/* 6 */ "SELECT coalesce(max(idx)+1, 0) FROM %Q.'%q_segdir' WHERE level=?",
-/* 7 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
-/* 8 */ "SELECT coalesce(max(blockid)+1, 1) FROM %Q.'%q_segments'",
-/* 9 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
+/* 5 */ "DELETE FROM %Q.'%q_docsize'",
+/* 6 */ "DELETE FROM %Q.'%q_stat'",
+/* 7 */ "SELECT * FROM %Q.'%q_content' WHERE rowid=?",
+/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
+/* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
+/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
+/* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
/* Return segments in order from oldest to newest.*/
-/* 10 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
+/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC",
-/* 11 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
+/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' ORDER BY level DESC, idx ASC",
-/* 12 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
-/* 13 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'",
+/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
+/* 15 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'",
-/* 14 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
-/* 15 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
-/* 16 */ "INSERT INTO %Q.'%q_content' VALUES(%z)",
-/* 17 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
+/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
+/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
+/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%z)",
+/* 19 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
+/* 20 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
+/* 21 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
+/* 22 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
+/* 23 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0",
+/* 24 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
};
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
@@ -104119,14 +111167,21 @@
** Returns SQLITE_OK if the statement is successfully executed, or an
** SQLite error code otherwise.
*/
-static int fts3SqlExec(Fts3Table *p, int eStmt, sqlite3_value **apVal){
+static void fts3SqlExec(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* The FTS3 table */
+ int eStmt, /* Index of statement to evaluate */
+ sqlite3_value **apVal /* Parameters to bind */
+){
sqlite3_stmt *pStmt;
- int rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
+ int rc;
+ if( *pRC ) return;
+ rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
if( rc==SQLITE_OK ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
}
- return rc;
+ *pRC = rc;
}
@@ -104306,11 +111361,17 @@
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
-static int fts3PendingTermsAdd(Fts3Table *p, const char *zText, int iCol){
+static int fts3PendingTermsAdd(
+ Fts3Table *p, /* FTS table into which text will be inserted */
+ const char *zText, /* Text of document to be inseted */
+ int iCol, /* Column number into which text is inserted */
+ u32 *pnWord /* OUT: Number of tokens inserted */
+){
int rc;
int iStart;
int iEnd;
int iPos;
+ int nWord = 0;
char const *zToken;
int nToken;
@@ -104334,6 +111395,8 @@
&& SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos))
){
PendingList *pList;
+
+ if( iPos>=nWord ) nWord = iPos+1;
/* Positions cannot be negative; we use -1 as a terminator internally.
** Tokens must have a non-zero length.
@@ -104363,6 +111426,7 @@
}
pModule->xClose(pCsr);
+ *pnWord = nWord;
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
}
@@ -104403,12 +111467,12 @@
** Argument apVal is the same as the similarly named argument passed to
** fts3InsertData(). Parameter iDocid is the docid of the new row.
*/
-static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal){
+static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
int i; /* Iterator variable */
for(i=2; i<p->nColumn+2; i++){
const char *zText = (const char *)sqlite3_value_text(apVal[i]);
if( zText ){
- int rc = fts3PendingTermsAdd(p, zText, i-2);
+ int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -104489,18 +111553,18 @@
** pending terms.
*/
static int fts3DeleteAll(Fts3Table *p){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
/* Discard the contents of the pending-terms hash table. */
sqlite3Fts3PendingTermsClear(p);
/* Delete everything from the %_content, %_segments and %_segdir tables. */
- rc = fts3SqlExec(p, SQL_DELETE_ALL_CONTENT, 0);
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGMENTS, 0);
- }
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGDIR, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
}
return rc;
}
@@ -104510,20 +111574,27 @@
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
-static int fts3DeleteTerms(Fts3Table *p, sqlite3_value **apVal){
+static void fts3DeleteTerms(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* The FTS table to delete from */
+ sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */
+ u32 *aSz /* Sizes of deleted document written here */
+){
int rc;
sqlite3_stmt *pSelect;
+ if( *pRC ) return;
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
for(i=1; i<=p->nColumn; i++){
const char *zText = (const char *)sqlite3_column_text(pSelect, i);
- rc = fts3PendingTermsAdd(p, zText, -1);
+ rc = fts3PendingTermsAdd(p, zText, -1, &aSz[i-1]);
if( rc!=SQLITE_OK ){
sqlite3_reset(pSelect);
- return rc;
+ *pRC = rc;
+ return;
}
}
}
@@ -104531,7 +111602,7 @@
}else{
sqlite3_reset(pSelect);
}
- return rc;
+ *pRC = rc;
}
/*
@@ -105651,7 +112722,7 @@
rc = sqlite3_reset(pDelete);
}
}else{
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGDIR, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
}
return rc;
@@ -106080,6 +113151,211 @@
}
/*
+** Encode N integers as varints into a blob.
+*/
+static void fts3EncodeIntArray(
+ int N, /* The number of integers to encode */
+ u32 *a, /* The integer values */
+ char *zBuf, /* Write the BLOB here */
+ int *pNBuf /* Write number of bytes if zBuf[] used here */
+){
+ int i, j;
+ for(i=j=0; i<N; i++){
+ j += sqlite3Fts3PutVarint(&zBuf[j], (sqlite3_int64)a[i]);
+ }
+ *pNBuf = j;
+}
+
+/*
+** Decode a blob of varints into N integers
+*/
+static void fts3DecodeIntArray(
+ int N, /* The number of integers to decode */
+ u32 *a, /* Write the integer values */
+ const char *zBuf, /* The BLOB containing the varints */
+ int nBuf /* size of the BLOB */
+){
+ int i, j;
+ UNUSED_PARAMETER(nBuf);
+ for(i=j=0; i<N; i++){
+ sqlite3_int64 x;
+ j += sqlite3Fts3GetVarint(&zBuf[j], &x);
+ assert(j<=nBuf);
+ a[i] = (u32)(x & 0xffffffff);
+ }
+}
+
+/*
+** Fill in the document size auxiliary information for the matchinfo
+** structure. The auxiliary information is:
+**
+** N Total number of documents in the full-text index
+** a0 Average length of column 0 over the whole index
+** n0 Length of column 0 on the matching row
+** ...
+** aM Average length of column M over the whole index
+** nM Length of column M on the matching row
+**
+** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
+** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
+*/
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
+ const char *pBlob; /* The BLOB holding %_docsize info */
+ int nBlob; /* Size of the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i, j; /* Loop counters */
+ sqlite3_int64 x; /* Varint value */
+ int rc; /* Result code from subfunctions */
+ Fts3Table *p; /* The FTS table */
+
+ p = (Fts3Table*)pCur->base.pVtab;
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
+ if( rc ){
+ return rc;
+ }
+ sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ nBlob = sqlite3_column_bytes(pStmt, 0);
+ pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
+ for(i=j=0; i<p->nColumn && j<nBlob; i++){
+ j = sqlite3Fts3GetVarint(&pBlob[j], &x);
+ a[2+i*2] = (u32)(x & 0xffffffff);
+ }
+ }
+ sqlite3_reset(pStmt);
+ return SQLITE_OK;
+}
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
+ const char *pBlob; /* The BLOB holding %_stat info */
+ int nBlob; /* Size of the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i, j; /* Loop counters */
+ sqlite3_int64 x; /* Varint value */
+ int nDoc; /* Number of documents */
+ int rc; /* Result code from subfunctions */
+ Fts3Table *p; /* The FTS table */
+
+ p = (Fts3Table*)pCur->base.pVtab;
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ return rc;
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ nBlob = sqlite3_column_bytes(pStmt, 0);
+ pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
+ j = sqlite3Fts3GetVarint(pBlob, &x);
+ a[0] = nDoc = (u32)(x & 0xffffffff);
+ for(i=0; i<p->nColumn && j<nBlob; i++){
+ j = sqlite3Fts3GetVarint(&pBlob[j], &x);
+ a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
+ }
+ }
+ sqlite3_reset(pStmt);
+ return SQLITE_OK;
+}
+
+/*
+** Insert the sizes (in tokens) for each column of the document
+** with docid equal to p->iPrevDocid. The sizes are encoded as
+** a blob of varints.
+*/
+static void fts3InsertDocsize(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* Table into which to insert */
+ u32 *aSz /* Sizes of each column */
+){
+ char *pBlob; /* The BLOB encoding of the document size */
+ int nBlob; /* Number of bytes in the BLOB */
+ sqlite3_stmt *pStmt; /* Statement used to insert the encoding */
+ int rc; /* Result code from subfunctions */
+
+ if( *pRC ) return;
+ pBlob = sqlite3_malloc( 10*p->nColumn );
+ if( pBlob==0 ){
+ *pRC = SQLITE_NOMEM;
+ return;
+ }
+ fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob);
+ rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(pBlob);
+ *pRC = rc;
+ return;
+ }
+ sqlite3_bind_int64(pStmt, 1, p->iPrevDocid);
+ sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free);
+ sqlite3_step(pStmt);
+ *pRC = sqlite3_reset(pStmt);
+}
+
+/*
+** Update the 0 record of the %_stat table so that it holds a blob
+** which contains the document count followed by the cumulative
+** document sizes for all columns.
+*/
+static void fts3UpdateDocTotals(
+ int *pRC, /* The result code */
+ Fts3Table *p, /* Table being updated */
+ u32 *aSzIns, /* Size increases */
+ u32 *aSzDel, /* Size decreases */
+ int nChng /* Change in the number of documents */
+){
+ char *pBlob; /* Storage for BLOB written into %_stat */
+ int nBlob; /* Size of BLOB written into %_stat */
+ u32 *a; /* Array of integers that becomes the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i; /* Loop counter */
+ int rc; /* Result code from subfunctions */
+
+ if( *pRC ) return;
+ a = sqlite3_malloc( (sizeof(u32)+10)*(p->nColumn+1) );
+ if( a==0 ){
+ *pRC = SQLITE_NOMEM;
+ return;
+ }
+ pBlob = (char*)&a[p->nColumn+1];
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(a);
+ *pRC = rc;
+ return;
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ fts3DecodeIntArray(p->nColumn+1, a,
+ sqlite3_column_blob(pStmt, 0),
+ sqlite3_column_bytes(pStmt, 0));
+ }else{
+ memset(a, 0, sizeof(u32)*(p->nColumn+1) );
+ }
+ sqlite3_reset(pStmt);
+ if( nChng<0 && a[0]<(u32)(-nChng) ){
+ a[0] = 0;
+ }else{
+ a[0] += nChng;
+ }
+ for(i=0; i<p->nColumn; i++){
+ u32 x = a[i+1];
+ if( x+aSzIns[i] < aSzDel[i] ){
+ x = 0;
+ }else{
+ x = x + aSzIns[i] - aSzDel[i];
+ }
+ a[i+1] = x;
+ }
+ fts3EncodeIntArray(p->nColumn+1, a, pBlob, &nBlob);
+ rc = fts3SqlStmt(p, SQL_REPLACE_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(a);
+ *pRC = rc;
+ return;
+ }
+ sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_STATIC);
+ sqlite3_step(pStmt);
+ *pRC = sqlite3_reset(pStmt);
+ sqlite3_free(a);
+}
+
+/*
** Handle a 'special' INSERT of the form:
**
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
@@ -106130,8 +113406,17 @@
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */
+ u32 *aSzIns; /* Sizes of inserted documents */
+ u32 *aSzDel; /* Sizes of deleted documents */
+ int nChng = 0; /* Net change in number of documents */
+ /* Allocate space to hold the change in document sizes */
+ aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*p->nColumn*2 );
+ if( aSzIns==0 ) return SQLITE_NOMEM;
+ aSzDel = &aSzIns[p->nColumn];
+ memset(aSzIns, 0, sizeof(aSzIns[0])*p->nColumn*2);
+
/* If this is a DELETE or UPDATE operation, remove the old record. */
if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
int isEmpty;
@@ -106147,15 +113432,16 @@
isRemove = 1;
iRemove = sqlite3_value_int64(apVal[0]);
rc = fts3PendingTermsDocid(p, iRemove);
- if( rc==SQLITE_OK ){
- rc = fts3DeleteTerms(p, apVal);
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_CONTENT, apVal);
- }
+ fts3DeleteTerms(&rc, p, apVal, aSzDel);
+ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
+ nChng--;
}
}
}
}else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
+ sqlite3_free(aSzIns);
return fts3SpecialInsert(p, apVal[p->nColumn+2]);
}
@@ -106166,10 +113452,19 @@
rc = fts3PendingTermsDocid(p, *pRowid);
}
if( rc==SQLITE_OK ){
- rc = fts3InsertTerms(p, apVal);
+ rc = fts3InsertTerms(p, apVal, aSzIns);
+ }
+ if( p->bHasDocsize ){
+ nChng++;
+ fts3InsertDocsize(&rc, p, aSzIns);
}
}
+ if( p->bHasDocsize ){
+ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
+ }
+
+ sqlite3_free(aSzIns);
return rc;
}
@@ -106216,727 +113511,97 @@
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-typedef struct Snippet Snippet;
/*
-** An instance of the following structure keeps track of generated
-** matching-word offset information and snippets.
+** Used as an fts3ExprIterate() context when loading phrase doclists to
+** Fts3Expr.aDoclist[]/nDoclist.
*/
-struct Snippet {
- int nMatch; /* Total number of matches */
- int nAlloc; /* Space allocated for aMatch[] */
- struct snippetMatch { /* One entry for each matching term */
- char snStatus; /* Status flag for use while constructing snippets */
- short int nByte; /* Number of bytes in the term */
- short int iCol; /* The column that contains the match */
- short int iTerm; /* The index in Query.pTerms[] of the matching term */
- int iToken; /* The index of the matching document token */
- int iStart; /* The offset to the first character of the term */
- } *aMatch; /* Points to space obtained from malloc */
- char *zOffset; /* Text rendering of aMatch[] */
- int nOffset; /* strlen(zOffset) */
- char *zSnippet; /* Snippet text */
- int nSnippet; /* strlen(zSnippet) */
+typedef struct LoadDoclistCtx LoadDoclistCtx;
+struct LoadDoclistCtx {
+ Fts3Table *pTab; /* FTS3 Table */
+ int nPhrase; /* Number of phrases seen so far */
+ int nToken; /* Number of tokens seen so far */
+};
+
+/*
+** The following types are used as part of the implementation of the
+** fts3BestSnippet() routine.
+*/
+typedef struct SnippetIter SnippetIter;
+typedef struct SnippetPhrase SnippetPhrase;
+typedef struct SnippetFragment SnippetFragment;
+
+struct SnippetIter {
+ Fts3Cursor *pCsr; /* Cursor snippet is being generated from */
+ int iCol; /* Extract snippet from this column */
+ int nSnippet; /* Requested snippet length (in tokens) */
+ int nPhrase; /* Number of phrases in query */
+ SnippetPhrase *aPhrase; /* Array of size nPhrase */
+ int iCurrent; /* First token of current snippet */
+};
+
+struct SnippetPhrase {
+ int nToken; /* Number of tokens in phrase */
+ char *pList; /* Pointer to start of phrase position list */
+ int iHead; /* Next value in position list */
+ char *pHead; /* Position list data following iHead */
+ int iTail; /* Next value in trailing position list */
+ char *pTail; /* Position list data following iTail */
+};
+
+struct SnippetFragment {
+ int iCol; /* Column snippet is extracted from */
+ int iPos; /* Index of first token in snippet */
+ u64 covered; /* Mask of query phrases covered */
+ u64 hlmask; /* Mask of snippet terms to highlight */
+};
+
+/*
+** This type is used as an fts3ExprIterate() context object while
+** accumulating the data returned by the matchinfo() function.
+*/
+typedef struct MatchInfo MatchInfo;
+struct MatchInfo {
+ Fts3Cursor *pCursor; /* FTS3 Cursor */
+ int nCol; /* Number of columns in table */
+ u32 *aMatchinfo; /* Pre-allocated buffer */
};
-/* It is not safe to call isspace(), tolower(), or isalnum() on
-** hi-bit-set characters. This is the same solution used in the
-** tokenizer.
+
+/*
+** The snippet() and offsets() functions both return text values. An instance
+** of the following structure is used to accumulate those values while the
+** functions are running. See fts3StringAppend() for details.
*/
-static int fts3snippetIsspace(char c){
- return (c&0x80)==0 ? isspace(c) : 0;
-}
+typedef struct StrBuffer StrBuffer;
+struct StrBuffer {
+ char *z; /* Pointer to buffer containing string */
+ int n; /* Length of z in bytes (excl. nul-term) */
+ int nAlloc; /* Allocated size of buffer z in bytes */
+};
/*
-** A StringBuffer object holds a zero-terminated string that grows
-** arbitrarily by appending. Space to hold the string is obtained
-** from sqlite3_malloc(). After any memory allocation failure,
-** StringBuffer.z is set to NULL and no further allocation is attempted.
-*/
-typedef struct StringBuffer {
- char *z; /* Text of the string. Space from malloc. */
- int nUsed; /* Number bytes of z[] used, not counting \000 terminator */
- int nAlloc; /* Bytes allocated for z[] */
-} StringBuffer;
-
-
-/*
-** Initialize a new StringBuffer.
-*/
-static void fts3SnippetSbInit(StringBuffer *p){
- p->nAlloc = 100;
- p->nUsed = 0;
- p->z = sqlite3_malloc( p->nAlloc );
-}
-
-/*
-** Append text to the string buffer.
-*/
-static void fts3SnippetAppend(StringBuffer *p, const char *zNew, int nNew){
- if( p->z==0 ) return;
- if( nNew<0 ) nNew = (int)strlen(zNew);
- if( p->nUsed + nNew >= p->nAlloc ){
- int nAlloc;
- char *zNew;
-
- nAlloc = p->nUsed + nNew + p->nAlloc;
- zNew = sqlite3_realloc(p->z, nAlloc);
- if( zNew==0 ){
- sqlite3_free(p->z);
- p->z = 0;
- return;
- }
- p->z = zNew;
- p->nAlloc = nAlloc;
- }
- memcpy(&p->z[p->nUsed], zNew, nNew);
- p->nUsed += nNew;
- p->z[p->nUsed] = 0;
-}
-
-/* If the StringBuffer ends in something other than white space, add a
-** single space character to the end.
-*/
-static void fts3SnippetAppendWhiteSpace(StringBuffer *p){
- if( p->z && p->nUsed && !fts3snippetIsspace(p->z[p->nUsed-1]) ){
- fts3SnippetAppend(p, " ", 1);
- }
-}
-
-/* Remove white space from the end of the StringBuffer */
-static void fts3SnippetTrimWhiteSpace(StringBuffer *p){
- if( p->z ){
- while( p->nUsed && fts3snippetIsspace(p->z[p->nUsed-1]) ){
- p->nUsed--;
- }
- p->z[p->nUsed] = 0;
- }
-}
-
-/*
-** Release all memory associated with the Snippet structure passed as
-** an argument.
-*/
-static void fts3SnippetFree(Snippet *p){
- if( p ){
- sqlite3_free(p->aMatch);
- sqlite3_free(p->zOffset);
- sqlite3_free(p->zSnippet);
- sqlite3_free(p);
- }
-}
-
-/*
-** Append a single entry to the p->aMatch[] log.
-*/
-static int snippetAppendMatch(
- Snippet *p, /* Append the entry to this snippet */
- int iCol, int iTerm, /* The column and query term */
- int iToken, /* Matching token in document */
- int iStart, int nByte /* Offset and size of the match */
-){
- int i;
- struct snippetMatch *pMatch;
- if( p->nMatch+1>=p->nAlloc ){
- struct snippetMatch *pNew;
- p->nAlloc = p->nAlloc*2 + 10;
- pNew = sqlite3_realloc(p->aMatch, p->nAlloc*sizeof(p->aMatch[0]) );
- if( pNew==0 ){
- p->aMatch = 0;
- p->nMatch = 0;
- p->nAlloc = 0;
- return SQLITE_NOMEM;
- }
- p->aMatch = pNew;
- }
- i = p->nMatch++;
- pMatch = &p->aMatch[i];
- pMatch->iCol = (short)iCol;
- pMatch->iTerm = (short)iTerm;
- pMatch->iToken = iToken;
- pMatch->iStart = iStart;
- pMatch->nByte = (short)nByte;
- return SQLITE_OK;
-}
-
-/*
-** Sizing information for the circular buffer used in snippetOffsetsOfColumn()
-*/
-#define FTS3_ROTOR_SZ (32)
-#define FTS3_ROTOR_MASK (FTS3_ROTOR_SZ-1)
-
-/*
-** Function to iterate through the tokens of a compiled expression.
+** This function is used to help iterate through a position-list. A position
+** list is a list of unique integers, sorted from smallest to largest. Each
+** element of the list is represented by an FTS3 varint that takes the value
+** of the difference between the current element and the previous one plus
+** two. For example, to store the position-list:
**
-** Except, skip all tokens on the right-hand side of a NOT operator.
-** This function is used to find tokens as part of snippet and offset
-** generation and we do nt want snippets and offsets to report matches
-** for tokens on the RHS of a NOT.
-*/
-static int fts3NextExprToken(Fts3Expr **ppExpr, int *piToken){
- Fts3Expr *p = *ppExpr;
- int iToken = *piToken;
- if( iToken<0 ){
- /* In this case the expression p is the root of an expression tree.
- ** Move to the first token in the expression tree.
- */
- while( p->pLeft ){
- p = p->pLeft;
- }
- iToken = 0;
- }else{
- assert(p && p->eType==FTSQUERY_PHRASE );
- if( iToken<(p->pPhrase->nToken-1) ){
- iToken++;
- }else{
- iToken = 0;
- while( p->pParent && p->pParent->pLeft!=p ){
- assert( p->pParent->pRight==p );
- p = p->pParent;
- }
- p = p->pParent;
- if( p ){
- assert( p->pRight!=0 );
- p = p->pRight;
- while( p->pLeft ){
- p = p->pLeft;
- }
- }
- }
- }
-
- *ppExpr = p;
- *piToken = iToken;
- return p?1:0;
-}
-
-/*
-** Return TRUE if the expression node pExpr is located beneath the
-** RHS of a NOT operator.
-*/
-static int fts3ExprBeneathNot(Fts3Expr *p){
- Fts3Expr *pParent;
- while( p ){
- pParent = p->pParent;
- if( pParent && pParent->eType==FTSQUERY_NOT && pParent->pRight==p ){
- return 1;
- }
- p = pParent;
- }
- return 0;
-}
-
-/*
-** Add entries to pSnippet->aMatch[] for every match that occurs against
-** document zDoc[0..nDoc-1] which is stored in column iColumn.
-*/
-static int snippetOffsetsOfColumn(
- Fts3Cursor *pCur, /* The fulltest search cursor */
- Snippet *pSnippet, /* The Snippet object to be filled in */
- int iColumn, /* Index of fulltext table column */
- const char *zDoc, /* Text of the fulltext table column */
- int nDoc /* Length of zDoc in bytes */
-){
- const sqlite3_tokenizer_module *pTModule; /* The tokenizer module */
- sqlite3_tokenizer *pTokenizer; /* The specific tokenizer */
- sqlite3_tokenizer_cursor *pTCursor; /* Tokenizer cursor */
- Fts3Table *pVtab; /* The full text index */
- int nColumn; /* Number of columns in the index */
- int i, j; /* Loop counters */
- int rc; /* Return code */
- unsigned int match, prevMatch; /* Phrase search bitmasks */
- const char *zToken; /* Next token from the tokenizer */
- int nToken; /* Size of zToken */
- int iBegin, iEnd, iPos; /* Offsets of beginning and end */
-
- /* The following variables keep a circular buffer of the last
- ** few tokens */
- unsigned int iRotor = 0; /* Index of current token */
- int iRotorBegin[FTS3_ROTOR_SZ]; /* Beginning offset of token */
- int iRotorLen[FTS3_ROTOR_SZ]; /* Length of token */
-
- pVtab = (Fts3Table *)pCur->base.pVtab;
- nColumn = pVtab->nColumn;
- pTokenizer = pVtab->pTokenizer;
- pTModule = pTokenizer->pModule;
- rc = pTModule->xOpen(pTokenizer, zDoc, nDoc, &pTCursor);
- if( rc ) return rc;
- pTCursor->pTokenizer = pTokenizer;
-
- prevMatch = 0;
- while( (rc = pTModule->xNext(pTCursor, &zToken, &nToken,
- &iBegin, &iEnd, &iPos))==SQLITE_OK ){
- Fts3Expr *pIter = pCur->pExpr;
- int iIter = -1;
- iRotorBegin[iRotor&FTS3_ROTOR_MASK] = iBegin;
- iRotorLen[iRotor&FTS3_ROTOR_MASK] = iEnd-iBegin;
- match = 0;
- for(i=0; i<(FTS3_ROTOR_SZ-1) && fts3NextExprToken(&pIter, &iIter); i++){
- int nPhrase; /* Number of tokens in current phrase */
- struct PhraseToken *pToken; /* Current token */
- int iCol; /* Column index */
-
- if( fts3ExprBeneathNot(pIter) ) continue;
- nPhrase = pIter->pPhrase->nToken;
- pToken = &pIter->pPhrase->aToken[iIter];
- iCol = pIter->pPhrase->iColumn;
- if( iCol>=0 && iCol<nColumn && iCol!=iColumn ) continue;
- if( pToken->n>nToken ) continue;
- if( !pToken->isPrefix && pToken->n<nToken ) continue;
- assert( pToken->n<=nToken );
- if( memcmp(pToken->z, zToken, pToken->n) ) continue;
- if( iIter>0 && (prevMatch & (1<<i))==0 ) continue;
- match |= 1<<i;
- if( i==(FTS3_ROTOR_SZ-2) || nPhrase==iIter+1 ){
- for(j=nPhrase-1; j>=0; j--){
- int k = (iRotor-j) & FTS3_ROTOR_MASK;
- rc = snippetAppendMatch(pSnippet, iColumn, i-j, iPos-j,
- iRotorBegin[k], iRotorLen[k]);
- if( rc ) goto end_offsets_of_column;
- }
- }
- }
- prevMatch = match<<1;
- iRotor++;
- }
-end_offsets_of_column:
- pTModule->xClose(pTCursor);
- return rc==SQLITE_DONE ? SQLITE_OK : rc;
-}
-
-/*
-** Remove entries from the pSnippet structure to account for the NEAR
-** operator. When this is called, pSnippet contains the list of token
-** offsets produced by treating all NEAR operators as AND operators.
-** This function removes any entries that should not be present after
-** accounting for the NEAR restriction. For example, if the queried
-** document is:
+** 4 9 113
**
-** "A B C D E A"
+** the three varints:
**
-** and the query is:
-**
-** A NEAR/0 E
+** 6 7 106
**
-** then when this function is called the Snippet contains token offsets
-** 0, 4 and 5. This function removes the "0" entry (because the first A
-** is not near enough to an E).
+** are encoded.
**
-** When this function is called, the value pointed to by parameter piLeft is
-** the integer id of the left-most token in the expression tree headed by
-** pExpr. This function increments *piLeft by the total number of tokens
-** in the expression tree headed by pExpr.
-**
-** Return 1 if any trimming occurs. Return 0 if no trimming is required.
+** When this function is called, *pp points to the start of an element of
+** the list. *piPos contains the value of the previous entry in the list.
+** After it returns, *piPos contains the value of the next element of the
+** list and *pp is advanced to the following varint.
*/
-static int trimSnippetOffsets(
- Fts3Expr *pExpr, /* The search expression */
- Snippet *pSnippet, /* The set of snippet offsets to be trimmed */
- int *piLeft /* Index of left-most token in pExpr */
-){
- if( pExpr ){
- if( trimSnippetOffsets(pExpr->pLeft, pSnippet, piLeft) ){
- return 1;
- }
-
- switch( pExpr->eType ){
- case FTSQUERY_PHRASE:
- *piLeft += pExpr->pPhrase->nToken;
- break;
- case FTSQUERY_NEAR: {
- /* The right-hand-side of a NEAR operator is always a phrase. The
- ** left-hand-side is either a phrase or an expression tree that is
- ** itself headed by a NEAR operator. The following initializations
- ** set local variable iLeft to the token number of the left-most
- ** token in the right-hand phrase, and iRight to the right most
- ** token in the same phrase. For example, if we had:
- **
- ** <col> MATCH '"abc def" NEAR/2 "ghi jkl"'
- **
- ** then iLeft will be set to 2 (token number of ghi) and nToken will
- ** be set to 4.
- */
- Fts3Expr *pLeft = pExpr->pLeft;
- Fts3Expr *pRight = pExpr->pRight;
- int iLeft = *piLeft;
- int nNear = pExpr->nNear;
- int nToken = pRight->pPhrase->nToken;
- int jj, ii;
- if( pLeft->eType==FTSQUERY_NEAR ){
- pLeft = pLeft->pRight;
- }
- assert( pRight->eType==FTSQUERY_PHRASE );
- assert( pLeft->eType==FTSQUERY_PHRASE );
- nToken += pLeft->pPhrase->nToken;
-
- for(ii=0; ii<pSnippet->nMatch; ii++){
- struct snippetMatch *p = &pSnippet->aMatch[ii];
- if( p->iTerm==iLeft ){
- int isOk = 0;
- /* Snippet ii is an occurence of query term iLeft in the document.
- ** It occurs at position (p->iToken) of the document. We now
- ** search for an instance of token (iLeft-1) somewhere in the
- ** range (p->iToken - nNear)...(p->iToken + nNear + nToken) within
- ** the set of snippetMatch structures. If one is found, proceed.
- ** If one cannot be found, then remove snippets ii..(ii+N-1)
- ** from the matching snippets, where N is the number of tokens
- ** in phrase pRight->pPhrase.
- */
- for(jj=0; isOk==0 && jj<pSnippet->nMatch; jj++){
- struct snippetMatch *p2 = &pSnippet->aMatch[jj];
- if( p2->iTerm==(iLeft-1) ){
- if( p2->iToken>=(p->iToken-nNear-1)
- && p2->iToken<(p->iToken+nNear+nToken)
- ){
- isOk = 1;
- }
- }
- }
- if( !isOk ){
- int kk;
- for(kk=0; kk<pRight->pPhrase->nToken; kk++){
- pSnippet->aMatch[kk+ii].iTerm = -2;
- }
- return 1;
- }
- }
- if( p->iTerm==(iLeft-1) ){
- int isOk = 0;
- for(jj=0; isOk==0 && jj<pSnippet->nMatch; jj++){
- struct snippetMatch *p2 = &pSnippet->aMatch[jj];
- if( p2->iTerm==iLeft ){
- if( p2->iToken<=(p->iToken+nNear+1)
- && p2->iToken>(p->iToken-nNear-nToken)
- ){
- isOk = 1;
- }
- }
- }
- if( !isOk ){
- int kk;
- for(kk=0; kk<pLeft->pPhrase->nToken; kk++){
- pSnippet->aMatch[ii-kk].iTerm = -2;
- }
- return 1;
- }
- }
- }
- break;
- }
- }
-
- if( trimSnippetOffsets(pExpr->pRight, pSnippet, piLeft) ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** Compute all offsets for the current row of the query.
-** If the offsets have already been computed, this routine is a no-op.
-*/
-static int snippetAllOffsets(Fts3Cursor *pCsr, Snippet **ppSnippet){
- Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; /* The FTS3 virtual table */
- int nColumn; /* Number of columns. Docid does count */
- int iColumn; /* Index of of a column */
- int i; /* Loop index */
- int iFirst; /* First column to search */
- int iLast; /* Last coumn to search */
- int iTerm = 0;
- Snippet *pSnippet;
- int rc = SQLITE_OK;
-
- if( pCsr->pExpr==0 ){
- return SQLITE_OK;
- }
-
- pSnippet = (Snippet *)sqlite3_malloc(sizeof(Snippet));
- *ppSnippet = pSnippet;
- if( !pSnippet ){
- return SQLITE_NOMEM;
- }
- memset(pSnippet, 0, sizeof(Snippet));
-
- nColumn = p->nColumn;
- iColumn = (pCsr->eSearch - 2);
- if( iColumn<0 || iColumn>=nColumn ){
- /* Look for matches over all columns of the full-text index */
- iFirst = 0;
- iLast = nColumn-1;
- }else{
- /* Look for matches in the iColumn-th column of the index only */
- iFirst = iColumn;
- iLast = iColumn;
- }
- for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
- const char *zDoc;
- int nDoc;
- zDoc = (const char*)sqlite3_column_text(pCsr->pStmt, i+1);
- nDoc = sqlite3_column_bytes(pCsr->pStmt, i+1);
- if( zDoc==0 && sqlite3_column_type(pCsr->pStmt, i+1)!=SQLITE_NULL ){
- rc = SQLITE_NOMEM;
- }else{
- rc = snippetOffsetsOfColumn(pCsr, pSnippet, i, zDoc, nDoc);
- }
- }
-
- while( trimSnippetOffsets(pCsr->pExpr, pSnippet, &iTerm) ){
- iTerm = 0;
- }
-
- return rc;
-}
-
-/*
-** Convert the information in the aMatch[] array of the snippet
-** into the string zOffset[0..nOffset-1]. This string is used as
-** the return of the SQL offsets() function.
-*/
-static void snippetOffsetText(Snippet *p){
- int i;
- int cnt = 0;
- StringBuffer sb;
- char zBuf[200];
- if( p->zOffset ) return;
- fts3SnippetSbInit(&sb);
- for(i=0; i<p->nMatch; i++){
- struct snippetMatch *pMatch = &p->aMatch[i];
- if( pMatch->iTerm>=0 ){
- /* If snippetMatch.iTerm is less than 0, then the match was
- ** discarded as part of processing the NEAR operator (see the
- ** trimSnippetOffsetsForNear() function for details). Ignore
- ** it in this case
- */
- zBuf[0] = ' ';
- sqlite3_snprintf(sizeof(zBuf)-1, &zBuf[cnt>0], "%d %d %d %d",
- pMatch->iCol, pMatch->iTerm, pMatch->iStart, pMatch->nByte);
- fts3SnippetAppend(&sb, zBuf, -1);
- cnt++;
- }
- }
- p->zOffset = sb.z;
- p->nOffset = sb.z ? sb.nUsed : 0;
-}
-
-/*
-** zDoc[0..nDoc-1] is phrase of text. aMatch[0..nMatch-1] are a set
-** of matching words some of which might be in zDoc. zDoc is column
-** number iCol.
-**
-** iBreak is suggested spot in zDoc where we could begin or end an
-** excerpt. Return a value similar to iBreak but possibly adjusted
-** to be a little left or right so that the break point is better.
-*/
-static int wordBoundary(
- int iBreak, /* The suggested break point */
- const char *zDoc, /* Document text */
- int nDoc, /* Number of bytes in zDoc[] */
- struct snippetMatch *aMatch, /* Matching words */
- int nMatch, /* Number of entries in aMatch[] */
- int iCol /* The column number for zDoc[] */
-){
- int i;
- if( iBreak<=10 ){
- return 0;
- }
- if( iBreak>=nDoc-10 ){
- return nDoc;
- }
- for(i=0; ALWAYS(i<nMatch) && aMatch[i].iCol<iCol; i++){}
- while( i<nMatch && aMatch[i].iStart+aMatch[i].nByte<iBreak ){ i++; }
- if( i<nMatch ){
- if( aMatch[i].iStart<iBreak+10 ){
- return aMatch[i].iStart;
- }
- if( i>0 && aMatch[i-1].iStart+aMatch[i-1].nByte>=iBreak ){
- return aMatch[i-1].iStart;
- }
- }
- for(i=1; i<=10; i++){
- if( fts3snippetIsspace(zDoc[iBreak-i]) ){
- return iBreak - i + 1;
- }
- if( fts3snippetIsspace(zDoc[iBreak+i]) ){
- return iBreak + i + 1;
- }
- }
- return iBreak;
-}
-
-
-
-/*
-** Allowed values for Snippet.aMatch[].snStatus
-*/
-#define SNIPPET_IGNORE 0 /* It is ok to omit this match from the snippet */
-#define SNIPPET_DESIRED 1 /* We want to include this match in the snippet */
-
-/*
-** Generate the text of a snippet.
-*/
-static void snippetText(
- Fts3Cursor *pCursor, /* The cursor we need the snippet for */
- Snippet *pSnippet,
- const char *zStartMark, /* Markup to appear before each match */
- const char *zEndMark, /* Markup to appear after each match */
- const char *zEllipsis /* Ellipsis mark */
-){
- int i, j;
- struct snippetMatch *aMatch;
- int nMatch;
- int nDesired;
- StringBuffer sb;
- int tailCol;
- int tailOffset;
- int iCol;
- int nDoc;
- const char *zDoc;
- int iStart, iEnd;
- int tailEllipsis = 0;
- int iMatch;
-
-
- sqlite3_free(pSnippet->zSnippet);
- pSnippet->zSnippet = 0;
- aMatch = pSnippet->aMatch;
- nMatch = pSnippet->nMatch;
- fts3SnippetSbInit(&sb);
-
- for(i=0; i<nMatch; i++){
- aMatch[i].snStatus = SNIPPET_IGNORE;
- }
- nDesired = 0;
- for(i=0; i<FTS3_ROTOR_SZ; i++){
- for(j=0; j<nMatch; j++){
- if( aMatch[j].iTerm==i ){
- aMatch[j].snStatus = SNIPPET_DESIRED;
- nDesired++;
- break;
- }
- }
- }
-
- iMatch = 0;
- tailCol = -1;
- tailOffset = 0;
- for(i=0; i<nMatch && nDesired>0; i++){
- if( aMatch[i].snStatus!=SNIPPET_DESIRED ) continue;
- nDesired--;
- iCol = aMatch[i].iCol;
- zDoc = (const char*)sqlite3_column_text(pCursor->pStmt, iCol+1);
- nDoc = sqlite3_column_bytes(pCursor->pStmt, iCol+1);
- iStart = aMatch[i].iStart - 40;
- iStart = wordBoundary(iStart, zDoc, nDoc, aMatch, nMatch, iCol);
- if( iStart<=10 ){
- iStart = 0;
- }
- if( iCol==tailCol && iStart<=tailOffset+20 ){
- iStart = tailOffset;
- }
- if( (iCol!=tailCol && tailCol>=0) || iStart!=tailOffset ){
- fts3SnippetTrimWhiteSpace(&sb);
- fts3SnippetAppendWhiteSpace(&sb);
- fts3SnippetAppend(&sb, zEllipsis, -1);
- fts3SnippetAppendWhiteSpace(&sb);
- }
- iEnd = aMatch[i].iStart + aMatch[i].nByte + 40;
- iEnd = wordBoundary(iEnd, zDoc, nDoc, aMatch, nMatch, iCol);
- if( iEnd>=nDoc-10 ){
- iEnd = nDoc;
- tailEllipsis = 0;
- }else{
- tailEllipsis = 1;
- }
- while( iMatch<nMatch && aMatch[iMatch].iCol<iCol ){ iMatch++; }
- while( iStart<iEnd ){
- while( iMatch<nMatch && aMatch[iMatch].iStart<iStart
- && aMatch[iMatch].iCol<=iCol ){
- iMatch++;
- }
- if( iMatch<nMatch && aMatch[iMatch].iStart<iEnd
- && aMatch[iMatch].iCol==iCol ){
- fts3SnippetAppend(&sb, &zDoc[iStart], aMatch[iMatch].iStart - iStart);
- iStart = aMatch[iMatch].iStart;
- fts3SnippetAppend(&sb, zStartMark, -1);
- fts3SnippetAppend(&sb, &zDoc[iStart], aMatch[iMatch].nByte);
- fts3SnippetAppend(&sb, zEndMark, -1);
- iStart += aMatch[iMatch].nByte;
- for(j=iMatch+1; j<nMatch; j++){
- if( aMatch[j].iTerm==aMatch[iMatch].iTerm
- && aMatch[j].snStatus==SNIPPET_DESIRED ){
- nDesired--;
- aMatch[j].snStatus = SNIPPET_IGNORE;
- }
- }
- }else{
- fts3SnippetAppend(&sb, &zDoc[iStart], iEnd - iStart);
- iStart = iEnd;
- }
- }
- tailCol = iCol;
- tailOffset = iEnd;
- }
- fts3SnippetTrimWhiteSpace(&sb);
- if( tailEllipsis ){
- fts3SnippetAppendWhiteSpace(&sb);
- fts3SnippetAppend(&sb, zEllipsis, -1);
- }
- pSnippet->zSnippet = sb.z;
- pSnippet->nSnippet = sb.z ? sb.nUsed : 0;
-}
-
-SQLITE_PRIVATE void sqlite3Fts3Offsets(
- sqlite3_context *pCtx, /* SQLite function call context */
- Fts3Cursor *pCsr /* Cursor object */
-){
- Snippet *p; /* Snippet structure */
- int rc = snippetAllOffsets(pCsr, &p);
- if( rc==SQLITE_OK ){
- snippetOffsetText(p);
- if( p->zOffset ){
- sqlite3_result_text(pCtx, p->zOffset, p->nOffset, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- fts3SnippetFree(p);
-}
-
-SQLITE_PRIVATE void sqlite3Fts3Snippet(
- sqlite3_context *pCtx, /* SQLite function call context */
- Fts3Cursor *pCsr, /* Cursor object */
- const char *zStart, /* Snippet start text - "<b>" */
- const char *zEnd, /* Snippet end text - "</b>" */
- const char *zEllipsis /* Snippet ellipsis text - "<b>...</b>" */
-){
- Snippet *p; /* Snippet structure */
- int rc = snippetAllOffsets(pCsr, &p);
- if( rc==SQLITE_OK ){
- snippetText(pCsr, p, zStart, zEnd, zEllipsis);
- if( p->zSnippet ){
- sqlite3_result_text(pCtx, p->zSnippet, p->nSnippet, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- fts3SnippetFree(p);
-}
-
-/*************************************************************************
-** Below this point is the alternative, experimental snippet() implementation.
-*/
-
-#define SNIPPET_BUFFER_CHUNK 64
-#define SNIPPET_BUFFER_SIZE SNIPPET_BUFFER_CHUNK*4
-#define SNIPPET_BUFFER_MASK (SNIPPET_BUFFER_SIZE-1)
-
static void fts3GetDeltaPosition(char **pp, int *piPos){
int iVal;
*pp += sqlite3Fts3GetVarint32(*pp, &iVal);
@@ -106944,6 +113609,31 @@
}
/*
+** Helper function for fts3ExprIterate() (see below).
+*/
+static int fts3ExprIterate2(
+ Fts3Expr *pExpr, /* Expression to iterate phrases of */
+ int *piPhrase, /* Pointer to phrase counter */
+ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
+ void *pCtx /* Second argument to pass to callback */
+){
+ int rc; /* Return code */
+ int eType = pExpr->eType; /* Type of expression node pExpr */
+
+ if( eType!=FTSQUERY_PHRASE ){
+ assert( pExpr->pLeft && pExpr->pRight );
+ rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx);
+ if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){
+ rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx);
+ }
+ }else{
+ rc = x(pExpr, *piPhrase, pCtx);
+ (*piPhrase)++;
+ }
+ return rc;
+}
+
+/*
** Iterate through all phrase nodes in an FTS3 query, except those that
** are part of a sub-tree that is the right-hand-side of a NOT operator.
** For each phrase node found, the supplied callback function is invoked.
@@ -106955,285 +113645,387 @@
*/
static int fts3ExprIterate(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
- int (*x)(Fts3Expr *, void *), /* Callback function to invoke for phrases */
+ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
void *pCtx /* Second argument to pass to callback */
){
- int rc;
- int eType = pExpr->eType;
- if( eType==FTSQUERY_NOT ){
- rc = SQLITE_OK;
- }else if( eType!=FTSQUERY_PHRASE ){
- assert( pExpr->pLeft && pExpr->pRight );
- rc = fts3ExprIterate(pExpr->pLeft, x, pCtx);
- if( rc==SQLITE_OK ){
- rc = fts3ExprIterate(pExpr->pRight, x, pCtx);
- }
- }else{
- rc = x(pExpr, pCtx);
- }
- return rc;
+ int iPhrase = 0; /* Variable used as the phrase counter */
+ return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
}
-typedef struct LoadDoclistCtx LoadDoclistCtx;
-struct LoadDoclistCtx {
- Fts3Table *pTab; /* FTS3 Table */
- int nPhrase; /* Number of phrases so far */
-};
-
-static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, void *ctx){
+/*
+** The argument to this function is always a phrase node. Its doclist
+** (Fts3Expr.aDoclist[]) and the doclists associated with all phrase nodes
+** to the left of this one in the query tree have already been loaded.
+**
+** If this phrase node is part of a series of phrase nodes joined by
+** NEAR operators (and is not the left-most of said series), then elements are
+** removed from the phrases doclist consistent with the NEAR restriction. If
+** required, elements may be removed from the doclists of phrases to the
+** left of this one that are part of the same series of NEAR operator
+** connected phrases.
+**
+** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
+*/
+static int fts3ExprNearTrim(Fts3Expr *pExpr){
int rc = SQLITE_OK;
- LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
- p->nPhrase++;
- if( pExpr->isLoaded==0 ){
- rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
- pExpr->isLoaded = 1;
- if( rc==SQLITE_OK && pExpr->aDoclist ){
- pExpr->pCurrent = pExpr->aDoclist;
- pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
- }
- }
- return rc;
-}
+ Fts3Expr *pParent = pExpr->pParent;
-static int fts3ExprLoadDoclists(Fts3Cursor *pCsr, int *pnPhrase){
- int rc;
- LoadDoclistCtx sCtx = {0, 0};
- sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
- *pnPhrase = sCtx.nPhrase;
+ assert( pExpr->eType==FTSQUERY_PHRASE );
+ while( rc==SQLITE_OK
+ && pParent
+ && pParent->eType==FTSQUERY_NEAR
+ && pParent->pRight==pExpr
+ ){
+ /* This expression (pExpr) is the right-hand-side of a NEAR operator.
+ ** Find the expression to the left of the same operator.
+ */
+ int nNear = pParent->nNear;
+ Fts3Expr *pLeft = pParent->pLeft;
+
+ if( pLeft->eType!=FTSQUERY_PHRASE ){
+ assert( pLeft->eType==FTSQUERY_NEAR );
+ assert( pLeft->pRight->eType==FTSQUERY_PHRASE );
+ pLeft = pLeft->pRight;
+ }
+
+ rc = sqlite3Fts3ExprNearTrim(pLeft, pExpr, nNear);
+
+ pExpr = pLeft;
+ pParent = pExpr->pParent;
+ }
+
return rc;
}
/*
-** Each call to this function populates a chunk of a snippet-buffer
-** SNIPPET_BUFFER_CHUNK bytes in size.
-**
-** Return true if the end of the data has been reached (and all subsequent
-** calls to fts3LoadSnippetBuffer() with the same arguments will be no-ops),
-** or false otherwise.
+** This is an fts3ExprIterate() callback used while loading the doclists
+** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** fts3ExprLoadDoclists().
*/
-static int fts3LoadSnippetBuffer(
- int iPos, /* Document token offset to load data for */
- u8 *aBuffer, /* Circular snippet buffer to populate */
- int nList, /* Number of position lists in appList */
- char **apList, /* IN/OUT: nList position list pointers */
- int *aiPrev /* IN/OUT: Previous positions read */
-){
- int i;
- int nFin = 0;
+static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ int rc = SQLITE_OK;
+ LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
- assert( (iPos&(SNIPPET_BUFFER_CHUNK-1))==0 );
+ UNUSED_PARAMETER(iPhrase);
- memset(&aBuffer[iPos&SNIPPET_BUFFER_MASK], 0, SNIPPET_BUFFER_CHUNK);
+ p->nPhrase++;
+ p->nToken += pExpr->pPhrase->nToken;
- for(i=0; i<nList; i++){
- int iPrev = aiPrev[i];
- char *pList = apList[i];
-
- if( !pList ){
- nFin++;
- continue;
+ if( pExpr->isLoaded==0 ){
+ rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
+ pExpr->isLoaded = 1;
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprNearTrim(pExpr);
}
-
- while( iPrev<(iPos+SNIPPET_BUFFER_CHUNK) ){
- if( iPrev>=iPos ){
- aBuffer[iPrev&SNIPPET_BUFFER_MASK] = (u8)(i+1);
- }
- if( 0==((*pList)&0xFE) ){
- nFin++;
- break;
- }
- fts3GetDeltaPosition(&pList, &iPrev);
- }
-
- aiPrev[i] = iPrev;
- apList[i] = pList;
}
- return (nFin==nList);
+ return rc;
}
-typedef struct SnippetCtx SnippetCtx;
-struct SnippetCtx {
- Fts3Cursor *pCsr;
- int iCol;
- int iPhrase;
- int *aiPrev;
- int *anToken;
- char **apList;
-};
-
-static int fts3SnippetFindPositions(Fts3Expr *pExpr, void *ctx){
- SnippetCtx *p = (SnippetCtx *)ctx;
- int iPhrase = p->iPhrase++;
- char *pCsr;
-
- p->anToken[iPhrase] = pExpr->pPhrase->nToken;
- pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
-
- if( pCsr ){
- int iVal;
- pCsr += sqlite3Fts3GetVarint32(pCsr, &iVal);
- p->apList[iPhrase] = pCsr;
- p->aiPrev[iPhrase] = iVal-2;
+/*
+** This is an fts3ExprIterate() callback used while loading the doclists
+** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** fts3ExprLoadDoclists().
+*/
+static int fts3ExprLoadDoclistsCb2(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ UNUSED_PARAMETER(iPhrase);
+ UNUSED_PARAMETER(ctx);
+ if( pExpr->aDoclist ){
+ pExpr->pCurrent = pExpr->aDoclist;
+ pExpr->iCurrent = 0;
+ pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent, &pExpr->iCurrent);
}
return SQLITE_OK;
}
-static void fts3SnippetCnt(
- int iIdx,
- int nSnippet,
- int *anCnt,
- u8 *aBuffer,
- int *anToken,
- u64 *pHlmask
+/*
+** Load the doclists for each phrase in the query associated with FTS3 cursor
+** pCsr.
+**
+** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
+** phrases in the expression (all phrases except those directly or
+** indirectly descended from the right-hand-side of a NOT operator). If
+** pnToken is not NULL, then it is set to the number of tokens in all
+** matchable phrases of the expression.
+*/
+static int fts3ExprLoadDoclists(
+ Fts3Cursor *pCsr, /* Fts3 cursor for current query */
+ int *pnPhrase, /* OUT: Number of phrases in query */
+ int *pnToken /* OUT: Number of tokens in query */
){
- int iSub = (iIdx-1)&SNIPPET_BUFFER_MASK;
- int iAdd = (iIdx+nSnippet-1)&SNIPPET_BUFFER_MASK;
- int iSub2 = (iIdx+(nSnippet/3)-1)&SNIPPET_BUFFER_MASK;
- int iAdd2 = (iIdx+(nSnippet*2/3)-1)&SNIPPET_BUFFER_MASK;
+ int rc; /* Return Code */
+ LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
+ sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
+ rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
+ if( rc==SQLITE_OK ){
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
+ }
+ if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
+ if( pnToken ) *pnToken = sCtx.nToken;
+ return rc;
+}
- u64 h = *pHlmask;
+/*
+** Advance the position list iterator specified by the first two
+** arguments so that it points to the first element with a value greater
+** than or equal to parameter iNext.
+*/
+static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
+ char *pIter = *ppIter;
+ if( pIter ){
+ int iIter = *piIter;
- anCnt[ aBuffer[iSub] ]--;
- anCnt[ aBuffer[iSub2] ]--;
- anCnt[ aBuffer[iAdd] ]++;
- anCnt[ aBuffer[iAdd2] ]++;
+ while( iIter<iNext ){
+ if( 0==(*pIter & 0xFE) ){
+ iIter = -1;
+ pIter = 0;
+ break;
+ }
+ fts3GetDeltaPosition(&pIter, &iIter);
+ }
- h = h >> 1;
- if( aBuffer[iAdd] ){
- int j;
- for(j=anToken[aBuffer[iAdd]-1]; j>=1; j--){
- h |= (u64)1 << (nSnippet-j);
+ *piIter = iIter;
+ *ppIter = pIter;
+ }
+}
+
+/*
+** Advance the snippet iterator to the next candidate snippet.
+*/
+static int fts3SnippetNextCandidate(SnippetIter *pIter){
+ int i; /* Loop counter */
+
+ if( pIter->iCurrent<0 ){
+ /* The SnippetIter object has just been initialized. The first snippet
+ ** candidate always starts at offset 0 (even if this candidate has a
+ ** score of 0.0).
+ */
+ pIter->iCurrent = 0;
+
+ /* Advance the 'head' iterator of each phrase to the first offset that
+ ** is greater than or equal to (iNext+nSnippet).
+ */
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet);
+ }
+ }else{
+ int iStart;
+ int iEnd = 0x7FFFFFFF;
+
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ if( pPhrase->pHead && pPhrase->iHead<iEnd ){
+ iEnd = pPhrase->iHead;
+ }
+ }
+ if( iEnd==0x7FFFFFFF ){
+ return 1;
+ }
+
+ pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1);
+ fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart);
}
}
- *pHlmask = h;
+
+ return 0;
}
-static int fts3SnippetScore(int n, int *anCnt){
- int j;
- int iScore = 0;
- for(j=1; j<=n; j++){
- int nCnt = anCnt[j];
- iScore += nCnt + (nCnt ? 1000 : 0);
+/*
+** Retrieve information about the current candidate snippet of snippet
+** iterator pIter.
+*/
+static void fts3SnippetDetails(
+ SnippetIter *pIter, /* Snippet iterator */
+ u64 mCovered, /* Bitmask of phrases already covered */
+ int *piToken, /* OUT: First token of proposed snippet */
+ int *piScore, /* OUT: "Score" for this snippet */
+ u64 *pmCover, /* OUT: Bitmask of phrases covered */
+ u64 *pmHighlight /* OUT: Bitmask of terms to highlight */
+){
+ int iStart = pIter->iCurrent; /* First token of snippet */
+ int iScore = 0; /* Score of this snippet */
+ int i; /* Loop counter */
+ u64 mCover = 0; /* Mask of phrases covered by this snippet */
+ u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */
+
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ if( pPhrase->pTail ){
+ char *pCsr = pPhrase->pTail;
+ int iCsr = pPhrase->iTail;
+
+ while( iCsr<(iStart+pIter->nSnippet) ){
+ int j;
+ u64 mPhrase = (u64)1 << i;
+ u64 mPos = (u64)1 << (iCsr - iStart);
+ assert( iCsr>=iStart );
+ if( (mCover|mCovered)&mPhrase ){
+ iScore++;
+ }else{
+ iScore += 1000;
+ }
+ mCover |= mPhrase;
+
+ for(j=0; j<pPhrase->nToken; j++){
+ mHighlight |= (mPos>>j);
+ }
+
+ if( 0==(*pCsr & 0x0FE) ) break;
+ fts3GetDeltaPosition(&pCsr, &iCsr);
+ }
+ }
}
- return iScore;
+
+ /* Set the output variables before returning. */
+ *piToken = iStart;
+ *piScore = iScore;
+ *pmCover = mCover;
+ *pmHighlight = mHighlight;
}
+/*
+** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
+** Each invocation populates an element of the SnippetIter.aPhrase[] array.
+*/
+static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ SnippetIter *p = (SnippetIter *)ctx;
+ SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
+ char *pCsr;
+
+ pPhrase->nToken = pExpr->pPhrase->nToken;
+
+ pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
+ if( pCsr ){
+ int iFirst = 0;
+ pPhrase->pList = pCsr;
+ fts3GetDeltaPosition(&pCsr, &iFirst);
+ pPhrase->pHead = pCsr;
+ pPhrase->pTail = pCsr;
+ pPhrase->iHead = iFirst;
+ pPhrase->iTail = iFirst;
+ }else{
+ assert( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 );
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Select the fragment of text consisting of nFragment contiguous tokens
+** from column iCol that represent the "best" snippet. The best snippet
+** is the snippet with the highest score, where scores are calculated
+** by adding:
+**
+** (a) +1 point for each occurence of a matchable phrase in the snippet.
+**
+** (b) +1000 points for the first occurence of each matchable phrase in
+** the snippet for which the corresponding mCovered bit is not set.
+**
+** The selected snippet parameters are stored in structure *pFragment before
+** returning. The score of the selected snippet is stored in *piScore
+** before returning.
+*/
static int fts3BestSnippet(
int nSnippet, /* Desired snippet length */
Fts3Cursor *pCsr, /* Cursor to create snippet for */
int iCol, /* Index of column to create snippet from */
- int *piPos, /* OUT: Starting token for best snippet */
- u64 *pHlmask /* OUT: Highlight mask for best snippet */
+ u64 mCovered, /* Mask of phrases already covered */
+ u64 *pmSeen, /* IN/OUT: Mask of phrases seen */
+ SnippetFragment *pFragment, /* OUT: Best snippet found */
+ int *piScore /* OUT: Score of snippet pFragment */
){
int rc; /* Return Code */
- u8 aBuffer[SNIPPET_BUFFER_SIZE];/* Circular snippet buffer */
- int *aiPrev; /* Used by fts3LoadSnippetBuffer() */
- int *anToken; /* Number of tokens in each phrase */
- char **apList; /* Array of position lists */
- int *anCnt; /* Running totals of phrase occurences */
- int nList;
+ int nList; /* Number of phrases in expression */
+ SnippetIter sIter; /* Iterates through snippet candidates */
+ int nByte; /* Number of bytes of space to allocate */
+ int iBestScore = -1; /* Best snippet score found so far */
+ int i; /* Loop counter */
- int i;
-
- u64 hlmask = 0; /* Current mask of highlighted terms */
- u64 besthlmask = 0; /* Mask of highlighted terms for iBestPos */
- int iBestPos = 0; /* Starting position of 'best' snippet */
- int iBestScore = 0; /* Score of best snippet higher->better */
- SnippetCtx sCtx;
+ memset(&sIter, 0, sizeof(sIter));
/* Iterate through the phrases in the expression to count them. The same
** callback makes sure the doclists are loaded for each phrase.
*/
- rc = fts3ExprLoadDoclists(pCsr, &nList);
+ rc = fts3ExprLoadDoclists(pCsr, &nList, 0);
if( rc!=SQLITE_OK ){
return rc;
}
/* Now that it is known how many phrases there are, allocate and zero
- ** the required arrays using malloc().
+ ** the required space using malloc().
*/
- apList = sqlite3_malloc(
- sizeof(u8*)*nList + /* apList */
- sizeof(int)*(nList) + /* anToken */
- sizeof(int)*nList + /* aiPrev */
- sizeof(int)*(nList+1) /* anCnt */
- );
- if( !apList ){
+ nByte = sizeof(SnippetPhrase) * nList;
+ sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
+ if( !sIter.aPhrase ){
return SQLITE_NOMEM;
}
- memset(apList, 0, sizeof(u8*)*nList+sizeof(int)*nList+sizeof(int)*nList);
- anToken = (int *)&apList[nList];
- aiPrev = &anToken[nList];
- anCnt = &aiPrev[nList];
+ memset(sIter.aPhrase, 0, nByte);
- /* Initialize the contents of the aiPrev and aiList arrays. */
- sCtx.pCsr = pCsr;
- sCtx.iCol = iCol;
- sCtx.apList = apList;
- sCtx.aiPrev = aiPrev;
- sCtx.anToken = anToken;
- sCtx.iPhrase = 0;
- (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sCtx);
+ /* Initialize the contents of the SnippetIter object. Then iterate through
+ ** the set of phrases in the expression to populate the aPhrase[] array.
+ */
+ sIter.pCsr = pCsr;
+ sIter.iCol = iCol;
+ sIter.nSnippet = nSnippet;
+ sIter.nPhrase = nList;
+ sIter.iCurrent = -1;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
- /* Load the first two chunks of data into the buffer. */
- memset(aBuffer, 0, SNIPPET_BUFFER_SIZE);
- fts3LoadSnippetBuffer(0, aBuffer, nList, apList, aiPrev);
- fts3LoadSnippetBuffer(SNIPPET_BUFFER_CHUNK, aBuffer, nList, apList, aiPrev);
-
- /* Set the initial contents of the highlight-mask and anCnt[] array. */
- for(i=1-nSnippet; i<=0; i++){
- fts3SnippetCnt(i, nSnippet, anCnt, aBuffer, anToken, &hlmask);
+ /* Set the *pmSeen output variable. */
+ for(i=0; i<nList; i++){
+ if( sIter.aPhrase[i].pHead ){
+ *pmSeen |= (u64)1 << i;
+ }
}
- iBestScore = fts3SnippetScore(nList, anCnt);
- besthlmask = hlmask;
- iBestPos = 0;
- for(i=1; 1; i++){
+ /* Loop through all candidate snippets. Store the best snippet in
+ ** *pFragment. Store its associated 'score' in iBestScore.
+ */
+ pFragment->iCol = iCol;
+ while( !fts3SnippetNextCandidate(&sIter) ){
+ int iPos;
int iScore;
-
- if( 0==(i&(SNIPPET_BUFFER_CHUNK-1)) ){
- int iLoad = i + SNIPPET_BUFFER_CHUNK;
- if( fts3LoadSnippetBuffer(iLoad, aBuffer, nList, apList, aiPrev) ) break;
- }
-
- /* Figure out how highly a snippet starting at token offset i scores
- ** according to fts3SnippetScore(). If it is higher than any previously
- ** considered position, save the current position, score and hlmask as
- ** the best snippet candidate found so far.
- */
- fts3SnippetCnt(i, nSnippet, anCnt, aBuffer, anToken, &hlmask);
- iScore = fts3SnippetScore(nList, anCnt);
+ u64 mCover;
+ u64 mHighlight;
+ fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight);
+ assert( iScore>=0 );
if( iScore>iBestScore ){
- iBestPos = i;
+ pFragment->iPos = iPos;
+ pFragment->hlmask = mHighlight;
+ pFragment->covered = mCover;
iBestScore = iScore;
- besthlmask = hlmask;
}
}
- sqlite3_free(apList);
- *piPos = iBestPos;
- *pHlmask = besthlmask;
+ sqlite3_free(sIter.aPhrase);
+ *piScore = iBestScore;
return SQLITE_OK;
}
-typedef struct StrBuffer StrBuffer;
-struct StrBuffer {
- char *z;
- int n;
- int nAlloc;
-};
+/*
+** Append a string to the string-buffer passed as the first argument.
+**
+** If nAppend is negative, then the length of the string zAppend is
+** determined using strlen().
+*/
static int fts3StringAppend(
- StrBuffer *pStr,
- const char *zAppend,
- int nAppend
+ StrBuffer *pStr, /* Buffer to append to */
+ const char *zAppend, /* Pointer to data to append to buffer */
+ int nAppend /* Size of zAppend in bytes (or -1) */
){
if( nAppend<0 ){
nAppend = (int)strlen(zAppend);
}
+ /* If there is insufficient space allocated at StrBuffer.z, use realloc()
+ ** to grow the buffer until so that it is big enough to accomadate the
+ ** appended data.
+ */
if( pStr->n+nAppend+1>=pStr->nAlloc ){
int nAlloc = pStr->nAlloc+nAppend+100;
char *zNew = sqlite3_realloc(pStr->z, nAlloc);
@@ -107244,6 +114036,7 @@
pStr->nAlloc = nAlloc;
}
+ /* Append the data to the string buffer. */
memcpy(&pStr->z[pStr->n], zAppend, nAppend);
pStr->n += nAppend;
pStr->z[pStr->n] = '\0';
@@ -107251,126 +114044,201 @@
return SQLITE_OK;
}
+/*
+** The fts3BestSnippet() function often selects snippets that end with a
+** query term. That is, the final term of the snippet is always a term
+** that requires highlighting. For example, if 'X' is a highlighted term
+** and '.' is a non-highlighted term, BestSnippet() may select:
+**
+** ........X.....X
+**
+** This function "shifts" the beginning of the snippet forward in the
+** document so that there are approximately the same number of
+** non-highlighted terms to the right of the final highlighted term as there
+** are to the left of the first highlighted term. For example, to this:
+**
+** ....X.....X....
+**
+** This is done as part of extracting the snippet text, not when selecting
+** the snippet. Snippet selection is done based on doclists only, so there
+** is no way for fts3BestSnippet() to know whether or not the document
+** actually contains terms that follow the final highlighted term.
+*/
+static int fts3SnippetShift(
+ Fts3Table *pTab, /* FTS3 table snippet comes from */
+ int nSnippet, /* Number of tokens desired for snippet */
+ const char *zDoc, /* Document text to extract snippet from */
+ int nDoc, /* Size of buffer zDoc in bytes */
+ int *piPos, /* IN/OUT: First token of snippet */
+ u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */
+){
+ u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */
+
+ if( hlmask ){
+ int nLeft; /* Tokens to the left of first highlight */
+ int nRight; /* Tokens to the right of last highlight */
+ int nDesired; /* Ideal number of tokens to shift forward */
+
+ for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++);
+ for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++);
+ nDesired = (nLeft-nRight)/2;
+
+ /* Ideally, the start of the snippet should be pushed forward in the
+ ** document nDesired tokens. This block checks if there are actually
+ ** nDesired tokens to the right of the snippet. If so, *piPos and
+ ** *pHlMask are updated to shift the snippet nDesired tokens to the
+ ** right. Otherwise, the snippet is shifted by the number of tokens
+ ** available.
+ */
+ if( nDesired>0 ){
+ int nShift; /* Number of tokens to shift snippet by */
+ int iCurrent = 0; /* Token counter */
+ int rc; /* Return Code */
+ sqlite3_tokenizer_module *pMod;
+ sqlite3_tokenizer_cursor *pC;
+ pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
+
+ /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
+ ** or more tokens in zDoc/nDoc.
+ */
+ rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pC->pTokenizer = pTab->pTokenizer;
+ while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
+ const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
+ rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
+ }
+ pMod->xClose(pC);
+ if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; }
+
+ nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet;
+ assert( nShift<=nDesired );
+ if( nShift>0 ){
+ *piPos += nShift;
+ *pHlmask = hlmask >> nShift;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Extract the snippet text for fragment pFragment from cursor pCsr and
+** append it to string buffer pOut.
+*/
static int fts3SnippetText(
Fts3Cursor *pCsr, /* FTS3 Cursor */
- const char *zDoc, /* Document to extract snippet from */
- int nDoc, /* Size of zDoc in bytes */
+ SnippetFragment *pFragment, /* Snippet to extract */
+ int iFragment, /* Fragment number */
+ int isLast, /* True for final fragment in snippet */
int nSnippet, /* Number of tokens in extracted snippet */
- int iPos, /* Index of first document token in snippet */
- u64 hlmask, /* Bitmask of terms to highlight in snippet */
const char *zOpen, /* String inserted before highlighted term */
const char *zClose, /* String inserted after highlighted term */
- const char *zEllipsis,
- char **pzSnippet /* OUT: Snippet text */
+ const char *zEllipsis, /* String inserted between snippets */
+ StrBuffer *pOut /* Write output here */
){
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
int rc; /* Return code */
- int iCurrent = 0;
- int iStart = 0;
- int iEnd;
-
+ const char *zDoc; /* Document text to extract snippet from */
+ int nDoc; /* Size of zDoc in bytes */
+ int iCurrent = 0; /* Current token number of document */
+ int iEnd = 0; /* Byte offset of end of current token */
+ int isShiftDone = 0; /* True after snippet is shifted */
+ int iPos = pFragment->iPos; /* First token of snippet */
+ u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */
+ int iCol = pFragment->iCol+1; /* Query column to extract text from */
sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
- const char *ZDUMMY; /* Dummy arguments used with tokenizer */
- int DUMMY1, DUMMY2, DUMMY3; /* Dummy arguments used with tokenizer */
+ const char *ZDUMMY; /* Dummy argument used with tokenizer */
+ int DUMMY1; /* Dummy argument used with tokenizer */
+
+ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
+ if( zDoc==0 ){
+ if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){
+ return SQLITE_NOMEM;
+ }
+ return SQLITE_OK;
+ }
+ nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol);
- StrBuffer res = {0, 0, 0}; /* Result string */
-
- /* Open a token cursor on the document. Read all tokens up to and
- ** including token iPos (the first token of the snippet). Set variable
- ** iStart to the byte offset in zDoc of the start of token iPos.
- */
+ /* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
- while( rc==SQLITE_OK && iCurrent<iPos ){
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iStart, &DUMMY2, &iCurrent);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
- iEnd = iStart;
-
- if( rc==SQLITE_OK && iStart>0 ){
- rc = fts3StringAppend(&res, zEllipsis, -1);
- }
+ pC->pTokenizer = pTab->pTokenizer;
while( rc==SQLITE_OK ){
- int iBegin;
- int iFin;
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
+ int iBegin; /* Offset in zDoc of start of token */
+ int iFin; /* Offset in zDoc of end of token */
+ int isHighlight; /* True for highlighted terms */
- if( rc==SQLITE_OK ){
- if( iCurrent>=(iPos+nSnippet) ){
- rc = SQLITE_DONE;
- }else{
- iEnd = iFin;
- if( hlmask & ((u64)1 << (iCurrent-iPos)) ){
- if( fts3StringAppend(&res, &zDoc[iStart], iBegin-iStart)
- || fts3StringAppend(&res, zOpen, -1)
- || fts3StringAppend(&res, &zDoc[iBegin], iEnd-iBegin)
- || fts3StringAppend(&res, zClose, -1)
- ){
- rc = SQLITE_NOMEM;
- }
- iStart = iEnd;
- }
+ rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ /* Special case - the last token of the snippet is also the last token
+ ** of the column. Append any punctuation that occurred between the end
+ ** of the previous token and the end of the document to the output.
+ ** Then break out of the loop. */
+ rc = fts3StringAppend(pOut, &zDoc[iEnd], -1);
}
+ break;
}
- }
- assert( rc!=SQLITE_OK );
- if( rc==SQLITE_DONE ){
- rc = fts3StringAppend(&res, &zDoc[iStart], iEnd-iStart);
- if( rc==SQLITE_OK ){
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
- if( rc==SQLITE_OK ){
- rc = fts3StringAppend(&res, zEllipsis, -1);
- }else if( rc==SQLITE_DONE ){
- rc = fts3StringAppend(&res, &zDoc[iEnd], -1);
+ if( iCurrent<iPos ){ continue; }
+
+ if( !isShiftDone ){
+ int n = nDoc - iBegin;
+ rc = fts3SnippetShift(pTab, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask);
+ isShiftDone = 1;
+
+ /* Now that the shift has been done, check if the initial "..." are
+ ** required. They are required if (a) this is not the first fragment,
+ ** or (b) this fragment does not begin at position 0 of its column.
+ */
+ if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
}
+ if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
}
+
+ if( iCurrent>=(iPos+nSnippet) ){
+ if( isLast ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
+ }
+ break;
+ }
+
+ /* Set isHighlight to true if this term should be highlighted. */
+ isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0;
+
+ if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd);
+ if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1);
+ if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin);
+ if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1);
+
+ iEnd = iFin;
}
pMod->xClose(pC);
- if( rc!=SQLITE_OK ){
- sqlite3_free(res.z);
- }else{
- *pzSnippet = res.z;
- }
return rc;
}
/*
-** An instance of this structure is used to collect the 'global' part of
-** the matchinfo statistics. The 'global' part consists of the following:
+** This function is used to count the entries in a column-list (a
+** delta-encoded list of term offsets within a single column of a single
+** row). When this function is called, *ppCollist should point to the
+** beginning of the first varint in the column-list (the varint that
+** contains the position of the first matching term in the column data).
+** Before returning, *ppCollist is set to point to the first byte after
+** the last varint in the column-list (either the 0x00 signifying the end
+** of the position-list, or the 0x01 that precedes the column number of
+** the next column in the position-list).
**
-** 1. The number of phrases in the query (nPhrase).
-**
-** 2. The number of columns in the FTS3 table (nCol).
-**
-** 3. A matrix of (nPhrase*nCol) integers containing the sum of the
-** number of hits for each phrase in each column across all rows
-** of the table.
-**
-** The total size of the global matchinfo array, assuming the number of
-** columns is N and the number of phrases is P is:
-**
-** 2 + P*(N+1)
-**
-** The number of hits for the 3rd phrase in the second column is found
-** using the expression:
-**
-** aGlobal[2 + P*(1+2) + 1]
-*/
-typedef struct MatchInfo MatchInfo;
-struct MatchInfo {
- Fts3Table *pTab; /* FTS3 Table */
- Fts3Cursor *pCursor; /* FTS3 Cursor */
- int iPhrase; /* Number of phrases so far */
- int nCol; /* Number of columns in table */
- u32 *aGlobal; /* Pre-allocated buffer */
-};
-
-/*
-** This function is used to count the entries in a column-list (delta-encoded
-** list of term offsets within a single column of a single row).
+** The number of elements in the column-list is returned.
*/
static int fts3ColumnlistCount(char **ppCollist){
char *pEnd = *ppCollist;
@@ -107387,15 +114255,21 @@
return nEntry;
}
-static void fts3LoadColumnlistCounts(char **pp, u32 *aOut){
+static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
char *pCsr = *pp;
while( *pCsr ){
+ int nHit;
sqlite3_int64 iCol = 0;
if( *pCsr==0x01 ){
pCsr++;
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
}
- aOut[iCol] += fts3ColumnlistCount(&pCsr);
+ nHit = fts3ColumnlistCount(&pCsr);
+ assert( nHit>0 );
+ if( isGlobal ){
+ aOut[iCol*3+1]++;
+ }
+ aOut[iCol*3] += nHit;
}
pCsr++;
*pp = pCsr;
@@ -107403,16 +114277,18 @@
/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query.
+** for a single query. The "global" stats are those elements of the matchinfo
+** array that are constant for all rows returned by the current query.
*/
static int fts3ExprGlobalMatchinfoCb(
Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number (numbered from zero) */
void *pCtx /* Pointer to MatchInfo structure */
){
MatchInfo *p = (MatchInfo *)pCtx;
char *pCsr;
char *pEnd;
- const int iStart = 2 + p->nCol*p->iPhrase;
+ const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;
assert( pExpr->isLoaded );
@@ -107420,84 +114296,108 @@
pCsr = pExpr->aDoclist;
pEnd = &pExpr->aDoclist[pExpr->nDoclist];
while( pCsr<pEnd ){
- while( *pCsr++ & 0x80 );
- fts3LoadColumnlistCounts(&pCsr, &p->aGlobal[iStart]);
- }
-
- p->iPhrase++;
- return SQLITE_OK;
-}
-
-static int fts3ExprLocalMatchinfoCb(
- Fts3Expr *pExpr, /* Phrase expression node */
- void *pCtx /* Pointer to MatchInfo structure */
-){
- MatchInfo *p = (MatchInfo *)pCtx;
- int iPhrase = p->iPhrase++;
-
- if( pExpr->aDoclist ){
- char *pCsr;
- int iOffset = 2 + p->nCol*(p->aGlobal[0]+iPhrase);
-
- memset(&p->aGlobal[iOffset], 0, p->nCol*sizeof(u32));
- pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
- if( pCsr ) fts3LoadColumnlistCounts(&pCsr, &p->aGlobal[iOffset]);
+ while( *pCsr++ & 0x80 ); /* Skip past docid. */
+ fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 1);
}
return SQLITE_OK;
}
/*
-** Populate pCsr->aMatchinfo[] with data for the current row. The 'matchinfo'
-** data is an array of 32-bit unsigned integers (C type u32).
+** fts3ExprIterate() callback used to collect the "local" matchinfo stats
+** for a single query. The "local" stats are those elements of the matchinfo
+** array that are different for each row returned by the query.
*/
-static int fts3GetMatchinfo(Fts3Cursor *pCsr){
- MatchInfo g;
- Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
- if( pCsr->aMatchinfo==0 ){
- int rc;
- int nPhrase;
- int nMatchinfo;
+static int fts3ExprLocalMatchinfoCb(
+ Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number */
+ void *pCtx /* Pointer to MatchInfo structure */
+){
+ MatchInfo *p = (MatchInfo *)pCtx;
- g.pTab = pTab;
- g.nCol = pTab->nColumn;
- g.iPhrase = 0;
- rc = fts3ExprLoadDoclists(pCsr, &nPhrase);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( pExpr->aDoclist ){
+ char *pCsr;
+ int iStart = 2 + (iPhrase * p->nCol * 3);
+ int i;
+
+ for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
+
+ pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
+ if( pCsr ){
+ fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
}
-
- nMatchinfo = 2 + 2*g.nCol*nPhrase;
-
- g.iPhrase = 0;
- g.aGlobal = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
- if( !g.aGlobal ){
- return SQLITE_NOMEM;
- }
- memset(g.aGlobal, 0, sizeof(u32)*nMatchinfo);
-
- g.aGlobal[0] = nPhrase;
- g.aGlobal[1] = g.nCol;
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb, (void *)&g);
-
- pCsr->aMatchinfo = g.aGlobal;
- }
-
- g.pTab = pTab;
- g.pCursor = pCsr;
- g.nCol = pTab->nColumn;
- g.iPhrase = 0;
- g.aGlobal = pCsr->aMatchinfo;
-
- if( pCsr->isMatchinfoOk ){
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void *)&g);
- pCsr->isMatchinfoOk = 0;
}
return SQLITE_OK;
}
-SQLITE_PRIVATE void sqlite3Fts3Snippet2(
+/*
+** Populate pCsr->aMatchinfo[] with data for the current row. The
+** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
+*/
+static int fts3GetMatchinfo(Fts3Cursor *pCsr){
+ MatchInfo sInfo;
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ int rc = SQLITE_OK;
+
+ sInfo.pCursor = pCsr;
+ sInfo.nCol = pTab->nColumn;
+
+ if( pCsr->aMatchinfo==0 ){
+ /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
+ ** matchinfo function has been called for this query. In this case
+ ** allocate the array used to accumulate the matchinfo data and
+ ** initialize those elements that are constant for every row.
+ */
+ int nPhrase; /* Number of phrases */
+ int nMatchinfo; /* Number of u32 elements in match-info */
+
+ /* Load doclists for each phrase in the query. */
+ rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
+ if( pTab->bHasDocsize ){
+ nMatchinfo += 1 + 2*pTab->nColumn;
+ }
+
+ sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
+ if( !sInfo.aMatchinfo ){
+ return SQLITE_NOMEM;
+ }
+ memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);
+
+
+ /* First element of match-info is the number of phrases in the query */
+ sInfo.aMatchinfo[0] = nPhrase;
+ sInfo.aMatchinfo[1] = sInfo.nCol;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
+ if( pTab->bHasDocsize ){
+ int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
+ rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
+ }
+ pCsr->aMatchinfo = sInfo.aMatchinfo;
+ pCsr->isMatchinfoNeeded = 1;
+ }
+
+ sInfo.aMatchinfo = pCsr->aMatchinfo;
+ if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
+ if( pTab->bHasDocsize ){
+ int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
+ rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
+ }
+ pCsr->isMatchinfoNeeded = 0;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of snippet() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3Snippet(
sqlite3_context *pCtx, /* SQLite function call context */
Fts3Cursor *pCsr, /* Cursor object */
const char *zStart, /* Snippet start text - "<b>" */
@@ -107506,35 +114406,292 @@
int iCol, /* Extract snippet from this column */
int nToken /* Approximate number of tokens in snippet */
){
- int rc;
- int iPos = 0;
- u64 hlmask = 0;
- char *z = 0;
- int nDoc;
- const char *zDoc;
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ int rc = SQLITE_OK;
+ int i;
+ StrBuffer res = {0, 0, 0};
- rc = fts3BestSnippet(nToken, pCsr, iCol, &iPos, &hlmask);
+ /* The returned text includes up to four fragments of text extracted from
+ ** the data in the current row. The first iteration of the for(...) loop
+ ** below attempts to locate a single fragment of text nToken tokens in
+ ** size that contains at least one instance of all phrases in the query
+ ** expression that appear in the current row. If such a fragment of text
+ ** cannot be found, the second iteration of the loop attempts to locate
+ ** a pair of fragments, and so on.
+ */
+ int nSnippet = 0; /* Number of fragments in this snippet */
+ SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */
+ int nFToken = -1; /* Number of tokens in each fragment */
- nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
- zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
-
- if( rc==SQLITE_OK ){
- rc = fts3SnippetText(
- pCsr, zDoc, nDoc, nToken, iPos, hlmask, zStart, zEnd, zEllipsis, &z);
+ if( !pCsr->pExpr ){
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
+ return;
}
+
+ for(nSnippet=1; 1; nSnippet++){
+
+ int iSnip; /* Loop counter 0..nSnippet-1 */
+ u64 mCovered = 0; /* Bitmask of phrases covered by snippet */
+ u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */
+
+ if( nToken>=0 ){
+ nFToken = (nToken+nSnippet-1) / nSnippet;
+ }else{
+ nFToken = -1 * nToken;
+ }
+
+ for(iSnip=0; iSnip<nSnippet; iSnip++){
+ int iBestScore = -1; /* Best score of columns checked so far */
+ int iRead; /* Used to iterate through columns */
+ SnippetFragment *pFragment = &aSnippet[iSnip];
+
+ memset(pFragment, 0, sizeof(*pFragment));
+
+ /* Loop through all columns of the table being considered for snippets.
+ ** If the iCol argument to this function was negative, this means all
+ ** columns of the FTS3 table. Otherwise, only column iCol is considered.
+ */
+ for(iRead=0; iRead<pTab->nColumn; iRead++){
+ SnippetFragment sF;
+ int iS;
+ if( iCol>=0 && iRead!=iCol ) continue;
+
+ /* Find the best snippet of nFToken tokens in column iRead. */
+ rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS);
+ if( rc!=SQLITE_OK ){
+ goto snippet_out;
+ }
+ if( iS>iBestScore ){
+ *pFragment = sF;
+ iBestScore = iS;
+ }
+ }
+
+ mCovered |= pFragment->covered;
+ }
+
+ /* If all query phrases seen by fts3BestSnippet() are present in at least
+ ** one of the nSnippet snippet fragments, break out of the loop.
+ */
+ assert( (mCovered&mSeen)==mCovered );
+ if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break;
+ }
+
+ assert( nFToken>0 );
+
+ for(i=0; i<nSnippet && rc==SQLITE_OK; i++){
+ rc = fts3SnippetText(pCsr, &aSnippet[i],
+ i, (i==nSnippet-1), nFToken, zStart, zEnd, zEllipsis, &res
+ );
+ }
+
+ snippet_out:
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
+ sqlite3_free(res.z);
}else{
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ sqlite3_result_text(pCtx, res.z, -1, sqlite3_free);
}
}
+
+typedef struct TermOffset TermOffset;
+typedef struct TermOffsetCtx TermOffsetCtx;
+
+struct TermOffset {
+ char *pList; /* Position-list */
+ int iPos; /* Position just read from pList */
+ int iOff; /* Offset of this term from read positions */
+};
+
+struct TermOffsetCtx {
+ int iCol; /* Column of table to populate aTerm for */
+ int iTerm;
+ sqlite3_int64 iDocid;
+ TermOffset *aTerm;
+};
+
+/*
+** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets().
+*/
+static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ TermOffsetCtx *p = (TermOffsetCtx *)ctx;
+ int nTerm; /* Number of tokens in phrase */
+ int iTerm; /* For looping through nTerm phrase terms */
+ char *pList; /* Pointer to position list for phrase */
+ int iPos = 0; /* First position in position-list */
+
+ UNUSED_PARAMETER(iPhrase);
+ pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol);
+ nTerm = pExpr->pPhrase->nToken;
+ if( pList ){
+ fts3GetDeltaPosition(&pList, &iPos);
+ assert( iPos>=0 );
+ }
+
+ for(iTerm=0; iTerm<nTerm; iTerm++){
+ TermOffset *pT = &p->aTerm[p->iTerm++];
+ pT->iOff = nTerm-iTerm-1;
+ pT->pList = pList;
+ pT->iPos = iPos;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of offsets() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3Offsets(
+ sqlite3_context *pCtx, /* SQLite function call context */
+ Fts3Cursor *pCsr /* Cursor object */
+){
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule;
+ const char *ZDUMMY; /* Dummy argument used with xNext() */
+ int NDUMMY; /* Dummy argument used with xNext() */
+ int rc; /* Return Code */
+ int nToken; /* Number of tokens in query */
+ int iCol; /* Column currently being processed */
+ StrBuffer res = {0, 0, 0}; /* Result string */
+ TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */
+
+ if( !pCsr->pExpr ){
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
+ return;
+ }
+
+ memset(&sCtx, 0, sizeof(sCtx));
+ assert( pCsr->isRequireSeek==0 );
+
+ /* Count the number of terms in the query */
+ rc = fts3ExprLoadDoclists(pCsr, 0, &nToken);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+
+ /* Allocate the array of TermOffset iterators. */
+ sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
+ if( 0==sCtx.aTerm ){
+ rc = SQLITE_NOMEM;
+ goto offsets_out;
+ }
+ sCtx.iDocid = pCsr->iPrevId;
+
+ /* Loop through the table columns, appending offset information to
+ ** string-buffer res for each column.
+ */
+ for(iCol=0; iCol<pTab->nColumn; iCol++){
+ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */
+ int iStart;
+ int iEnd;
+ int iCurrent;
+ const char *zDoc;
+ int nDoc;
+
+ /* Initialize the contents of sCtx.aTerm[] for column iCol. There is
+ ** no way that this operation can fail, so the return code from
+ ** fts3ExprIterate() can be discarded.
+ */
+ sCtx.iCol = iCol;
+ sCtx.iTerm = 0;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
+
+ /* Retreive the text stored in column iCol. If an SQL NULL is stored
+ ** in column iCol, jump immediately to the next iteration of the loop.
+ ** If an OOM occurs while retrieving the data (this can happen if SQLite
+ ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
+ ** to the caller.
+ */
+ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
+ nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+ if( zDoc==0 ){
+ if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){
+ continue;
+ }
+ rc = SQLITE_NOMEM;
+ goto offsets_out;
+ }
+
+ /* Initialize a tokenizer iterator to iterate through column iCol. */
+ rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+ pC->pTokenizer = pTab->pTokenizer;
+
+ rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
+ while( rc==SQLITE_OK ){
+ int i; /* Used to loop through terms */
+ int iMinPos = 0x7FFFFFFF; /* Position of next token */
+ TermOffset *pTerm = 0; /* TermOffset associated with next token */
+
+ for(i=0; i<nToken; i++){
+ TermOffset *pT = &sCtx.aTerm[i];
+ if( pT->pList && (pT->iPos-pT->iOff)<iMinPos ){
+ iMinPos = pT->iPos-pT->iOff;
+ pTerm = pT;
+ }
+ }
+
+ if( !pTerm ){
+ /* All offsets for this column have been gathered. */
+ break;
+ }else{
+ assert( iCurrent<=iMinPos );
+ if( 0==(0xFE&*pTerm->pList) ){
+ pTerm->pList = 0;
+ }else{
+ fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos);
+ }
+ while( rc==SQLITE_OK && iCurrent<iMinPos ){
+ rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
+ }
+ if( rc==SQLITE_OK ){
+ char aBuffer[64];
+ sqlite3_snprintf(sizeof(aBuffer), aBuffer,
+ "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
+ );
+ rc = fts3StringAppend(&res, aBuffer, -1);
+ }else if( rc==SQLITE_DONE ){
+ rc = SQLITE_CORRUPT;
+ }
+ }
+ }
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ }
+
+ pMod->xClose(pC);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+ }
+
+ offsets_out:
+ sqlite3_free(sCtx.aTerm);
+ assert( rc!=SQLITE_DONE );
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pCtx, rc);
+ sqlite3_free(res.z);
+ }else{
+ sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free);
+ }
+ return;
+}
+
+/*
+** Implementation of matchinfo() function.
+*/
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
- int rc = fts3GetMatchinfo(pCsr);
+ int rc;
+ if( !pCsr->pExpr ){
+ sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
+ return;
+ }
+ rc = fts3GetMatchinfo(pCsr);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pContext, rc);
}else{
- int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*2);
+ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
+ int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
+ if( pTab->bHasDocsize ){
+ n += sizeof(u32)*(1 + 2*pTab->nColumn);
+ }
sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
}
}
@@ -107964,6 +115121,7 @@
rc = sqlite3_step(pRtree->pReadNode);
if( rc==SQLITE_ROW ){
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
+ assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
nodeReference(pParent);
}else{
@@ -110023,6 +117181,7 @@
}
rc = sqlite3_reset(pRtree->pReadRowid);
}
+ *pRowid = cell.iRowid;
if( rc==SQLITE_OK ){
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
@@ -110160,31 +117319,69 @@
}
/*
-** This routine queries database handle db for the page-size used by
-** database zDb. If successful, the page-size in bytes is written to
-** *piPageSize and SQLITE_OK returned. Otherwise, and an SQLite error
-** code is returned.
+** The second argument to this function contains the text of an SQL statement
+** that returns a single integer value. The statement is compiled and executed
+** using database connection db. If successful, the integer value returned
+** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
+** code is returned and the value of *piVal after returning is not defined.
*/
-static int getPageSize(sqlite3 *db, const char *zDb, int *piPageSize){
+static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
int rc = SQLITE_NOMEM;
+ if( zSql ){
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ *piVal = sqlite3_column_int(pStmt, 0);
+ }
+ rc = sqlite3_finalize(pStmt);
+ }
+ }
+ return rc;
+}
+
+/*
+** This function is called from within the xConnect() or xCreate() method to
+** determine the node-size used by the rtree table being created or connected
+** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
+** Otherwise, an SQLite error code is returned.
+**
+** If this function is being called as part of an xConnect(), then the rtree
+** table already exists. In this case the node-size is determined by inspecting
+** the root node of the tree.
+**
+** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
+** This ensures that each node is stored on a single database page. If the
+** database page-size is so large that more than RTREE_MAXCELLS entries
+** would fit in a single node, use a smaller node-size.
+*/
+static int getNodeSize(
+ sqlite3 *db, /* Database handle */
+ Rtree *pRtree, /* Rtree handle */
+ int isCreate /* True for xCreate, false for xConnect */
+){
+ int rc;
char *zSql;
- sqlite3_stmt *pStmt = 0;
-
- zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
- if( !zSql ){
- return SQLITE_NOMEM;
+ if( isCreate ){
+ int iPageSize;
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
+ rc = getIntFromStmt(db, zSql, &iPageSize);
+ if( rc==SQLITE_OK ){
+ pRtree->iNodeSize = iPageSize-64;
+ if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
+ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
+ }
+ }
+ }else{
+ zSql = sqlite3_mprintf(
+ "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
+ pRtree->zDb, pRtree->zName
+ );
+ rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
}
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- *piPageSize = sqlite3_column_int(pStmt, 0);
- }
- return sqlite3_finalize(pStmt);
+ return rc;
}
/*
@@ -110205,7 +117402,6 @@
int isCreate /* True for xCreate, false for xConnect */
){
int rc = SQLITE_OK;
- int iPageSize = 0;
Rtree *pRtree;
int nDb; /* Length of string argv[1] */
int nName; /* Length of string argv[2] */
@@ -110224,11 +117420,6 @@
return SQLITE_ERROR;
}
- rc = getPageSize(db, argv[1], &iPageSize);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
@@ -110247,44 +117438,37 @@
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
- /* Figure out the node size to use. By default, use 64 bytes less than
- ** the database page-size. This ensures that each node is stored on
- ** a single database page.
- **
- ** If the databasd page-size is so large that more than RTREE_MAXCELLS
- ** entries would fit in a single node, use a smaller node-size.
- */
- pRtree->iNodeSize = iPageSize-64;
- if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
- pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
- }
+ /* Figure out the node size to use. */
+ rc = getNodeSize(db, pRtree, isCreate);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
- if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
- *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- }else{
- char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
- char *zTmp;
- int ii;
- for(ii=4; zSql && ii<argc; ii++){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
- sqlite3_free(zTmp);
- }
- if( zSql ){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s);", zTmp);
- sqlite3_free(zTmp);
- }
- if( !zSql ){
- rc = SQLITE_NOMEM;
- }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ if( rc==SQLITE_OK ){
+ if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }else{
+ char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
+ char *zTmp;
+ int ii;
+ for(ii=4; zSql && ii<argc; ii++){
+ zTmp = zSql;
+ zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
+ sqlite3_free(zTmp);
+ }
+ if( zSql ){
+ zTmp = zSql;
+ zSql = sqlite3_mprintf("%s);", zTmp);
+ sqlite3_free(zTmp);
+ }
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ sqlite3_free(zSql);
}
- sqlite3_free(zSql);
}
if( rc==SQLITE_OK ){
@@ -111160,18 +118344,3 @@
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
/************** End of fts3_icu.c ********************************************/
-// Begin Android Add
-/*
-** Change the default behavior of BEGIN to IMMEDIATE instead of DEFERRED.
-*/
-SQLITE_API int sqlite3_set_transaction_default_immediate(sqlite3* db, int immediate){
- sqlite3_mutex_enter(db->mutex);
- if( immediate ){
- db->flags|=SQLITE_BeginImmediate;
- }else{
- db->flags&=~SQLITE_BeginImmediate;
- }
- sqlite3_mutex_leave(db->mutex);
- return SQLITE_OK;
-}
-// End Android Add
diff --git a/dist/sqlite3.c.orig b/dist/sqlite3.c.orig
index f84e675..2ac17c8 100644
--- a/dist/sqlite3.c.orig
+++ b/dist/sqlite3.c.orig
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.6.22. By combining all the individual C code files into this
+** version 3.7.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a one translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -191,6 +191,14 @@
#endif
/*
+** The default number of frames to accumulate in the log file before
+** checkpointing the database in WAL mode.
+*/
+#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
+#endif
+
+/*
** The maximum number of attached databases. This must be between 0
** and 30. The upper bound on 30 is because a 32-bit integer bitmap
** is used internally to track attached databases.
@@ -307,41 +315,43 @@
#include <inttypes.h>
#endif
+/*
+** The number of samples of an index that SQLite takes in order to
+** construct a histogram of the table content when running ANALYZE
+** and with SQLITE_ENABLE_STAT2
+*/
#define SQLITE_INDEX_SAMPLES 10
/*
-** This macro is used to "hide" some ugliness in casting an int
-** value to a ptr value under the MSVC 64-bit compiler. Casting
-** non 64-bit values to ptr types results in a "hard" error with
-** the MSVC 64-bit compiler which this attempts to avoid.
+** 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.
**
-** A simple compiler pragma or casting sequence could not be found
-** to correct this in all situations, so this macro was introduced.
-**
-** It could be argued that the intptr_t type could be used in this
-** case, but that type is not available on all compilers, or
-** requires the #include of specific headers which differs between
-** platforms.
+** 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(__GNUC__)
-# if defined(HAVE_STDINT_H)
-# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
-# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
-# else
-# define SQLITE_INT_TO_PTR(X) ((void*)(X))
-# define SQLITE_PTR_TO_INT(X) ((int)(X))
-# endif
-#else
-# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
-# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
+#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) ((int)(__PTRDIFF_TYPE__)(X))
+#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
+# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
+# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
+#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
+# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
+#else /* Generates a warning - but it always works */
+# define SQLITE_INT_TO_PTR(X) ((void*)(X))
+# define SQLITE_PTR_TO_INT(X) ((int)(X))
#endif
-
/*
** The SQLITE_THREADSAFE macro must be defined as either 0 or 1.
** Older versions of SQLite used an optional THREADSAFE macro.
@@ -371,23 +381,18 @@
**
** SQLITE_SYSTEM_MALLOC // Use normal system malloc()
** SQLITE_MEMDEBUG // Debugging version of system malloc()
-** SQLITE_MEMORY_SIZE // internal allocator #1
-** SQLITE_MMAP_HEAP_SIZE // internal mmap() allocator
-** SQLITE_POW2_MEMORY_SIZE // internal power-of-two allocator
+**
+** (Historical note: There used to be several other options, but we've
+** pared it down to just these two.)
**
** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
** the default.
*/
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
- defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
- defined(SQLITE_POW2_MEMORY_SIZE)>1
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)>1
# error "At most one of the following compile-time configuration options\
- is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG, SQLITE_MEMORY_SIZE,\
- SQLITE_MMAP_HEAP_SIZE, SQLITE_POW2_MEMORY_SIZE"
+ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_MEMDEBUG"
#endif
-#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)+\
- defined(SQLITE_MEMORY_SIZE)+defined(SQLITE_MMAP_HEAP_SIZE)+\
- defined(SQLITE_POW2_MEMORY_SIZE)==0
+#if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_MEMDEBUG)==0
# define SQLITE_SYSTEM_MALLOC 1
#endif
@@ -507,6 +512,13 @@
#endif
/*
+** Return true (non-zero) if the input is a integer that is too large
+** to fit in 32-bits. This macro is used inside of various testcase()
+** macros to verify that we have tested SQLite for large-file support.
+*/
+#define IS_BIG_INT(X) (((X)&(i64)0xffffffff)!=0)
+
+/*
** The macro unlikely() is a hint that surrounds a boolean
** expression that is usually false. Macro likely() surrounds
** a boolean expression that is usually true. GCC is able to
@@ -631,13 +643,13 @@
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.6.22"
-#define SQLITE_VERSION_NUMBER 3006022
-#define SQLITE_SOURCE_ID "2010-03-22 23:55:10 82dd61fccff3e4c77e060e5734cd4b4e2eeb7c32"
+#define SQLITE_VERSION "3.7.0"
+#define SQLITE_VERSION_NUMBER 3007000
+#define SQLITE_SOURCE_ID "2010-07-07 14:45:41 8eefc287265443ec043bdab629597e79c9d22006"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version
+** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -659,9 +671,9 @@
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function a pointer
-** to a string constant whose value is the same as the [SQLITE_SOURCE_ID]
-** C preprocessor macro.
+** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
+** [SQLITE_SOURCE_ID] C preprocessor macro.
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -671,6 +683,33 @@
SQLITE_API int sqlite3_libversion_number(void);
/*
+** CAPI3REF: Run-Time Library Compilation Options Diagnostics
+**
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
+**
+** ^The sqlite3_compileoption_get() function allows interating
+** over the list of options that were defined at compile time by
+** returning the N-th compile time option string. ^If N is out of range,
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get().
+**
+** ^Support for the diagnostic functions sqlite3_compileoption_used()
+** and sqlite3_compileoption_get() may be omitted by specifing the
+** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
+**
+** See also: SQL functions [sqlite_compileoption_used()] and
+** [sqlite_compileoption_get()] and the [compile_options pragma].
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *sqlite3_compileoption_get(int N);
+#endif
+
+/*
** CAPI3REF: Test To See If The Library Is Threadsafe
**
** ^The sqlite3_threadsafe() function returns zero if and only if
@@ -890,7 +929,7 @@
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
@@ -946,7 +985,12 @@
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
-#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
+#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
+#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
+#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
+#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
+#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -961,6 +1005,7 @@
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
+#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
@@ -993,17 +1038,18 @@
** information is written to disk in the same order as calls
** to xWrite().
*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
@@ -1154,6 +1200,13 @@
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Methods above are valid for version 1 */
+ int (*xShmOpen)(sqlite3_file*);
+ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
+ int (*xShmMap)(sqlite3_file*, int iPage, int pgsz, int, void volatile**);
+ void (*xShmBarrier)(sqlite3_file*);
+ int (*xShmClose)(sqlite3_file*, int deleteFlag);
+ /* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -1171,11 +1224,19 @@
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
+**
+** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
+** layer a hint of how large the database file will grow to be during the
+** current transaction. This hint is not guaranteed to be accurate but it
+** is often close. The underlying VFS might choose to preallocate database
+** file space based on this hint in order to help writes to the database
+** file run faster.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
/*
** CAPI3REF: Mutex Handle
@@ -1307,20 +1368,27 @@
** handled as a fatal error by SQLite, vfs implementations should endeavor
** to prevent this by setting mxPathname to a sufficiently large value.
**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
+** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
+** interfaces are not strictly a part of the filesystem, but they are
** included in the VFS structure for completeness.
** The xRandomness() function attempts to return nBytes bytes
** of good-quality randomness into zOut. The return value is
** the actual number of bytes of randomness obtained.
** The xSleep() method causes the calling thread to sleep for at
** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and time.
-**
+** method returns a Julian Day Number for the current date and time as
+** a floating point value.
+** The xCurrentTimeInt64() method returns, as an integer, the Julian
+** Day Number multipled by 86400000 (the number of milliseconds in
+** a 24-hour day).
+** ^SQLite will use the xCurrentTimeInt64() method to get the current
+** date and time if that method is available (if iVersion is 2 or
+** greater and the function pointer is not NULL) and will fall back
+** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
*/
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
- int iVersion; /* Structure version number */
+ int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@@ -1339,8 +1407,16 @@
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
+ /*
+ ** The methods above are in version 1 of the sqlite_vfs object
+ ** definition. Those that follow are added in version 2 or later
+ */
+ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
+ /*
+ ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
+ ** New fields may be appended in figure versions. The iVersion
+ ** value will increment whenever this happens.
+ */
};
/*
@@ -1361,6 +1437,44 @@
#define SQLITE_ACCESS_READ 2
/*
+** CAPI3REF: Flags for the xShmLock VFS method
+**
+** These integer constants define the various locking operations
+** allowed by the xShmLock method of [sqlite3_io_methods]. The
+** following are the only legal combinations of flags to the
+** xShmLock method:
+**
+** <ul>
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
+** </ul>
+**
+** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
+** was given no the corresponding lock.
+**
+** The xShmLock method can transition between unlocked and SHARED or
+** between unlocked and EXCLUSIVE. It cannot transition between SHARED
+** and EXCLUSIVE.
+*/
+#define SQLITE_SHM_UNLOCK 1
+#define SQLITE_SHM_LOCK 2
+#define SQLITE_SHM_SHARED 4
+#define SQLITE_SHM_EXCLUSIVE 8
+
+/*
+** CAPI3REF: Maximum xShmLock index
+**
+** The xShmLock method on [sqlite3_io_methods] may use values
+** between 0 and this upper bound as its "offset" argument.
+** The SQLite core will never attempt to acquire or release a
+** lock outside of this range
+*/
+#define SQLITE_SHM_NLOCK 8
+
+
+/*
** CAPI3REF: Initialize The SQLite Library
**
** ^The sqlite3_initialize() routine initializes the
@@ -1469,11 +1583,10 @@
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
-** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -1493,11 +1606,10 @@
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
-** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@@ -1579,7 +1691,6 @@
/*
** CAPI3REF: Configuration Options
-** EXPERIMENTAL
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1765,6 +1876,24 @@
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
+** <dt>SQLITE_CONFIG_LOG</dt>
+** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** function with a call signature of void(*)(void*,int,const char*),
+** and a pointer to void. ^If the function pointer is not NULL, it is
+** invoked by [sqlite3_log()] to process each logging event. ^If the
+** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
+** passed through as the first parameter to the application-defined logger
+** function whenever that function is invoked. ^The second parameter to
+** the logger function is a copy of the first parameter to the corresponding
+** [sqlite3_log()] call and is intended to be a [result code] or an
+** [extended result code]. ^The third parameter passed to the logger is
+** log message after formatting via [sqlite3_snprintf()].
+** The SQLite logging interface is not reentrant; the logger function
+** supplied by the application must not invoke any SQLite interface.
+** In a multi-threaded application, the application-defined logger
+** function must be threadsafe. </dd>
+**
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1785,8 +1914,7 @@
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
+** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@@ -2562,7 +2690,6 @@
/*
** CAPI3REF: Tracing And Profiling Functions
-** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2580,7 +2707,7 @@
** the original statement text and an estimate of wall-clock time
** of how long that statement took to run.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
@@ -3373,6 +3500,14 @@
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
+** For all versions of SQLite up to and including 3.6.23.1, it was required
+** after sqlite3_step() returned anything other than [SQLITE_ROW] that
+** [sqlite3_reset()] be called before any subsequent invocation of
+** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
+** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
+** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
+** automatically in this circumstance rather than returning [SQLITE_MISUSE].
+**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@@ -4185,6 +4320,7 @@
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
+#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@@ -4211,6 +4347,25 @@
);
/*
+** Specify the activation key for a SEE database. Unless
+** activated, none of the SEE routines will work.
+*/
+SQLITE_API void sqlite3_activate_see(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+#ifdef SQLITE_ENABLE_CEROD
+/*
+** Specify the activation key for a CEROD database. Unless
+** activated, none of the CEROD routines will work.
+*/
+SQLITE_API void sqlite3_activate_cerod(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+/*
** CAPI3REF: Suspend Execution For A Short Time
**
** ^The sqlite3_sleep() function causes the current thread to suspend execution
@@ -4348,8 +4503,6 @@
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
-** ^The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@@ -4635,8 +4788,6 @@
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -4656,7 +4807,6 @@
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
-** EXPERIMENTAL
**
** This structure, sometimes called a a "virtual table module",
** defines the implementation of a [virtual tables].
@@ -4703,7 +4853,6 @@
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
-** EXPERIMENTAL
**
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the [xBestIndex]
@@ -4785,7 +4934,6 @@
/*
** CAPI3REF: Register A Virtual Table Implementation
-** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -4807,13 +4955,13 @@
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -4824,7 +4972,6 @@
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@@ -4850,7 +4997,6 @@
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@@ -4872,18 +5018,16 @@
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
-** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
-** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -4898,7 +5042,7 @@
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -4908,8 +5052,6 @@
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@@ -5252,7 +5394,6 @@
/*
** CAPI3REF: Mutex Methods Object
-** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@@ -5465,11 +5606,11 @@
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_LAST 16
+#define SQLITE_TESTCTRL_PGHDRSZ 17
+#define SQLITE_TESTCTRL_LAST 17
/*
** CAPI3REF: SQLite Runtime Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about the preformance of SQLite, and optionally to reset various
@@ -5497,12 +5638,11 @@
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
-** EXPERIMENTAL
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
@@ -5589,14 +5729,15 @@
/*
** CAPI3REF: Database Connection Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
-** is the parameter to interrogate. ^Currently, the only allowed value
-** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
-** Additional options will likely appear in future releases of SQLite.
+** is an integer constant, taken from the set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
+** determiness the parameter to interrogate. The set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
+** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
@@ -5605,11 +5746,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
-** EXPERIMENTAL
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@@ -5624,14 +5764,21 @@
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
+**
+** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
+** <dd>^This parameter returns the approximate number of of bytes of heap
+** memory used by all pager caches associated with the database connection.
+** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+** checked out.</dd>)^
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
+#define SQLITE_DBSTATUS_CACHE_USED 1
+#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
-** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
@@ -5653,11 +5800,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
-** EXPERIMENTAL
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
@@ -5675,14 +5821,21 @@
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.</dd>
**
+** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
+** <dd>^This is the number of rows inserted into transient indices that
+** were created automatically in order to help joins run faster.
+** A non-zero value in this counter may indicate an opportunity to
+** improvement performance by adding permanent indices that do not
+** need to be reinitialized each time the statement is run.</dd>
+**
** </dl>
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
+#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
-** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@@ -5697,7 +5850,6 @@
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
-** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
** register an alternative page cache implementation by passing in an
@@ -5839,7 +5991,6 @@
/*
** CAPI3REF: Online Backup Object
-** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@@ -5852,7 +6003,6 @@
/*
** CAPI3REF: Online Backup API.
-** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
@@ -5921,10 +6071,14 @@
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
-** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
-** database was opened read-only or if
-** the destination is an in-memory database with a different page size
-** from the source database.
+** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
+** <ol>
+** <li> the destination database was opened read-only, or
+** <li> the destination database is using write-ahead-log journaling
+** and the destination and source page sizes differ, or
+** <li> The destination database is an in-memory database and the
+** destination and source page sizes differ.
+** </ol>)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
@@ -6040,7 +6194,6 @@
/*
** CAPI3REF: Unlock Notification
-** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -6162,7 +6315,6 @@
/*
** CAPI3REF: String Comparison
-** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
@@ -6173,16 +6325,19 @@
/*
** CAPI3REF: Error Logging Interface
-** EXPERIMENTAL
**
** ^The [sqlite3_log()] interface writes a message into the error log
-** established by the [SQLITE_CONFIG_ERRORLOG] option to [sqlite3_config()].
+** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
+** ^If logging is enabled, the zFormat string and subsequent arguments are
+** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
** nothing to prevent an application from calling sqlite3_log(), doing so
** is considered bad form.
**
+** The zFormat string must not be NULL.
+**
** To avoid deadlocks and other threading problems, the sqlite3_log() routine
** will not use dynamically allocated memory. The log message is stored in
** a fixed-length buffer on the stack. If the log message is longer than
@@ -6192,6 +6347,89 @@
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
+** CAPI3REF: Write-Ahead Log Commit Hook
+**
+** ^The [sqlite3_wal_hook()] function is used to register a callback that
+** will be invoked each time a database connection commits data to a
+** [write-ahead log] (i.e. whenever a transaction is committed in
+** [journal_mode | journal_mode=WAL mode]).
+**
+** ^The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released, so the implementation
+** may read, write or [checkpoint] the database as required.
+**
+** ^The first parameter passed to the callback function when it is invoked
+** is a copy of the third parameter passed to sqlite3_wal_hook() when
+** registering the callback. ^The second is a copy of the database handle.
+** ^The third parameter is the name of the database that was written to -
+** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
+** is the number of pages currently in the write-ahead log file,
+** including those that were just committed.
+**
+** The callback function should normally return [SQLITE_OK]. ^If an error
+** code is returned, that error will propagate back up through the
+** SQLite code base to cause the statement that provoked the callback
+** to report an error, though the commit will have still occurred. If the
+** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
+** that does not correspond to any valid SQLite error code, the results
+** are undefined.
+**
+** A single database handle may have at most a single write-ahead log callback
+** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
+** previously registered write-ahead log callback. ^Note that the
+** [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
+** those overwrite any prior [sqlite3_wal_hook()] settings.
+*/
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3*,
+ int(*)(void *,sqlite3*,const char*,int),
+ void*
+);
+
+/*
+** CAPI3REF: Configure an auto-checkpoint
+**
+** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
+** [sqlite3_wal_hook()] that causes any database on [database connection] D
+** to automatically [checkpoint]
+** after committing a transaction if there are N or
+** more frames in the [write-ahead log] file. ^Passing zero or
+** a negative value as the nFrame parameter disables automatic
+** checkpoints entirely.
+**
+** ^The callback registered by this function replaces any existing callback
+** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
+** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
+** configured by this function.
+**
+** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
+** from SQL.
+**
+** ^Every new [database connection] defaults to having the auto-checkpoint
+** enabled with a threshold of 1000 pages. The use of this interface
+** is only necessary if the default setting is found to be suboptimal
+** for a particular application.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+
+/*
+** CAPI3REF: Checkpoint a database
+**
+** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
+** on [database connection] D to be [checkpointed]. ^If X is NULL or an
+** empty string, then a checkpoint is run on all databases of
+** connection D. ^If the database connection D is not in
+** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+**
+** ^The [wal_checkpoint pragma] can be used to invoke this interface
+** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] can be used to cause this interface to be
+** run whenever the WAL reaches a certain size threshold.
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+
+/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
@@ -6482,6 +6720,7 @@
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
+# define float sqlite_int64
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
@@ -6507,20 +6746,6 @@
#endif
/*
-** If the following macro is set to 1, then NULL values are considered
-** distinct when determining whether or not two entries are the same
-** in a UNIQUE index. This is the way PostgreSQL, Oracle, DB2, MySQL,
-** OCELOT, and Firebird all work. The SQL92 spec explicitly says this
-** is the way things are suppose to work.
-**
-** If the following macro is set to 0, the NULLs are indistinct for
-** a UNIQUE index. In this mode, you can only have a single NULL entry
-** for a column declared UNIQUE. This is the way Informix and SQL Server
-** work.
-*/
-#define NULL_DISTINCT_FOR_UNIQUE 1
-
-/*
** The "file format" number is an integer that is incremented whenever
** the VDBE-level file format changes. The following macros define the
** the default file format for new databases and the maximum file format
@@ -6531,6 +6756,10 @@
# define SQLITE_DEFAULT_FILE_FORMAT 1
#endif
+/*
+** Determine whether triggers are recursive by default. This can be
+** changed at run-time using a pragma.
+*/
#ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS
# define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0
#endif
@@ -6775,7 +7004,6 @@
typedef struct AuthContext AuthContext;
typedef struct AutoincInfo AutoincInfo;
typedef struct Bitvec Bitvec;
-typedef struct RowSet RowSet;
typedef struct CollSeq CollSeq;
typedef struct Column Column;
typedef struct Db Db;
@@ -6796,6 +7024,7 @@
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
+typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SrcList SrcList;
@@ -6803,9 +7032,9 @@
typedef struct Table Table;
typedef struct TableLock TableLock;
typedef struct Token Token;
+typedef struct Trigger Trigger;
typedef struct TriggerPrg TriggerPrg;
typedef struct TriggerStep TriggerStep;
-typedef struct Trigger Trigger;
typedef struct UnpackedRecord UnpackedRecord;
typedef struct VTable VTable;
typedef struct Walker Walker;
@@ -6903,6 +7132,8 @@
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
+SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
@@ -7006,6 +7237,8 @@
SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *);
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
+
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
@@ -7296,83 +7529,83 @@
#define OP_VerifyCookie 37
#define OP_OpenRead 38
#define OP_OpenWrite 39
-#define OP_OpenEphemeral 40
-#define OP_OpenPseudo 41
-#define OP_Close 42
-#define OP_SeekLt 43
-#define OP_SeekLe 44
-#define OP_SeekGe 45
-#define OP_SeekGt 46
-#define OP_Seek 47
-#define OP_NotFound 48
-#define OP_Found 49
-#define OP_IsUnique 50
-#define OP_NotExists 51
-#define OP_Sequence 52
-#define OP_NewRowid 53
-#define OP_Insert 54
-#define OP_InsertInt 55
-#define OP_Delete 56
-#define OP_ResetCount 57
-#define OP_RowKey 58
-#define OP_RowData 59
-#define OP_Rowid 60
-#define OP_NullRow 61
-#define OP_Last 62
-#define OP_Sort 63
-#define OP_Rewind 64
-#define OP_Prev 65
-#define OP_Next 66
-#define OP_IdxInsert 67
-#define OP_IdxDelete 70
-#define OP_IdxRowid 71
-#define OP_IdxLT 72
-#define OP_IdxGE 81
-#define OP_Destroy 92
-#define OP_Clear 95
-#define OP_CreateIndex 96
-#define OP_CreateTable 97
-#define OP_ParseSchema 98
-#define OP_LoadAnalysis 99
-#define OP_DropTable 100
-#define OP_DropIndex 101
-#define OP_DropTrigger 102
-#define OP_IntegrityCk 103
-#define OP_RowSetAdd 104
-#define OP_RowSetRead 105
-#define OP_RowSetTest 106
-#define OP_Program 107
-#define OP_Param 108
-#define OP_FkCounter 109
-#define OP_FkIfZero 110
-#define OP_MemMax 111
-#define OP_IfPos 112
-#define OP_IfNeg 113
-#define OP_IfZero 114
-#define OP_AggStep 115
-#define OP_AggFinal 116
-#define OP_Vacuum 117
-#define OP_IncrVacuum 118
-#define OP_Expire 119
-#define OP_TableLock 120
-#define OP_VBegin 121
-#define OP_VCreate 122
-#define OP_VDestroy 123
-#define OP_VOpen 124
-#define OP_VFilter 125
-#define OP_VColumn 126
-#define OP_VNext 127
-#define OP_VRename 128
-#define OP_VUpdate 129
-#define OP_Pagecount 131
-#define OP_Trace 132
-#define OP_Noop 133
-#define OP_Explain 134
+#define OP_OpenAutoindex 40
+#define OP_OpenEphemeral 41
+#define OP_OpenPseudo 42
+#define OP_Close 43
+#define OP_SeekLt 44
+#define OP_SeekLe 45
+#define OP_SeekGe 46
+#define OP_SeekGt 47
+#define OP_Seek 48
+#define OP_NotFound 49
+#define OP_Found 50
+#define OP_IsUnique 51
+#define OP_NotExists 52
+#define OP_Sequence 53
+#define OP_NewRowid 54
+#define OP_Insert 55
+#define OP_InsertInt 56
+#define OP_Delete 57
+#define OP_ResetCount 58
+#define OP_RowKey 59
+#define OP_RowData 60
+#define OP_Rowid 61
+#define OP_NullRow 62
+#define OP_Last 63
+#define OP_Sort 64
+#define OP_Rewind 65
+#define OP_Prev 66
+#define OP_Next 67
+#define OP_IdxInsert 70
+#define OP_IdxDelete 71
+#define OP_IdxRowid 72
+#define OP_IdxLT 81
+#define OP_IdxGE 92
+#define OP_Destroy 95
+#define OP_Clear 96
+#define OP_CreateIndex 97
+#define OP_CreateTable 98
+#define OP_ParseSchema 99
+#define OP_LoadAnalysis 100
+#define OP_DropTable 101
+#define OP_DropIndex 102
+#define OP_DropTrigger 103
+#define OP_IntegrityCk 104
+#define OP_RowSetAdd 105
+#define OP_RowSetRead 106
+#define OP_RowSetTest 107
+#define OP_Program 108
+#define OP_Param 109
+#define OP_FkCounter 110
+#define OP_FkIfZero 111
+#define OP_MemMax 112
+#define OP_IfPos 113
+#define OP_IfNeg 114
+#define OP_IfZero 115
+#define OP_AggStep 116
+#define OP_AggFinal 117
+#define OP_Checkpoint 118
+#define OP_JournalMode 119
+#define OP_Vacuum 120
+#define OP_IncrVacuum 121
+#define OP_Expire 122
+#define OP_TableLock 123
+#define OP_VBegin 124
+#define OP_VCreate 125
+#define OP_VDestroy 126
+#define OP_VOpen 127
+#define OP_VFilter 128
+#define OP_VColumn 129
+#define OP_VNext 131
+#define OP_VRename 132
+#define OP_VUpdate 133
+#define OP_Pagecount 134
+#define OP_Trace 135
+#define OP_Noop 136
+#define OP_Explain 137
/* The following opcode values are never used */
-#define OP_NotUsed_135 135
-#define OP_NotUsed_136 136
-#define OP_NotUsed_137 137
#define OP_NotUsed_138 138
#define OP_NotUsed_139 139
#define OP_NotUsed_140 140
@@ -7391,22 +7624,22 @@
#define OPFLG_OUT3 0x0040 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\
-/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x24, 0x24,\
+/* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\
/* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\
/* 24 */ 0x00, 0x01, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
/* 32 */ 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,\
-/* 40 */ 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x08,\
-/* 48 */ 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01,\
-/* 64 */ 0x01, 0x01, 0x01, 0x08, 0x4c, 0x4c, 0x00, 0x02,\
-/* 72 */ 0x01, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,\
+/* 48 */ 0x08, 0x11, 0x11, 0x11, 0x11, 0x02, 0x02, 0x00,\
+/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,\
+/* 64 */ 0x01, 0x01, 0x01, 0x01, 0x4c, 0x4c, 0x08, 0x00,\
+/* 72 */ 0x02, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\
/* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,\
-/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x02, 0x24, 0x02, 0x00,\
-/* 96 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 104 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\
-/* 112 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,\
-/* 128 */ 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
+/* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x02,\
+/* 96 */ 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 104 */ 0x00, 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01,\
+/* 112 */ 0x08, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02,\
+/* 120 */ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x00,\
/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,\
/* 144 */ 0x04, 0x04,}
@@ -7552,14 +7785,15 @@
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
-** Valid values for the second argument to sqlite3PagerJournalMode().
+** Numeric constants that encode the journalmode.
*/
-#define PAGER_JOURNALMODE_QUERY -1
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** The remainder of this file contains the declarations of the functions
@@ -7587,7 +7821,9 @@
SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int);
SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
@@ -7617,9 +7853,16 @@
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
+
/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*);
SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
@@ -7631,6 +7874,10 @@
/* Functions used to truncate the database file. */
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
+#endif
+
/* Functions to support testing and debugging. */
#if !defined(NDEBUG) || defined(SQLITE_TEST)
SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
@@ -8032,7 +8279,11 @@
** 1GB boundary.
**
*/
-#define PENDING_BYTE sqlite3PendingByte
+#ifdef SQLITE_OMIT_WSD
+# define PENDING_BYTE (0x40000000)
+#else
+# define PENDING_BYTE sqlite3PendingByte
+#endif
#define RESERVED_BYTE (PENDING_BYTE+1)
#define SHARED_FIRST (PENDING_BYTE+2)
#define SHARED_SIZE 510
@@ -8058,6 +8309,11 @@
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmOpen(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmClose(sqlite3_file *id, int);
+SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
/*
** Functions for accessing sqlite3_vfs methods
@@ -8074,7 +8330,7 @@
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
** Convenience functions for opening and closing files using
@@ -8209,7 +8465,7 @@
/*
** These macros can be used to test, set, or clear bits in the
-** Db.flags field.
+** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
@@ -8217,7 +8473,7 @@
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
/*
-** Allowed values for the DB.flags field.
+** Allowed values for the DB.pSchema->flags field.
**
** The DB_SchemaLoaded flag is set after the database schema has been
** read into internal hash tables.
@@ -8281,7 +8537,7 @@
};
/*
-** Each database is an instance of the following structure.
+** Each database connection is an instance of the following structure.
**
** The sqlite.lastRowid records the last insert rowid generated by an
** insert statement. Inserts on views do not affect its value. Each
@@ -8351,6 +8607,10 @@
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+#ifndef SQLITE_OMIT_WAL
+ int (*xWalCallback)(void *, sqlite3 *, const char *, int);
+ void *pWalArg;
+#endif
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
@@ -8440,6 +8700,8 @@
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
+#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
/*
** Bits of the sqlite3.flags field that are used by the
@@ -8451,7 +8713,8 @@
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
-#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
+#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
+#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/*
** Possible values for the sqlite.magic field.
@@ -9302,6 +9565,9 @@
** and the next table on the list. The parser builds the list this way.
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
** jointype expresses the join between the table and the previous table.
+**
+** In the colUsed field, the high-order bit (bit 63) is set if the table
+** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -9413,7 +9679,7 @@
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
-#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
+#define WHERE_OMIT_OPEN 0x0010 /* Table cursors are already open */
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
@@ -9436,6 +9702,7 @@
int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
+ double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
@@ -9677,6 +9944,7 @@
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
+ double nQueryLoop; /* Estimated number of iterations of a query */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
@@ -9955,6 +10223,15 @@
/*
+** FTS4 is really an extension for FTS3. It is enabled using the
+** SQLITE_ENABLE_FTS3 macro. But to avoid confusion we also all
+** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
+*/
+#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
+# define SQLITE_ENABLE_FTS3
+#endif
+
+/*
** The ctype.h header is needed for non-ASCII systems. It is also
** needed by FTS3 when FTS3 is included in the amalgamation.
*/
@@ -10043,7 +10320,8 @@
#ifndef SQLITE_MUTEX_OMIT
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void);
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void);
SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int);
SQLITE_PRIVATE int sqlite3MutexInit(void);
SQLITE_PRIVATE int sqlite3MutexEnd(void);
@@ -10053,7 +10331,11 @@
SQLITE_PRIVATE void sqlite3StatusAdd(int, int);
SQLITE_PRIVATE void sqlite3StatusSet(int, int);
-SQLITE_PRIVATE int sqlite3IsNaN(double);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+SQLITE_PRIVATE int sqlite3IsNaN(double);
+#else
+# define sqlite3IsNaN(X) 0
+#endif
SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, int, const char*, va_list);
#ifndef SQLITE_OMIT_TRACE
@@ -10171,6 +10453,7 @@
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u16);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int);
+SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
@@ -10197,6 +10480,7 @@
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*);
+SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
@@ -10374,7 +10658,7 @@
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
-SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int);
+SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
#ifdef SQLITE_ENABLE_STAT2
SQLITE_PRIVATE char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *);
#endif
@@ -10386,11 +10670,13 @@
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
+#endif
SQLITE_PRIVATE void sqlite3RootPageMoved(Db*, int, int);
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
-SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3*);
+SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
@@ -10499,6 +10785,9 @@
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
+SQLITE_PRIVATE const char *sqlite3JournalModename(int);
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int);
+SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -10605,7 +10894,46 @@
# define sqlite3VdbeIOTraceSql(X)
#endif
+/*
+** These routines are available for the mem2.c debugging memory allocator
+** only. They are used to verify that different "types" of memory
+** allocations are properly tracked by the system.
+**
+** sqlite3MemdebugSetType() sets the "type" of an allocation to one of
+** the MEMTYPE_* macros defined below. The type must be a bitmask with
+** a single bit set.
+**
+** sqlite3MemdebugHasType() returns true if any of the bits in its second
+** argument match the type set by the previous sqlite3MemdebugSetType().
+** sqlite3MemdebugHasType() is intended for use inside assert() statements.
+** For example:
+**
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+**
+** Perhaps the most important point is the difference between MEMTYPE_HEAP
+** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have
+** been allocated by lookaside, except the allocation was too large or
+** lookaside was already full. It is important to verify that allocations
+** that might have been satisfied by lookaside are not passed back to
+** non-lookaside free() routines. Asserts such as the example above are
+** placed on the non-lookaside free() routines to verify this constraint.
+**
+** All of this is no-op for a production build. It only comes into
+** play when the SQLITE_MEMDEBUG compile-time option is used.
+*/
+#ifdef SQLITE_MEMDEBUG
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8);
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8);
+#else
+# define sqlite3MemdebugSetType(X,Y) /* no-op */
+# define sqlite3MemdebugHasType(X,Y) 1
#endif
+#define MEMTYPE_HEAP 0x01 /* General heap allocations */
+#define MEMTYPE_DB 0x02 /* Associated with a database connection */
+#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
+#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+
+#endif /* _SQLITEINT_H_ */
/************** End of sqliteInt.h *******************************************/
/************** Begin file global.c ******************************************/
@@ -10804,7 +11132,9 @@
** Changing the pending byte during operating results in undefined
** and dileterious behavior.
*/
+#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+#endif
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
@@ -10815,6 +11145,398 @@
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
/************** End of global.c **********************************************/
+/************** Begin file ctime.c *******************************************/
+/*
+** 2010 February 23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements routines used to report what compile-time options
+** SQLite was built with.
+*/
+
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+
+
+/*
+** 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[] = {
+
+/* 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)
+
+#ifdef SQLITE_32BIT_ROWID
+ "32BIT_ROWID",
+#endif
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+ "4_BYTE_ALIGNED_MALLOC",
+#endif
+#ifdef SQLITE_CASE_SENSITIVE_LIKE
+ "CASE_SENSITIVE_LIKE",
+#endif
+#ifdef SQLITE_CHECK_PAGES
+ "CHECK_PAGES",
+#endif
+#ifdef SQLITE_COVERAGE_TEST
+ "COVERAGE_TEST",
+#endif
+#ifdef SQLITE_DEBUG
+ "DEBUG",
+#endif
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
+#endif
+#ifdef SQLITE_DISABLE_DIRSYNC
+ "DISABLE_DIRSYNC",
+#endif
+#ifdef SQLITE_DISABLE_LFS
+ "DISABLE_LFS",
+#endif
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ "ENABLE_ATOMIC_WRITE",
+#endif
+#ifdef SQLITE_ENABLE_CEROD
+ "ENABLE_CEROD",
+#endif
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ "ENABLE_COLUMN_METADATA",
+#endif
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ "ENABLE_EXPENSIVE_ASSERT",
+#endif
+#ifdef SQLITE_ENABLE_FTS1
+ "ENABLE_FTS1",
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+ "ENABLE_FTS2",
+#endif
+#ifdef SQLITE_ENABLE_FTS3
+ "ENABLE_FTS3",
+#endif
+#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+ "ENABLE_FTS3_PARENTHESIS",
+#endif
+#ifdef SQLITE_ENABLE_FTS4
+ "ENABLE_FTS4",
+#endif
+#ifdef SQLITE_ENABLE_ICU
+ "ENABLE_ICU",
+#endif
+#ifdef SQLITE_ENABLE_IOTRACE
+ "ENABLE_IOTRACE",
+#endif
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+ "ENABLE_LOAD_EXTENSION",
+#endif
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
+#endif
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
+ "ENABLE_MEMORY_MANAGEMENT",
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS3
+ "ENABLE_MEMSYS3",
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS5
+ "ENABLE_MEMSYS5",
+#endif
+#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+ "ENABLE_OVERSIZE_CELL_CHECK",
+#endif
+#ifdef SQLITE_ENABLE_RTREE
+ "ENABLE_RTREE",
+#endif
+#ifdef SQLITE_ENABLE_STAT2
+ "ENABLE_STAT2",
+#endif
+#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+ "ENABLE_UNLOCK_NOTIFY",
+#endif
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ "ENABLE_UPDATE_DELETE_LIMIT",
+#endif
+#ifdef SQLITE_HAS_CODEC
+ "HAS_CODEC",
+#endif
+#ifdef SQLITE_HAVE_ISNAN
+ "HAVE_ISNAN",
+#endif
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ "HOMEGROWN_RECURSIVE_MUTEX",
+#endif
+#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
+ "IGNORE_AFP_LOCK_ERRORS",
+#endif
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+ "IGNORE_FLOCK_LOCK_ERRORS",
+#endif
+#ifdef SQLITE_INT64_TYPE
+ "INT64_TYPE",
+#endif
+#ifdef SQLITE_LOCK_TRACE
+ "LOCK_TRACE",
+#endif
+#ifdef SQLITE_MEMDEBUG
+ "MEMDEBUG",
+#endif
+#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+ "MIXED_ENDIAN_64BIT_FLOAT",
+#endif
+#ifdef SQLITE_NO_SYNC
+ "NO_SYNC",
+#endif
+#ifdef SQLITE_OMIT_ALTERTABLE
+ "OMIT_ALTERTABLE",
+#endif
+#ifdef SQLITE_OMIT_ANALYZE
+ "OMIT_ANALYZE",
+#endif
+#ifdef SQLITE_OMIT_ATTACH
+ "OMIT_ATTACH",
+#endif
+#ifdef SQLITE_OMIT_AUTHORIZATION
+ "OMIT_AUTHORIZATION",
+#endif
+#ifdef SQLITE_OMIT_AUTOINCREMENT
+ "OMIT_AUTOINCREMENT",
+#endif
+#ifdef SQLITE_OMIT_AUTOINIT
+ "OMIT_AUTOINIT",
+#endif
+#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
+ "OMIT_AUTOMATIC_INDEX",
+#endif
+#ifdef SQLITE_OMIT_AUTOVACUUM
+ "OMIT_AUTOVACUUM",
+#endif
+#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
+ "OMIT_BETWEEN_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_BLOB_LITERAL
+ "OMIT_BLOB_LITERAL",
+#endif
+#ifdef SQLITE_OMIT_BTREECOUNT
+ "OMIT_BTREECOUNT",
+#endif
+#ifdef SQLITE_OMIT_BUILTIN_TEST
+ "OMIT_BUILTIN_TEST",
+#endif
+#ifdef SQLITE_OMIT_CAST
+ "OMIT_CAST",
+#endif
+#ifdef SQLITE_OMIT_CHECK
+ "OMIT_CHECK",
+#endif
+/* // redundant
+** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
+** "OMIT_COMPILEOPTION_DIAGS",
+** #endif
+*/
+#ifdef SQLITE_OMIT_COMPLETE
+ "OMIT_COMPLETE",
+#endif
+#ifdef SQLITE_OMIT_COMPOUND_SELECT
+ "OMIT_COMPOUND_SELECT",
+#endif
+#ifdef SQLITE_OMIT_DATETIME_FUNCS
+ "OMIT_DATETIME_FUNCS",
+#endif
+#ifdef SQLITE_OMIT_DECLTYPE
+ "OMIT_DECLTYPE",
+#endif
+#ifdef SQLITE_OMIT_DEPRECATED
+ "OMIT_DEPRECATED",
+#endif
+#ifdef SQLITE_OMIT_DISKIO
+ "OMIT_DISKIO",
+#endif
+#ifdef SQLITE_OMIT_EXPLAIN
+ "OMIT_EXPLAIN",
+#endif
+#ifdef SQLITE_OMIT_FLAG_PRAGMAS
+ "OMIT_FLAG_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ "OMIT_FLOATING_POINT",
+#endif
+#ifdef SQLITE_OMIT_FOREIGN_KEY
+ "OMIT_FOREIGN_KEY",
+#endif
+#ifdef SQLITE_OMIT_GET_TABLE
+ "OMIT_GET_TABLE",
+#endif
+#ifdef SQLITE_OMIT_INCRBLOB
+ "OMIT_INCRBLOB",
+#endif
+#ifdef SQLITE_OMIT_INTEGRITY_CHECK
+ "OMIT_INTEGRITY_CHECK",
+#endif
+#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
+ "OMIT_LIKE_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ "OMIT_LOAD_EXTENSION",
+#endif
+#ifdef SQLITE_OMIT_LOCALTIME
+ "OMIT_LOCALTIME",
+#endif
+#ifdef SQLITE_OMIT_LOOKASIDE
+ "OMIT_LOOKASIDE",
+#endif
+#ifdef SQLITE_OMIT_MEMORYDB
+ "OMIT_MEMORYDB",
+#endif
+#ifdef SQLITE_OMIT_OR_OPTIMIZATION
+ "OMIT_OR_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_PAGER_PRAGMAS
+ "OMIT_PAGER_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_PRAGMA
+ "OMIT_PRAGMA",
+#endif
+#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
+ "OMIT_PROGRESS_CALLBACK",
+#endif
+#ifdef SQLITE_OMIT_QUICKBALANCE
+ "OMIT_QUICKBALANCE",
+#endif
+#ifdef SQLITE_OMIT_REINDEX
+ "OMIT_REINDEX",
+#endif
+#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
+ "OMIT_SCHEMA_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+ "OMIT_SCHEMA_VERSION_PRAGMAS",
+#endif
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ "OMIT_SHARED_CACHE",
+#endif
+#ifdef SQLITE_OMIT_SUBQUERY
+ "OMIT_SUBQUERY",
+#endif
+#ifdef SQLITE_OMIT_TCL_VARIABLE
+ "OMIT_TCL_VARIABLE",
+#endif
+#ifdef SQLITE_OMIT_TEMPDB
+ "OMIT_TEMPDB",
+#endif
+#ifdef SQLITE_OMIT_TRACE
+ "OMIT_TRACE",
+#endif
+#ifdef SQLITE_OMIT_TRIGGER
+ "OMIT_TRIGGER",
+#endif
+#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+ "OMIT_TRUNCATE_OPTIMIZATION",
+#endif
+#ifdef SQLITE_OMIT_UTF16
+ "OMIT_UTF16",
+#endif
+#ifdef SQLITE_OMIT_VACUUM
+ "OMIT_VACUUM",
+#endif
+#ifdef SQLITE_OMIT_VIEW
+ "OMIT_VIEW",
+#endif
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ "OMIT_VIRTUALTABLE",
+#endif
+#ifdef SQLITE_OMIT_WAL
+ "OMIT_WAL",
+#endif
+#ifdef SQLITE_OMIT_WSD
+ "OMIT_WSD",
+#endif
+#ifdef SQLITE_OMIT_XFER_OPT
+ "OMIT_XFER_OPT",
+#endif
+#ifdef SQLITE_PERFORMANCE_TRACE
+ "PERFORMANCE_TRACE",
+#endif
+#ifdef SQLITE_PROXY_DEBUG
+ "PROXY_DEBUG",
+#endif
+#ifdef SQLITE_SECURE_DELETE
+ "SECURE_DELETE",
+#endif
+#ifdef SQLITE_SMALL_STACK
+ "SMALL_STACK",
+#endif
+#ifdef SQLITE_SOUNDEX
+ "SOUNDEX",
+#endif
+#ifdef SQLITE_TCL
+ "TCL",
+#endif
+#ifdef SQLITE_TEMP_STORE
+ "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
+#endif
+#ifdef SQLITE_TEST
+ "TEST",
+#endif
+#ifdef SQLITE_THREADSAFE
+ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+#endif
+#ifdef SQLITE_USE_ALLOCA
+ "USE_ALLOCA",
+#endif
+#ifdef SQLITE_ZERO_MALLOC
+ "ZERO_MALLOC"
+#endif
+};
+
+/*
+** 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.
+*/
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
+ int i, n;
+ 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<ArraySize(azCompileOpt); i++){
+ if( (sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0)
+ && ( (azCompileOpt[i][n]==0) || (azCompileOpt[i][n]=='=') ) ) return 1;
+ }
+ return 0;
+}
+
+/*
+** Return the N-th compile-time option string. If N is out of range,
+** return a NULL pointer.
+*/
+SQLITE_API const char *sqlite3_compileoption_get(int N){
+ if( N>=0 && N<ArraySize(azCompileOpt) ){
+ return azCompileOpt[N];
+ }
+ return 0;
+}
+
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+/************** End of ctime.c ***********************************************/
/************** Begin file status.c ******************************************/
/*
** 2008 June 18
@@ -10929,6 +11651,26 @@
}
break;
}
+
+ /*
+ ** Return an approximation for the amount of memory currently used
+ ** by all pagers associated with the given database connection. The
+ ** highwater mark is meaningless and is returned as zero.
+ */
+ case SQLITE_DBSTATUS_CACHE_USED: {
+ int totalUsed = 0;
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ totalUsed += sqlite3PagerMemUsed(pPager);
+ }
+ }
+ *pCurrent = totalUsed;
+ *pHighwater = 0;
+ break;
+ }
default: {
return SQLITE_ERROR;
}
@@ -11251,10 +11993,8 @@
** Set the time to the current time reported by the VFS
*/
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
- double r;
sqlite3 *db = sqlite3_context_db_handle(context);
- sqlite3OsCurrentTime(db->pVfs, &r);
- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
p->validJD = 1;
}
@@ -11975,22 +12715,15 @@
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
sqlite3 *db;
- double rT;
+ sqlite3_int64 iT;
char zBuf[20];
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
db = sqlite3_context_db_handle(context);
- sqlite3OsCurrentTime(db->pVfs, &rT);
-#ifndef SQLITE_OMIT_FLOATING_POINT
- t = 86400.0*(rT - 2440587.5) + 0.5;
-#else
- /* without floating point support, rT will have
- ** already lost fractional day precision.
- */
- t = 86400 * (rT - 2440587) - 43200;
-#endif
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
+ t = iT/1000 - 10000*(sqlite3_int64)21086676;
#ifdef HAVE_GMTIME_R
{
struct tm sNow;
@@ -12029,8 +12762,8 @@
FUNCTION(current_date, 0, 0, 0, cdateFunc ),
#else
STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
- STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d", 0, currentTimeFunc),
- STR_FUNCTION(current_date, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
+ STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),
+ STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
int i;
@@ -12079,8 +12812,10 @@
** sqlite3OsLock()
**
*/
-#if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0)
- #define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \
+#if defined(SQLITE_TEST)
+SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
+ #define DO_OS_MALLOC_TEST(x) \
+ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
sqlite3_free(pTstAlloc); \
@@ -12143,6 +12878,27 @@
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+SQLITE_PRIVATE int sqlite3OsShmOpen(sqlite3_file *id){
+ return id->pMethods->xShmOpen(id);
+}
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
+ return id->pMethods->xShmLock(id, offset, n, flags);
+}
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
+ id->pMethods->xShmBarrier(id);
+}
+SQLITE_PRIVATE int sqlite3OsShmClose(sqlite3_file *id, int deleteFlag){
+ return id->pMethods->xShmClose(id, deleteFlag);
+}
+SQLITE_PRIVATE int sqlite3OsShmMap(
+ sqlite3_file *id,
+ int iPage,
+ int pgsz,
+ int isWrite,
+ void volatile **pp
+){
+ return id->pMethods->xShmMap(id, iPage, pgsz, isWrite, pp);
+}
/*
** The next group of routines are convenience wrappers around the
@@ -12157,11 +12913,11 @@
){
int rc;
DO_OS_MALLOC_TEST(0);
- /* 0x7f1f is a mask of SQLITE_OPEN_ flags that are valid to be passed
+ /* 0x7f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
- rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f1f, pFlagsOut);
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x7f3f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
@@ -12206,8 +12962,16 @@
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
-SQLITE_PRIVATE int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
- return pVfs->xCurrentTime(pVfs, pTimeOut);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+ int rc;
+ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
+ rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
+ }else{
+ double r;
+ rc = pVfs->xCurrentTime(pVfs, &r);
+ *pTimeOut = (sqlite3_int64)(r*86400000.0);
+ }
+ return rc;
}
SQLITE_PRIVATE int sqlite3OsOpenMalloc(
@@ -12584,7 +13348,6 @@
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
nByte = ROUND8(nByte);
- p = (sqlite3_int64*)pPrior;
p--;
p = realloc(p, nByte+8 );
if( p ){
@@ -12703,7 +13466,8 @@
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
- short nTitle; /* Bytes of title; includes '\0' */
+ u8 nTitle; /* Bytes of title; includes '\0' */
+ u8 eType; /* Allocation type code */
int iForeGuard; /* Guard word for sanity */
};
@@ -12911,6 +13675,7 @@
}
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
+ pHdr->eType = MEMTYPE_HEAP;
pHdr->nBacktraceSlots = mem.nBacktrace;
pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
@@ -12946,7 +13711,8 @@
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
- assert( sqlite3GlobalConfig.bMemstat || mem.mutex!=0 );
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
+ || mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
@@ -13018,6 +13784,47 @@
}
/*
+** Set the "type" of an allocation.
+*/
+SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
+ if( p ){
+ struct MemBlockHdr *pHdr;
+ pHdr = sqlite3MemsysGetHeader(p);
+ assert( pHdr->iForeGuard==FOREGUARD );
+ pHdr->eType = eType;
+ }
+}
+
+/*
+** Return TRUE if the mask of type in eType matches the type of the
+** allocation p. Also return true if p==NULL.
+**
+** This routine is designed for use within an assert() statement, to
+** verify the type of an allocation. For example:
+**
+** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
+*/
+SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
+ int rc = 1;
+ if( p ){
+ struct MemBlockHdr *pHdr;
+ pHdr = sqlite3MemsysGetHeader(p);
+ assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
+ assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */
+ if( (pHdr->eType&eType)==0 ){
+ void **pBt;
+ pBt = (void**)pHdr;
+ pBt -= pHdr->nBacktraceSlots;
+ backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr));
+ fprintf(stderr, "\n");
+ rc = 0;
+ }
+ }
+ return rc;
+}
+
+
+/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns off backtracing. The number is always rounded
** up to a multiple of 2.
@@ -14418,23 +15225,26 @@
*/
SQLITE_PRIVATE int sqlite3MutexInit(void){
int rc = SQLITE_OK;
- if( sqlite3GlobalConfig.bCoreMutex ){
- if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
- /* If the xMutexAlloc method has not been set, then the user did not
- ** install a mutex implementation via sqlite3_config() prior to
- ** sqlite3_initialize() being called. This block copies pointers to
- ** the default implementation into the sqlite3GlobalConfig structure.
- */
- sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex();
- sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
+ if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
+ /* If the xMutexAlloc method has not been set, then the user did not
+ ** install a mutex implementation via sqlite3_config() prior to
+ ** sqlite3_initialize() being called. This block copies pointers to
+ ** the default implementation into the sqlite3GlobalConfig structure.
+ */
+ sqlite3_mutex_methods const *pFrom;
+ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
- memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
- memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
- sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
- pTo->xMutexAlloc = pFrom->xMutexAlloc;
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pFrom = sqlite3DefaultMutex();
+ }else{
+ pFrom = sqlite3NoopMutex();
}
- rc = sqlite3GlobalConfig.mutex.xMutexInit();
+ memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
+ memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
+ sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
+ pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
+ rc = sqlite3GlobalConfig.mutex.xMutexInit();
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 1;
@@ -14566,25 +15376,30 @@
** called correctly.
*/
+#ifndef SQLITE_MUTEX_OMIT
-#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
+#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/
-static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
-static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
-static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
-static void noopMutexFree(sqlite3_mutex *p){ return; }
-static void noopMutexEnter(sqlite3_mutex *p){ return; }
-static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
-static void noopMutexLeave(sqlite3_mutex *p){ return; }
+static sqlite3_mutex *noopMutexAlloc(int id){
+ UNUSED_PARAMETER(id);
+ return (sqlite3_mutex*)8;
+}
+static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
+static int noopMutexTry(sqlite3_mutex *p){
+ UNUSED_PARAMETER(p);
+ return SQLITE_OK;
+}
+static void noopMutexLeave(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
noopMutexInit,
noopMutexEnd,
noopMutexAlloc,
@@ -14593,15 +15408,15 @@
noopMutexTry,
noopMutexLeave,
- noopMutexHeld,
- noopMutexNotheld
+ 0,
+ 0,
};
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
+#endif /* !SQLITE_DEBUG */
-#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
+#ifdef SQLITE_DEBUG
/*
** In this implementation, error checking is provided for testing
** and debugging purposes. The mutexes still do not provide any
@@ -14611,19 +15426,21 @@
/*
** The mutex object
*/
-struct sqlite3_mutex {
+typedef struct sqlite3_debug_mutex {
int id; /* The mutex type */
int cnt; /* Number of entries without a matching leave */
-};
+} sqlite3_debug_mutex;
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-static int debugMutexHeld(sqlite3_mutex *p){
+static int debugMutexHeld(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt>0;
}
-static int debugMutexNotheld(sqlite3_mutex *p){
+static int debugMutexNotheld(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt==0;
}
@@ -14639,8 +15456,8 @@
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
- static sqlite3_mutex aStatic[6];
- sqlite3_mutex *pNew = 0;
+ static sqlite3_debug_mutex aStatic[6];
+ sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
@@ -14659,13 +15476,14 @@
break;
}
}
- return pNew;
+ return (sqlite3_mutex*)pNew;
}
/*
** This routine deallocates a previously allocated mutex.
*/
-static void debugMutexFree(sqlite3_mutex *p){
+static void debugMutexFree(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
sqlite3_free(p);
@@ -14682,12 +15500,14 @@
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
-static void debugMutexEnter(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+static void debugMutexEnter(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
}
-static int debugMutexTry(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+static int debugMutexTry(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
return SQLITE_OK;
}
@@ -14698,14 +15518,15 @@
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
-static void debugMutexLeave(sqlite3_mutex *p){
- assert( debugMutexHeld(p) );
+static void debugMutexLeave(sqlite3_mutex *pX){
+ sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
+ assert( debugMutexHeld(pX) );
p->cnt--;
- assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3NoopMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
debugMutexInit,
debugMutexEnd,
debugMutexAlloc,
@@ -14720,7 +15541,18 @@
return &sMutex;
}
-#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */
+#endif /* SQLITE_DEBUG */
+
+/*
+** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
+** is used regardless of the run-time threadsafety setting.
+*/
+#ifdef SQLITE_MUTEX_NOOP
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ return sqlite3NoopMutex();
+}
+#endif /* SQLITE_MUTEX_NOOP */
+#endif /* SQLITE_MUTEX_OMIT */
/************** End of mutex_noop.c ******************************************/
/************** Begin file mutex_os2.c ***************************************/
@@ -14976,8 +15808,8 @@
DosReleaseMutexSem(p->mutex);
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
os2MutexInit,
os2MutexEnd,
os2MutexAlloc,
@@ -15022,23 +15854,33 @@
#include <pthread.h>
+/*
+** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
+** are necessary under two condidtions: (1) Debug builds and (2) using
+** home-grown mutexes. Encapsulate these conditions into a single #define.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
+# define SQLITE_MUTEX_NREF 1
+#else
+# define SQLITE_MUTEX_NREF 0
+#endif
/*
** Each recursive mutex is an instance of the following structure.
*/
struct sqlite3_mutex {
pthread_mutex_t mutex; /* Mutex controlling the lock */
+#if SQLITE_MUTEX_NREF
int id; /* Mutex type */
- int nRef; /* Number of entrances */
- pthread_t owner; /* Thread that is within this mutex */
-#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of entrances */
+ volatile pthread_t owner; /* Thread that is within this mutex */
int trace; /* True to trace changes */
#endif
};
-#ifdef SQLITE_DEBUG
+#if SQLITE_MUTEX_NREF
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0, 0 }
#else
-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0, (pthread_t)0 }
+#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#endif
/*
@@ -15140,14 +15982,18 @@
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
}
break;
}
case SQLITE_MUTEX_FAST: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
pthread_mutex_init(&p->mutex, 0);
}
break;
@@ -15156,7 +16002,9 @@
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(staticMutexes) );
p = &staticMutexes[iType-2];
+#if SQLITE_MUTEX_NREF
p->id = iType;
+#endif
break;
}
}
@@ -15216,9 +16064,11 @@
/* Use the built-in recursive mutexes if they are available.
*/
pthread_mutex_lock(&p->mutex);
+#if SQLITE_MUTEX_NREF
p->owner = pthread_self();
p->nRef++;
#endif
+#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
@@ -15259,8 +16109,10 @@
/* Use the built-in recursive mutexes if they are available.
*/
if( pthread_mutex_trylock(&p->mutex)==0 ){
+#if SQLITE_MUTEX_NREF
p->owner = pthread_self();
p->nRef++;
+#endif
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
@@ -15283,7 +16135,9 @@
*/
static void pthreadMutexLeave(sqlite3_mutex *p){
assert( pthreadMutexHeld(p) );
+#if SQLITE_MUTEX_NREF
p->nRef--;
+#endif
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
@@ -15301,8 +16155,8 @@
#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
pthreadMutexInit,
pthreadMutexEnd,
pthreadMutexAlloc,
@@ -15352,9 +16206,18 @@
struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
- int nRef; /* Number of enterances */
- DWORD owner; /* Thread holding this mutex */
+#ifdef SQLITE_DEBUG
+ volatile int nRef; /* Number of enterances */
+ volatile DWORD owner; /* Thread holding this mutex */
+ int trace; /* True to trace changes */
+#endif
};
+#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
+#ifdef SQLITE_DEBUG
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
+#else
+#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
+#endif
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
@@ -15398,8 +16261,12 @@
static int winMutexHeld(sqlite3_mutex *p){
return p->nRef!=0 && p->owner==GetCurrentThreadId();
}
+static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
+ return p->nRef==0 || p->owner!=tid;
+}
static int winMutexNotheld(sqlite3_mutex *p){
- return p->nRef==0 || p->owner!=GetCurrentThreadId();
+ DWORD tid = GetCurrentThreadId();
+ return winMutexNotheld2(p, tid);
}
#endif
@@ -15407,7 +16274,14 @@
/*
** Initialize and deinitialize the mutex subsystem.
*/
-static sqlite3_mutex winMutex_staticMutexes[6];
+static sqlite3_mutex winMutex_staticMutexes[6] = {
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER,
+ SQLITE3_MUTEX_INITIALIZER
+};
static int winMutex_isInit = 0;
/* As winMutexInit() and winMutexEnd() are called as part
** of the sqlite3_initialize and sqlite3_shutdown()
@@ -15498,7 +16372,9 @@
case SQLITE_MUTEX_RECURSIVE: {
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
InitializeCriticalSection(&p->mutex);
}
break;
@@ -15508,7 +16384,9 @@
assert( iType-2 >= 0 );
assert( iType-2 < ArraySize(winMutex_staticMutexes) );
p = &winMutex_staticMutexes[iType-2];
+#ifdef SQLITE_DEBUG
p->id = iType;
+#endif
break;
}
}
@@ -15541,14 +16419,25 @@
** more than once, the behavior is undefined.
*/
static void winMutexEnter(sqlite3_mutex *p){
- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
+#ifdef SQLITE_DEBUG
+ DWORD tid = GetCurrentThreadId();
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
+#endif
EnterCriticalSection(&p->mutex);
- p->owner = GetCurrentThreadId();
+#ifdef SQLITE_DEBUG
+ p->owner = tid;
p->nRef++;
+ if( p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
}
static int winMutexTry(sqlite3_mutex *p){
+#ifndef NDEBUG
+ DWORD tid = GetCurrentThreadId();
+#endif
int rc = SQLITE_BUSY;
- assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld(p) );
+ assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
/*
** The sqlite3_mutex_try() routine is very rarely used, and when it
** is used it is merely an optimization. So it is OK for it to always
@@ -15562,13 +16451,18 @@
*/
#if 0
if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
- p->owner = GetCurrentThreadId();
+ p->owner = tid;
p->nRef++;
rc = SQLITE_OK;
}
#else
UNUSED_PARAMETER(p);
#endif
+#ifdef SQLITE_DEBUG
+ if( rc==SQLITE_OK && p->trace ){
+ printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
return rc;
}
@@ -15579,15 +16473,23 @@
** is not currently allocated. SQLite will never do either.
*/
static void winMutexLeave(sqlite3_mutex *p){
+#ifndef NDEBUG
+ DWORD tid = GetCurrentThreadId();
assert( p->nRef>0 );
- assert( p->owner==GetCurrentThreadId() );
+ assert( p->owner==tid );
p->nRef--;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
+#endif
LeaveCriticalSection(&p->mutex);
+#ifdef SQLITE_DEBUG
+ if( p->trace ){
+ printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
+ }
+#endif
}
-SQLITE_PRIVATE sqlite3_mutex_methods *sqlite3DefaultMutex(void){
- static sqlite3_mutex_methods sMutex = {
+SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
winMutexInit,
winMutexEnd,
winMutexAlloc,
@@ -15925,11 +16827,11 @@
assert( n>0 );
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than one scratch allocation per thread
+ /* Verify that no more than two scratch allocation per thread
** is outstanding at one time. (This is only checked in the
** single-threaded case since checking in the multi-threaded case
** would be much more complicated.) */
- assert( scratchAllocOut==0 );
+ assert( scratchAllocOut<=1 );
#endif
if( sqlite3GlobalConfig.szScratch<n ){
@@ -15966,6 +16868,7 @@
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
scratchAllocOut = p!=0;
#endif
@@ -15973,19 +16876,11 @@
}
SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
if( p ){
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than one scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut==1 );
- scratchAllocOut = 0;
-#endif
-
if( sqlite3GlobalConfig.pScratch==0
|| p<sqlite3GlobalConfig.pScratch
|| p>=(void*)mem0.aScratchFree ){
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
@@ -16006,6 +16901,16 @@
mem0.aScratchFree[mem0.nScratchFree++] = i;
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_USED, -1);
sqlite3_mutex_leave(mem0.mutex);
+
+#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
+ /* Verify that no more than two scratch allocation per thread
+ ** is outstanding at one time. (This is only checked in the
+ ** single-threaded case since checking in the multi-threaded case
+ ** would be much more complicated.) */
+ assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
+ scratchAllocOut = 0;
+#endif
+
}
}
}
@@ -16026,6 +16931,7 @@
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
@@ -16033,6 +16939,8 @@
if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
+ assert( sqlite3MemdebugHasType(p,
+ db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
}
@@ -16042,6 +16950,7 @@
*/
SQLITE_API void sqlite3_free(void *p){
if( p==0 ) return;
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
@@ -16064,6 +16973,8 @@
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
}else{
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
}
@@ -16096,6 +17007,7 @@
mem0.alarmThreshold ){
sqlite3MallocAlarm(nNew-nOld);
}
+ assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
if( pNew==0 && mem0.alarmCallback ){
sqlite3MallocAlarm(nBytes);
@@ -16193,6 +17105,8 @@
if( !p && db ){
db->mallocFailed = 1;
}
+ sqlite3MemdebugSetType(p,
+ (db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP);
return p;
}
@@ -16218,10 +17132,14 @@
sqlite3DbFree(db, p);
}
}else{
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc(p, n);
if( !pNew ){
db->mallocFailed = 1;
}
+ sqlite3MemdebugSetType(pNew,
+ db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP);
}
}
return pNew;
@@ -16782,7 +17700,9 @@
case etEXP:
case etGENERIC:
realvalue = va_arg(ap,double);
-#ifndef SQLITE_OMIT_FLOATING_POINT
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ length = 0;
+#else
if( precision<0 ) precision = 6; /* Set default precision */
if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10;
if( realvalue<0.0 ){
@@ -16928,7 +17848,7 @@
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif
+#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
case etSIZE:
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -16975,7 +17895,7 @@
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
k = precision;
- for(i=n=0; (ch=escarg[i])!=0 && k!=0; i++, k--){
+ for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
if( ch==q ) n++;
}
needQuote = !isnull && xtype==etSQLESCAPE2;
@@ -17269,12 +18189,8 @@
** mutex is held.
*/
static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
- StrAccum acc; /* String accumulator */
-#ifdef SQLITE_SMALL_STACK
- char zMsg[150]; /* Complete log message */
-#else
- char zMsg[400]; /* Complete log message */
-#endif
+ StrAccum acc; /* String accumulator */
+ char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
sqlite3StrAccumInit(&acc, zMsg, sizeof(zMsg), 0);
acc.useMalloc = 0;
@@ -17827,7 +18743,7 @@
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
i64 startTime; /* Time when query started - used for profiling */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
- int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
+ int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
@@ -17879,7 +18795,11 @@
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
-SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
+#ifdef SQLITE_OMIT_FLOATING_POINT
+# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
+#else
+SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
+#endif
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
@@ -18332,11 +19252,11 @@
**
** NULL is returned if there is an allocation error.
*/
-SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte){
+SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
Mem m;
memset(&m, 0, sizeof(m));
m.db = db;
- sqlite3VdbeMemSetStr(&m, z, nByte, SQLITE_UTF16NATIVE, SQLITE_STATIC);
+ sqlite3VdbeMemSetStr(&m, z, nByte, enc, SQLITE_STATIC);
sqlite3VdbeChangeEncoding(&m, SQLITE_UTF8);
if( db->mallocFailed ){
sqlite3VdbeMemRelease(&m);
@@ -18344,7 +19264,9 @@
}
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
- return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z);
+ assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
+ assert( m.z || db->mallocFailed );
+ return m.z;
}
/*
@@ -18485,6 +19407,7 @@
}
#endif
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
**
@@ -18529,6 +19452,7 @@
testcase( rc );
return rc;
}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Compute a string length that is limited to what can be stored in
@@ -18706,6 +19630,7 @@
z += incr;
*realnum = 0;
while( sqlite3Isdigit(*z) ){ z += incr; }
+#ifndef SQLITE_OMIT_FLOATING_POINT
if( *z=='.' ){
z += incr;
if( !sqlite3Isdigit(*z) ) return 0;
@@ -18719,6 +19644,7 @@
while( sqlite3Isdigit(*z) ){ z += incr; }
*realnum = 1;
}
+#endif
return *z==0;
}
@@ -18880,6 +19806,9 @@
c = memcmp(zNum,"922337203685477580",18)*10;
if( c==0 ){
c = zNum[18] - '8';
+ testcase( c==(-1) );
+ testcase( c==0 );
+ testcase( c==(+1) );
}
return c;
}
@@ -18916,6 +19845,9 @@
v = v*10 + c - '0';
}
*pNum = neg ? -v : v;
+ testcase( i==18 );
+ testcase( i==19 );
+ testcase( i==20 );
if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranting that it is too large) */
@@ -18959,6 +19891,9 @@
zNum++; /* Skip leading zeros. Ticket #2454 */
}
for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
+ testcase( i==18 );
+ testcase( i==19 );
+ testcase( i==20 );
if( i<19 ){
/* Guaranteed to fit if less than 19 digits */
return 1;
@@ -18999,9 +19934,11 @@
** 1234567890
** 2^31 -> 2147483648
*/
+ testcase( i==10 );
if( i>10 ){
return 0;
}
+ testcase( v-neg==2147483647 );
if( v-neg>2147483647 ){
return 0;
}
@@ -19090,6 +20027,19 @@
}
/*
+** Bitmasks used by sqlite3GetVarint(). These precomputed constants
+** are defined here rather than simply putting the constant expressions
+** inline in order to work around bugs in the RVT compiler.
+**
+** SLOT_2_0 A mask for (0x7f<<14) | 0x7f
+**
+** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0
+*/
+#define SLOT_2_0 0x001fc07f
+#define SLOT_4_2_0 0xf01fc07f
+
+
+/*
** Read a 64-bit variable-length integer from memory starting at p[0].
** Return the number of bytes read. The value is stored in *v.
*/
@@ -19116,13 +20066,17 @@
return 2;
}
+ /* Verify that constants are precomputed correctly */
+ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
+ assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
+
p++;
a = a<<14;
a |= *p;
/* a: p0<<14 | p2 (unmasked) */
if (!(a&0x80))
{
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
b &= 0x7f;
b = b<<7;
a |= b;
@@ -19131,14 +20085,14 @@
}
/* CSE1 from below */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
p++;
b = b<<14;
b |= *p;
/* b: p1<<14 | p3 (unmasked) */
if (!(b&0x80))
{
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
/* moved CSE1 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@@ -19152,7 +20106,7 @@
/* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
/* moved CSE1 up */
/* a &= (0x7f<<14)|(0x7f); */
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
s = a;
/* s: p0<<14 | p2 (masked) */
@@ -19185,7 +20139,7 @@
{
/* we can skip this cause it was (effectively) done above in calc'ing s */
/* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
a = a<<7;
a |= b;
s = s>>18;
@@ -19199,8 +20153,8 @@
/* a: p2<<28 | p4<<14 | p6 (unmasked) */
if (!(a&0x80))
{
- a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
- b &= (0x7f<<14)|(0x7f);
+ a &= SLOT_4_2_0;
+ b &= SLOT_2_0;
b = b<<7;
a |= b;
s = s>>11;
@@ -19209,14 +20163,14 @@
}
/* CSE2 from below */
- a &= (0x7f<<14)|(0x7f);
+ a &= SLOT_2_0;
p++;
b = b<<14;
b |= *p;
/* b: p3<<28 | p5<<14 | p7 (unmasked) */
if (!(b&0x80))
{
- b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
+ b &= SLOT_4_2_0;
/* moved CSE2 up */
/* a &= (0x7f<<14)|(0x7f); */
a = a<<7;
@@ -19233,7 +20187,7 @@
/* moved CSE2 up */
/* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
- b &= (0x7f<<14)|(0x7f);
+ b &= SLOT_2_0;
b = b<<8;
a |= b;
@@ -19353,9 +20307,9 @@
/* a: p0<<28 | p2<<14 | p4 (unmasked) */
if (!(a&0x80))
{
- /* Walues between 268435456 and 34359738367 */
- a &= (0x1f<<28)|(0x7f<<14)|(0x7f);
- b &= (0x1f<<28)|(0x7f<<14)|(0x7f);
+ /* Values between 268435456 and 34359738367 */
+ a &= SLOT_4_2_0;
+ b &= SLOT_4_2_0;
b = b<<7;
*v = a | b;
return 5;
@@ -19482,7 +20436,8 @@
}
magic = db->magic;
if( magic!=SQLITE_MAGIC_OPEN ){
- if( !sqlite3SafetyCheckSickOrOk(db) ){
+ if( sqlite3SafetyCheckSickOrOk(db) ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
logBadConnection("unopened");
}
return 0;
@@ -19496,6 +20451,7 @@
if( magic!=SQLITE_MAGIC_SICK &&
magic!=SQLITE_MAGIC_OPEN &&
magic!=SQLITE_MAGIC_BUSY ){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
logBadConnection("invalid");
return 0;
}else{
@@ -19827,39 +20783,39 @@
/* 37 */ "VerifyCookie",
/* 38 */ "OpenRead",
/* 39 */ "OpenWrite",
- /* 40 */ "OpenEphemeral",
- /* 41 */ "OpenPseudo",
- /* 42 */ "Close",
- /* 43 */ "SeekLt",
- /* 44 */ "SeekLe",
- /* 45 */ "SeekGe",
- /* 46 */ "SeekGt",
- /* 47 */ "Seek",
- /* 48 */ "NotFound",
- /* 49 */ "Found",
- /* 50 */ "IsUnique",
- /* 51 */ "NotExists",
- /* 52 */ "Sequence",
- /* 53 */ "NewRowid",
- /* 54 */ "Insert",
- /* 55 */ "InsertInt",
- /* 56 */ "Delete",
- /* 57 */ "ResetCount",
- /* 58 */ "RowKey",
- /* 59 */ "RowData",
- /* 60 */ "Rowid",
- /* 61 */ "NullRow",
- /* 62 */ "Last",
- /* 63 */ "Sort",
- /* 64 */ "Rewind",
- /* 65 */ "Prev",
- /* 66 */ "Next",
- /* 67 */ "IdxInsert",
+ /* 40 */ "OpenAutoindex",
+ /* 41 */ "OpenEphemeral",
+ /* 42 */ "OpenPseudo",
+ /* 43 */ "Close",
+ /* 44 */ "SeekLt",
+ /* 45 */ "SeekLe",
+ /* 46 */ "SeekGe",
+ /* 47 */ "SeekGt",
+ /* 48 */ "Seek",
+ /* 49 */ "NotFound",
+ /* 50 */ "Found",
+ /* 51 */ "IsUnique",
+ /* 52 */ "NotExists",
+ /* 53 */ "Sequence",
+ /* 54 */ "NewRowid",
+ /* 55 */ "Insert",
+ /* 56 */ "InsertInt",
+ /* 57 */ "Delete",
+ /* 58 */ "ResetCount",
+ /* 59 */ "RowKey",
+ /* 60 */ "RowData",
+ /* 61 */ "Rowid",
+ /* 62 */ "NullRow",
+ /* 63 */ "Last",
+ /* 64 */ "Sort",
+ /* 65 */ "Rewind",
+ /* 66 */ "Prev",
+ /* 67 */ "Next",
/* 68 */ "Or",
/* 69 */ "And",
- /* 70 */ "IdxDelete",
- /* 71 */ "IdxRowid",
- /* 72 */ "IdxLT",
+ /* 70 */ "IdxInsert",
+ /* 71 */ "IdxDelete",
+ /* 72 */ "IdxRowid",
/* 73 */ "IsNull",
/* 74 */ "NotNull",
/* 75 */ "Ne",
@@ -19868,7 +20824,7 @@
/* 78 */ "Le",
/* 79 */ "Lt",
/* 80 */ "Ge",
- /* 81 */ "IdxGE",
+ /* 81 */ "IdxLT",
/* 82 */ "BitAnd",
/* 83 */ "BitOr",
/* 84 */ "ShiftLeft",
@@ -19879,52 +20835,52 @@
/* 89 */ "Divide",
/* 90 */ "Remainder",
/* 91 */ "Concat",
- /* 92 */ "Destroy",
+ /* 92 */ "IdxGE",
/* 93 */ "BitNot",
/* 94 */ "String8",
- /* 95 */ "Clear",
- /* 96 */ "CreateIndex",
- /* 97 */ "CreateTable",
- /* 98 */ "ParseSchema",
- /* 99 */ "LoadAnalysis",
- /* 100 */ "DropTable",
- /* 101 */ "DropIndex",
- /* 102 */ "DropTrigger",
- /* 103 */ "IntegrityCk",
- /* 104 */ "RowSetAdd",
- /* 105 */ "RowSetRead",
- /* 106 */ "RowSetTest",
- /* 107 */ "Program",
- /* 108 */ "Param",
- /* 109 */ "FkCounter",
- /* 110 */ "FkIfZero",
- /* 111 */ "MemMax",
- /* 112 */ "IfPos",
- /* 113 */ "IfNeg",
- /* 114 */ "IfZero",
- /* 115 */ "AggStep",
- /* 116 */ "AggFinal",
- /* 117 */ "Vacuum",
- /* 118 */ "IncrVacuum",
- /* 119 */ "Expire",
- /* 120 */ "TableLock",
- /* 121 */ "VBegin",
- /* 122 */ "VCreate",
- /* 123 */ "VDestroy",
- /* 124 */ "VOpen",
- /* 125 */ "VFilter",
- /* 126 */ "VColumn",
- /* 127 */ "VNext",
- /* 128 */ "VRename",
- /* 129 */ "VUpdate",
+ /* 95 */ "Destroy",
+ /* 96 */ "Clear",
+ /* 97 */ "CreateIndex",
+ /* 98 */ "CreateTable",
+ /* 99 */ "ParseSchema",
+ /* 100 */ "LoadAnalysis",
+ /* 101 */ "DropTable",
+ /* 102 */ "DropIndex",
+ /* 103 */ "DropTrigger",
+ /* 104 */ "IntegrityCk",
+ /* 105 */ "RowSetAdd",
+ /* 106 */ "RowSetRead",
+ /* 107 */ "RowSetTest",
+ /* 108 */ "Program",
+ /* 109 */ "Param",
+ /* 110 */ "FkCounter",
+ /* 111 */ "FkIfZero",
+ /* 112 */ "MemMax",
+ /* 113 */ "IfPos",
+ /* 114 */ "IfNeg",
+ /* 115 */ "IfZero",
+ /* 116 */ "AggStep",
+ /* 117 */ "AggFinal",
+ /* 118 */ "Checkpoint",
+ /* 119 */ "JournalMode",
+ /* 120 */ "Vacuum",
+ /* 121 */ "IncrVacuum",
+ /* 122 */ "Expire",
+ /* 123 */ "TableLock",
+ /* 124 */ "VBegin",
+ /* 125 */ "VCreate",
+ /* 126 */ "VDestroy",
+ /* 127 */ "VOpen",
+ /* 128 */ "VFilter",
+ /* 129 */ "VColumn",
/* 130 */ "Real",
- /* 131 */ "Pagecount",
- /* 132 */ "Trace",
- /* 133 */ "Noop",
- /* 134 */ "Explain",
- /* 135 */ "NotUsed_135",
- /* 136 */ "NotUsed_136",
- /* 137 */ "NotUsed_137",
+ /* 131 */ "VNext",
+ /* 132 */ "VRename",
+ /* 133 */ "VUpdate",
+ /* 134 */ "Pagecount",
+ /* 135 */ "Trace",
+ /* 136 */ "Noop",
+ /* 137 */ "Explain",
/* 138 */ "NotUsed_138",
/* 139 */ "NotUsed_139",
/* 140 */ "NotUsed_140",
@@ -20029,23 +20985,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -20241,7 +21183,7 @@
APIRET rc = NO_ERROR;
os2File *pFile;
if( id && (pFile = (os2File*)id) != 0 ){
- OSTRACE2( "CLOSE %d\n", pFile->h );
+ OSTRACE(( "CLOSE %d\n", pFile->h ));
rc = DosClose( pFile->h );
pFile->locktype = NO_LOCK;
if( pFile->pathToDel != NULL ){
@@ -20272,7 +21214,7 @@
os2File *pFile = (os2File*)id;
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_READ );
- OSTRACE3( "READ %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "READ %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20305,7 +21247,7 @@
assert( id!=0 );
SimulateIOError( return SQLITE_IOERR_WRITE );
SimulateDiskfullError( return SQLITE_FULL );
- OSTRACE3( "WRITE %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "WRITE %d lock=%d\n", pFile->h, pFile->locktype ));
if( DosSetFilePtr(pFile->h, offset, FILE_BEGIN, &fileLocation) != NO_ERROR ){
return SQLITE_IOERR;
}
@@ -20327,7 +21269,7 @@
static int os2Truncate( sqlite3_file *id, i64 nByte ){
APIRET rc = NO_ERROR;
os2File *pFile = (os2File*)id;
- OSTRACE3( "TRUNCATE %d %lld\n", pFile->h, nByte );
+ OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte ));
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
rc = DosSetFileSize( pFile->h, nByte );
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
@@ -20347,7 +21289,7 @@
*/
static int os2Sync( sqlite3_file *id, int flags ){
os2File *pFile = (os2File*)id;
- OSTRACE3( "SYNC %d lock=%d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "SYNC %d lock=%d\n", pFile->h, pFile->locktype ));
#ifdef SQLITE_TEST
if( flags & SQLITE_SYNC_FULL){
sqlite3_fullsync_count++;
@@ -20397,7 +21339,7 @@
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "GETREADLOCK %d res=%d\n", pFile->h, res );
+ OSTRACE(( "GETREADLOCK %d res=%d\n", pFile->h, res ));
return res;
}
@@ -20415,7 +21357,7 @@
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( id->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 1L );
- OSTRACE3( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res );
+ OSTRACE(( "UNLOCK-READLOCK file handle=%d res=%d?\n", id->h, res ));
return res;
}
@@ -20456,14 +21398,14 @@
memset(&LockArea, 0, sizeof(LockArea));
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
- OSTRACE4( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "LOCK %d %d was %d\n", pFile->h, locktype, pFile->locktype ));
/* If there is already a lock of this type or more restrictive on the
** os2File, do nothing. Don't use the end_lock: exit path, as
** sqlite3_mutex_enter() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
- OSTRACE3( "LOCK %d %d ok (already held)\n", pFile->h, locktype );
+ OSTRACE(( "LOCK %d %d ok (already held)\n", pFile->h, locktype ));
return SQLITE_OK;
}
@@ -20490,7 +21432,7 @@
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, 100L, 0L );
if( res == NO_ERROR ){
gotPendingLock = 1;
- OSTRACE3( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d pending lock boolean set. res=%d\n", pFile->h, res ));
}
}
@@ -20502,7 +21444,7 @@
if( res == NO_ERROR ){
newLocktype = SHARED_LOCK;
}
- OSTRACE3( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire shared lock. res=%d\n", pFile->h, res ));
}
/* Acquire a RESERVED lock
@@ -20517,7 +21459,7 @@
if( res == NO_ERROR ){
newLocktype = RESERVED_LOCK;
}
- OSTRACE3( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire reserved lock. res=%d\n", pFile->h, res ));
}
/* Acquire a PENDING lock
@@ -20525,7 +21467,8 @@
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
newLocktype = PENDING_LOCK;
gotPendingLock = 0;
- OSTRACE2( "LOCK %d acquire pending lock. pending lock boolean unset.\n", pFile->h );
+ OSTRACE(( "LOCK %d acquire pending lock. pending lock boolean unset.\n",
+ pFile->h ));
}
/* Acquire an EXCLUSIVE lock
@@ -20533,7 +21476,7 @@
if( locktype==EXCLUSIVE_LOCK && res == NO_ERROR ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2( "unreadlock = %d\n", res );
+ OSTRACE(( "unreadlock = %d\n", res ));
LockArea.lOffset = SHARED_FIRST;
LockArea.lRange = SHARED_SIZE;
UnlockArea.lOffset = 0L;
@@ -20542,10 +21485,10 @@
if( res == NO_ERROR ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- OSTRACE2( "OS/2 error-code = %d\n", res );
+ OSTRACE(( "OS/2 error-code = %d\n", res ));
getReadLock(pFile);
}
- OSTRACE3( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res );
+ OSTRACE(( "LOCK %d acquire exclusive lock. res=%d\n", pFile->h, res ));
}
/* If we are holding a PENDING lock that ought to be released, then
@@ -20558,7 +21501,7 @@
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
r = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r );
+ OSTRACE(( "LOCK %d unlocking pending/is shared. r=%d\n", pFile->h, r ));
}
/* Update the state of the lock has held in the file descriptor then
@@ -20567,12 +21510,12 @@
if( res == NO_ERROR ){
rc = SQLITE_OK;
}else{
- OSTRACE4( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype );
+ OSTRACE(( "LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype ));
rc = SQLITE_BUSY;
}
pFile->locktype = newLocktype;
- OSTRACE3( "LOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "LOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -20587,7 +21530,7 @@
assert( pFile!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
r = 1;
- OSTRACE3( "TEST WR-LOCK %d %d (local)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (local)\n", pFile->h, r ));
}else{
FILELOCK LockArea,
UnlockArea;
@@ -20599,7 +21542,7 @@
UnlockArea.lOffset = 0L;
UnlockArea.lRange = 0L;
rc = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc );
+ OSTRACE(( "TEST WR-LOCK %d lock reserved byte rc=%d\n", pFile->h, rc ));
if( rc == NO_ERROR ){
APIRET rcu = NO_ERROR; /* return code for unlocking */
LockArea.lOffset = 0L;
@@ -20607,10 +21550,10 @@
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
rcu = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu );
+ OSTRACE(( "TEST WR-LOCK %d unlock reserved byte r=%d\n", pFile->h, rcu ));
}
r = !(rc == NO_ERROR);
- OSTRACE3( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r );
+ OSTRACE(( "TEST WR-LOCK %d %d (remote)\n", pFile->h, r ));
}
*pOut = r;
return SQLITE_OK;
@@ -20638,7 +21581,7 @@
memset(&UnlockArea, 0, sizeof(UnlockArea));
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE4( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype );
+ OSTRACE(( "UNLOCK %d to %d was %d\n", pFile->h, locktype, pFile->locktype ));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
LockArea.lOffset = 0L;
@@ -20646,11 +21589,11 @@
UnlockArea.lOffset = SHARED_FIRST;
UnlockArea.lRange = SHARED_SIZE;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d exclusive lock res=%d\n", pFile->h, res ));
if( locktype==SHARED_LOCK && getReadLock(pFile) != NO_ERROR ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- OSTRACE3( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype );
+ OSTRACE(( "UNLOCK %d to %d getReadLock() failed\n", pFile->h, locktype ));
rc = SQLITE_IOERR_UNLOCK;
}
}
@@ -20660,11 +21603,12 @@
UnlockArea.lOffset = RESERVED_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d reserved res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d reserved res=%d\n", pFile->h, res ));
}
if( locktype==NO_LOCK && type>=SHARED_LOCK ){
res = unlockReadLock(pFile);
- OSTRACE5( "UNLOCK %d is %d want %d res=%d\n", pFile->h, type, locktype, res );
+ OSTRACE(( "UNLOCK %d is %d want %d res=%d\n",
+ pFile->h, type, locktype, res ));
}
if( type>=PENDING_LOCK ){
LockArea.lOffset = 0L;
@@ -20672,10 +21616,10 @@
UnlockArea.lOffset = PENDING_BYTE;
UnlockArea.lRange = 1L;
res = DosSetFileLocks( pFile->h, &UnlockArea, &LockArea, LOCK_TIMEOUT, 0L );
- OSTRACE3( "UNLOCK %d pending res=%d\n", pFile->h, res );
+ OSTRACE(( "UNLOCK %d pending res=%d\n", pFile->h, res ));
}
pFile->locktype = locktype;
- OSTRACE3( "UNLOCK %d now %d\n", pFile->h, pFile->locktype );
+ OSTRACE(( "UNLOCK %d now %d\n", pFile->h, pFile->locktype ));
return rc;
}
@@ -20686,7 +21630,8 @@
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = ((os2File*)id)->locktype;
- OSTRACE3( "FCNTL_LOCKSTATE %d lock=%d\n", ((os2File*)id)->h, ((os2File*)id)->locktype );
+ OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n",
+ ((os2File*)id)->h, ((os2File*)id)->locktype ));
return SQLITE_OK;
}
}
@@ -20873,7 +21818,7 @@
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- OSTRACE2( "TEMP FILENAME: %s\n", zBuf );
+ OSTRACE(( "TEMP FILENAME: %s\n", zBuf ));
return SQLITE_OK;
}
@@ -20936,30 +21881,30 @@
memset( pFile, 0, sizeof(*pFile) );
- OSTRACE2( "OPEN want %d\n", flags );
+ OSTRACE( "OPEN want %d\n", flags ));
if( flags & SQLITE_OPEN_READWRITE ){
ulOpenMode |= OPEN_ACCESS_READWRITE;
- OSTRACE1( "OPEN read/write\n" );
+ OSTRACE(( "OPEN read/write\n" ));
}else{
ulOpenMode |= OPEN_ACCESS_READONLY;
- OSTRACE1( "OPEN read only\n" );
+ OSTRACE(( "OPEN read only\n" ));
}
if( flags & SQLITE_OPEN_CREATE ){
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
- OSTRACE1( "OPEN open new/create\n" );
+ OSTRACE(( "OPEN open new/create\n" ));
}else{
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
- OSTRACE1( "OPEN open existing\n" );
+ OSTRACE(( "OPEN open existing\n" ));
}
if( flags & SQLITE_OPEN_MAIN_DB ){
ulOpenMode |= OPEN_SHARE_DENYNONE;
- OSTRACE1( "OPEN share read/write\n" );
+ OSTRACE(( "OPEN share read/write\n" ));
}else{
ulOpenMode |= OPEN_SHARE_DENYWRITE;
- OSTRACE1( "OPEN share read only\n" );
+ OSTRACE(( "OPEN share read only\n" ));
}
if( flags & SQLITE_OPEN_DELETEONCLOSE ){
@@ -20969,10 +21914,10 @@
#endif
os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
- OSTRACE1( "OPEN hidden/delete on close file attributes\n" );
+ OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
}else{
pFile->pathToDel = NULL;
- OSTRACE1( "OPEN normal file attribute\n" );
+ OSTRACE(( "OPEN normal file attribute\n" ));
}
/* always open in random access mode for possibly better speed */
@@ -20991,13 +21936,14 @@
(PEAOP2)NULL );
free( zNameCp );
if( rc != NO_ERROR ){
- OSTRACE7( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
- rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode );
+ OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
+ rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
if( pFile->pathToDel )
free( pFile->pathToDel );
pFile->pathToDel = NULL;
if( flags & SQLITE_OPEN_READWRITE ){
- OSTRACE2( "OPEN %d Invalid handle\n", ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) );
+ OSTRACE(( "OPEN %d Invalid handle\n",
+ ((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
return os2Open( pVfs, zName, id,
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
pOutFlags );
@@ -21013,7 +21959,7 @@
pFile->pMethod = &os2IoMethod;
pFile->h = h;
OpenCounter(+1);
- OSTRACE3( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags );
+ OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
return SQLITE_OK;
}
@@ -21030,7 +21976,7 @@
SimulateIOError( return SQLITE_IOERR_DELETE );
rc = DosDelete( (PSZ)zFilenameCp );
free( zFilenameCp );
- OSTRACE2( "DELETE \"%s\"\n", zFilename );
+ OSTRACE(( "DELETE \"%s\"\n", zFilename ));
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
@@ -21051,17 +21997,17 @@
rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD,
&fsts3ConfigInfo, sizeof(FILESTATUS3) );
free( zFilenameCp );
- OSTRACE4( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
- fsts3ConfigInfo.attrFile, flags, rc );
+ OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n",
+ fsts3ConfigInfo.attrFile, flags, rc ));
switch( flags ){
case SQLITE_ACCESS_READ:
case SQLITE_ACCESS_EXISTS:
rc = (rc == NO_ERROR);
- OSTRACE3( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc );
+ OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc));
break;
case SQLITE_ACCESS_READWRITE:
rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 );
- OSTRACE3( "ACCESS %s access of read/write rc=%d\n", zFilename, rc );
+ OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc ));
break;
default:
assert( !"Invalid flags argument" );
@@ -21271,7 +22217,7 @@
os2Randomness, /* xRandomness */
os2Sleep, /* xSleep */
os2CurrentTime, /* xCurrentTime */
- os2GetLastError /* xGetLastError */
+ os2GetLastError, /* xGetLastError */
};
sqlite3_vfs_register(&os2Vfs, 1);
initUconvObjects();
@@ -21405,6 +22351,7 @@
#include <unistd.h>
#include <sys/time.h>
#include <errno.h>
+#include <sys/mman.h>
#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
@@ -21414,10 +22361,18 @@
# else
# include <sys/file.h>
# include <sys/param.h>
-# include <sys/mount.h>
# endif
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+#if defined(__APPLE__) || (SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORKS)
+# include <sys/mount.h>
+#endif
+
+/*
+** Allowed values of unixFile.fsFlags
+*/
+#define SQLITE_FSFLAGS_IS_MSDOS 0x1
+
/*
** If we are to be thread-safe, include the pthreads header and define
** the SQLITE_UNIX_THREADS macro.
@@ -21451,6 +22406,11 @@
*/
#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
+/* Forward references */
+typedef struct unixShm unixShm; /* Connection shared memory */
+typedef struct unixShmNode unixShmNode; /* Shared memory instance */
+typedef struct unixInodeInfo unixInodeInfo; /* An i-node */
+typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */
/*
** Sometimes, after a file handle is closed by SQLite, the file descriptor
@@ -21458,7 +22418,6 @@
** structure are used to store the file descriptor while waiting for an
** opportunity to either close or reuse it.
*/
-typedef struct UnixUnusedFd UnixUnusedFd;
struct UnixUnusedFd {
int fd; /* File descriptor to close */
int flags; /* Flags this file descriptor was opened with */
@@ -21472,24 +22431,25 @@
typedef struct unixFile unixFile;
struct unixFile {
sqlite3_io_methods const *pMethod; /* Always the first entry */
- struct unixOpenCnt *pOpen; /* Info about all open fd's on this inode */
- struct unixLockInfo *pLock; /* Info about locks on this inode */
- int h; /* The file descriptor */
- int dirfd; /* File descriptor for the directory */
- unsigned char locktype; /* The type of lock held on this fd */
- int lastErrno; /* The unix errno from the last I/O error */
- void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
- int fileFlags; /* Miscellanous flags */
+ unixInodeInfo *pInode; /* Info about locks on this inode */
+ int h; /* The file descriptor */
+ int dirfd; /* File descriptor for the directory */
+ unsigned char eFileLock; /* The type of lock held on this fd */
+ int lastErrno; /* The unix errno from last I/O error */
+ void *lockingContext; /* Locking style specific state */
+ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+ int fileFlags; /* Miscellanous flags */
+ const char *zPath; /* Name of the file */
+ unixShm *pShm; /* Shared memory segment information */
#if SQLITE_ENABLE_LOCKING_STYLE
- int openFlags; /* The flags specified at open() */
+ int openFlags; /* The flags specified at open() */
#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* The thread that "owns" this unixFile */
+#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
+ unsigned fsFlags; /* cached details from statfs() */
#endif
#if OS_VXWORKS
- int isDelete; /* Delete on close if true */
- struct vxworksFileId *pId; /* Unique file ID */
+ int isDelete; /* Delete on close if true */
+ struct vxworksFileId *pId; /* Unique file ID */
#endif
#ifndef NDEBUG
/* The next group of variables are used to track whether or not the
@@ -21554,23 +22514,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -21780,7 +22726,7 @@
/*
** Helper functions to obtain and relinquish the global mutex. The
-** global mutex is used to protect the unixOpenCnt, unixLockInfo and
+** global mutex is used to protect the unixInodeInfo and
** vxworksFileId objects used by this file, all of which may be
** shared by multiple threads.
**
@@ -21811,8 +22757,8 @@
** binaries. This returns the string represetation of the supplied
** integer lock-type.
*/
-static const char *locktypeName(int locktype){
- switch( locktype ){
+static const char *azFileLock(int eFileLock){
+ switch( eFileLock ){
case NO_LOCK: return "NONE";
case SHARED_LOCK: return "SHARED";
case RESERVED_LOCK: return "RESERVED";
@@ -22149,13 +23095,12 @@
**
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
-** released. To work around this problem, each unixFile structure contains
-** a pointer to an unixOpenCnt structure. There is one unixOpenCnt structure
-** per open inode, which means that multiple unixFile can point to a single
-** unixOpenCnt. When an attempt is made to close an unixFile, if there are
+** released. To work around this problem, each unixInodeInfo object
+** maintains a count of the number of pending locks on tha inode.
+** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
-** The unixOpenCnt structure keeps a list of file descriptors that need to
+** The unixInodeInfo structure keeps a list of file descriptors that need to
** be closed and that list is walked (and cleared) when the last lock
** clears.
**
@@ -22170,46 +23115,19 @@
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
** compile-time whether or not thread A can override locks on thread B.
-** We have to do a run-time check to discover the behavior of the
+** One has to do a run-time check to discover the behavior of the
** current process.
**
-** On systems where thread A is unable to modify locks created by
-** thread B, we have to keep track of which thread created each
-** lock. Hence there is an extra field in the key to the unixLockInfo
-** structure to record this information. And on those systems it
-** is illegal to begin a transaction in one thread and finish it
-** in another. For this latter restriction, there is no work-around.
-** It is a limitation of LinuxThreads.
+** SQLite used to support LinuxThreads. But support for LinuxThreads
+** was dropped beginning with version 3.7.0. SQLite will still work with
+** LinuxThreads provided that (1) there is no more than one connection
+** per database file in the same process and (2) database connections
+** do not move across threads.
*/
/*
-** Set or check the unixFile.tid field. This field is set when an unixFile
-** is first opened. All subsequent uses of the unixFile verify that the
-** same thread is operating on the unixFile. Some operating systems do
-** not allow locks to be overridden by other threads and that restriction
-** means that sqlite3* database handles cannot be moved from one thread
-** to another while locks are held.
-**
-** Version 3.3.1 (2006-01-15): unixFile can be moved from one thread to
-** another as long as we are running on a system that supports threads
-** overriding each others locks (which is now the most common behavior)
-** or if no locks are held. But the unixFile.pLock field needs to be
-** recomputed because its key includes the thread-id. See the
-** transferOwnership() function below for additional information
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# define SET_THREADID(X) (X)->tid = pthread_self()
-# define CHECK_THREADID(X) (threadsOverrideEachOthersLocks==0 && \
- !pthread_equal((X)->tid, pthread_self()))
-#else
-# define SET_THREADID(X)
-# define CHECK_THREADID(X) 0
-#endif
-
-/*
** An instance of the following structure serves as the key used
-** to locate a particular unixOpenCnt structure given its inode. This
-** is the same as the unixLockKey except that the thread ID is omitted.
+** to locate a particular unixInodeInfo object.
*/
struct unixFileId {
dev_t dev; /* Device number */
@@ -22221,23 +23139,6 @@
};
/*
-** An instance of the following structure serves as the key used
-** to locate a particular unixLockInfo structure given its inode.
-**
-** If threads cannot override each others locks (LinuxThreads), then we
-** set the unixLockKey.tid field to the thread ID. If threads can override
-** each others locks (Posix and NPTL) then tid is always set to zero.
-** tid is omitted if we compile without threading support or on an OS
-** other than linux.
-*/
-struct unixLockKey {
- struct unixFileId fid; /* Unique identifier for the file */
-#if SQLITE_THREADSAFE && defined(__linux__)
- pthread_t tid; /* Thread ID of lock owner. Zero if not using LinuxThreads */
-#endif
-};
-
-/*
** An instance of the following structure is allocated for each open
** inode. Or, on LinuxThreads, there is one of these structures for
** each inode opened by each thread.
@@ -22246,227 +23147,109 @@
** structure contains a pointer to an instance of this object and this
** object keeps a count of the number of unixFile pointing to it.
*/
-struct unixLockInfo {
- struct unixLockKey lockKey; /* The lookup key */
- int cnt; /* Number of SHARED locks held */
- int locktype; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+struct unixInodeInfo {
+ struct unixFileId fileId; /* The lookup key */
+ int nShared; /* Number of SHARED locks held */
+ int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
int nRef; /* Number of pointers to this structure */
- struct unixLockInfo *pNext; /* List of all unixLockInfo objects */
- struct unixLockInfo *pPrev; /* .... doubly linked */
-};
-
-/*
-** An instance of the following structure is allocated for each open
-** inode. This structure keeps track of the number of locks on that
-** inode. If a close is attempted against an inode that is holding
-** locks, the close is deferred until all locks clear by adding the
-** file descriptor to be closed to the pending list.
-**
-** TODO: Consider changing this so that there is only a single file
-** descriptor for each open file, even when it is opened multiple times.
-** The close() system call would only occur when the last database
-** using the file closes.
-*/
-struct unixOpenCnt {
- struct unixFileId fileId; /* The lookup key */
- int nRef; /* Number of pointers to this structure */
- int nLock; /* Number of outstanding locks */
- UnixUnusedFd *pUnused; /* Unused file descriptors to close */
+ unixShmNode *pShmNode; /* Shared memory associated with this inode */
+ int nLock; /* Number of outstanding file locks */
+ UnixUnusedFd *pUnused; /* Unused file descriptors to close */
+ unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
+ unixInodeInfo *pPrev; /* .... doubly linked */
+#if defined(SQLITE_ENABLE_LOCKING_STYLE)
+ unsigned long long sharedByte; /* for AFP simulated shared lock */
+#endif
#if OS_VXWORKS
- sem_t *pSem; /* Named POSIX semaphore */
- char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
+ sem_t *pSem; /* Named POSIX semaphore */
+ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */
#endif
- struct unixOpenCnt *pNext, *pPrev; /* List of all unixOpenCnt objects */
};
/*
-** Lists of all unixLockInfo and unixOpenCnt objects. These used to be hash
-** tables. But the number of objects is rarely more than a dozen and
-** never exceeds a few thousand. And lookup is not on a critical
-** path so a simple linked list will suffice.
+** A lists of all unixInodeInfo objects.
*/
-static struct unixLockInfo *lockList = 0;
-static struct unixOpenCnt *openList = 0;
+static unixInodeInfo *inodeList = 0;
/*
-** This variable remembers whether or not threads can override each others
-** locks.
+** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** If all such file descriptors are closed without error, the list is
+** cleared and SQLITE_OK returned.
**
-** 0: No. Threads cannot override each others locks. (LinuxThreads)
-** 1: Yes. Threads can override each others locks. (Posix & NLPT)
-** -1: We don't know yet.
-**
-** On some systems, we know at compile-time if threads can override each
-** others locks. On those systems, the SQLITE_THREAD_OVERRIDE_LOCK macro
-** will be set appropriately. On other systems, we have to check at
-** runtime. On these latter systems, SQLTIE_THREAD_OVERRIDE_LOCK is
-** undefined.
-**
-** This variable normally has file scope only. But during testing, we make
-** it a global so that the test code can change its value in order to verify
-** that the right stuff happens in either case.
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-# ifndef SQLITE_THREAD_OVERRIDE_LOCK
-# define SQLITE_THREAD_OVERRIDE_LOCK -1
-# endif
-# ifdef SQLITE_TEST
-int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# else
-static int threadsOverrideEachOthersLocks = SQLITE_THREAD_OVERRIDE_LOCK;
-# endif
-#endif
-
-/*
-** This structure holds information passed into individual test
-** threads by the testThreadLockingBehavior() routine.
-*/
-struct threadTestData {
- int fd; /* File to be locked */
- struct flock lock; /* The locking operation */
- int result; /* Result of the locking operation */
-};
-
-#if SQLITE_THREADSAFE && defined(__linux__)
-/*
-** This function is used as the main routine for a thread launched by
-** testThreadLockingBehavior(). It tests whether the shared-lock obtained
-** by the main thread in testThreadLockingBehavior() conflicts with a
-** hypothetical write-lock obtained by this thread on the same file.
-**
-** The write-lock is not actually acquired, as this is not possible if
-** the file is open in read-only mode (see ticket #3472).
+** Otherwise, if an error occurs, then successfully closed file descriptor
+** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
+** not deleted and SQLITE_IOERR_CLOSE returned.
*/
-static void *threadLockingTest(void *pArg){
- struct threadTestData *pData = (struct threadTestData*)pArg;
- pData->result = fcntl(pData->fd, F_GETLK, &pData->lock);
- return pArg;
-}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
-
-
-#if SQLITE_THREADSAFE && defined(__linux__)
-/*
-** This procedure attempts to determine whether or not threads
-** can override each others locks then sets the
-** threadsOverrideEachOthersLocks variable appropriately.
-*/
-static void testThreadLockingBehavior(int fd_orig){
- int fd;
- int rc;
- struct threadTestData d;
- struct flock l;
- pthread_t t;
-
- fd = dup(fd_orig);
- if( fd<0 ) return;
- memset(&l, 0, sizeof(l));
- l.l_type = F_RDLCK;
- l.l_len = 1;
- l.l_start = 0;
- l.l_whence = SEEK_SET;
- rc = fcntl(fd_orig, F_SETLK, &l);
- if( rc!=0 ) return;
- memset(&d, 0, sizeof(d));
- d.fd = fd;
- d.lock = l;
- d.lock.l_type = F_WRLCK;
- if( pthread_create(&t, 0, threadLockingTest, &d)==0 ){
- pthread_join(t, 0);
+static int closePendingFds(unixFile *pFile){
+ int rc = SQLITE_OK;
+ unixInodeInfo *pInode = pFile->pInode;
+ UnixUnusedFd *pError = 0;
+ UnixUnusedFd *p;
+ UnixUnusedFd *pNext;
+ for(p=pInode->pUnused; p; p=pNext){
+ pNext = p->pNext;
+ if( close(p->fd) ){
+ pFile->lastErrno = errno;
+ rc = SQLITE_IOERR_CLOSE;
+ p->pNext = pError;
+ pError = p;
+ }else{
+ sqlite3_free(p);
+ }
}
- close(fd);
- if( d.result!=0 ) return;
- threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK);
+ pInode->pUnused = pError;
+ return rc;
}
-#endif /* SQLITE_THREADSAFE && defined(__linux__) */
/*
-** Release a unixLockInfo structure previously allocated by findLockInfo().
+** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
*/
-static void releaseLockInfo(struct unixLockInfo *pLock){
+static void releaseInodeInfo(unixFile *pFile){
+ unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
- if( pLock ){
- pLock->nRef--;
- if( pLock->nRef==0 ){
- if( pLock->pPrev ){
- assert( pLock->pPrev->pNext==pLock );
- pLock->pPrev->pNext = pLock->pNext;
+ if( pInode ){
+ pInode->nRef--;
+ if( pInode->nRef==0 ){
+ assert( pInode->pShmNode==0 );
+ closePendingFds(pFile);
+ if( pInode->pPrev ){
+ assert( pInode->pPrev->pNext==pInode );
+ pInode->pPrev->pNext = pInode->pNext;
}else{
- assert( lockList==pLock );
- lockList = pLock->pNext;
+ assert( inodeList==pInode );
+ inodeList = pInode->pNext;
}
- if( pLock->pNext ){
- assert( pLock->pNext->pPrev==pLock );
- pLock->pNext->pPrev = pLock->pPrev;
+ if( pInode->pNext ){
+ assert( pInode->pNext->pPrev==pInode );
+ pInode->pNext->pPrev = pInode->pPrev;
}
- sqlite3_free(pLock);
+ sqlite3_free(pInode);
}
}
}
/*
-** Release a unixOpenCnt structure previously allocated by findLockInfo().
-**
-** The mutex entered using the unixEnterMutex() function must be held
-** when this function is called.
-*/
-static void releaseOpenCnt(struct unixOpenCnt *pOpen){
- assert( unixMutexHeld() );
- if( pOpen ){
- pOpen->nRef--;
- if( pOpen->nRef==0 ){
- if( pOpen->pPrev ){
- assert( pOpen->pPrev->pNext==pOpen );
- pOpen->pPrev->pNext = pOpen->pNext;
- }else{
- assert( openList==pOpen );
- openList = pOpen->pNext;
- }
- if( pOpen->pNext ){
- assert( pOpen->pNext->pPrev==pOpen );
- pOpen->pNext->pPrev = pOpen->pPrev;
- }
-#if SQLITE_THREADSAFE && defined(__linux__)
- assert( !pOpen->pUnused || threadsOverrideEachOthersLocks==0 );
-#endif
-
- /* If pOpen->pUnused is not null, then memory and file-descriptors
- ** are leaked.
- **
- ** This will only happen if, under Linuxthreads, the user has opened
- ** a transaction in one thread, then attempts to close the database
- ** handle from another thread (without first unlocking the db file).
- ** This is a misuse. */
- sqlite3_free(pOpen);
- }
- }
-}
-
-/*
-** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that
-** describes that file descriptor. Create new ones if necessary. The
-** return values might be uninitialized if an error occurs.
+** Given a file descriptor, locate the unixInodeInfo object that
+** describes that file descriptor. Create a new one if necessary. The
+** return value might be uninitialized if an error occurs.
**
** The mutex entered using the unixEnterMutex() function must be held
** when this function is called.
**
** Return an appropriate error code.
*/
-static int findLockInfo(
+static int findInodeInfo(
unixFile *pFile, /* Unix file with file desc used in the key */
- struct unixLockInfo **ppLock, /* Return the unixLockInfo structure here */
- struct unixOpenCnt **ppOpen /* Return the unixOpenCnt structure here */
+ unixInodeInfo **ppInode /* Return the unixInodeInfo object here */
){
int rc; /* System call return code */
int fd; /* The file descriptor for pFile */
- struct unixLockKey lockKey; /* Lookup key for the unixLockInfo structure */
- struct unixFileId fileId; /* Lookup key for the unixOpenCnt struct */
+ struct unixFileId fileId; /* Lookup key for the unixInodeInfo */
struct stat statbuf; /* Low-level file information */
- struct unixLockInfo *pLock = 0;/* Candidate unixLockInfo object */
- struct unixOpenCnt *pOpen; /* Candidate unixOpenCnt object */
+ unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */
assert( unixMutexHeld() );
@@ -22494,9 +23277,10 @@
** is a race condition such that another thread has already populated
** the first page of the database, no damage is done.
*/
- if( statbuf.st_size==0 ){
+ if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
rc = write(fd, "S", 1);
if( rc!=1 ){
+ pFile->lastErrno = errno;
return SQLITE_IOERR;
}
rc = fstat(fd, &statbuf);
@@ -22507,120 +23291,36 @@
}
#endif
- memset(&lockKey, 0, sizeof(lockKey));
- lockKey.fid.dev = statbuf.st_dev;
+ memset(&fileId, 0, sizeof(fileId));
+ fileId.dev = statbuf.st_dev;
#if OS_VXWORKS
- lockKey.fid.pId = pFile->pId;
+ fileId.pId = pFile->pId;
#else
- lockKey.fid.ino = statbuf.st_ino;
+ fileId.ino = statbuf.st_ino;
#endif
-#if SQLITE_THREADSAFE && defined(__linux__)
- if( threadsOverrideEachOthersLocks<0 ){
- testThreadLockingBehavior(fd);
+ pInode = inodeList;
+ while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
+ pInode = pInode->pNext;
}
- lockKey.tid = threadsOverrideEachOthersLocks ? 0 : pthread_self();
-#endif
- fileId = lockKey.fid;
- if( ppLock!=0 ){
- pLock = lockList;
- while( pLock && memcmp(&lockKey, &pLock->lockKey, sizeof(lockKey)) ){
- pLock = pLock->pNext;
+ if( pInode==0 ){
+ pInode = sqlite3_malloc( sizeof(*pInode) );
+ if( pInode==0 ){
+ return SQLITE_NOMEM;
}
- if( pLock==0 ){
- pLock = sqlite3_malloc( sizeof(*pLock) );
- if( pLock==0 ){
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memcpy(&pLock->lockKey,&lockKey,sizeof(lockKey));
- pLock->nRef = 1;
- pLock->cnt = 0;
- pLock->locktype = 0;
- pLock->pNext = lockList;
- pLock->pPrev = 0;
- if( lockList ) lockList->pPrev = pLock;
- lockList = pLock;
- }else{
- pLock->nRef++;
- }
- *ppLock = pLock;
+ memset(pInode, 0, sizeof(*pInode));
+ memcpy(&pInode->fileId, &fileId, sizeof(fileId));
+ pInode->nRef = 1;
+ pInode->pNext = inodeList;
+ pInode->pPrev = 0;
+ if( inodeList ) inodeList->pPrev = pInode;
+ inodeList = pInode;
+ }else{
+ pInode->nRef++;
}
- if( ppOpen!=0 ){
- pOpen = openList;
- while( pOpen && memcmp(&fileId, &pOpen->fileId, sizeof(fileId)) ){
- pOpen = pOpen->pNext;
- }
- if( pOpen==0 ){
- pOpen = sqlite3_malloc( sizeof(*pOpen) );
- if( pOpen==0 ){
- releaseLockInfo(pLock);
- rc = SQLITE_NOMEM;
- goto exit_findlockinfo;
- }
- memset(pOpen, 0, sizeof(*pOpen));
- pOpen->fileId = fileId;
- pOpen->nRef = 1;
- pOpen->pNext = openList;
- if( openList ) openList->pPrev = pOpen;
- openList = pOpen;
- }else{
- pOpen->nRef++;
- }
- *ppOpen = pOpen;
- }
-
-exit_findlockinfo:
- return rc;
+ *ppInode = pInode;
+ return SQLITE_OK;
}
-/*
-** If we are currently in a different thread than the thread that the
-** unixFile argument belongs to, then transfer ownership of the unixFile
-** over to the current thread.
-**
-** A unixFile is only owned by a thread on systems that use LinuxThreads.
-**
-** Ownership transfer is only allowed if the unixFile is currently unlocked.
-** If the unixFile is locked and an ownership is wrong, then return
-** SQLITE_MISUSE. SQLITE_OK is returned if everything works.
-*/
-#if SQLITE_THREADSAFE && defined(__linux__)
-static int transferOwnership(unixFile *pFile){
- int rc;
- pthread_t hSelf;
- if( threadsOverrideEachOthersLocks ){
- /* Ownership transfers not needed on this system */
- return SQLITE_OK;
- }
- hSelf = pthread_self();
- if( pthread_equal(pFile->tid, hSelf) ){
- /* We are still in the same thread */
- OSTRACE1("No-transfer, same thread\n");
- return SQLITE_OK;
- }
- if( pFile->locktype!=NO_LOCK ){
- /* We cannot change ownership while we are holding a lock! */
- return SQLITE_MISUSE_BKPT;
- }
- OSTRACE4("Transfer ownership of %d from %d to %d\n",
- pFile->h, pFile->tid, hSelf);
- pFile->tid = hSelf;
- if (pFile->pLock != NULL) {
- releaseLockInfo(pFile->pLock);
- rc = findLockInfo(pFile, &pFile->pLock, 0);
- OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
- locktypeName(pFile->locktype),
- locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
- return rc;
- } else {
- return SQLITE_OK;
- }
-}
-#else /* if not SQLITE_THREADSAFE */
- /* On single-threaded builds, ownership transfer is a no-op */
-# define transferOwnership(X) SQLITE_OK
-#endif /* SQLITE_THREADSAFE */
-
/*
** This routine checks if there is a RESERVED lock held on the specified
@@ -22636,10 +23336,10 @@
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
assert( pFile );
- unixEnterMutex(); /* Because pFile->pLock is shared across threads */
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( pFile->pLock->locktype>SHARED_LOCK ){
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -22663,70 +23363,14 @@
#endif
unixLeaveMutex();
- OSTRACE4("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Perform a file locking operation on a range of bytes in a file.
-** The "op" parameter should be one of F_RDLCK, F_WRLCK, or F_UNLCK.
-** Return 0 on success or -1 for failure. On failure, write the error
-** code into *pErrcode.
-**
-** If the SQLITE_WHOLE_FILE_LOCKING bit is clear, then only lock
-** the range of bytes on the locking page between SHARED_FIRST and
-** SHARED_SIZE. If SQLITE_WHOLE_FILE_LOCKING is set, then lock all
-** bytes from 0 up to but not including PENDING_BYTE, and all bytes
-** that follow SHARED_FIRST.
-**
-** In other words, of SQLITE_WHOLE_FILE_LOCKING if false (the historical
-** default case) then only lock a small range of bytes from SHARED_FIRST
-** through SHARED_FIRST+SHARED_SIZE-1. But if SQLITE_WHOLE_FILE_LOCKING is
-** true then lock every byte in the file except for PENDING_BYTE and
-** RESERVED_BYTE.
-**
-** SQLITE_WHOLE_FILE_LOCKING=true overlaps SQLITE_WHOLE_FILE_LOCKING=false
-** and so the locking schemes are compatible. One type of lock will
-** effectively exclude the other type. The reason for using the
-** SQLITE_WHOLE_FILE_LOCKING=true is that by indicating the full range
-** of bytes to be read or written, we give hints to NFS to help it
-** maintain cache coherency. On the other hand, whole file locking
-** is slower, so we don't want to use it except for NFS.
-*/
-static int rangeLock(unixFile *pFile, int op, int *pErrcode){
- struct flock lock;
- int rc;
- lock.l_type = op;
- lock.l_start = SHARED_FIRST;
- lock.l_whence = SEEK_SET;
- if( (pFile->fileFlags & SQLITE_WHOLE_FILE_LOCKING)==0 ){
- lock.l_len = SHARED_SIZE;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- *pErrcode = errno;
- }else{
- lock.l_len = 0;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- *pErrcode = errno;
- if( NEVER(op==F_UNLCK) || rc!=(-1) ){
- lock.l_start = 0;
- lock.l_len = PENDING_BYTE;
- rc = fcntl(pFile->h, F_SETLK, &lock);
- if( ALWAYS(op!=F_UNLCK) && rc==(-1) ){
- *pErrcode = errno;
- lock.l_type = F_UNLCK;
- lock.l_start = SHARED_FIRST;
- lock.l_len = 0;
- fcntl(pFile->h, F_SETLK, &lock);
- }
- }
- }
- return rc;
-}
-
-/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -22749,7 +23393,7 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int unixLock(sqlite3_file *id, int locktype){
+static int unixLock(sqlite3_file *id, int eFileLock){
/* The following describes the implementation of the various locks and
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
@@ -22790,23 +23434,23 @@
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- struct unixLockInfo *pLock = pFile->pLock;
+ unixInodeInfo *pInode = pFile->pInode;
struct flock lock;
int s = 0;
- int tErrno;
+ int tErrno = 0;
assert( pFile );
- OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype),
- locktypeName(pLock->locktype), pLock->cnt , getpid());
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (unix)\n", pFile->h,
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock),
+ azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the end_lock: exit path, as
** unixEnterMutex() hasn't been called yet.
*/
- if( pFile->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (unix)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
@@ -22815,28 +23459,20 @@
** (2) SQLite never explicitly requests a pendig lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+ assert( eFileLock!=PENDING_LOCK );
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
- /* This mutex is needed because pFile->pLock is shared across threads
+ /* This mutex is needed because pFile->pInode is shared across threads
*/
unixEnterMutex();
-
- /* Make sure the current thread owns the pFile.
- */
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
- }
- pLock = pFile->pLock;
+ pInode = pFile->pInode;
/* If some thread using this PID has a lock via a different unixFile*
** handle that precludes the requested lock, return BUSY.
*/
- if( (pFile->locktype!=pLock->locktype &&
- (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK))
+ if( (pFile->eFileLock!=pInode->eFileLock &&
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
goto end_lock;
@@ -22846,14 +23482,14 @@
** has a SHARED or RESERVED lock, then increment reference counts and
** return SQLITE_OK.
*/
- if( locktype==SHARED_LOCK &&
- (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
- assert( locktype==SHARED_LOCK );
- assert( pFile->locktype==0 );
- assert( pLock->cnt>0 );
- pFile->locktype = SHARED_LOCK;
- pLock->cnt++;
- pFile->pOpen->nLock++;
+ if( eFileLock==SHARED_LOCK &&
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+ assert( eFileLock==SHARED_LOCK );
+ assert( pFile->eFileLock==0 );
+ assert( pInode->nShared>0 );
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nShared++;
+ pInode->nLock++;
goto end_lock;
}
@@ -22864,10 +23500,10 @@
*/
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+ if( eFileLock==SHARED_LOCK
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
- lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
+ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
s = fcntl(pFile->h, F_SETLK, &lock);
if( s==(-1) ){
@@ -22884,13 +23520,16 @@
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- assert( pLock->cnt==0 );
- assert( pLock->locktype==0 );
+ if( eFileLock==SHARED_LOCK ){
+ assert( pInode->nShared==0 );
+ assert( pInode->eFileLock==0 );
/* Now get the read-lock */
- s = rangeLock(pFile, F_RDLCK, &tErrno);
-
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
+ if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
+ tErrno = errno;
+ }
/* Drop the temporary PENDING lock */
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
@@ -22912,11 +23551,11 @@
pFile->lastErrno = tErrno;
}
}else{
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
- pLock->cnt = 1;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
- }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
@@ -22925,21 +23564,22 @@
** assumed that there is a SHARED or greater lock on the file
** already.
*/
- assert( 0!=pFile->locktype );
+ assert( 0!=pFile->eFileLock );
lock.l_type = F_WRLCK;
- switch( locktype ){
+ switch( eFileLock ){
case RESERVED_LOCK:
lock.l_start = RESERVED_BYTE;
- s = fcntl(pFile->h, F_SETLK, &lock);
- tErrno = errno;
break;
case EXCLUSIVE_LOCK:
- s = rangeLock(pFile, F_WRLCK, &tErrno);
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
break;
default:
assert(0);
}
+ s = fcntl(pFile->h, F_SETLK, &lock);
if( s==(-1) ){
+ tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
@@ -22955,8 +23595,8 @@
** write operation (not a hot journal rollback).
*/
if( rc==SQLITE_OK
- && pFile->locktype<=SHARED_LOCK
- && locktype==RESERVED_LOCK
+ && pFile->eFileLock<=SHARED_LOCK
+ && eFileLock==RESERVED_LOCK
){
pFile->transCntrChng = 0;
pFile->dbUpdate = 0;
@@ -22966,47 +23606,17 @@
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- pLock->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
- pLock->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (unix)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
- return rc;
-}
-
-/*
-** Close all file descriptors accumuated in the unixOpenCnt->pUnused list.
-** If all such file descriptors are closed without error, the list is
-** cleared and SQLITE_OK returned.
-**
-** Otherwise, if an error occurs, then successfully closed file descriptor
-** entries are removed from the list, and SQLITE_IOERR_CLOSE returned.
-** not deleted and SQLITE_IOERR_CLOSE returned.
-*/
-static int closePendingFds(unixFile *pFile){
- int rc = SQLITE_OK;
- struct unixOpenCnt *pOpen = pFile->pOpen;
- UnixUnusedFd *pError = 0;
- UnixUnusedFd *p;
- UnixUnusedFd *pNext;
- for(p=pOpen->pUnused; p; p=pNext){
- pNext = p->pNext;
- if( close(p->fd) ){
- pFile->lastErrno = errno;
- rc = SQLITE_IOERR_CLOSE;
- p->pNext = pError;
- pError = p;
- }else{
- sqlite3_free(p);
- }
- }
- pOpen->pUnused = pError;
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
@@ -23015,46 +23625,50 @@
** pUnused list.
*/
static void setPendingFd(unixFile *pFile){
- struct unixOpenCnt *pOpen = pFile->pOpen;
+ unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *p = pFile->pUnused;
- p->pNext = pOpen->pUnused;
- pOpen->pUnused = p;
+ p->pNext = pInode->pUnused;
+ pInode->pUnused = p;
pFile->h = -1;
pFile->pUnused = 0;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
+**
+** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
+** the byte range is divided into 2 parts and the first part is unlocked then
+** set to a read lock, then the other part is simply unlocked. This works
+** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
+** remove the write lock on a region when a read lock is set.
*/
-static int unixUnlock(sqlite3_file *id, int locktype){
- unixFile *pFile = (unixFile*)id; /* The open file */
- struct unixLockInfo *pLock; /* Structure describing current lock state */
- struct flock lock; /* Information passed into fcntl() */
- int rc = SQLITE_OK; /* Return code from this interface */
- int h; /* The underlying file descriptor */
+static int _posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
+ unixFile *pFile = (unixFile*)id;
+ unixInodeInfo *pInode;
+ struct flock lock;
+ int rc = SQLITE_OK;
+ int h;
int tErrno; /* Error code from system call errors */
assert( pFile );
- OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, locktype,
- pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (unix)\n", pFile->h, eFileLock,
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
+ getpid()));
- assert( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
h = pFile->h;
- pLock = pFile->pLock;
- assert( pLock->cnt!=0 );
- if( pFile->locktype>SHARED_LOCK ){
- assert( pLock->locktype==pFile->locktype );
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
@@ -23068,20 +23682,76 @@
** the file has changed and hence might not know to flush their
** cache. The use of a stale cache can lead to database corruption.
*/
+#if 0
assert( pFile->inNormalWrite==0
|| pFile->dbUpdate==0
|| pFile->transCntrChng==1 );
+#endif
pFile->inNormalWrite = 0;
#endif
-
- if( locktype==SHARED_LOCK ){
- if( rangeLock(pFile, F_RDLCK, &tErrno)==(-1) ){
- rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
- if( IS_LOCK_ERROR(rc) ){
- pFile->lastErrno = tErrno;
+ /* downgrading to a shared lock on NFS involves clearing the write lock
+ ** before establishing the readlock - to avoid a race condition we downgrade
+ ** the lock in 2 blocks, so that part of the range will be covered by a
+ ** write lock until the rest is covered by a read lock:
+ ** 1: [WWWWW]
+ ** 2: [....W]
+ ** 3: [RRRRW]
+ ** 4: [RRRR.]
+ */
+ if( eFileLock==SHARED_LOCK ){
+ if( handleNFSUnlock ){
+ off_t divSize = SHARED_SIZE - 1;
+
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
}
- goto end_unlock;
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST+divSize;
+ lock.l_len = SHARED_SIZE-divSize;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
+ }else{
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = SHARED_FIRST;
+ lock.l_len = SHARED_SIZE;
+ if( fcntl(h, F_SETLK, &lock)==(-1) ){
+ tErrno = errno;
+ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
+ if( IS_LOCK_ERROR(rc) ){
+ pFile->lastErrno = tErrno;
+ }
+ goto end_unlock;
+ }
}
}
lock.l_type = F_UNLCK;
@@ -23089,7 +23759,7 @@
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = SHARED_LOCK;
+ pInode->eFileLock = SHARED_LOCK;
}else{
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
@@ -23099,15 +23769,13 @@
goto end_unlock;
}
}
- if( locktype==NO_LOCK ){
- struct unixOpenCnt *pOpen;
-
+ if( eFileLock==NO_LOCK ){
/* Decrement the shared lock counter. Release the lock using an
** OS call only when all threads in this same process have released
** the lock.
*/
- pLock->cnt--;
- if( pLock->cnt==0 ){
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
@@ -23115,15 +23783,15 @@
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
if( fcntl(h, F_SETLK, &lock)!=(-1) ){
- pLock->locktype = NO_LOCK;
+ pInode->eFileLock = NO_LOCK;
}else{
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
- pLock->locktype = NO_LOCK;
- pFile->locktype = NO_LOCK;
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
}
}
@@ -23131,10 +23799,9 @@
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
*/
- pOpen = pFile->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
int rc2 = closePendingFds(pFile);
if( rc==SQLITE_OK ){
rc = rc2;
@@ -23144,11 +23811,22 @@
end_unlock:
unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->locktype = locktype;
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
/*
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+** must be either NO_LOCK or SHARED_LOCK.
+**
+** If the locking level of the file descriptor is already at or below
+** the requested locking level, this routine is a no-op.
+*/
+static int unixUnlock(sqlite3_file *id, int eFileLock){
+ return _posixUnlock(id, eFileLock, 0);
+}
+
+/*
** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
** handles, if they are valid, and sets all fields of the unixFile
@@ -23186,7 +23864,7 @@
pFile->pId = 0;
}
#endif
- OSTRACE2("CLOSE %-3d\n", pFile->h);
+ OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
sqlite3_free(pFile->pUnused);
memset(pFile, 0, sizeof(unixFile));
@@ -23203,16 +23881,15 @@
unixFile *pFile = (unixFile *)id;
unixUnlock(id, NO_LOCK);
unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->nLock ){
+ if( pFile->pInode && pFile->pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->pUnused list. It will be automatically closed
+ ** descriptor to pInode->pUnused list. It will be automatically closed
** when the last lock is cleared.
*/
setPendingFd(pFile);
}
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
rc = closeUnixFile(id);
unixLeaveMutex();
}
@@ -23311,7 +23988,7 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
/* Either this connection or some other connection in the same process
** holds a lock on the file. No need to check further. */
reserved = 1;
@@ -23320,13 +23997,13 @@
const char *zLockFile = (const char*)pFile->lockingContext;
reserved = access(zLockFile, 0)==0;
}
- OSTRACE4("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23352,7 +24029,7 @@
** With dotfile locking, we really only support state (4): EXCLUSIVE.
** But we track the other locking levels internally.
*/
-static int dotlockLock(sqlite3_file *id, int locktype) {
+static int dotlockLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
char *zLockFile = (char *)pFile->lockingContext;
@@ -23362,8 +24039,8 @@
/* If we have any lock, then the lock file already exists. All we have
** to do is adjust our internal record of the lock level.
*/
- if( pFile->locktype > NO_LOCK ){
- pFile->locktype = locktype;
+ if( pFile->eFileLock > NO_LOCK ){
+ pFile->eFileLock = eFileLock;
#if !OS_VXWORKS
/* Always update the timestamp on the old file */
utimes(zLockFile, NULL);
@@ -23392,12 +24069,12 @@
}
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
@@ -23405,30 +24082,30 @@
**
** When the locking level reaches NO_LOCK, delete the lock file.
*/
-static int dotlockUnlock(sqlite3_file *id, int locktype) {
+static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
char *zLockFile = (char *)pFile->lockingContext;
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* To downgrade to shared, simply update our internal notion of the
** lock state. No need to mess with the file on disk.
*/
- if( locktype==SHARED_LOCK ){
- pFile->locktype = SHARED_LOCK;
+ if( eFileLock==SHARED_LOCK ){
+ pFile->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
/* To fully unlock the database, delete the lock file */
- assert( locktype==NO_LOCK );
+ assert( eFileLock==NO_LOCK );
if( unlink(zLockFile) ){
int rc = 0;
int tErrno = errno;
@@ -23440,7 +24117,7 @@
}
return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -23493,7 +24170,7 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -23524,7 +24201,7 @@
}
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
@@ -23537,7 +24214,7 @@
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23565,7 +24242,7 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int flockLock(sqlite3_file *id, int locktype) {
+static int flockLock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -23573,8 +24250,8 @@
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23589,10 +24266,10 @@
}
} else {
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
}
- OSTRACE4("LOCK %d %s %s (flock)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
@@ -23603,28 +24280,28 @@
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int flockUnlock(sqlite3_file *id, int locktype) {
+static int flockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23644,7 +24321,7 @@
return r;
} else {
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
}
@@ -23692,13 +24369,13 @@
assert( pFile );
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
/* Otherwise see if some other process holds it. */
if( !reserved ){
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
struct stat statBuf;
if( sem_trywait(pSem)==-1 ){
@@ -23708,21 +24385,21 @@
pFile->lastErrno = tErrno;
} else {
/* someone else has the lock when we are in NO_LOCK */
- reserved = (pFile->locktype < SHARED_LOCK);
+ reserved = (pFile->eFileLock < SHARED_LOCK);
}
}else{
/* we could have it if we want it */
sem_post(pSem);
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved);
+ OSTRACE(("TEST WR-LOCK %d %d %d (sem)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23750,16 +24427,16 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int semLock(sqlite3_file *id, int locktype) {
+static int semLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int fd;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
/* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
- if (pFile->locktype > NO_LOCK) {
- pFile->locktype = locktype;
+ if (pFile->eFileLock > NO_LOCK) {
+ pFile->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
@@ -23771,37 +24448,37 @@
}
/* got it, set the type and return ok */
- pFile->locktype = locktype;
+ pFile->eFileLock = eFileLock;
sem_end_lock:
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int semUnlock(sqlite3_file *id, int locktype) {
+static int semUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
- sem_t *pSem = pFile->pOpen->pSem;
+ sem_t *pSem = pFile->pInode->pSem;
assert( pFile );
assert( pSem );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, locktype,
- pFile->locktype, getpid());
- assert( locktype<=SHARED_LOCK );
+ OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
+ pFile->eFileLock, getpid()));
+ assert( eFileLock<=SHARED_LOCK );
/* no-op if possible */
- if( pFile->locktype==locktype ){
+ if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
/* shared can just be set because we always have an exclusive */
- if (locktype==SHARED_LOCK) {
- pFile->locktype = locktype;
+ if (eFileLock==SHARED_LOCK) {
+ pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
@@ -23814,7 +24491,7 @@
}
return rc;
}
- pFile->locktype = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
}
@@ -23827,8 +24504,7 @@
semUnlock(id, NO_LOCK);
assert( pFile );
unixEnterMutex();
- releaseLockInfo(pFile->pLock);
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
unixLeaveMutex();
closeUnixFile(id);
}
@@ -23859,7 +24535,7 @@
*/
typedef struct afpLockingContext afpLockingContext;
struct afpLockingContext {
- unsigned long long sharedByte;
+ int reserved;
const char *dbPath; /* Name of the open file */
};
@@ -23897,15 +24573,15 @@
pb.length = length;
pb.fd = pFile->h;
- OSTRACE6("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
(setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
- offset, length);
+ offset, length));
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
if ( err==-1 ) {
int rc;
int tErrno = errno;
- OSTRACE4("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
- path, tErrno, strerror(tErrno));
+ OSTRACE(("AFPSETLOCK failed to fsctl() '%s' %d %s\n",
+ path, tErrno, strerror(tErrno)));
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
rc = SQLITE_BUSY;
#else
@@ -23936,9 +24612,14 @@
assert( pFile );
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ if( context->reserved ){
+ *pResOut = 1;
+ return SQLITE_OK;
+ }
+ unixEnterMutex(); /* Because pFile->pInode is shared across threads */
/* Check if a thread in this process holds such a lock */
- if( pFile->locktype>SHARED_LOCK ){
+ if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
@@ -23960,14 +24641,15 @@
}
}
- OSTRACE4("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved);
+ unixLeaveMutex();
+ OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
*pResOut = reserved;
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -23990,49 +24672,72 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int afpLock(sqlite3_file *id, int locktype){
+static int afpLock(sqlite3_file *id, int eFileLock){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
+ unixInodeInfo *pInode = pFile->pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
assert( pFile );
- OSTRACE5("LOCK %d %s was %s pid=%d (afp)\n", pFile->h,
- locktypeName(locktype), locktypeName(pFile->locktype), getpid());
+ OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
+ azFileLock(eFileLock), azFileLock(pFile->eFileLock),
+ azFileLock(pInode->eFileLock), pInode->nShared , getpid()));
/* If there is already a lock of this type or more restrictive on the
** unixFile, do nothing. Don't use the afp_end_lock: exit path, as
** unixEnterMutex() hasn't been called yet.
*/
- if( pFile->locktype>=locktype ){
- OSTRACE3("LOCK %d %s ok (already held) (afp)\n", pFile->h,
- locktypeName(locktype));
+ if( pFile->eFileLock>=eFileLock ){
+ OSTRACE(("LOCK %d %s ok (already held) (afp)\n", pFile->h,
+ azFileLock(eFileLock)));
return SQLITE_OK;
}
/* Make sure the locking sequence is correct
+ ** (1) We never move from unlocked to anything higher than shared lock.
+ ** (2) SQLite never explicitly requests a pendig lock.
+ ** (3) A shared lock is always held when a reserve lock is requested.
*/
- assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
- assert( locktype!=PENDING_LOCK );
- assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
+ assert( eFileLock!=PENDING_LOCK );
+ assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
- /* This mutex is needed because pFile->pLock is shared across threads
+ /* This mutex is needed because pFile->pInode is shared across threads
*/
unixEnterMutex();
+ pInode = pFile->pInode;
- /* Make sure the current thread owns the pFile.
+ /* If some thread using this PID has a lock via a different unixFile*
+ ** handle that precludes the requested lock, return BUSY.
*/
- rc = transferOwnership(pFile);
- if( rc!=SQLITE_OK ){
- unixLeaveMutex();
- return rc;
+ if( (pFile->eFileLock!=pInode->eFileLock &&
+ (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
+ ){
+ rc = SQLITE_BUSY;
+ goto afp_end_lock;
+ }
+
+ /* If a SHARED lock is requested, and some thread using this PID already
+ ** has a SHARED or RESERVED lock, then increment reference counts and
+ ** return SQLITE_OK.
+ */
+ if( eFileLock==SHARED_LOCK &&
+ (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
+ assert( eFileLock==SHARED_LOCK );
+ assert( pFile->eFileLock==0 );
+ assert( pInode->nShared>0 );
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nShared++;
+ pInode->nLock++;
+ goto afp_end_lock;
}
/* A PENDING lock is needed before acquiring a SHARED lock and before
** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
** be released.
*/
- if( locktype==SHARED_LOCK
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK)
+ if( eFileLock==SHARED_LOCK
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
int failed;
failed = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 1);
@@ -24045,16 +24750,20 @@
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
- if( locktype==SHARED_LOCK ){
- int lk, lrc1, lrc2;
- int lrc1Errno = 0;
+ if( eFileLock==SHARED_LOCK ){
+ int lrc1, lrc2, lrc1Errno;
+ long lk, mask;
+ assert( pInode->nShared==0 );
+ assert( pInode->eFileLock==0 );
+
+ mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
/* Now get the read-lock SHARED_LOCK */
/* note that the quality of the randomness doesn't matter that much */
lk = random();
- context->sharedByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
lrc1 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST+context->sharedByte, 1, 1);
+ SHARED_FIRST+pInode->sharedByte, 1, 1);
if( IS_LOCK_ERROR(lrc1) ){
lrc1Errno = pFile->lastErrno;
}
@@ -24071,34 +24780,42 @@
} else if( lrc1 != SQLITE_OK ) {
rc = lrc1;
} else {
- pFile->locktype = SHARED_LOCK;
- pFile->pOpen->nLock++;
+ pFile->eFileLock = SHARED_LOCK;
+ pInode->nLock++;
+ pInode->nShared = 1;
}
+ }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
+ /* We are trying for an exclusive lock but another thread in this
+ ** same process is still holding a shared lock. */
+ rc = SQLITE_BUSY;
}else{
/* The request was for a RESERVED or EXCLUSIVE lock. It is
** assumed that there is a SHARED or greater lock on the file
** already.
*/
int failed = 0;
- assert( 0!=pFile->locktype );
- if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
+ assert( 0!=pFile->eFileLock );
+ if (eFileLock >= RESERVED_LOCK && pFile->eFileLock < RESERVED_LOCK) {
/* Acquire a RESERVED lock */
failed = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
+ if( !failed ){
+ context->reserved = 1;
+ }
}
- if (!failed && locktype == EXCLUSIVE_LOCK) {
+ if (!failed && eFileLock == EXCLUSIVE_LOCK) {
/* Acquire an EXCLUSIVE lock */
/* Remove the shared lock before trying the range. we'll need to
** reestablish the shared lock if we can't get the afpUnlock
*/
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
- context->sharedByte, 1, 0)) ){
+ pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
/* now attemmpt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
- SHARED_FIRST + context->sharedByte, 1, 1)) ){
+ SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
/* Can't reestablish the shared lock. Sqlite can't deal, this is
** a critical I/O error
*/
@@ -24116,78 +24833,124 @@
}
if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- }else if( locktype==EXCLUSIVE_LOCK ){
- pFile->locktype = PENDING_LOCK;
+ pFile->eFileLock = eFileLock;
+ pInode->eFileLock = eFileLock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
afp_end_lock:
unixLeaveMutex();
- OSTRACE4("LOCK %d %s %s (afp)\n", pFile->h, locktypeName(locktype),
- rc==SQLITE_OK ? "ok" : "failed");
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
+ rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int afpUnlock(sqlite3_file *id, int locktype) {
+static int afpUnlock(sqlite3_file *id, int eFileLock) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
- afpLockingContext *pCtx = (afpLockingContext *) pFile->lockingContext;
+ unixInodeInfo *pInode;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ int skipShared = 0;
+#ifdef SQLITE_TEST
+ int h = pFile->h;
+#endif
assert( pFile );
- OSTRACE5("UNLOCK %d %d was %d pid=%d (afp)\n", pFile->h, locktype,
- pFile->locktype, getpid());
+ OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
+ pFile->eFileLock, pFile->pInode->eFileLock, pFile->pInode->nShared,
+ getpid()));
- assert( locktype<=SHARED_LOCK );
- if( pFile->locktype<=locktype ){
+ assert( eFileLock<=SHARED_LOCK );
+ if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- if( CHECK_THREADID(pFile) ){
- return SQLITE_MISUSE_BKPT;
- }
unixEnterMutex();
- if( pFile->locktype>SHARED_LOCK ){
+ pInode = pFile->pInode;
+ assert( pInode->nShared!=0 );
+ if( pFile->eFileLock>SHARED_LOCK ){
+ assert( pInode->eFileLock==pFile->eFileLock );
+ SimulateIOErrorBenign(1);
+ SimulateIOError( h=(-1) )
+ SimulateIOErrorBenign(0);
- if( pFile->locktype==EXCLUSIVE_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
- if( rc==SQLITE_OK && locktype==SHARED_LOCK ){
+#ifndef NDEBUG
+ /* When reducing a lock such that other processes can start
+ ** reading the database file again, make sure that the
+ ** transaction counter was updated if any part of the database
+ ** file changed. If the transaction counter is not updated,
+ ** other connections to the same file might not realize that
+ ** the file has changed and hence might not know to flush their
+ ** cache. The use of a stale cache can lead to database corruption.
+ */
+ assert( pFile->inNormalWrite==0
+ || pFile->dbUpdate==0
+ || pFile->transCntrChng==1 );
+ pFile->inNormalWrite = 0;
+#endif
+
+ if( pFile->eFileLock==EXCLUSIVE_LOCK ){
+ rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
/* only re-establish the shared lock if necessary */
- int sharedLockByte = SHARED_FIRST+pCtx->sharedByte;
- rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 1);
+ int sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 1);
+ } else {
+ skipShared = 1;
}
}
- if( rc==SQLITE_OK && pFile->locktype>=PENDING_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, PENDING_BYTE, 1, 0);
+ if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
+ rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
}
- if( rc==SQLITE_OK && pFile->locktype>=RESERVED_LOCK ){
- rc = afpSetLock(pCtx->dbPath, pFile, RESERVED_BYTE, 1, 0);
+ if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
+ rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
+ if( !rc ){
+ context->reserved = 0;
+ }
}
- }else if( locktype==NO_LOCK ){
- /* clear the shared lock */
- int sharedLockByte = SHARED_FIRST+pCtx->sharedByte;
- rc = afpSetLock(pCtx->dbPath, pFile, sharedLockByte, 1, 0);
+ if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
+ pInode->eFileLock = SHARED_LOCK;
+ }
}
+ if( rc==SQLITE_OK && eFileLock==NO_LOCK ){
- if( rc==SQLITE_OK ){
- if( locktype==NO_LOCK ){
- struct unixOpenCnt *pOpen = pFile->pOpen;
- pOpen->nLock--;
- assert( pOpen->nLock>=0 );
- if( pOpen->nLock==0 ){
+ /* Decrement the shared lock counter. Release the lock using an
+ ** OS call only when all threads in this same process have released
+ ** the lock.
+ */
+ unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
+ pInode->nShared--;
+ if( pInode->nShared==0 ){
+ SimulateIOErrorBenign(1);
+ SimulateIOError( h=(-1) )
+ SimulateIOErrorBenign(0);
+ if( !skipShared ){
+ rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
+ }
+ if( !rc ){
+ pInode->eFileLock = NO_LOCK;
+ pFile->eFileLock = NO_LOCK;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInode->nLock--;
+ assert( pInode->nLock>=0 );
+ if( pInode->nLock==0 ){
rc = closePendingFds(pFile);
}
}
}
+
unixLeaveMutex();
- if( rc==SQLITE_OK ){
- pFile->locktype = locktype;
- }
+ if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
return rc;
}
@@ -24195,24 +24958,25 @@
** Close a file & cleanup AFP specific locking context
*/
static int afpClose(sqlite3_file *id) {
+ int rc = SQLITE_OK;
if( id ){
unixFile *pFile = (unixFile*)id;
afpUnlock(id, NO_LOCK);
unixEnterMutex();
- if( pFile->pOpen && pFile->pOpen->nLock ){
+ if( pFile->pInode && pFile->pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->aPending. It will be automatically closed when
+ ** descriptor to pInode->aPending. It will be automatically closed when
** the last lock is cleared.
*/
setPendingFd(pFile);
}
- releaseOpenCnt(pFile->pOpen);
+ releaseInodeInfo(pFile);
sqlite3_free(pFile->lockingContext);
- closeUnixFile(id);
+ rc = closeUnixFile(id);
unixLeaveMutex();
}
- return SQLITE_OK;
+ return rc;
}
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
@@ -24225,6 +24989,29 @@
********************* End of the AFP lock implementation **********************
******************************************************************************/
+/******************************************************************************
+*************************** Begin NFS Locking ********************************/
+
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+/*
+ ** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
+ ** must be either NO_LOCK or SHARED_LOCK.
+ **
+ ** If the locking level of the file descriptor is already at or below
+ ** the requested locking level, this routine is a no-op.
+ */
+static int nfsUnlock(sqlite3_file *id, int eFileLock){
+ return _posixUnlock(id, eFileLock, 1);
+}
+
+#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
+/*
+** The code above is the NFS lock implementation. The code is specific
+** to MacOSX and does not work on other unix platforms. No alternative
+** is available.
+**
+********************* End of the NFS lock implementation **********************
+******************************************************************************/
/******************************************************************************
**************** Non-locking sqlite3_file methods *****************************
@@ -24251,7 +25038,9 @@
*/
static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
int got;
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
+#endif
TIMER_START;
#if defined(USE_PREAD)
got = pread(id->h, pBuf, cnt, offset);
@@ -24276,7 +25065,7 @@
if( got<0 ){
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -24297,10 +25086,12 @@
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
+#if 0
assert( pFile->pUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
+#endif
got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){
@@ -24325,7 +25116,9 @@
*/
static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
int got;
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
i64 newOffset;
+#endif
TIMER_START;
#if defined(USE_PREAD)
got = pwrite(id->h, pBuf, cnt, offset);
@@ -24348,7 +25141,7 @@
((unixFile*)id)->lastErrno = errno;
}
- OSTRACE5("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED);
+ OSTRACE(("WRITE %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
return got;
}
@@ -24370,10 +25163,12 @@
/* If this is a database file (not a journal, master-journal or temp
** file), the bytes in the locking range should never be read or written. */
+#if 0
assert( pFile->pUnused==0
|| offset>=PENDING_BYTE+512
|| offset+amt<=PENDING_BYTE
);
+#endif
#ifndef NDEBUG
/* If we are doing a normal write to a database file (as opposed to
@@ -24519,6 +25314,11 @@
*/
if( rc ) rc = fsync(fd);
+#elif defined(__APPLE__)
+ /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
+ ** so currently we default to the macro that redefines fdatasync to fsync
+ */
+ rc = fsync(fd);
#else
rc = fdatasync(fd);
#if OS_VXWORKS
@@ -24567,7 +25367,7 @@
SimulateDiskfullError( return SQLITE_FULL );
assert( pFile );
- OSTRACE2("SYNC %-3d\n", pFile->h);
+ OSTRACE(("SYNC %-3d\n", pFile->h));
rc = full_fsync(pFile->h, isFullsync, isDataOnly);
SimulateIOError( rc=1 );
if( rc ){
@@ -24576,8 +25376,8 @@
}
if( pFile->dirfd>=0 ){
int err;
- OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
- HAVE_FULLFSYNC, isFullsync);
+ OSTRACE(("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
+ HAVE_FULLFSYNC, isFullsync));
#ifndef SQLITE_DISABLE_DIRSYNC
/* The directory sync is only attempted if full_fsync is
** turned off or unavailable. If a full_fsync occurred above,
@@ -24649,7 +25449,7 @@
}
*pSize = buf.st_size;
- /* When opening a zero-size database, the findLockInfo() procedure
+ /* When opening a zero-size database, the findInodeInfo() procedure
** writes a single byte into that file in order to work around a bug
** in the OS-X msdos filesystem. In order to avoid problems with upper
** layers, we need to report this file size as zero even though it is
@@ -24676,13 +25476,21 @@
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
switch( op ){
case SQLITE_FCNTL_LOCKSTATE: {
- *(int*)pArg = ((unixFile*)id)->locktype;
+ *(int*)pArg = ((unixFile*)id)->eFileLock;
return SQLITE_OK;
}
case SQLITE_LAST_ERRNO: {
*(int*)pArg = ((unixFile*)id)->lastErrno;
return SQLITE_OK;
}
+ case SQLITE_FCNTL_SIZE_HINT: {
+#if 0 /* No performance advantage seen on Linux */
+ sqlite3_int64 szFile = *(sqlite3_int64*)pArg;
+ unixFile *pFile = (unixFile*)id;
+ ftruncate(pFile->h, szFile);
+#endif
+ return SQLITE_OK;
+ }
#ifndef NDEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@@ -24727,6 +25535,562 @@
return 0;
}
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** Object used to represent an shared memory buffer.
+**
+** When multiple threads all reference the same wal-index, each thread
+** has its own unixShm object, but they all point to a single instance
+** of this unixShmNode object. In other words, each wal-index is opened
+** only once per process.
+**
+** Each unixShmNode object is connected to a single unixInodeInfo object.
+** We could coalesce this object into unixInodeInfo, but that would mean
+** every open file that does not use shared memory (in other words, most
+** open files) would have to carry around this extra information. So
+** the unixInodeInfo object contains a pointer to this unixShmNode object
+** and the unixShmNode object is created only when needed.
+**
+** unixMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
+**
+** nRef
+**
+** The following fields are read-only after the object is created:
+**
+** fid
+** zFilename
+**
+** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
+** unixMutexHeld() is true when reading or writing any other field
+** in this structure.
+*/
+struct unixShmNode {
+ unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ char *zFilename; /* Name of the mmapped file */
+ int h; /* Open file descriptor */
+ int szRegion; /* Size of shared-memory regions */
+ int nRegion; /* Size of array apRegion */
+ char **apRegion; /* Array of mapped shared-memory regions */
+ int nRef; /* Number of unixShm objects pointing to this */
+ unixShm *pFirst; /* All unixShm objects pointing to this */
+#ifdef SQLITE_DEBUG
+ u8 exclMask; /* Mask of exclusive locks held */
+ u8 sharedMask; /* Mask of shared locks held */
+ u8 nextShmId; /* Next available unixShm.id value */
+#endif
+};
+
+/*
+** Structure used internally by this VFS to record the state of an
+** open shared memory connection.
+**
+** The following fields are initialized when this object is created and
+** are read-only thereafter:
+**
+** unixShm.pFile
+** unixShm.id
+**
+** All other fields are read/write. The unixShm.pFile->mutex must be held
+** while accessing any read/write fields.
+*/
+struct unixShm {
+ unixShmNode *pShmNode; /* The underlying unixShmNode object */
+ unixShm *pNext; /* Next unixShm with the same unixShmNode */
+ u8 hasMutex; /* True if holding the unixShmNode mutex */
+ u16 sharedMask; /* Mask of shared locks held */
+ u16 exclMask; /* Mask of exclusive locks held */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection within its unixShmNode */
+#endif
+};
+
+/*
+** Constants used for locking
+*/
+#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
+**
+** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking
+** otherwise.
+*/
+static int unixShmSystemLock(
+ unixShmNode *pShmNode, /* Apply locks to this open shared-memory segment */
+ int lockType, /* F_UNLCK, F_RDLCK, or F_WRLCK */
+ int ofst, /* First byte of the locking range */
+ int n /* Number of bytes to lock */
+){
+ struct flock f; /* The posix advisory locking structure */
+ int rc = SQLITE_OK; /* Result code form fcntl() */
+
+ /* Access to the unixShmNode object is serialized by the caller */
+ assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
+
+ /* Shared locks never span more than one byte */
+ assert( n==1 || lockType!=F_RDLCK );
+
+ /* Locks are within range */
+ assert( n>=1 && n<SQLITE_SHM_NLOCK );
+
+ /* Initialize the locking parameters */
+ memset(&f, 0, sizeof(f));
+ f.l_type = lockType;
+ f.l_whence = SEEK_SET;
+ f.l_start = ofst;
+ f.l_len = n;
+
+ rc = fcntl(pShmNode->h, F_SETLK, &f);
+ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+
+ /* Update the global lock state and do debug tracing */
+#ifdef SQLITE_DEBUG
+ { u16 mask;
+ OSTRACE(("SHM-LOCK "));
+ mask = (1<<(ofst+n)) - (1<<ofst);
+ if( rc==SQLITE_OK ){
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock %d ok", ofst));
+ pShmNode->exclMask &= ~mask;
+ pShmNode->sharedMask &= ~mask;
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock %d ok", ofst));
+ pShmNode->exclMask &= ~mask;
+ pShmNode->sharedMask |= mask;
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock %d ok", ofst));
+ pShmNode->exclMask |= mask;
+ pShmNode->sharedMask &= ~mask;
+ }
+ }else{
+ if( lockType==F_UNLCK ){
+ OSTRACE(("unlock %d failed", ofst));
+ }else if( lockType==F_RDLCK ){
+ OSTRACE(("read-lock failed"));
+ }else{
+ assert( lockType==F_WRLCK );
+ OSTRACE(("write-lock %d failed", ofst));
+ }
+ }
+ OSTRACE((" - afterwards %03x,%03x\n",
+ pShmNode->sharedMask, pShmNode->exclMask));
+ }
+#endif
+
+ return rc;
+}
+
+
+/*
+** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void unixShmPurge(unixFile *pFd){
+ unixShmNode *p = pFd->pInode->pShmNode;
+ assert( unixMutexHeld() );
+ if( p && p->nRef==0 ){
+ int i;
+ assert( p->pInode==pFd->pInode );
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ for(i=0; i<p->nRegion; i++){
+ munmap(p->apRegion[i], p->szRegion);
+ }
+ sqlite3_free(p->apRegion);
+ if( p->h>=0 ) close(p->h);
+ p->pInode->pShmNode = 0;
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Open a shared-memory area associated with open database file fd.
+** This particular implementation uses mmapped files.
+**
+** The file used to implement shared-memory is in the same directory
+** as the open database file and has the same name as the open database
+** file with the "-shm" suffix added. For example, if the database file
+** is "/home/user1/config.db" then the file that is created and mmapped
+** for shared memory will be called "/home/user1/config.db-shm". We
+** experimented with using files in /dev/tmp or an some other tmpfs mount.
+** But if a file in a different directory from the database file is used,
+** then differing access permissions or a chroot() might cause two different
+** processes on the same database to end up using different files for
+** shared memory - meaning that their memory would not really be shared -
+** resulting in database corruption.
+**
+** When opening a new shared-memory file, if no other instances of that
+** file are currently open, in this process or in other processes, then
+** the file must be truncated to zero length or have its header cleared.
+*/
+static int unixShmOpen(
+ sqlite3_file *fd /* The file descriptor of the associated database */
+){
+ struct unixShm *p = 0; /* The connection to be opened */
+ struct unixShmNode *pShmNode = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct unixFile *pDbFd; /* Underlying database file */
+ unixInodeInfo *pInode; /* The inode of fd */
+ char *zShmFilename; /* Name of the file used for SHM */
+ int nShmFilename; /* Size of the SHM filename in bytes */
+
+ /* Allocate space for the new sqlite3_shm object.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ pDbFd = (struct unixFile*)fd;
+ assert( pDbFd->pShm==0 );
+
+ /* Check to see if a unixShmNode object already exists. Reuse an existing
+ ** one if present. Create a new one if necessary.
+ */
+ unixEnterMutex();
+ pInode = pDbFd->pInode;
+ pShmNode = pInode->pShmNode;
+ if( pShmNode==0 ){
+ nShmFilename = 5 + (int)strlen(pDbFd->zPath);
+ pShmNode = sqlite3_malloc( sizeof(*pShmNode) + nShmFilename );
+ if( pShmNode==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+ memset(pShmNode, 0, sizeof(*pShmNode));
+ zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
+ sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+ pShmNode->h = -1;
+ pDbFd->pInode->pShmNode = pShmNode;
+ pShmNode->pInode = pDbFd->pInode;
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+
+ pShmNode->h = open(zShmFilename, O_RDWR|O_CREAT, 0664);
+ if( pShmNode->h<0 ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ rc = SQLITE_OK;
+ if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
+ if( ftruncate(pShmNode->h, 0) ){
+ rc = SQLITE_IOERR_SHMOPEN;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the unixShmNode */
+ p->pShmNode = pShmNode;
+ p->pNext = pShmNode->pFirst;
+#ifdef SQLITE_DEBUG
+ p->id = pShmNode->nextShmId++;
+#endif
+ pShmNode->pFirst = p;
+ pShmNode->nRef++;
+ pDbFd->pShm = p;
+ unixLeaveMutex();
+ return SQLITE_OK;
+
+ /* Jump here on any error */
+shm_open_err:
+ unixShmPurge(pDbFd); /* This call frees pShmNode if required */
+ sqlite3_free(p);
+ unixLeaveMutex();
+ return rc;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int unixShmClose(
+ sqlite3_file *fd, /* The underlying database file */
+ int deleteFlag /* Delete shared-memory if true */
+){
+ unixShm *p; /* The connection to be closed */
+ unixShmNode *pShmNode; /* The underlying shared-memory file */
+ unixShm **pp; /* For looping over sibling connections */
+ unixFile *pDbFd; /* The underlying database file */
+
+ pDbFd = (unixFile*)fd;
+ p = pDbFd->pShm;
+ if( p==0 ) return SQLITE_OK;
+ pShmNode = p->pShmNode;
+
+ assert( pShmNode==pDbFd->pInode->pShmNode );
+ assert( pShmNode->pInode==pDbFd->pInode );
+
+ /* Remove connection p from the set of connections associated
+ ** with pShmNode */
+ sqlite3_mutex_enter(pShmNode->mutex);
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+ *pp = p->pNext;
+
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
+ sqlite3_mutex_leave(pShmNode->mutex);
+
+ /* If pShmNode->nRef has reached 0, then close the underlying
+ ** shared-memory file, too */
+ unixEnterMutex();
+ assert( pShmNode->nRef>0 );
+ pShmNode->nRef--;
+ if( pShmNode->nRef==0 ){
+ if( deleteFlag ) unlink(pShmNode->zFilename);
+ unixShmPurge(pDbFd);
+ }
+ unixLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+**
+** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+** different here than in posix. In xShmLock(), one can go from unlocked
+** to shared and back or from unlocked to exclusive and back. But one may
+** not go from shared to exclusive or from exclusive to shared.
+*/
+static int unixShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int ofst, /* First lock to acquire or release */
+ int n, /* Number of locks to acquire or release */
+ int flags /* What to do with the lock */
+){
+ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
+ unixShm *p = pDbFd->pShm; /* The shared memory being locked */
+ unixShm *pX; /* For looping over all siblings */
+ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
+ int rc = SQLITE_OK; /* Result code */
+ u16 mask; /* Mask of locks to take or release */
+
+ assert( pShmNode==pDbFd->pInode->pShmNode );
+ assert( pShmNode->pInode==pDbFd->pInode );
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ mask = (1<<(ofst+n)) - (1<<ofst);
+ assert( n>1 || mask==(1<<ofst) );
+ sqlite3_mutex_enter(pShmNode->mutex);
+ if( flags & SQLITE_SHM_UNLOCK ){
+ u16 allMask = 0; /* Mask of locks held by siblings */
+
+ /* See if any siblings hold this same lock */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( pX==p ) continue;
+ assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
+ allMask |= pX->sharedMask;
+ }
+
+ /* Unlock the system-level locks */
+ if( (mask & allMask)==0 ){
+ rc = unixShmSystemLock(pShmNode, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ /* Undo the local locks */
+ if( rc==SQLITE_OK ){
+ p->exclMask &= ~mask;
+ p->sharedMask &= ~mask;
+ }
+ }else if( flags & SQLITE_SHM_SHARED ){
+ u16 allShared = 0; /* Union of locks held by connections other than "p" */
+
+ /* Find out which shared locks are already held by sibling connections.
+ ** If any sibling already holds an exclusive lock, go ahead and return
+ ** SQLITE_BUSY.
+ */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( (pX->exclMask & mask)!=0 ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ allShared |= pX->sharedMask;
+ }
+
+ /* Get shared locks at the system level, if necessary */
+ if( rc==SQLITE_OK ){
+ if( (allShared & mask)==0 ){
+ rc = unixShmSystemLock(pShmNode, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ }else{
+ rc = SQLITE_OK;
+ }
+ }
+
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= mask;
+ }
+ }else{
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away.
+ */
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
+ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also mark the local connection as being locked.
+ */
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pShmNode, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ assert( (p->sharedMask & mask)==0 );
+ p->exclMask |= mask;
+ }
+ }
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
+ p->id, getpid(), p->sharedMask, p->exclMask));
+ return rc;
+}
+
+/*
+** Implement a memory barrier or memory fence on shared memory.
+**
+** All loads and stores begun before the barrier must complete before
+** any load or store begun after the barrier.
+*/
+static void unixShmBarrier(
+ sqlite3_file *fd /* Database file holding the shared memory */
+){
+ UNUSED_PARAMETER(fd);
+ unixEnterMutex();
+ unixLeaveMutex();
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
+** bytes in size.
+**
+** If an error occurs, an error code is returned and *pp is set to NULL.
+**
+** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+** region has not been allocated (by any client, including one running in a
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
+** been allocated, it is allocated by this function.
+**
+** If the shared-memory region has already been allocated or is allocated by
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
+** memory and SQLITE_OK returned.
+*/
+static int unixShmMap(
+ sqlite3_file *fd, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int isWrite, /* True to extend file if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ unixFile *pDbFd = (unixFile*)fd;
+ unixShm *p = pDbFd->pShm;
+ unixShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_OK;
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+ if( pShmNode->nRegion<=iRegion ){
+ char **apNew; /* New apRegion[] array */
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ struct stat sStat; /* Used by fstat() */
+
+ pShmNode->szRegion = szRegion;
+
+ /* The requested region is not mapped into this processes address space.
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
+ ** large enough to contain the requested region).
+ */
+ if( fstat(pShmNode->h, &sStat) ){
+ rc = SQLITE_IOERR_SHMSIZE;
+ goto shmpage_out;
+ }
+
+ if( sStat.st_size<nByte ){
+ /* The requested memory region does not exist. If isWrite is set to
+ ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
+ **
+ ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
+ ** the requested memory region.
+ */
+ if( !isWrite ) goto shmpage_out;
+ if( ftruncate(pShmNode->h, nByte) ){
+ rc = SQLITE_IOERR_SHMSIZE;
+ goto shmpage_out;
+ }
+ }
+
+ /* Map the requested memory region into this processes address space. */
+ apNew = (char **)sqlite3_realloc(
+ pShmNode->apRegion, (iRegion+1)*sizeof(char *)
+ );
+ if( !apNew ){
+ rc = SQLITE_IOERR_NOMEM;
+ goto shmpage_out;
+ }
+ pShmNode->apRegion = apNew;
+ while(pShmNode->nRegion<=iRegion){
+ void *pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
+ MAP_SHARED, pShmNode->h, iRegion*szRegion
+ );
+ if( pMem==MAP_FAILED ){
+ rc = SQLITE_IOERR;
+ goto shmpage_out;
+ }
+ pShmNode->apRegion[pShmNode->nRegion] = pMem;
+ pShmNode->nRegion++;
+ }
+ }
+
+shmpage_out:
+ if( pShmNode->nRegion>iRegion ){
+ *pp = pShmNode->apRegion[iRegion];
+ }else{
+ *pp = 0;
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+}
+
+#else
+# define unixShmOpen 0
+# define unixShmLock 0
+# define unixShmMap 0
+# define unixShmBarrier 0
+# define unixShmClose 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
/*
** Here ends the implementation of all sqlite3_file methods.
**
@@ -24767,9 +26131,9 @@
** * An I/O method finder function called FINDER that returns a pointer
** to the METHOD object in the previous bullet.
*/
-#define IOMETHODS(FINDER, METHOD, CLOSE, LOCK, UNLOCK, CKLOCK) \
+#define IOMETHODS(FINDER, METHOD, VERSION, CLOSE, LOCK, UNLOCK, CKLOCK) \
static const sqlite3_io_methods METHOD = { \
- 1, /* iVersion */ \
+ VERSION, /* iVersion */ \
CLOSE, /* xClose */ \
unixRead, /* xRead */ \
unixWrite, /* xWrite */ \
@@ -24781,7 +26145,12 @@
CKLOCK, /* xCheckReservedLock */ \
unixFileControl, /* xFileControl */ \
unixSectorSize, /* xSectorSize */ \
- unixDeviceCharacteristics /* xDeviceCapabilities */ \
+ unixDeviceCharacteristics, /* xDeviceCapabilities */ \
+ unixShmOpen, /* xShmOpen */ \
+ unixShmLock, /* xShmLock */ \
+ unixShmMap, /* xShmMap */ \
+ unixShmBarrier, /* xShmBarrier */ \
+ unixShmClose /* xShmClose */ \
}; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@@ -24798,6 +26167,7 @@
IOMETHODS(
posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */
+ 2, /* ShmOpen is enabled */
unixClose, /* xClose method */
unixLock, /* xLock method */
unixUnlock, /* xUnlock method */
@@ -24806,6 +26176,7 @@
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
@@ -24814,6 +26185,7 @@
IOMETHODS(
dotlockIoFinder, /* Finder function name */
dotlockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
dotlockClose, /* xClose method */
dotlockLock, /* xLock method */
dotlockUnlock, /* xUnlock method */
@@ -24824,6 +26196,7 @@
IOMETHODS(
flockIoFinder, /* Finder function name */
flockIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
flockClose, /* xClose method */
flockLock, /* xLock method */
flockUnlock, /* xUnlock method */
@@ -24835,6 +26208,7 @@
IOMETHODS(
semIoFinder, /* Finder function name */
semIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
semClose, /* xClose method */
semLock, /* xLock method */
semUnlock, /* xUnlock method */
@@ -24846,6 +26220,7 @@
IOMETHODS(
afpIoFinder, /* Finder function name */
afpIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
afpClose, /* xClose method */
afpLock, /* xLock method */
afpUnlock, /* xUnlock method */
@@ -24854,23 +26229,6 @@
#endif
/*
-** The "Whole File Locking" finder returns the same set of methods as
-** the posix locking finder. But it also sets the SQLITE_WHOLE_FILE_LOCKING
-** flag to force the posix advisory locks to cover the whole file instead
-** of just a small span of bytes near the 1GiB boundary. Whole File Locking
-** is useful on NFS-mounted files since it helps NFS to maintain cache
-** coherency. But it is a detriment to other filesystems since it runs
-** slower.
-*/
-static const sqlite3_io_methods *posixWflIoFinderImpl(const char*z, unixFile*p){
- UNUSED_PARAMETER(z);
- p->fileFlags = SQLITE_WHOLE_FILE_LOCKING;
- return &posixIoMethods;
-}
-static const sqlite3_io_methods
- *(*const posixWflIoFinder)(const char*,unixFile *p) = posixWflIoFinderImpl;
-
-/*
** The proxy locking method is a "super-method" in the sense that it
** opens secondary file descriptors for the conch and lock files and
** it uses proxy, dot-file, AFP, and flock() locking methods on those
@@ -24887,6 +26245,7 @@
IOMETHODS(
proxyIoFinder, /* Finder function name */
proxyIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
proxyClose, /* xClose method */
proxyLock, /* xLock method */
proxyUnlock, /* xUnlock method */
@@ -24894,6 +26253,18 @@
)
#endif
+/* nfs lockd on OSX 10.3+ doesn't clear write locks when a read lock is set */
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+IOMETHODS(
+ nfsIoFinder, /* Finder function name */
+ nfsIoMethods, /* sqlite3_io_methods object name */
+ 1, /* ShmOpen is disabled */
+ unixClose, /* xClose method */
+ unixLock, /* xLock method */
+ nfsUnlock, /* xUnlock method */
+ unixCheckReservedLock /* xCheckReservedLock method */
+)
+#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
@@ -24914,11 +26285,7 @@
{ "hfs", &posixIoMethods },
{ "ufs", &posixIoMethods },
{ "afpfs", &afpIoMethods },
-#ifdef SQLITE_ENABLE_AFP_LOCKING_SMB
{ "smbfs", &afpIoMethods },
-#else
- { "smbfs", &flockIoMethods },
-#endif
{ "webdav", &nolockIoMethods },
{ 0, 0 }
};
@@ -24951,8 +26318,11 @@
lockInfo.l_whence = SEEK_SET;
lockInfo.l_type = F_RDLCK;
if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) {
- pNew->fileFlags = SQLITE_WHOLE_FILE_LOCKING;
- return &posixIoMethods;
+ if( strcmp(fsInfo.f_fstypename, "nfs")==0 ){
+ return &nfsIoMethods;
+ } else {
+ return &posixIoMethods;
+ }
}else{
return &dotlockIoMethods;
}
@@ -25029,19 +26399,19 @@
unixFile *pNew = (unixFile *)pId;
int rc = SQLITE_OK;
- assert( pNew->pLock==NULL );
- assert( pNew->pOpen==NULL );
+ assert( pNew->pInode==NULL );
/* Parameter isDelete is only used on vxworks. Express this explicitly
** here to prevent compiler warnings about unused parameters.
*/
UNUSED_PARAMETER(isDelete);
- OSTRACE3("OPEN %-3d %s\n", h, zFilename);
+ OSTRACE(("OPEN %-3d %s\n", h, zFilename));
pNew->h = h;
pNew->dirfd = dirfd;
- SET_THREADID(pNew);
pNew->fileFlags = 0;
+ assert( zFilename==0 || zFilename[0]=='/' ); /* Never a relative pathname */
+ pNew->zPath = zFilename;
#if OS_VXWORKS
pNew->pId = vxworksFindFileId(zFilename);
@@ -25063,12 +26433,16 @@
#endif
}
- if( pLockingStyle == &posixIoMethods ){
+ if( pLockingStyle == &posixIoMethods
+#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
+ || pLockingStyle == &nfsIoMethods
+#endif
+ ){
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
if( rc!=SQLITE_OK ){
- /* If an error occured in findLockInfo(), close the file descriptor
- ** immediately, before releasing the mutex. findLockInfo() may fail
+ /* If an error occured in findInodeInfo(), close the file descriptor
+ ** immediately, before releasing the mutex. findInodeInfo() may fail
** in two scenarios:
**
** (a) A call to fstat() failed.
@@ -25077,7 +26451,7 @@
** Scenario (b) may only occur if the process is holding no other
** file descriptors open on the same file. If there were other file
** descriptors on this file, then no malloc would be required by
- ** findLockInfo(). If this is the case, it is quite safe to close
+ ** findInodeInfo(). If this is the case, it is quite safe to close
** handle h - as it is guaranteed that no posix locks will be released
** by doing so.
**
@@ -25105,9 +26479,15 @@
** according to requirement F11141. So we do not need to make a
** copy of the filename. */
pCtx->dbPath = zFilename;
+ pCtx->reserved = 0;
srandomdev();
unixEnterMutex();
- rc = findLockInfo(pNew, NULL, &pNew->pOpen);
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pNew->lockingContext);
+ close(h);
+ h = -1;
+ }
unixLeaveMutex();
}
}
@@ -25135,18 +26515,18 @@
** included in the semLockingContext
*/
unixEnterMutex();
- rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen);
- if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){
- char *zSemName = pNew->pOpen->aSemName;
+ rc = findInodeInfo(pNew, &pNew->pInode);
+ if( (rc==SQLITE_OK) && (pNew->pInode->pSem==NULL) ){
+ char *zSemName = pNew->pInode->aSemName;
int n;
sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem",
pNew->pId->zCanonicalName);
for( n=1; zSemName[n]; n++ )
if( zSemName[n]=='/' ) zSemName[n] = '_';
- pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
- if( pNew->pOpen->pSem == SEM_FAILED ){
+ pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
+ if( pNew->pInode->pSem == SEM_FAILED ){
rc = SQLITE_NOMEM;
- pNew->pOpen->aSemName[0] = '\0';
+ pNew->pInode->aSemName[0] = '\0';
}
}
unixLeaveMutex();
@@ -25156,6 +26536,8 @@
pNew->lastErrno = 0;
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
+ if( h>=0 ) close(h);
+ h = -1;
unlink(zFilename);
isDelete = 0;
}
@@ -25195,7 +26577,7 @@
#ifdef FD_CLOEXEC
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
#endif
- OSTRACE3("OPENDIR %-3d %s\n", fd, zDirname);
+ OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
}
}
*pFd = fd;
@@ -25203,26 +26585,46 @@
}
/*
-** Create a temporary file name in zBuf. zBuf must be allocated
-** by the calling process and must be big enough to hold at least
-** pVfs->mxPathname bytes.
+** Return the name of a directory in which to put temporary files.
+** If no suitable temporary file directory can be found, return NULL.
*/
-static int getTempname(int nBuf, char *zBuf){
+static const char *unixTempFileDir(void){
static const char *azDirs[] = {
0,
0,
"/var/tmp",
"/usr/tmp",
"/tmp",
- ".",
+ 0 /* List terminator */
};
+ unsigned int i;
+ struct stat buf;
+ const char *zDir = 0;
+
+ azDirs[0] = sqlite3_temp_directory;
+ if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
+ for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
+ if( zDir==0 ) continue;
+ if( stat(zDir, &buf) ) continue;
+ if( !S_ISDIR(buf.st_mode) ) continue;
+ if( access(zDir, 07) ) continue;
+ break;
+ }
+ return zDir;
+}
+
+/*
+** Create a temporary file name in zBuf. zBuf must be allocated
+** by the calling process and must be big enough to hold at least
+** pVfs->mxPathname bytes.
+*/
+static int unixGetTempname(int nBuf, char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
unsigned int i, j;
- struct stat buf;
- const char *zDir = ".";
+ const char *zDir;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
@@ -25230,19 +26632,8 @@
*/
SimulateIOError( return SQLITE_IOERR );
- azDirs[0] = sqlite3_temp_directory;
- if (NULL == azDirs[1]) {
- azDirs[1] = getenv("TMPDIR");
- }
-
- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
- if( azDirs[i]==0 ) continue;
- if( stat(azDirs[i], &buf) ) continue;
- if( !S_ISDIR(buf.st_mode) ) continue;
- if( access(azDirs[i], 07) ) continue;
- zDir = azDirs[i];
- break;
- }
+ zDir = unixTempFileDir();
+ if( zDir==0 ) zDir = ".";
/* Check that the output buffer is large enough for the temporary file
** name. If it is not, return SQLITE_ERROR.
@@ -25308,17 +26699,17 @@
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a resusable file descriptor are not dire. */
if( 0==stat(zPath, &sStat) ){
- struct unixOpenCnt *pOpen;
+ unixInodeInfo *pInode;
unixEnterMutex();
- pOpen = openList;
- while( pOpen && (pOpen->fileId.dev!=sStat.st_dev
- || pOpen->fileId.ino!=sStat.st_ino) ){
- pOpen = pOpen->pNext;
+ pInode = inodeList;
+ while( pInode && (pInode->fileId.dev!=sStat.st_dev
+ || pInode->fileId.ino!=sStat.st_ino) ){
+ pInode = pInode->pNext;
}
- if( pOpen ){
+ if( pInode ){
UnixUnusedFd **pp;
- for(pp=&pOpen->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
+ for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
*pp = pUnused->pNext;
@@ -25372,6 +26763,9 @@
int isCreate = (flags & SQLITE_OPEN_CREATE);
int isReadonly = (flags & SQLITE_OPEN_READONLY);
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
+#if SQLITE_ENABLE_LOCKING_STYLE
+ int isAutoProxy = (flags & SQLITE_OPEN_AUTOPROXY);
+#endif
/* If creating a master or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
@@ -25429,7 +26823,7 @@
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !isOpenDirectory);
- rc = getTempname(MAX_PATHNAME+1, zTmpname);
+ rc = unixGetTempname(MAX_PATHNAME+1, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -25449,7 +26843,7 @@
if( fd<0 ){
mode_t openMode = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS);
fd = open(zName, openFlags, openMode);
- OSTRACE4("OPENX %-3d %s 0%o\n", fd, zName, openFlags);
+ OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
/* Failed to open the file for read/write access. Try read-only. */
flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
@@ -25505,8 +26899,25 @@
noLock = eType!=SQLITE_OPEN_MAIN_DB;
+
+#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
+ struct statfs fsInfo;
+ if( fstatfs(fd, &fsInfo) == -1 ){
+ ((unixFile*)pFile)->lastErrno = errno;
+ if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
+ close(fd); /* silently leak if fail, in error */
+ return SQLITE_IOERR_ACCESS;
+ }
+ if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
+ ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
+ }
+#endif
+
+#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
- if( zPath!=NULL && !noLock && pVfs->xOpen ){
+ isAutoProxy = 1;
+#endif
+ if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
int useProxy = 0;
@@ -25538,6 +26949,14 @@
rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
if( rc==SQLITE_OK ){
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
+ if( rc!=SQLITE_OK ){
+ /* Use unixClose to clean up the resources added in fillInUnixFile
+ ** and clear all the structure's references. Specifically,
+ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
+ */
+ unixClose(pFile);
+ return rc;
+ }
}
goto open_finished;
}
@@ -25622,6 +27041,12 @@
assert(!"Invalid flags argument");
}
*pResOut = (access(zPath, amode)==0);
+ if( flags==SQLITE_ACCESS_EXISTS && *pResOut ){
+ struct stat buf;
+ if( 0==stat(zPath, &buf) && buf.st_size==0 ){
+ *pResOut = 0;
+ }
+ }
return SQLITE_OK;
}
@@ -25810,35 +27235,49 @@
#endif
/*
+** Find the current time (in Universal Coordinated Time). Write into *piNow
+** the current time and date as a Julian Day number times 86_400_000. In
+** other words, write into *piNow the number of milliseconds since the Julian
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+** proleptic Gregorian calendar.
+**
+** On success, return 0. Return 1 if the time and date cannot be found.
+*/
+static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#if defined(NO_GETTOD)
+ time_t t;
+ time(&t);
+ *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
+#elif OS_VXWORKS
+ struct timespec sNow;
+ clock_gettime(CLOCK_REALTIME, &sNow);
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
+#else
+ struct timeval sNow;
+ gettimeofday(&sNow, 0);
+ *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+#endif
+
+#ifdef SQLITE_TEST
+ if( sqlite3_current_time ){
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
+ }
+#endif
+ UNUSED_PARAMETER(NotUsed);
+ return 0;
+}
+
+/*
** Find the current time (in Universal Coordinated Time). Write the
** current time and date as a Julian Day number into *prNow and
** return 0. Return 1 if the time and date cannot be found.
*/
static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
-#if defined(SQLITE_OMIT_FLOATING_POINT)
- time_t t;
- time(&t);
- *prNow = (((sqlite3_int64)t)/8640 + 24405875)/10;
-#elif defined(NO_GETTOD)
- time_t t;
- time(&t);
- *prNow = t/86400.0 + 2440587.5;
-#elif OS_VXWORKS
- struct timespec sNow;
- clock_gettime(CLOCK_REALTIME, &sNow);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_nsec/86400000000000.0;
-#else
- struct timeval sNow;
- gettimeofday(&sNow, 0);
- *prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
-#endif
-
-#ifdef SQLITE_TEST
- if( sqlite3_current_time ){
- *prNow = sqlite3_current_time/86400.0 + 2440587.5;
- }
-#endif
+ sqlite3_int64 i;
UNUSED_PARAMETER(NotUsed);
+ unixCurrentTimeInt64(0, &i);
+ *prNow = i/86400000.0;
return 0;
}
@@ -25856,6 +27295,7 @@
return 0;
}
+
/*
************************ End of sqlite3_vfs methods ***************************
******************************************************************************/
@@ -25965,11 +27405,6 @@
** of the database file for multiple readers and writers on the same
** host (the conch ensures that they all use the same local lock file).
**
-** There is a third file - the host ID file - used as a persistent record
-** of a unique identifier for the host, a 128-byte unique host id file
-** in the path defined by the HOSTIDPATH macro (default value is
-** /Library/Caches/.com.apple.sqliteConchHostId).
-**
** Requesting the lock proxy does not immediately take the conch, it is
** only taken when the first request to lock database file is made.
** This matches the semantics of the traditional locking behavior, where
@@ -25995,10 +27430,6 @@
** Enables the logging of error messages during host id file
** retrieval and creation
**
-** HOSTIDPATH
-**
-** Overrides the default host ID file path location
-**
** LOCKPROXYDIR
**
** Overrides the default directory used for lock proxy files that
@@ -26023,11 +27454,6 @@
*/
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-#ifdef SQLITE_TEST
-/* simulate multiple hosts by creating unique hostid file paths */
-SQLITE_API int sqlite3_hostid_num = 0;
-#endif
-
/*
** The proxyLockingContext has the path and file structures for the remote
** and local proxy files in it
@@ -26039,134 +27465,16 @@
unixFile *lockProxy; /* Open proxy lock file */
char *lockProxyPath; /* Name of the proxy lock file */
char *dbPath; /* Name of the open file */
- int conchHeld; /* True if the conch is currently held */
+ int conchHeld; /* 1 if the conch is held, -1 if lockless */
void *oldLockingContext; /* Original lockingcontext to restore on close */
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
-/* HOSTIDLEN and CONCHLEN both include space for the string
-** terminating nul
+/*
+** The proxy lock file path for the database at dbPath is written into lPath,
+** which must point to valid, writable memory large enough for a maxLen length
+** file path.
*/
-#define HOSTIDLEN 128
-#define CONCHLEN (MAXPATHLEN+HOSTIDLEN+1)
-#ifndef HOSTIDPATH
-# define HOSTIDPATH "/Library/Caches/.com.apple.sqliteConchHostId"
-#endif
-
-/* basically a copy of unixRandomness with different
-** test behavior built in */
-static int proxyGenerateHostID(char *pHostID){
- int pid, fd, len;
- unsigned char *key = (unsigned char *)pHostID;
-
- memset(key, 0, HOSTIDLEN);
- len = 0;
- fd = open("/dev/urandom", O_RDONLY);
- if( fd>=0 ){
- len = read(fd, key, HOSTIDLEN);
- close(fd); /* silently leak the fd if it fails */
- }
- if( len < HOSTIDLEN ){
- time_t t;
- time(&t);
- memcpy(key, &t, sizeof(t));
- pid = getpid();
- memcpy(&key[sizeof(t)], &pid, sizeof(pid));
- }
-
-#ifdef MAKE_PRETTY_HOSTID
- {
- int i;
- /* filter the bytes into printable ascii characters and NUL terminate */
- key[(HOSTIDLEN-1)] = 0x00;
- for( i=0; i<(HOSTIDLEN-1); i++ ){
- unsigned char pa = key[i]&0x7F;
- if( pa<0x20 ){
- key[i] = (key[i]&0x80 == 0x80) ? pa+0x40 : pa+0x20;
- }else if( pa==0x7F ){
- key[i] = (key[i]&0x80 == 0x80) ? pa=0x20 : pa+0x7E;
- }
- }
- }
-#endif
- return SQLITE_OK;
-}
-
-/* writes the host id path to path, path should be an pre-allocated buffer
-** with enough space for a path
-*/
-static void proxyGetHostIDPath(char *path, size_t len){
- strlcpy(path, HOSTIDPATH, len);
-#ifdef SQLITE_TEST
- if( sqlite3_hostid_num>0 ){
- char suffix[2] = "1";
- suffix[0] = suffix[0] + sqlite3_hostid_num;
- strlcat(path, suffix, len);
- }
-#endif
- OSTRACE3("GETHOSTIDPATH %s pid=%d\n", path, getpid());
-}
-
-/* get the host ID from a sqlite hostid file stored in the
-** user-specific tmp directory, create the ID if it's not there already
-*/
-static int proxyGetHostID(char *pHostID, int *pError){
- int fd;
- char path[MAXPATHLEN];
- size_t len;
- int rc=SQLITE_OK;
-
- proxyGetHostIDPath(path, MAXPATHLEN);
- /* try to create the host ID file, if it already exists read the contents */
- fd = open(path, O_CREAT|O_WRONLY|O_EXCL, 0644);
- if( fd<0 ){
- int err=errno;
-
- if( err!=EEXIST ){
-#ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */
- fprintf(stderr, "sqlite error creating host ID file %s: %s\n",
- path, strerror(err));
-#endif
- return SQLITE_PERM;
- }
- /* couldn't create the file, read it instead */
- fd = open(path, O_RDONLY|O_EXCL);
- if( fd<0 ){
-#ifdef SQLITE_PROXY_DEBUG /* set the sqlite error message instead */
- int err = errno;
- fprintf(stderr, "sqlite error opening host ID file %s: %s\n",
- path, strerror(err));
-#endif
- return SQLITE_PERM;
- }
- len = pread(fd, pHostID, HOSTIDLEN, 0);
- if( len<0 ){
- *pError = errno;
- rc = SQLITE_IOERR_READ;
- }else if( len<HOSTIDLEN ){
- *pError = 0;
- rc = SQLITE_IOERR_SHORT_READ;
- }
- close(fd); /* silently leak the fd if it fails */
- OSTRACE3("GETHOSTID read %s pid=%d\n", pHostID, getpid());
- return rc;
- }else{
- /* we're creating the host ID file (use a random string of bytes) */
- proxyGenerateHostID(pHostID);
- len = pwrite(fd, pHostID, HOSTIDLEN, 0);
- if( len<0 ){
- *pError = errno;
- rc = SQLITE_IOERR_WRITE;
- }else if( len<HOSTIDLEN ){
- *pError = 0;
- rc = SQLITE_IOERR_WRITE;
- }
- close(fd); /* silently leak the fd if it fails */
- OSTRACE3("GETHOSTID wrote %s pid=%d\n", pHostID, getpid());
- return rc;
- }
-}
-
static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
int len;
int dbLen;
@@ -26177,21 +27485,12 @@
#else
# ifdef _CS_DARWIN_USER_TEMP_DIR
{
- confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen);
- len = strlcat(lPath, "sqliteplocks", maxLen);
- if( mkdir(lPath, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
- /* if mkdir fails, handle as lock file creation failure */
-# ifdef SQLITE_DEBUG
- int err = errno;
- if( err!=EEXIST ){
- fprintf(stderr, "proxyGetLockPath: mkdir(%s,0%o) error %d %s\n", lPath,
- SQLITE_DEFAULT_PROXYDIR_PERMISSIONS, err, strerror(err));
- }
-# endif
- }else{
- OSTRACE3("GETLOCKPATH mkdir %s pid=%d\n", lPath, getpid());
+ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){
+ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n",
+ lPath, errno, getpid()));
+ return SQLITE_IOERR_LOCK;
}
-
+ len = strlcat(lPath, "sqliteplocks", maxLen);
}
# else
len = strlcpy(lPath, "/tmp/", maxLen);
@@ -26204,15 +27503,52 @@
/* transform the db path to a unique cache name */
dbLen = (int)strlen(dbPath);
- for( i=0; i<dbLen && (i+len+7)<maxLen; i++){
+ for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
char c = dbPath[i];
lPath[i+len] = (c=='/')?'_':c;
}
lPath[i+len]='\0';
strlcat(lPath, ":auto:", maxLen);
+ OSTRACE(("GETLOCKPATH proxy lock path=%s pid=%d\n", lPath, getpid()));
return SQLITE_OK;
}
+/*
+ ** Creates the lock file and any missing directories in lockPath
+ */
+static int proxyCreateLockPath(const char *lockPath){
+ int i, len;
+ char buf[MAXPATHLEN];
+ int start = 0;
+
+ assert(lockPath!=NULL);
+ /* try to create all the intermediate directories */
+ len = (int)strlen(lockPath);
+ buf[0] = lockPath[0];
+ for( i=1; i<len; i++ ){
+ if( lockPath[i] == '/' && (i - start > 0) ){
+ /* only mkdir if leaf dir != "." or "/" or ".." */
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
+ || (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
+ buf[i]='\0';
+ if( mkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
+ int err=errno;
+ if( err!=EEXIST ) {
+ OSTRACE(("CREATELOCKPATH FAILED creating %s, "
+ "'%s' proxy lock path=%s pid=%d\n",
+ buf, strerror(err), lockPath, getpid()));
+ return err;
+ }
+ }
+ }
+ start=i+1;
+ }
+ buf[i] = lockPath[i];
+ }
+ OSTRACE(("CREATELOCKPATH proxy lock path=%s pid=%d\n", lockPath, getpid()));
+ return 0;
+}
+
/*
** Create a new VFS file descriptor (stored in memory obtained from
** sqlite3_malloc) and open the file named "path" in the file descriptor.
@@ -26220,29 +27556,25 @@
** The caller is responsible not only for closing the file descriptor
** but also for freeing the memory associated with the file descriptor.
*/
-static int proxyCreateUnixFile(const char *path, unixFile **ppFile) {
+static int proxyCreateUnixFile(
+ const char *path, /* path for the new unixFile */
+ unixFile **ppFile, /* unixFile created and returned by ref */
+ int islockfile /* if non zero missing dirs will be created */
+) {
+ int fd = -1;
+ int dirfd = -1;
unixFile *pNew;
- int flags = SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
int rc = SQLITE_OK;
+ int openFlags = O_RDWR | O_CREAT;
sqlite3_vfs dummyVfs;
+ int terrno = 0;
+ UnixUnusedFd *pUnused = NULL;
- pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile));
- if( !pNew ){
- return SQLITE_NOMEM;
- }
- memset(pNew, 0, sizeof(unixFile));
-
- /* Call unixOpen() to open the proxy file. The flags passed to unixOpen()
- ** suggest that the file being opened is a "main database". This is
- ** necessary as other file types do not necessarily support locking. It
- ** is better to use unixOpen() instead of opening the file directly with
- ** open(), as unixOpen() sets up the various mechanisms required to
- ** make sure a call to close() does not cause the system to discard
- ** POSIX locks prematurely.
- **
- ** It is important that the xOpen member of the VFS object passed to
- ** unixOpen() is NULL. This tells unixOpen() may try to open a proxy-file
- ** for the proxy-file (creating a potential infinite loop).
+ /* 1. first try to open/create the file
+ ** 2. if that fails, and this is a lock file (not-conch), try creating
+ ** the parent directories and then try again.
+ ** 3. if that fails, try to open the file read-only
+ ** otherwise return BUSY (if lock file) or CANTOPEN for the conch file
*/
pUnused = findReusableFd(path, openFlags);
if( pUnused ){
@@ -26289,23 +27621,202 @@
memset(pNew, 0, sizeof(unixFile));
pNew->openFlags = openFlags;
dummyVfs.pAppData = (void*)&autolockIoFinder;
- dummyVfs.xOpen = 0;
- rc = unixOpen(&dummyVfs, path, (sqlite3_file *)pNew, flags, &flags);
- if( rc==SQLITE_OK && (flags&SQLITE_OPEN_READONLY) ){
- pNew->pMethod->xClose((sqlite3_file *)pNew);
- rc = SQLITE_CANTOPEN;
+ pUnused->fd = fd;
+ pUnused->flags = openFlags;
+ pNew->pUnused = pUnused;
+
+ rc = fillInUnixFile(&dummyVfs, fd, dirfd, (sqlite3_file*)pNew, path, 0, 0);
+ if( rc==SQLITE_OK ){
+ *ppFile = pNew;
+ return SQLITE_OK;
}
-
- if( rc!=SQLITE_OK ){
- sqlite3_free(pNew);
- pNew = 0;
- }
-
- *ppFile = pNew;
+end_create_proxy:
+ close(fd); /* silently leak fd if error, we're already in error */
+ sqlite3_free(pNew);
+ sqlite3_free(pUnused);
return rc;
}
-/* takes the conch by taking a shared lock and read the contents conch, if
+#ifdef SQLITE_TEST
+/* simulate multiple hosts by creating unique hostid file paths */
+SQLITE_API int sqlite3_hostid_num = 0;
+#endif
+
+#define PROXY_HOSTIDLEN 16 /* conch file host id length */
+
+/* Not always defined in the headers as it ought to be */
+extern int gethostuuid(uuid_t id, const struct timespec *wait);
+
+/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
+** bytes of writable memory.
+*/
+static int proxyGetHostID(unsigned char *pHostID, int *pError){
+ struct timespec timeout = {1, 0}; /* 1 sec timeout */
+
+ assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
+ memset(pHostID, 0, PROXY_HOSTIDLEN);
+ if( gethostuuid(pHostID, &timeout) ){
+ int err = errno;
+ if( pError ){
+ *pError = err;
+ }
+ return SQLITE_IOERR;
+ }
+#ifdef SQLITE_TEST
+ /* simulate multiple hosts by creating unique hostid file paths */
+ if( sqlite3_hostid_num != 0){
+ pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
+ }
+#endif
+
+ return SQLITE_OK;
+}
+
+/* The conch file contains the header, host id and lock file path
+ */
+#define PROXY_CONCHVERSION 2 /* 1-byte header, 16-byte host id, path */
+#define PROXY_HEADERLEN 1 /* conch file header length */
+#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
+#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
+
+/*
+** Takes an open conch file, copies the contents to a new path and then moves
+** it back. The newly created file's file descriptor is assigned to the
+** conch file structure and finally the original conch file descriptor is
+** closed. Returns zero if successful.
+*/
+static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ unixFile *conchFile = pCtx->conchFile;
+ char tPath[MAXPATHLEN];
+ char buf[PROXY_MAXCONCHLEN];
+ char *cPath = pCtx->conchFilePath;
+ size_t readLen = 0;
+ size_t pathLen = 0;
+ char errmsg[64] = "";
+ int fd = -1;
+ int rc = -1;
+ UNUSED_PARAMETER(myHostID);
+
+ /* create a new path by replace the trailing '-conch' with '-break' */
+ pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
+ if( pathLen>MAXPATHLEN || pathLen<6 ||
+ (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
+ sprintf(errmsg, "path error (len %d)", (int)pathLen);
+ goto end_breaklock;
+ }
+ /* read the conch content */
+ readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
+ if( readLen<PROXY_PATHINDEX ){
+ sprintf(errmsg, "read error (len %d)", (int)readLen);
+ goto end_breaklock;
+ }
+ /* write it out to the temporary break file */
+ fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
+ if( fd<0 ){
+ sprintf(errmsg, "create failed (%d)", errno);
+ goto end_breaklock;
+ }
+ if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
+ sprintf(errmsg, "write failed (%d)", errno);
+ goto end_breaklock;
+ }
+ if( rename(tPath, cPath) ){
+ sprintf(errmsg, "rename failed (%d)", errno);
+ goto end_breaklock;
+ }
+ rc = 0;
+ fprintf(stderr, "broke stale lock on %s\n", cPath);
+ close(conchFile->h);
+ conchFile->h = fd;
+ conchFile->openFlags = O_RDWR | O_CREAT;
+
+end_breaklock:
+ if( rc ){
+ if( fd>=0 ){
+ unlink(tPath);
+ close(fd);
+ }
+ fprintf(stderr, "failed to break stale lock on %s, %s\n", cPath, errmsg);
+ }
+ return rc;
+}
+
+/* Take the requested lock on the conch file and break a stale lock if the
+** host id matches.
+*/
+static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ unixFile *conchFile = pCtx->conchFile;
+ int rc = SQLITE_OK;
+ int nTries = 0;
+ struct timespec conchModTime;
+
+ do {
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+ nTries ++;
+ if( rc==SQLITE_BUSY ){
+ /* If the lock failed (busy):
+ * 1st try: get the mod time of the conch, wait 0.5s and try again.
+ * 2nd try: fail if the mod time changed or host id is different, wait
+ * 10 sec and try again
+ * 3rd try: break the lock unless the mod time has changed.
+ */
+ struct stat buf;
+ if( fstat(conchFile->h, &buf) ){
+ pFile->lastErrno = errno;
+ return SQLITE_IOERR_LOCK;
+ }
+
+ if( nTries==1 ){
+ conchModTime = buf.st_mtimespec;
+ usleep(500000); /* wait 0.5 sec and try the lock again*/
+ continue;
+ }
+
+ assert( nTries>1 );
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
+ conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
+ return SQLITE_BUSY;
+ }
+
+ if( nTries==2 ){
+ char tBuf[PROXY_MAXCONCHLEN];
+ int len = pread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
+ if( len<0 ){
+ pFile->lastErrno = errno;
+ return SQLITE_IOERR_LOCK;
+ }
+ if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
+ /* don't break the lock if the host id doesn't match */
+ if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
+ return SQLITE_BUSY;
+ }
+ }else{
+ /* don't break the lock on short read or a version mismatch */
+ return SQLITE_BUSY;
+ }
+ usleep(10000000); /* wait 10 sec and try the lock again */
+ continue;
+ }
+
+ assert( nTries==3 );
+ if( 0==proxyBreakConchLock(pFile, myHostID) ){
+ rc = SQLITE_OK;
+ if( lockType==EXCLUSIVE_LOCK ){
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
+ }
+ if( !rc ){
+ rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
+ }
+ }
+ }
+ } while( rc==SQLITE_BUSY && nTries<3 );
+
+ return rc;
+}
+
+/* Takes the conch by taking a shared lock and read the contents conch, if
** lockPath is non-NULL, the host ID and lock file path must match. A NULL
** lockPath means that the lockPath in the conch file will be used if the
** host IDs match, or a new lock path will be generated automatically
@@ -26314,145 +27825,83 @@
static int proxyTakeConch(unixFile *pFile){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- if( pCtx->conchHeld>0 ){
+ if( pCtx->conchHeld!=0 ){
return SQLITE_OK;
}else{
unixFile *conchFile = pCtx->conchFile;
- char testValue[CONCHLEN];
- char conchValue[CONCHLEN];
+ uuid_t myHostID;
+ int pError = 0;
+ char readBuf[PROXY_MAXCONCHLEN];
char lockPath[MAXPATHLEN];
- char *tLockPath = NULL;
+ char *tempLockPath = NULL;
int rc = SQLITE_OK;
- int readRc = SQLITE_OK;
- int syncPerms = 0;
+ int createConch = 0;
+ int hostIdMatch = 0;
+ int readLen = 0;
+ int tryOldLockPath = 0;
+ int forceNewLockPath = 0;
+
+ OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));
- OSTRACE4("TAKECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid());
-
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);
- if( rc==SQLITE_OK ){
- int pError = 0;
- memset(testValue, 0, CONCHLEN); /* conch is fixed size */
- rc = proxyGetHostID(testValue, &pError);
- if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = pError;
- }
- if( pCtx->lockProxyPath ){
- strlcpy(&testValue[HOSTIDLEN], pCtx->lockProxyPath, MAXPATHLEN);
- }
+ rc = proxyGetHostID(myHostID, &pError);
+ if( (rc&0xff)==SQLITE_IOERR ){
+ pFile->lastErrno = pError;
+ goto end_takeconch;
}
+ rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
if( rc!=SQLITE_OK ){
goto end_takeconch;
}
-
- readRc = unixRead((sqlite3_file *)conchFile, conchValue, CONCHLEN, 0);
- if( readRc!=SQLITE_IOERR_SHORT_READ ){
- if( readRc!=SQLITE_OK ){
- if( (rc&0xff)==SQLITE_IOERR ){
- pFile->lastErrno = conchFile->lastErrno;
- }
- rc = readRc;
- goto end_takeconch;
- }
- /* if the conch has data compare the contents */
- if( !pCtx->lockProxyPath ){
- /* for auto-named local lock file, just check the host ID and we'll
- ** use the local lock file path that's already in there */
- if( !memcmp(testValue, conchValue, HOSTIDLEN) ){
- tLockPath = (char *)&conchValue[HOSTIDLEN];
- goto end_takeconch;
- }
- }else{
- /* we've got the conch if conchValue matches our path and host ID */
- if( !memcmp(testValue, conchValue, CONCHLEN) ){
- goto end_takeconch;
- }
- }
- }else{
- /* a short read means we're "creating" the conch (even though it could
- ** have been user-intervention), if we acquire the exclusive lock,
- ** we'll try to match the current on-disk permissions of the database
+ /* read the existing conch file */
+ readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
+ if( readLen<0 ){
+ /* I/O error: lastErrno set by seekAndRead */
+ pFile->lastErrno = conchFile->lastErrno;
+ rc = SQLITE_IOERR_READ;
+ goto end_takeconch;
+ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
+ readBuf[0]!=(char)PROXY_CONCHVERSION ){
+ /* a short read or version format mismatch means we need to create a new
+ ** conch file.
*/
- syncPerms = 1;
+ createConch = 1;
}
-
- /* either conch was emtpy or didn't match */
- if( !pCtx->lockProxyPath ){
- proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
- tLockPath = lockPath;
- strlcpy(&testValue[HOSTIDLEN], lockPath, MAXPATHLEN);
- }
-
- /* update conch with host and path (this will fail if other process
- ** has a shared lock already) */
- rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
- if( rc==SQLITE_OK ){
- rc = unixWrite((sqlite3_file *)conchFile, testValue, CONCHLEN, 0);
- if( rc==SQLITE_OK && syncPerms ){
- struct stat buf;
- int err = fstat(pFile->h, &buf);
- if( err==0 ){
- /* try to match the database file permissions, ignore failure */
-#ifndef SQLITE_PROXY_DEBUG
- fchmod(conchFile->h, buf.st_mode);
-#else
- if( fchmod(conchFile->h, buf.st_mode)!=0 ){
- int code = errno;
- fprintf(stderr, "fchmod %o FAILED with %d %s\n",
- buf.st_mode, code, strerror(code));
- } else {
- fprintf(stderr, "fchmod %o SUCCEDED\n",buf.st_mode);
- }
- }else{
- int code = errno;
- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
- err, code, strerror(code));
-#endif
- }
- }
- }
- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
-
-end_takeconch:
- OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h);
- if( rc==SQLITE_OK && pFile->openFlags ){
- if( pFile->h>=0 ){
-#ifdef STRICT_CLOSE_ERROR
- if( close(pFile->h) ){
- pFile->lastErrno = errno;
- return SQLITE_IOERR_CLOSE;
- }
-#else
- close(pFile->h); /* silently leak fd if fail */
-#endif
- }
- pFile->h = -1;
- int fd = open(pCtx->dbPath, pFile->openFlags,
- SQLITE_DEFAULT_FILE_PERMISSIONS);
- OSTRACE2("TRANSPROXY: OPEN %d\n", fd);
- if( fd>=0 ){
- pFile->h = fd;
- }else{
- rc=SQLITE_CANTOPEN; /* SQLITE_BUSY? proxyTakeConch called
- during locking */
- }
- }
- if( rc==SQLITE_OK && !pCtx->lockProxy ){
- char *path = tLockPath ? tLockPath : pCtx->lockProxyPath;
- /* ACS: Need to make a copy of path sometimes */
- rc = proxyCreateUnixFile(path, &pCtx->lockProxy);
- }
- if( rc==SQLITE_OK ){
- pCtx->conchHeld = 1;
+ /* if the host id matches and the lock path already exists in the conch
+ ** we'll try to use the path there, if we can't open that path, we'll
+ ** retry with a new auto-generated path
+ */
+ do { /* in case we need to try again for an :auto: named lock file */
- if( tLockPath ){
- pCtx->lockProxyPath = sqlite3DbStrDup(0, tLockPath);
- if( pCtx->lockProxy->pMethod == &afpIoMethods ){
- ((afpLockingContext *)pCtx->lockProxy->lockingContext)->dbPath =
- pCtx->lockProxyPath;
+ if( !createConch && !forceNewLockPath ){
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
+ PROXY_HOSTIDLEN);
+ /* if the conch has data compare the contents */
+ if( !pCtx->lockProxyPath ){
+ /* for auto-named local lock file, just check the host ID and we'll
+ ** use the local lock file path that's already in there
+ */
+ if( hostIdMatch ){
+ size_t pathLen = (readLen - PROXY_PATHINDEX);
+
+ if( pathLen>=MAXPATHLEN ){
+ pathLen=MAXPATHLEN-1;
+ }
+ memcpy(lockPath, &readBuf[PROXY_PATHINDEX], pathLen);
+ lockPath[pathLen] = 0;
+ tempLockPath = lockPath;
+ tryOldLockPath = 1;
+ /* create a copy of the lock path if the conch is taken */
+ goto end_takeconch;
+ }
+ }else if( hostIdMatch
+ && !strncmp(pCtx->lockProxyPath, &readBuf[PROXY_PATHINDEX],
+ readLen-PROXY_PATHINDEX)
+ ){
+ /* conch host and lock path match */
+ goto end_takeconch;
}
}
->>>>>>> BEGIN MERGE CONFLICT
/* if the conch isn't writable and doesn't match, we can't take it */
if( (conchFile->openFlags&O_RDWR) == 0 ){
@@ -26473,7 +27922,7 @@
*/
futimes(conchFile->h, NULL);
if( hostIdMatch && !createConch ){
- if( conchFile->pLock && conchFile->pLock->cnt>1 ){
+ if( conchFile->pInode && conchFile->pInode->nShared>1 ){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
@@ -26529,7 +27978,7 @@
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
end_takeconch:
- OSTRACE2("TRANSPROXY: CLOSE %d\n", pFile->h);
+ OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
if( rc==SQLITE_OK && pFile->openFlags ){
if( pFile->h>=0 ){
#ifdef STRICT_CLOSE_ERROR
@@ -26544,7 +27993,7 @@
pFile->h = -1;
int fd = open(pCtx->dbPath, pFile->openFlags,
SQLITE_DEFAULT_FILE_PERMISSIONS);
- OSTRACE2("TRANSPROXY: OPEN %d\n", fd);
+ OSTRACE(("TRANSPROXY: OPEN %d\n", fd));
if( fd>=0 ){
pFile->h = fd;
}else{
@@ -26586,16 +28035,11 @@
} else {
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
}
- OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed");
+ OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
+ rc==SQLITE_OK?"ok":"failed"));
return rc;
- } while (1); /* in case we need to retry the :auto: lock file - we should never get here except via the 'continue' call. */
-============================
- } else {
- conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
- }
- OSTRACE3("TAKECONCH %d %s\n", conchFile->h, rc==SQLITE_OK?"ok":"failed");
- return rc;
-<<<<<<< END MERGE CONFLICT
+ } while (1); /* in case we need to retry the :auto: lock file -
+ ** we should never get here except via the 'continue' call. */
}
}
@@ -26603,19 +28047,21 @@
** If pFile holds a lock on a conch file, then release that lock.
*/
static int proxyReleaseConch(unixFile *pFile){
- int rc; /* Subroutine return code */
+ int rc = SQLITE_OK; /* Subroutine return code */
proxyLockingContext *pCtx; /* The locking context for the proxy lock */
unixFile *conchFile; /* Name of the conch file */
pCtx = (proxyLockingContext *)pFile->lockingContext;
conchFile = pCtx->conchFile;
- OSTRACE4("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
+ OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
- getpid());
+ getpid()));
+ if( pCtx->conchHeld>0 ){
+ rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
+ }
pCtx->conchHeld = 0;
- rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
- OSTRACE3("RELEASECONCH %d %s\n", conchFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("RELEASECONCH %d %s\n", conchFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -26672,7 +28118,7 @@
char *oldPath = pCtx->lockProxyPath;
int rc = SQLITE_OK;
- if( pFile->locktype!=NO_LOCK ){
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
@@ -26709,8 +28155,8 @@
/* afp style keeps a reference to the db path in the filePath field
** of the struct */
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath);
- }else
+ strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath, MAXPATHLEN);
+ } else
#endif
if( pFile->pMethod == &dotlockIoMethods ){
/* dot lock style uses the locking context to store the dot lock
@@ -26720,7 +28166,7 @@
}else{
/* all other styles use the locking context to store the db file path */
assert( strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
- strcpy(dbPath, (char *)pFile->lockingContext);
+ strlcpy(dbPath, (char *)pFile->lockingContext, MAXPATHLEN);
}
return SQLITE_OK;
}
@@ -26739,7 +28185,7 @@
char *lockPath=NULL;
int rc = SQLITE_OK;
- if( pFile->locktype!=NO_LOCK ){
+ if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
proxyGetDbPathForUnixFile(pFile, dbPath);
@@ -26749,8 +28195,8 @@
lockPath=(char *)path;
}
- OSTRACE4("TRANSPROXY %d for %s pid=%d\n", pFile->h,
- (lockPath ? lockPath : ":auto:"), getpid());
+ OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
+ (lockPath ? lockPath : ":auto:"), getpid()));
pCtx = sqlite3_malloc( sizeof(*pCtx) );
if( pCtx==0 ){
@@ -26760,32 +28206,58 @@
rc = proxyCreateConchPathname(dbPath, &pCtx->conchFilePath);
if( rc==SQLITE_OK ){
- rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile);
+ rc = proxyCreateUnixFile(pCtx->conchFilePath, &pCtx->conchFile, 0);
+ if( rc==SQLITE_CANTOPEN && ((pFile->openFlags&O_RDWR) == 0) ){
+ /* if (a) the open flags are not O_RDWR, (b) the conch isn't there, and
+ ** (c) the file system is read-only, then enable no-locking access.
+ ** Ugh, since O_RDONLY==0x0000 we test for !O_RDWR since unixOpen asserts
+ ** that openFlags will have only one of O_RDONLY or O_RDWR.
+ */
+ struct statfs fsInfo;
+ struct stat conchInfo;
+ int goLockless = 0;
+
+ if( stat(pCtx->conchFilePath, &conchInfo) == -1 ) {
+ int err = errno;
+ if( (err==ENOENT) && (statfs(dbPath, &fsInfo) != -1) ){
+ goLockless = (fsInfo.f_flags&MNT_RDONLY) == MNT_RDONLY;
+ }
+ }
+ if( goLockless ){
+ pCtx->conchHeld = -1; /* read only FS/ lockless */
+ rc = SQLITE_OK;
+ }
+ }
}
if( rc==SQLITE_OK && lockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
}
if( rc==SQLITE_OK ){
+ pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
+ if( pCtx->dbPath==NULL ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
/* all memory is allocated, proxys are created and assigned,
** switch the locking context and pMethod then return.
*/
- pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
pCtx->oldLockingContext = pFile->lockingContext;
pFile->lockingContext = pCtx;
pCtx->pOldMethod = pFile->pMethod;
pFile->pMethod = &proxyIoMethods;
}else{
if( pCtx->conchFile ){
- rc = pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
- if( rc ) return rc;
+ pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
sqlite3_free(pCtx->conchFile);
}
+ sqlite3_free(pCtx->lockProxyPath);
sqlite3_free(pCtx->conchFilePath);
sqlite3_free(pCtx);
}
- OSTRACE3("TRANSPROXY %d %s\n", pFile->h,
- (rc==SQLITE_OK ? "ok" : "failed"));
+ OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
+ (rc==SQLITE_OK ? "ok" : "failed")));
return rc;
}
@@ -26869,14 +28341,18 @@
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ return proxy->pMethod->xCheckReservedLock((sqlite3_file*)proxy, pResOut);
+ }else{ /* conchHeld < 0 is lockless */
+ pResOut=0;
+ }
}
return rc;
}
/*
-** Lock the file with the lock specified by parameter locktype - one
+** Lock the file with the lock specified by parameter eFileLock - one
** of the following:
**
** (1) SHARED_LOCK
@@ -26899,34 +28375,42 @@
** This routine will only increase a lock. Use the sqlite3OsUnlock()
** routine to lower a locking level.
*/
-static int proxyLock(sqlite3_file *id, int locktype) {
+static int proxyLock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xLock((sqlite3_file*)proxy, locktype);
- pFile->locktype = proxy->locktype;
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ rc = proxy->pMethod->xLock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
+ }else{
+ /* conchHeld < 0 is lockless */
+ }
}
return rc;
}
/*
-** Lower the locking level on file descriptor pFile to locktype. locktype
+** Lower the locking level on file descriptor pFile to eFileLock. eFileLock
** must be either NO_LOCK or SHARED_LOCK.
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
*/
-static int proxyUnlock(sqlite3_file *id, int locktype) {
+static int proxyUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
int rc = proxyTakeConch(pFile);
if( rc==SQLITE_OK ){
proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
- unixFile *proxy = pCtx->lockProxy;
- rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, locktype);
- pFile->locktype = proxy->locktype;
+ if( pCtx->conchHeld>0 ){
+ unixFile *proxy = pCtx->lockProxy;
+ rc = proxy->pMethod->xUnlock((sqlite3_file*)proxy, eFileLock);
+ pFile->eFileLock = proxy->eFileLock;
+ }else{
+ /* conchHeld < 0 is lockless */
+ }
}
return rc;
}
@@ -27018,7 +28502,7 @@
** that filesystem time.
*/
#define UNIXVFS(VFSNAME, FINDER) { \
- 1, /* iVersion */ \
+ 2, /* iVersion */ \
sizeof(unixFile), /* szOsFile */ \
MAX_PATHNAME, /* mxPathname */ \
0, /* pNext */ \
@@ -27035,7 +28519,8 @@
unixRandomness, /* xRandomness */ \
unixSleep, /* xSleep */ \
unixCurrentTime, /* xCurrentTime */ \
- unixGetLastError /* xGetLastError */ \
+ unixGetLastError, /* xGetLastError */ \
+ unixCurrentTimeInt64, /* xCurrentTimeInt64 */ \
}
/*
@@ -27053,7 +28538,6 @@
#endif
UNIXVFS("unix-none", nolockIoFinder ),
UNIXVFS("unix-dotfile", dotlockIoFinder ),
- UNIXVFS("unix-wfl", posixWflIoFinder ),
#if OS_VXWORKS
UNIXVFS("unix-namedsem", semIoFinder ),
#endif
@@ -27065,6 +28549,7 @@
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
UNIXVFS("unix-afp", afpIoFinder ),
+ UNIXVFS("unix-nfs", nfsIoFinder ),
UNIXVFS("unix-proxy", proxyIoFinder ),
#endif
};
@@ -27186,23 +28671,9 @@
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3OSTrace = 0;
-#define OSTRACE1(X) if( sqlite3OSTrace ) sqlite3DebugPrintf(X)
-#define OSTRACE2(X,Y) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y)
-#define OSTRACE3(X,Y,Z) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B) if( sqlite3OSTrace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D) \
- if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
+#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
-#define OSTRACE1(X)
-#define OSTRACE2(X,Y)
-#define OSTRACE3(X,Y,Z)
-#define OSTRACE4(X,Y,Z,A)
-#define OSTRACE5(X,Y,Z,A,B)
-#define OSTRACE6(X,Y,Z,A,B,C)
-#define OSTRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE(X)
#endif
/*
@@ -27388,6 +28859,10 @@
# define FormatMessageW(a,b,c,d,e,f,g) 0
#endif
+/* Forward references */
+typedef struct winShm winShm; /* A connection to shared-memory */
+typedef struct winShmNode winShmNode; /* A region of shared-memory */
+
/*
** WinCE lacks native support for file locking so we have to fake it
** with some code of our own.
@@ -27407,12 +28882,15 @@
*/
typedef struct winFile winFile;
struct winFile {
- const sqlite3_io_methods *pMethod;/* Must be first */
+ const sqlite3_io_methods *pMethod; /*** Must be first ***/
+ sqlite3_vfs *pVfs; /* The VFS used to open this file */
HANDLE h; /* Handle for accessing the file */
unsigned char locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */
DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */
+ winShm *pShm; /* Instance of shared memory on this file */
+ const char *zPath; /* Full pathname of this file */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
@@ -27940,7 +29418,8 @@
winFile *pFile = (winFile*)id;
assert( id!=0 );
- OSTRACE2("CLOSE %d\n", pFile->h);
+ assert( pFile->pShm==0 );
+ OSTRACE(("CLOSE %d\n", pFile->h));
do{
rc = CloseHandle(pFile->h);
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
@@ -27959,6 +29438,7 @@
free(pFile->zDeleteOnClose);
}
#endif
+ OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
OpenCounter(-1);
return rc ? SQLITE_OK : SQLITE_IOERR;
}
@@ -27990,7 +29470,7 @@
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
- OSTRACE3("READ %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
@@ -28029,11 +29509,15 @@
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
- OSTRACE3("WRITE %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
- return SQLITE_FULL;
+ if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
+ return SQLITE_FULL;
+ }else{
+ return SQLITE_IOERR_WRITE;
+ }
}
assert( amt>0 );
while(
@@ -28046,7 +29530,11 @@
}
if( !rc || amt>(int)wrote ){
pFile->lastErrno = GetLastError();
- return SQLITE_FULL;
+ if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
+ return SQLITE_FULL;
+ }else{
+ return SQLITE_IOERR_WRITE;
+ }
}
return SQLITE_OK;
}
@@ -28057,24 +29545,25 @@
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(nByte & 0xffffffff);
- DWORD rc;
+ DWORD dwRet;
winFile *pFile = (winFile*)id;
DWORD error;
+ int rc = SQLITE_OK;
assert( id!=0 );
- OSTRACE3("TRUNCATE %d %lld\n", pFile->h, nByte);
+ OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
- rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
- if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
+ dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
+ if( dwRet==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
- return SQLITE_IOERR_TRUNCATE;
- }
+ rc = SQLITE_IOERR_TRUNCATE;
/* SetEndOfFile will fail if nByte is negative */
- if( !SetEndOfFile(pFile->h) ){
+ }else if( !SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
- return SQLITE_IOERR_TRUNCATE;
+ rc = SQLITE_IOERR_TRUNCATE;
}
- return SQLITE_OK;
+ OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc==SQLITE_OK ? "ok" : "failed"));
+ return rc;
}
#ifdef SQLITE_TEST
@@ -28094,7 +29583,7 @@
winFile *pFile = (winFile*)id;
assert( id!=0 );
- OSTRACE3("SYNC %d lock=%d\n", pFile->h, pFile->locktype);
+ OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
#else
UNUSED_PARAMETER(id);
#endif
@@ -28235,8 +29724,8 @@
DWORD error = NO_ERROR;
assert( id!=0 );
- OSTRACE5("LOCK %d %d was %d(%d)\n",
- pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("LOCK %d %d was %d(%d)\n",
+ pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
/* If there is already a lock of this type or more restrictive on the
** OsFile, do nothing. Don't use the end_lock: exit path, as
@@ -28266,7 +29755,7 @@
/* Try 3 times to get the pending lock. The pending lock might be
** held by another reader process who will release it momentarily.
*/
- OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
+ OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
Sleep(1);
}
gotPendingLock = res;
@@ -28311,13 +29800,13 @@
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- OSTRACE2("unreadlock = %d\n", res);
+ OSTRACE(("unreadlock = %d\n", res));
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
error = GetLastError();
- OSTRACE2("error-code = %d\n", error);
+ OSTRACE(("error-code = %d\n", error));
getReadLock(pFile);
}
}
@@ -28335,8 +29824,8 @@
if( res ){
rc = SQLITE_OK;
}else{
- OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
- locktype, newLocktype);
+ OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ locktype, newLocktype));
pFile->lastErrno = error;
rc = SQLITE_BUSY;
}
@@ -28356,14 +29845,14 @@
assert( id!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+ OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
}
*pResOut = rc;
return SQLITE_OK;
@@ -28386,8 +29875,8 @@
int rc = SQLITE_OK;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
- pFile->locktype, pFile->sharedLockByte);
+ OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ pFile->locktype, pFile->sharedLockByte));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
@@ -28423,6 +29912,11 @@
*(int*)pArg = (int)((winFile*)id)->lastErrno;
return SQLITE_OK;
}
+ case SQLITE_FCNTL_SIZE_HINT: {
+ sqlite3_int64 sz = *(sqlite3_int64*)pArg;
+ winTruncate(id, sz);
+ return SQLITE_OK;
+ }
}
return SQLITE_ERROR;
}
@@ -28447,15 +29941,538 @@
*/
static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id);
- return 0;
+ return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}
+/****************************************************************************
+********************************* Shared Memory *****************************
+**
+** The next subdivision of code manages the shared-memory primitives.
+*/
+#ifndef SQLITE_OMIT_WAL
+
+/*
+** Helper functions to obtain and relinquish the global mutex. The
+** global mutex is used to protect the winLockInfo objects used by
+** this file, all of which may be shared by multiple threads.
+**
+** Function winShmMutexHeld() is used to assert() that the global mutex
+** is held when required. This function is only used as part of assert()
+** statements. e.g.
+**
+** winShmEnterMutex()
+** assert( winShmMutexHeld() );
+** winEnterLeave()
+*/
+static void winShmEnterMutex(void){
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+static void winShmLeaveMutex(void){
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+#ifdef SQLITE_DEBUG
+static int winShmMutexHeld(void) {
+ return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+#endif
+
+/*
+** Object used to represent a single file opened and mmapped to provide
+** shared memory. When multiple threads all reference the same
+** log-summary, each thread has its own winFile object, but they all
+** point to a single instance of this object. In other words, each
+** log-summary is opened only once per process.
+**
+** winShmMutexHeld() must be true when creating or destroying
+** this object or while reading or writing the following fields:
+**
+** nRef
+** pNext
+**
+** The following fields are read-only after the object is created:
+**
+** fid
+** zFilename
+**
+** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
+** winShmMutexHeld() is true when reading or writing any other field
+** in this structure.
+**
+** To avoid deadlocks, mutex and mutexBuf are always released in the
+** reverse order that they are acquired. mutexBuf is always acquired
+** first and released last. This invariant is check by asserting
+** sqlite3_mutex_notheld() on mutex whenever mutexBuf is acquired or
+** released.
+*/
+struct winShmNode {
+ sqlite3_mutex *mutex; /* Mutex to access this object */
+ char *zFilename; /* Name of the file */
+ winFile hFile; /* File handle from winOpen */
+
+ int szRegion; /* Size of shared-memory regions */
+ int nRegion; /* Size of array apRegion */
+ struct ShmRegion {
+ HANDLE hMap; /* File handle from CreateFileMapping */
+ void *pMap;
+ } *aRegion;
+ DWORD lastErrno; /* The Windows errno from the last I/O error */
+
+ int nRef; /* Number of winShm objects pointing to this */
+ winShm *pFirst; /* All winShm objects pointing to this */
+ winShmNode *pNext; /* Next in list of all winShmNode objects */
+#ifdef SQLITE_DEBUG
+ u8 nextShmId; /* Next available winShm.id value */
+#endif
+};
+
+/*
+** A global array of all winShmNode objects.
+**
+** The winShmMutexHeld() must be true while reading or writing this list.
+*/
+static winShmNode *winShmNodeList = 0;
+
+/*
+** Structure used internally by this VFS to record the state of an
+** open shared memory connection.
+**
+** winShm.pFile->mutex must be held while reading or writing the
+** winShm.pNext and winShm.locks[] elements.
+**
+** The winShm.pFile element is initialized when the object is created
+** and is read-only thereafter.
+*/
+struct winShm {
+ winShmNode *pShmNode; /* The underlying winShmNode object */
+ winShm *pNext; /* Next winShm with the same winShmNode */
+ u8 hasMutex; /* True if holding the winShmNode mutex */
+ u8 hasMutexBuf; /* True if holding pFile->mutexBuf */
+#ifdef SQLITE_DEBUG
+ u8 id; /* Id of this connection with its winShmNode */
+#endif
+};
+
+/*
+** Constants used for locking
+*/
+#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
+#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
+
+/*
+** Apply advisory locks for all n bytes beginning at ofst.
+*/
+#define _SHM_UNLCK 1
+#define _SHM_RDLCK 2
+#define _SHM_WRLCK 3
+static int winShmSystemLock(
+ winShmNode *pFile, /* Apply locks to this open shared-memory segment */
+ int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
+ int ofst, /* Offset to first byte to be locked/unlocked */
+ int nByte /* Number of bytes to lock or unlock */
+){
+ OVERLAPPED ovlp;
+ DWORD dwFlags;
+ int rc = 0; /* Result code form Lock/UnlockFileEx() */
+
+ /* Access to the winShmNode object is serialized by the caller */
+ assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+
+ /* Initialize the locking parameters */
+ dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
+ if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ /* Find the first bit in lockMask that is set */
+ memset(&ovlp, 0, sizeof(OVERLAPPED));
+ ovlp.Offset = ofst;
+
+ /* Release/Acquire the system-level lock */
+ if( lockType==_SHM_UNLCK ){
+ rc = UnlockFileEx(pFile->hFile.h, 0, nByte, 0, &ovlp);
+ }else{
+ rc = LockFileEx(pFile->hFile.h, dwFlags, 0, nByte, 0, &ovlp);
+ }
+ if( !rc ){
+ OSTRACE(("SHM-LOCK %d %s ERROR 0x%08lx\n",
+ pFile->hFile.h,
+ lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
+ GetLastError()));
+ }
+ rc = (rc!=0) ? SQLITE_OK : SQLITE_BUSY;
+
+ return rc;
+}
+
+/* Forward references to VFS methods */
+static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
+static int winDelete(sqlite3_vfs *,const char*,int);
+
+/*
+** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
+**
+** This is not a VFS shared-memory method; it is a utility function called
+** by VFS shared-memory methods.
+*/
+static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
+ winShmNode **pp;
+ winShmNode *p;
+ assert( winShmMutexHeld() );
+ pp = &winShmNodeList;
+ while( (p = *pp)!=0 ){
+ if( p->nRef==0 ){
+ int i;
+ if( p->mutex ) sqlite3_mutex_free(p->mutex);
+ for(i=0; i<p->nRegion; i++){
+ UnmapViewOfFile(p->aRegion[i].pMap);
+ CloseHandle(p->aRegion[i].hMap);
+ }
+ if( p->hFile.h != INVALID_HANDLE_VALUE ) {
+ winClose((sqlite3_file *)&p->hFile);
+ }
+ if( deleteFlag ) winDelete(pVfs, p->zFilename, 0);
+ *pp = p->pNext;
+ sqlite3_free(p->aRegion);
+ sqlite3_free(p);
+ }else{
+ pp = &p->pNext;
+ }
+ }
+}
+
+/*
+** Open a shared-memory area. This particular implementation uses
+** mmapped files.
+**
+** zName is a filename used to identify the shared-memory area. The
+** implementation does not (and perhaps should not) use this name
+** directly, but rather use it as a template for finding an appropriate
+** name for the shared-memory storage. In this implementation, the
+** string "-index" is appended to zName and used as the name of the
+** mmapped file.
+**
+** When opening a new shared-memory file, if no other instances of that
+** file are currently open, in this process or in other processes, then
+** the file must be truncated to zero length or have its header cleared.
+*/
+static int winShmOpen(
+ sqlite3_file *fd /* The file to which to attach shared memory */
+){
+ struct winFile *pDbFd; /* Database to which to attach SHM */
+ struct winShm *p; /* The connection to be opened */
+ struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
+ int rc; /* Result code */
+ struct winShmNode *pNew; /* Newly allocated winShmNode */
+ int nName; /* Size of zName in bytes */
+
+ pDbFd = (winFile*)fd;
+ assert( pDbFd->pShm==0 ); /* Not previously opened */
+
+ /* Allocate space for the new sqlite3_shm object. Also speculatively
+ ** allocate space for a new winShmNode and filename.
+ */
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(*p));
+ nName = sqlite3Strlen30(pDbFd->zPath);
+ pNew = sqlite3_malloc( sizeof(*pShmNode) + nName + 15 );
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->zFilename = (char*)&pNew[1];
+ sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
+
+ /* Look to see if there is an existing winShmNode that can be used.
+ ** If no matching winShmNode currently exists, create a new one.
+ */
+ winShmEnterMutex();
+ for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
+ /* TBD need to come up with better match here. Perhaps
+ ** use FILE_ID_BOTH_DIR_INFO Structure.
+ */
+ if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
+ }
+ if( pShmNode ){
+ sqlite3_free(pNew);
+ }else{
+ pShmNode = pNew;
+ pNew = 0;
+ ((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
+ pShmNode->pNext = winShmNodeList;
+ winShmNodeList = pShmNode;
+
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM;
+ goto shm_open_err;
+ }
+ rc = winOpen(pDbFd->pVfs,
+ pShmNode->zFilename, /* Name of the file (UTF-8) */
+ (sqlite3_file*)&pShmNode->hFile, /* File handle here */
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, /* Mode flags */
+ 0);
+ if( SQLITE_OK!=rc ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto shm_open_err;
+ }
+
+ /* Check to see if another process is holding the dead-man switch.
+ ** If not, truncate the file to zero length.
+ */
+ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
+ if( rc!=SQLITE_OK ){
+ rc = SQLITE_IOERR_SHMOPEN;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+ }
+ if( rc ) goto shm_open_err;
+ }
+
+ /* Make the new connection a child of the winShmNode */
+ p->pShmNode = pShmNode;
+ p->pNext = pShmNode->pFirst;
+#ifdef SQLITE_DEBUG
+ p->id = pShmNode->nextShmId++;
+#endif
+ pShmNode->pFirst = p;
+ pShmNode->nRef++;
+ pDbFd->pShm = p;
+ winShmLeaveMutex();
+ return SQLITE_OK;
+
+ /* Jump here on any error */
+shm_open_err:
+ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
+ sqlite3_free(p);
+ sqlite3_free(pNew);
+ winShmLeaveMutex();
+ return rc;
+}
+
+/*
+** Close a connection to shared-memory. Delete the underlying
+** storage if deleteFlag is true.
+*/
+static int winShmClose(
+ sqlite3_file *fd, /* Database holding shared memory */
+ int deleteFlag /* Delete after closing if true */
+){
+ winFile *pDbFd; /* Database holding shared-memory */
+ winShm *p; /* The connection to be closed */
+ winShmNode *pShmNode; /* The underlying shared-memory file */
+ winShm **pp; /* For looping over sibling connections */
+
+ pDbFd = (winFile*)fd;
+ p = pDbFd->pShm;
+ pShmNode = p->pShmNode;
+
+ /* Remove connection p from the set of connections associated
+ ** with pShmNode */
+ sqlite3_mutex_enter(pShmNode->mutex);
+ for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
+ *pp = p->pNext;
+
+ /* Free the connection p */
+ sqlite3_free(p);
+ pDbFd->pShm = 0;
+ sqlite3_mutex_leave(pShmNode->mutex);
+
+ /* If pShmNode->nRef has reached 0, then close the underlying
+ ** shared-memory file, too */
+ winShmEnterMutex();
+ assert( pShmNode->nRef>0 );
+ pShmNode->nRef--;
+ if( pShmNode->nRef==0 ){
+ winShmPurge(pDbFd->pVfs, deleteFlag);
+ }
+ winShmLeaveMutex();
+
+ return SQLITE_OK;
+}
+
+/*
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
+** bytes in size.
+**
+** If an error occurs, an error code is returned and *pp is set to NULL.
+**
+** Otherwise, if the isWrite parameter is 0 and the requested shared-memory
+** region has not been allocated (by any client, including one running in a
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** isWrite is non-zero and the requested shared-memory region has not yet
+** been allocated, it is allocated by this function.
+**
+** If the shared-memory region has already been allocated or is allocated by
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
+** memory and SQLITE_OK returned.
+*/
+static int winShmMap(
+ sqlite3_file *fd, /* Handle open on database file */
+ int iRegion, /* Region to retrieve */
+ int szRegion, /* Size of regions */
+ int isWrite, /* True to extend file if necessary */
+ void volatile **pp /* OUT: Mapped memory */
+){
+ winFile *pDbFd = (winFile*)fd;
+ winShm *p = pDbFd->pShm;
+ winShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_OK;
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
+
+ if( pShmNode->nRegion<=iRegion ){
+ struct ShmRegion *apNew; /* New aRegion[] array */
+ int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ sqlite3_int64 sz; /* Current size of wal-index file */
+
+ pShmNode->szRegion = szRegion;
+
+ /* The requested region is not mapped into this processes address space.
+ ** Check to see if it has been allocated (i.e. if the wal-index file is
+ ** large enough to contain the requested region).
+ */
+ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
+ if( rc!=SQLITE_OK ){
+ goto shmpage_out;
+ }
+
+ if( sz<nByte ){
+ /* The requested memory region does not exist. If isWrite is set to
+ ** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
+ **
+ ** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
+ ** the requested memory region.
+ */
+ if( !isWrite ) goto shmpage_out;
+ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
+ if( rc!=SQLITE_OK ){
+ goto shmpage_out;
+ }
+ }
+
+ /* Map the requested memory region into this processes address space. */
+ apNew = (struct ShmRegion *)sqlite3_realloc(
+ pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
+ );
+ if( !apNew ){
+ rc = SQLITE_IOERR_NOMEM;
+ goto shmpage_out;
+ }
+ pShmNode->aRegion = apNew;
+
+ while( pShmNode->nRegion<=iRegion ){
+ HANDLE hMap; /* file-mapping handle */
+ void *pMap = 0; /* Mapped memory region */
+
+ hMap = CreateFileMapping(pShmNode->hFile.h,
+ NULL, PAGE_READWRITE, 0, nByte, NULL
+ );
+ if( hMap ){
+ pMap = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ 0, 0, nByte
+ );
+ }
+ if( !pMap ){
+ pShmNode->lastErrno = GetLastError();
+ rc = SQLITE_IOERR;
+ if( hMap ) CloseHandle(hMap);
+ goto shmpage_out;
+ }
+
+ pShmNode->aRegion[pShmNode->nRegion].pMap = pMap;
+ pShmNode->aRegion[pShmNode->nRegion].hMap = hMap;
+ pShmNode->nRegion++;
+ }
+ }
+
+shmpage_out:
+ if( pShmNode->nRegion>iRegion ){
+ char *p = (char *)pShmNode->aRegion[iRegion].pMap;
+ *pp = (void *)&p[iRegion*szRegion];
+ }else{
+ *pp = 0;
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ return rc;
+}
+
+/*
+** Change the lock state for a shared-memory segment.
+*/
+static int winShmLock(
+ sqlite3_file *fd, /* Database file holding the shared memory */
+ int ofst, /* First lock to acquire or release */
+ int n, /* Number of locks to acquire or release */
+ int flags /* What to do with the lock */
+){
+ winFile *pDbFd = (winFile*)fd;
+ winShm *p = pDbFd->pShm;
+ winShmNode *pShmNode = p->pShmNode;
+ int rc = SQLITE_PROTOCOL;
+
+ assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
+ assert( n>=1 );
+ assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
+ || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
+ assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
+
+ sqlite3_mutex_enter(pShmNode->mutex);
+ if( flags & SQLITE_SHM_UNLOCK ){
+ rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
+ }else if( flags & SQLITE_SHM_SHARED ){
+ rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
+ }else{
+ rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
+ }
+ sqlite3_mutex_leave(pShmNode->mutex);
+ OSTRACE(("SHM-LOCK shmid-%d, pid-%d %s\n",
+ p->id, (int)GetCurrentProcessId(), rc ? "failed" : "ok"));
+ return rc;
+}
+
+/*
+** Implement a memory barrier or memory fence on shared memory.
+**
+** All loads and stores begun before the barrier must complete before
+** any load or store begun after the barrier.
+*/
+static void winShmBarrier(
+ sqlite3_file *fd /* Database holding the shared memory */
+){
+ UNUSED_PARAMETER(fd);
+ /* MemoryBarrier(); // does not work -- do not know why not */
+ winShmEnterMutex();
+ winShmLeaveMutex();
+}
+
+#else
+# define winShmOpen 0
+# define winShmMap 0
+# define winShmLock 0
+# define winShmBarrier 0
+# define winShmClose 0
+#endif /* #ifndef SQLITE_OMIT_WAL */
+/*
+***************************** End Shared Memory *****************************
+****************************************************************************/
+
/*
** This vector defines all the methods that can operate on an
** sqlite3_file for win32.
*/
static const sqlite3_io_methods winIoMethod = {
- 1, /* iVersion */
+ 2, /* iVersion */
winClose,
winRead,
winWrite,
@@ -28467,7 +30484,12 @@
winCheckReservedLock,
winFileControl,
winSectorSize,
- winDeviceCharacteristics
+ winDeviceCharacteristics,
+ winShmOpen, /* xShmOpen */
+ winShmLock, /* xShmLock */
+ winShmMap, /* xShmMap */
+ winShmBarrier, /* xShmBarrier */
+ winShmClose /* xShmClose */
};
/***************************************************************************
@@ -28549,7 +30571,7 @@
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
- OSTRACE2("TEMP FILENAME: %s\n", zBuf);
+ OSTRACE(("TEMP FILENAME: %s\n", zBuf));
return SQLITE_OK;
}
@@ -28641,6 +30663,8 @@
assert( id!=0 );
UNUSED_PARAMETER(pVfs);
+ pFile->h = INVALID_HANDLE_VALUE;
+
/* If the second argument to this function is NULL, generate a
** temporary file name to use
*/
@@ -28722,6 +30746,9 @@
);
#endif
}
+ OSTRACE(("OPEN %d %s 0x%lx %s\n",
+ h, zName, dwDesiredAccess,
+ h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
free(zConverted);
if( flags & SQLITE_OPEN_READWRITE ){
@@ -28742,6 +30769,9 @@
pFile->pMethod = &winIoMethod;
pFile->h = h;
pFile->lastErrno = NO_ERROR;
+ pFile->pVfs = pVfs;
+ pFile->pShm = 0;
+ pFile->zPath = zName;
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE
if( (flags & (SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB)) ==
@@ -28813,7 +30843,10 @@
#endif
}
free(zConverted);
- OSTRACE2("DELETE \"%s\"\n", zFilename);
+ OSTRACE(("DELETE \"%s\" %s\n", zFilename,
+ ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ?
+ "ok" : "failed" ));
+
return ( (rc == INVALID_FILE_ATTRIBUTES)
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
}
@@ -28829,13 +30862,38 @@
){
DWORD attr;
int rc = 0;
- void *zConverted = convertUtf8Filename(zFilename);
+ void *zConverted;
UNUSED_PARAMETER(pVfs);
+
+ SimulateIOError( return SQLITE_IOERR_ACCESS; );
+ zConverted = convertUtf8Filename(zFilename);
if( zConverted==0 ){
return SQLITE_NOMEM;
}
if( isNT() ){
- attr = GetFileAttributesW((WCHAR*)zConverted);
+ WIN32_FILE_ATTRIBUTE_DATA sAttrData;
+ memset(&sAttrData, 0, sizeof(sAttrData));
+ if( GetFileAttributesExW((WCHAR*)zConverted,
+ GetFileExInfoStandard,
+ &sAttrData) ){
+ /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
+ ** as if it does not exist.
+ */
+ if( flags==SQLITE_ACCESS_EXISTS
+ && sAttrData.nFileSizeHigh==0
+ && sAttrData.nFileSizeLow==0 ){
+ attr = INVALID_FILE_ATTRIBUTES;
+ }else{
+ attr = sAttrData.dwFileAttributes;
+ }
+ }else{
+ if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
+ free(zConverted);
+ return SQLITE_IOERR_ACCESS;
+ }else{
+ attr = INVALID_FILE_ATTRIBUTES;
+ }
+ }
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
** Since the ASCII version of these Windows API do not exist for WINCE,
** it's important to not reference them for WINCE builds.
@@ -29106,34 +31164,32 @@
}
/*
-** The following variable, if set to a non-zero value, becomes the result
-** returned from sqlite3OsCurrentTime(). This is used for testing.
+** The following variable, if set to a non-zero value, is interpreted as
+** the number of seconds since 1970 and is used to set the result of
+** sqlite3OsCurrentTime() during testing.
*/
#ifdef SQLITE_TEST
-SQLITE_API int sqlite3_current_time = 0;
+SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1970. */
#endif
/*
-** Find the current time (in Universal Coordinated Time). Write the
-** current time and date as a Julian Day number into *prNow and
-** return 0. Return 1 if the time and date cannot be found.
+** Find the current time (in Universal Coordinated Time). Write into *piNow
+** the current time and date as a Julian Day number times 86_400_000. In
+** other words, write into *piNow the number of milliseconds since the Julian
+** epoch of noon in Greenwich on November 24, 4714 B.C according to the
+** proleptic Gregorian calendar.
+**
+** On success, return 0. Return 1 if the time and date cannot be found.
*/
-int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
- FILETIME ft;
+static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
/* FILETIME structure is a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (= JD 2305813.5).
*/
- sqlite3_int64 timeW; /* Whole days */
- sqlite3_int64 timeF; /* Fractional Days */
-
- /* Number of 100-nanosecond intervals in a single day */
- static const sqlite3_int64 ntuPerDay =
- 10000000*(sqlite3_int64)86400;
-
- /* Number of 100-nanosecond intervals in half of a day */
- static const sqlite3_int64 ntuPerHalfDay =
- 10000000*(sqlite3_int64)43200;
-
+ FILETIME ft;
+ static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000;
+#ifdef SQLITE_TEST
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+#endif
/* 2^32 - to avoid use of LL and warnings in gcc */
static const sqlite3_int64 max32BitValue =
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296;
@@ -29148,24 +31204,36 @@
#else
GetSystemTimeAsFileTime( &ft );
#endif
- UNUSED_PARAMETER(pVfs);
- timeW = (((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) + (sqlite3_int64)ft.dwLowDateTime;
- timeF = timeW % ntuPerDay; /* fractional days (100-nanoseconds) */
- timeW = timeW / ntuPerDay; /* whole days */
- timeW = timeW + 2305813; /* add whole days (from 2305813.5) */
- timeF = timeF + ntuPerHalfDay; /* add half a day (from 2305813.5) */
- timeW = timeW + (timeF/ntuPerDay); /* add whole day if half day made one */
- timeF = timeF % ntuPerDay; /* compute new fractional days */
- *prNow = (double)timeW + ((double)timeF / (double)ntuPerDay);
+
+ *piNow = winFiletimeEpoch +
+ ((((sqlite3_int64)ft.dwHighDateTime)*max32BitValue) +
+ (sqlite3_int64)ft.dwLowDateTime)/(sqlite3_int64)10000;
+
#ifdef SQLITE_TEST
if( sqlite3_current_time ){
- *prNow = ((double)sqlite3_current_time + (double)43200) / (double)86400 + (double)2440587;
+ *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch;
}
#endif
+ UNUSED_PARAMETER(pVfs);
return 0;
}
/*
+** Find the current time (in Universal Coordinated Time). Write the
+** current time and date as a Julian Day number into *prNow and
+** return 0. Return 1 if the time and date cannot be found.
+*/
+int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
+ int rc;
+ sqlite3_int64 i;
+ rc = winCurrentTimeInt64(pVfs, &i);
+ if( !rc ){
+ *prNow = i/86400000.0;
+ }
+ return rc;
+}
+
+/*
** The idea is that this function works like a combination of
** GetLastError() and FormatMessage() on windows (or errno and
** strerror_r() on unix). After an error is returned by an OS
@@ -29200,30 +31268,32 @@
return getLastErrorMsg(nBuf, zBuf);
}
+
+
/*
** Initialize and deinitialize the operating system interface.
*/
SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
- 1, /* iVersion */
- sizeof(winFile), /* szOsFile */
- MAX_PATH, /* mxPathname */
- 0, /* pNext */
- "win32", /* zName */
- 0, /* pAppData */
-
- winOpen, /* xOpen */
- winDelete, /* xDelete */
- winAccess, /* xAccess */
- winFullPathname, /* xFullPathname */
- winDlOpen, /* xDlOpen */
- winDlError, /* xDlError */
- winDlSym, /* xDlSym */
- winDlClose, /* xDlClose */
- winRandomness, /* xRandomness */
- winSleep, /* xSleep */
- winCurrentTime, /* xCurrentTime */
- winGetLastError /* xGetLastError */
+ 2, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ MAX_PATH, /* mxPathname */
+ 0, /* pNext */
+ "win32", /* zName */
+ 0, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
};
sqlite3_vfs_register(&winVfs, 1);
@@ -29908,15 +31978,17 @@
if( pPage ){
if( !pPage->pData ){
- memset(pPage, 0, sizeof(PgHdr) + pCache->szExtra);
- pPage->pExtra = (void*)&pPage[1];
- pPage->pData = (void *)&((char *)pPage)[sizeof(PgHdr) + pCache->szExtra];
+ memset(pPage, 0, sizeof(PgHdr));
+ pPage->pData = (void *)&pPage[1];
+ pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
+ memset(pPage->pExtra, 0, pCache->szExtra);
pPage->pCache = pCache;
pPage->pgno = pgno;
}
assert( pPage->pCache==pCache );
assert( pPage->pgno==pgno );
- assert( pPage->pExtra==(void *)&pPage[1] );
+ assert( pPage->pData==(void *)&pPage[1] );
+ assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
if( 0==pPage->nRef ){
pCache->nRef++;
@@ -30055,7 +32127,12 @@
PgHdr *pNext;
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
- if( p->pgno>pgno ){
+ /* This routine never gets call with a positive pgno except right
+ ** after sqlite3PcacheCleanAll(). So if there are dirty pages,
+ ** it must be that pgno==0.
+ */
+ assert( p->pgno>0 );
+ if( ALWAYS(p->pgno>pgno) ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
@@ -30399,6 +32476,7 @@
int sz = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
}
+ sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
}
return p;
}
@@ -30416,7 +32494,10 @@
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
}else{
- int iSize = sqlite3MallocSize(p);
+ int iSize;
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ iSize = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3_free(p);
}
@@ -30938,7 +33019,7 @@
** already provided an alternative.
*/
SQLITE_PRIVATE void sqlite3PCacheSetDefault(void){
- static sqlite3_pcache_methods defaultMethods = {
+ static const sqlite3_pcache_methods defaultMethods = {
0, /* pArg */
pcache1Init, /* xInit */
pcache1Shutdown, /* xShutdown */
@@ -31451,6 +33532,198 @@
** another is writing.
*/
#ifndef SQLITE_OMIT_DISKIO
+/************** Include wal.h in the middle of pager.c ***********************/
+/************** Begin file wal.h *********************************************/
+/*
+** 2010 February 1
+**
+** 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 header file defines the interface to the write-ahead logging
+** system. Refer to the comments below and the header comment attached to
+** the implementation of each function in log.c for further details.
+*/
+
+#ifndef _WAL_H_
+#define _WAL_H_
+
+
+#ifdef SQLITE_OMIT_WAL
+# define sqlite3WalOpen(x,y,z) 0
+# define sqlite3WalClose(w,x,y,z) 0
+# define sqlite3WalBeginReadTransaction(y,z) 0
+# define sqlite3WalEndReadTransaction(z)
+# define sqlite3WalRead(v,w,x,y,z) 0
+# define sqlite3WalDbsize(y,z)
+# define sqlite3WalBeginWriteTransaction(y) 0
+# define sqlite3WalEndWriteTransaction(x) 0
+# define sqlite3WalUndo(x,y,z) 0
+# define sqlite3WalSavepoint(y,z)
+# define sqlite3WalSavepointUndo(y,z) 0
+# define sqlite3WalFrames(u,v,w,x,y,z) 0
+# define sqlite3WalCheckpoint(u,v,w,x) 0
+# define sqlite3WalCallback(z) 0
+# define sqlite3WalExclusiveMode(y,z) 0
+#else
+
+#define WAL_SAVEPOINT_NDATA 4
+
+/* Connection to a write-ahead log (WAL) file.
+** There is one object of this type for each pager.
+*/
+typedef struct Wal Wal;
+
+/* Open and close a connection to a write-ahead log. */
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
+SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+
+/* Used by readers to open (lock) and close (unlock) a snapshot. A
+** snapshot is like a read-transaction. It is the state of the database
+** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
+** preserves the current state even if the other threads or processes
+** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
+** transaction and releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
+
+/* Read a page from the write-ahead log, if it is present. */
+SQLITE_PRIVATE int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
+
+/* Return the size of the database as it existed at the beginning
+** of the snapshot */
+SQLITE_PRIVATE void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
+
+/* Obtain or release the WRITER lock. */
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal);
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal);
+
+/* Undo any frames written (but not committed) to the log */
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
+
+/* Return an integer that records the current (uncommitted) write
+** position in the WAL */
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData);
+
+/* Move the write position of the WAL back to iFrame. Called in
+** response to a ROLLBACK TO command. */
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
+
+/* Write a frame or frames to the log. */
+SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
+
+/* Copy pages from the log to the database file */
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Write-ahead log connection */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of buffer nBuf */
+ u8 *zBuf /* Temporary buffer to use */
+);
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called. If no commits have occurred since
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal);
+
+/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
+** by the pager layer on the database file.
+*/
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
+
+#endif /* ifndef SQLITE_OMIT_WAL */
+#endif /* _WAL_H_ */
+
+/************** End of wal.h *************************************************/
+/************** Continuing where we left off in pager.c **********************/
+
+/*
+******************** NOTES ON THE DESIGN OF THE PAGER ************************
+**
+** Within this comment block, a page is deemed to have been synced
+** automatically as soon as it is written when PRAGMA synchronous=OFF.
+** Otherwise, the page is not synced until the xSync method of the VFS
+** is called successfully on the file containing the page.
+**
+** Definition: A page of the database file is said to be "overwriteable" if
+** one or more of the following are true about the page:
+**
+** (a) The original content of the page as it was at the beginning of
+** the transaction has been written into the rollback journal and
+** synced.
+**
+** (b) The page was a freelist leaf page at the start of the transaction.
+**
+** (c) The page number is greater than the largest page that existed in
+** the database file at the start of the transaction.
+**
+** (1) A page of the database file is never overwritten unless one of the
+** following are true:
+**
+** (a) The page and all other pages on the same sector are overwriteable.
+**
+** (b) The atomic page write optimization is enabled, and the entire
+** transaction other than the update of the transaction sequence
+** number consists of a single page change.
+**
+** (2) The content of a page written into the rollback journal exactly matches
+** both the content in the database when the rollback journal was written
+** and the content in the database at the beginning of the current
+** transaction.
+**
+** (3) Writes to the database file are an integer multiple of the page size
+** in length and are aligned to a page boundary.
+**
+** (4) Reads from the database file are either aligned on a page boundary and
+** an integer multiple of the page size in length or are taken from the
+** first 100 bytes of the database file.
+**
+** (5) All writes to the database file are synced prior to the rollback journal
+** being deleted, truncated, or zeroed.
+**
+** (6) If a master journal file is used, then all writes to the database file
+** are synced prior to the master journal being deleted.
+**
+** Definition: Two databases (or the same database at two points it time)
+** are said to be "logically equivalent" if they give the same answer to
+** all queries. Note in particular the the content of freelist leaf
+** pages can be changed arbitarily without effecting the logical equivalence
+** of the database.
+**
+** (7) At any time, if any subset, including the empty set and the total set,
+** of the unsynced changes to a rollback journal are removed and the
+** journal is rolled back, the resulting database file will be logical
+** equivalent to the database file at the beginning of the transaction.
+**
+** (8) When a transaction is rolled back, the xTruncate method of the VFS
+** is called to restore the database file to the same size it was at
+** the beginning of the transaction. (In some VFSes, the xTruncate
+** method is a no-op, but that does not change the fact the SQLite will
+** invoke it.)
+**
+** (9) Whenever the database file is modified, at least one bit in the range
+** of bytes from 24 through 39 inclusive will be changed prior to releasing
+** the EXCLUSIVE lock.
+**
+** (10) The pattern of bits in bytes 24 through 39 shall not repeat in less
+** than one billion transactions.
+**
+** (11) A database file is well-formed at the beginning and at the conclusion
+** of every transaction.
+**
+** (12) An EXCLUSIVE lock is held on the database file when writing to
+** the database file.
+**
+** (13) A SHARED lock is held on the database file while reading any
+** content out of the database file.
+*/
/*
** Macros for troubleshooting. Normally turned off
@@ -31570,6 +33843,9 @@
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
Pgno nOrig; /* Original number of pages in file */
Pgno iSubRec; /* Index of first record in sub-journal */
+#ifndef SQLITE_OMIT_WAL
+ u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
+#endif
};
/*
@@ -31628,7 +33904,8 @@
**
** journalStarted
**
-** This flag is set whenever the the main journal is synced.
+** This flag is set whenever the the main journal is opened and
+** initialized
**
** The point of this flag is that it must be set after the
** first journal header in a journal file has been synced to disk.
@@ -31652,9 +33929,15 @@
** master journal name is only written to the journal file the first
** time CommitPhaseOne() is called.
**
-** doNotSync
+** doNotSpill, doNotSyncSpill
**
-** This variable is set and cleared by sqlite3PagerWrite().
+** When enabled, cache spills are prohibited. The doNotSpill variable
+** inhibits all cache spill and doNotSyncSpill inhibits those spills that
+** would require a journal sync. The doNotSyncSpill is set and cleared
+** by sqlite3PagerWrite() in order to prevent a journal sync from happening
+** in between the journalling of two pages on the same sector. The
+** doNotSpill value set to prevent pagerStress() from trying to use
+** the journal during a rollback.
**
** needSync
**
@@ -31698,7 +33981,8 @@
u8 journalStarted; /* True if header of journal is synced */
u8 changeCountDone; /* Set after incrementing the change-counter */
u8 setMaster; /* True if a m-j name has been written to jrnl */
- u8 doNotSync; /* Boolean. While true, do not spill the cache */
+ u8 doNotSpill; /* Do not spill the cache when non-zero */
+ u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
u8 dbSizeValid; /* Set when dbSize is correct */
u8 subjInMemory; /* True to use in-memory sub-journals */
Pgno dbSize; /* Number of pages in the database */
@@ -31714,6 +33998,7 @@
sqlite3_file *sjfd; /* File descriptor for sub-journal */
i64 journalOff; /* Current write offset in the journal file */
i64 journalHdr; /* Byte offset to previous journal header */
+ i64 journalSizeLimit; /* Size limit for persistent journal files */
PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */
char dbFileVers[16]; /* Changes whenever database file changes */
@@ -31740,9 +34025,12 @@
void *pCodec; /* First argument to xCodec... methods */
#endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
- i64 journalSizeLimit; /* Size limit for persistent journal files */
PCache *pPCache; /* Pointer to page cache object */
sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */
+#ifndef SQLITE_OMIT_WAL
+ Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */
+ char *zWal; /* File name for write-ahead log */
+#endif
};
/*
@@ -32256,6 +34544,7 @@
for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
+ assert( pPager->journalHdr <= pPager->journalOff );
pPager->journalOff += nHeader;
}
@@ -32414,6 +34703,7 @@
}
pPager->setMaster = 1;
assert( isOpen(pPager->jfd) );
+ assert( pPager->journalHdr <= pPager->journalOff );
/* Calculate the length in bytes and the checksum of zMaster */
for(nMaster=0; zMaster[nMaster]; nMaster++){
@@ -32530,6 +34820,22 @@
}
/*
+** Return true if this pager uses a write-ahead log instead of the usual
+** rollback journal. Otherwise false.
+*/
+#ifndef SQLITE_OMIT_WAL
+static int pagerUseWal(Pager *pPager){
+ return (pPager->pWal!=0);
+}
+#else
+# define pagerUseWal(x) 0
+# define pagerRollbackWal(x) 0
+# define pagerWalFrames(v,w,x,y,z) 0
+# define pagerOpenWalIfPresent(z) SQLITE_OK
+# define pagerBeginReadTransaction(z) SQLITE_OK
+#endif
+
+/*
** Unlock the database file. This function is a no-op if the pager
** is in exclusive mode.
**
@@ -32541,25 +34847,43 @@
*/
static void pager_unlock(Pager *pPager){
if( !pPager->exclusiveMode ){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
+ int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
- /* Always close the journal file when dropping the database lock.
- ** Otherwise, another connection with journal_mode=delete might
- ** delete the file out from under us.
+ /* If the operating system support deletion of open files, then
+ ** close the journal file when dropping the database lock. Otherwise
+ ** another connection with journal_mode=delete might delete the file
+ ** out from under us.
*/
- sqlite3OsClose(pPager->jfd);
+ assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
+ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+ if( 0==(iDc & SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN)
+ || 1!=(pPager->journalMode & 5)
+ ){
+ sqlite3OsClose(pPager->jfd);
+ }
+
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
releaseAllSavepoints(pPager);
/* If the file is unlocked, somebody else might change it. The
** values stored in Pager.dbSize etc. might become invalid if
- ** this happens. TODO: Really, this doesn't need to be cleared
+ ** this happens. One can argue that this doesn't need to be cleared
** until the change-counter check fails in PagerSharedLock().
+ ** Clearing the page size cache here is being conservative.
*/
pPager->dbSizeValid = 0;
- rc = osUnlock(pPager->fd, NO_LOCK);
+ if( pagerUseWal(pPager) ){
+ sqlite3WalEndReadTransaction(pPager->pWal);
+ }else{
+ rc = osUnlock(pPager->fd, NO_LOCK);
+ }
if( rc ){
pPager->errCode = rc;
}
@@ -32590,7 +34914,7 @@
** to this function.
**
** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL
-** the error becomes persistent. Until the persisten error is cleared,
+** the error becomes persistent. Until the persistent error is cleared,
** subsequent API calls on this Pager will immediately return the same
** error code.
**
@@ -32708,6 +35032,7 @@
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
if( isOpen(pPager->jfd) ){
+ assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
if( sqlite3IsMemJournal(pPager->jfd) ){
@@ -32721,8 +35046,8 @@
}
pPager->journalOff = 0;
pPager->journalStarted = 0;
- }else if( pPager->exclusiveMode
- || pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
+ || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasMaster);
pager_error(pPager, rc);
@@ -32732,9 +35057,11 @@
/* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to
- ** the database file, it will do so using an in-memory journal. */
+ ** the database file, it will do so using an in-memory journal.
+ */
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
if( !pPager->tempFile ){
@@ -32745,14 +35072,24 @@
#ifdef SQLITE_CHECK_PAGES
sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
#endif
-
- sqlite3PcacheCleanAll(pPager->pPCache);
- sqlite3BitvecDestroy(pPager->pInJournal);
- pPager->pInJournal = 0;
- pPager->nRec = 0;
}
+ sqlite3BitvecDestroy(pPager->pInJournal);
+ pPager->pInJournal = 0;
+ pPager->nRec = 0;
+ sqlite3PcacheCleanAll(pPager->pPCache);
- if( !pPager->exclusiveMode ){
+ if( pagerUseWal(pPager) ){
+ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
+ assert( rc2==SQLITE_OK );
+ pPager->state = PAGER_SHARED;
+
+ /* If the connection was in locking_mode=exclusive mode but is no longer,
+ ** drop the EXCLUSIVE lock held on the database file.
+ */
+ if( !pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, 0) ){
+ rc2 = osUnlock(pPager->fd, SHARED_LOCK);
+ }
+ }else if( !pPager->exclusiveMode ){
rc2 = osUnlock(pPager->fd, SHARED_LOCK);
pPager->state = PAGER_SHARED;
pPager->changeCountDone = 0;
@@ -32804,6 +35141,21 @@
}
/*
+** Report the current page size and number of reserved bytes back
+** to the codec.
+*/
+#ifdef SQLITE_HAS_CODEC
+static void pagerReportSize(Pager *pPager){
+ if( pPager->xCodecSizeChng ){
+ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
+ (int)pPager->nReserve);
+ }
+}
+#else
+# define pagerReportSize(X) /* No-op if we do not support a codec */
+#endif
+
+/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
@@ -32843,11 +35195,10 @@
*/
static int pager_playback_one_page(
Pager *pPager, /* The pager being played back */
- int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
- int isUnsync, /* True if reading from unsynced main journal */
i64 *pOffset, /* Offset of record to playback */
- int isSavepnt, /* True for a savepoint rollback */
- Bitvec *pDone /* Bitvec of pages already played back */
+ Bitvec *pDone, /* Bitvec of pages already played back */
+ int isMainJrnl, /* 1 -> main journal. 0 -> sub-journal. */
+ int isSavepnt /* True for a savepoint rollback */
){
int rc;
PgHdr *pPg; /* An existing page in the cache */
@@ -32855,6 +35206,7 @@
u32 cksum; /* Checksum used for sanity checking */
char *aData; /* Temporary storage for the page */
sqlite3_file *jfd; /* The file descriptor for the journal file */
+ int isSynced; /* True if journal page is synced */
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
@@ -32863,6 +35215,7 @@
aData = pPager->pTmpSpace;
assert( aData ); /* Temp storage must have already been allocated */
+ assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
/* Read the page number and page data from the journal or sub-journal
** file. Return an error code to the caller if an IO error occurs.
@@ -32894,12 +35247,21 @@
}
}
+ /* If this page has already been played by before during the current
+ ** rollback, then don't bother to play it back again.
+ */
if( pDone && (rc = sqlite3BitvecSet(pDone, pgno))!=SQLITE_OK ){
return rc;
}
-
assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE );
+ /* When playing back page 1, restore the nReserve setting
+ */
+ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
+ pPager->nReserve = ((u8*)aData)[20];
+ pagerReportSize(pPager);
+ }
+
/* If the pager is in RESERVED state, then there must be a copy of this
** page in the pager cache. In this case just update the pager cache,
** not the database file. The page is left marked dirty in this case.
@@ -32932,18 +35294,28 @@
** is possible to fail a statement on a database that does not yet exist.
** Do not attempt to write if database file has never been opened.
*/
- pPg = pager_lookup(pPager, pgno);
+ if( pagerUseWal(pPager) ){
+ pPg = 0;
+ }else{
+ pPg = pager_lookup(pPager, pgno);
+ }
assert( pPg || !MEMDB );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
(isMainJrnl?"main-journal":"sub-journal")
));
+ if( isMainJrnl ){
+ isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
+ }else{
+ isSynced = (pPg==0 || 0==(pPg->flags & PGHDR_NEED_SYNC));
+ }
if( (pPager->state>=PAGER_EXCLUSIVE)
- && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC))
&& isOpen(pPager->fd)
- && !isUnsync
+ && isSynced
){
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
+ testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
+ assert( !pagerUseWal(pPager) );
rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
@@ -32971,9 +35343,12 @@
** requiring a journal-sync before it is written.
*/
assert( isSavepnt );
- if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1))!=SQLITE_OK ){
- return rc;
- }
+ assert( pPager->doNotSpill==0 );
+ pPager->doNotSpill++;
+ rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
+ assert( pPager->doNotSpill==1 );
+ pPager->doNotSpill--;
+ if( rc!=SQLITE_OK ) return rc;
pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
}
@@ -32992,7 +35367,8 @@
/* If the contents of this page were just restored from the main
** journal file, then its content must be as they were when the
** transaction was first opened. In this case we can mark the page
- ** as clean, since there will be no need to write it out to the.
+ ** as clean, since there will be no need to write it out to the
+ ** database.
**
** There is one exception to this rule. If the page is being rolled
** back as part of a savepoint (or statement) rollback from an
@@ -33007,6 +35383,7 @@
** segment is synced. If a crash occurs during or following this,
** database corruption may ensue.
*/
+ assert( !pagerUseWal(pPager) );
sqlite3PcacheMakeClean(pPg);
}
#ifdef SQLITE_CHECK_PAGES
@@ -33075,6 +35452,9 @@
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
char *zMasterJournal = 0; /* Contents of master journal file */
i64 nMasterJournal; /* Size of master journal file */
+ char *zJournal; /* Pointer to one journal within MJ file */
+ char *zMasterPtr; /* Space to hold MJ filename from a journal file */
+ int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
/* Allocate space for both the pJournal and pMaster file descriptors.
** If successful, open the master journal file for reading.
@@ -33089,73 +35469,68 @@
}
if( rc!=SQLITE_OK ) goto delmaster_out;
+ /* Load the entire master journal file into space obtained from
+ ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
+ ** sufficient space (in zMasterPtr) to hold the names of master
+ ** journal files extracted from regular rollback-journals.
+ */
rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
if( rc!=SQLITE_OK ) goto delmaster_out;
+ nMasterPtr = pVfs->mxPathname+1;
+ zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
+ if( !zMasterJournal ){
+ rc = SQLITE_NOMEM;
+ goto delmaster_out;
+ }
+ zMasterPtr = &zMasterJournal[nMasterJournal+1];
+ rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
+ if( rc!=SQLITE_OK ) goto delmaster_out;
+ zMasterJournal[nMasterJournal] = 0;
- if( nMasterJournal>0 ){
- char *zJournal;
- char *zMasterPtr = 0;
- int nMasterPtr = pVfs->mxPathname+1;
-
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal.
- */
- zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1);
- if( !zMasterJournal ){
- rc = SQLITE_NOMEM;
+ zJournal = zMasterJournal;
+ while( (zJournal-zMasterJournal)<nMasterJournal ){
+ int exists;
+ rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+1];
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- zMasterJournal[nMasterJournal] = 0;
-
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)<nMasterJournal ){
- int exists;
- rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( exists ){
+ /* One of the journals pointed to by the master journal exists.
+ ** Open it and check if it points at the master journal. If
+ ** so, return without deleting the master journal file.
+ */
+ int c;
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
- if( exists ){
- /* One of the journals pointed to by the master journal exists.
- ** Open it and check if it points at the master journal. If
- ** so, return without deleting the master journal file.
- */
- int c;
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
- sqlite3OsClose(pJournal);
- if( rc!=SQLITE_OK ){
- goto delmaster_out;
- }
-
- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
- if( c ){
- /* We have a match. Do not delete the master journal file. */
- goto delmaster_out;
- }
+ rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+ sqlite3OsClose(pJournal);
+ if( rc!=SQLITE_OK ){
+ goto delmaster_out;
}
- zJournal += (sqlite3Strlen30(zJournal)+1);
+
+ c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
+ if( c ){
+ /* We have a match. Do not delete the master journal file. */
+ goto delmaster_out;
+ }
}
+ zJournal += (sqlite3Strlen30(zJournal)+1);
}
-
+
+ sqlite3OsClose(pMaster);
rc = sqlite3OsDelete(pVfs, zMaster, 0);
delmaster_out:
- if( zMasterJournal ){
- sqlite3_free(zMasterJournal);
- }
+ sqlite3_free(zMasterJournal);
if( pMaster ){
sqlite3OsClose(pMaster);
assert( !isOpen(pJournal) );
+ sqlite3_free(pMaster);
}
- sqlite3_free(pMaster);
return rc;
}
@@ -33339,8 +35714,6 @@
** occurs.
*/
while( 1 ){
- int isUnsync = 0;
-
/* Read the next journal header from the journal file. If there are
** not enough bytes left in the journal file for a complete header, or
** it is corrupted, then a process must of failed while writing it.
@@ -33381,7 +35754,6 @@
if( nRec==0 && !isHot &&
pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
- isUnsync = 1;
}
/* If this is the first header read from the journal, truncate the
@@ -33403,12 +35775,20 @@
pager_reset(pPager);
needPagerReset = 0;
}
- rc = pager_playback_one_page(pPager,1,isUnsync,&pPager->journalOff,0,0);
+ rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
pPager->journalOff = szJ;
break;
+ }else if( rc==SQLITE_IOERR_SHORT_READ ){
+ /* If the journal has been truncated, simply stop reading and
+ ** processing the journal. This might happen if the journal was
+ ** not completely written and synced prior to a crash. In that
+ ** case, the database should have never been written in the
+ ** first place so it is OK to simply abandon the rollback. */
+ rc = SQLITE_OK;
+ goto end_playback;
}else{
/* If we are unable to rollback, quit and return the error
** code. This will cause the pager to enter the error state
@@ -33453,6 +35833,9 @@
if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
}
+ if( rc==SQLITE_OK && pPager->noSync==0 && pPager->state>=PAGER_EXCLUSIVE ){
+ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ }
if( rc==SQLITE_OK ){
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
testcase( rc!=SQLITE_OK );
@@ -33473,6 +35856,262 @@
return rc;
}
+
+/*
+** Read the content for page pPg out of the database file and into
+** pPg->pData. A shared lock or greater must be held on the database
+** file before this function is called.
+**
+** If page 1 is read, then the value of Pager.dbFileVers[] is set to
+** the value read from the database file.
+**
+** If an IO error occurs, then the IO error is returned to the caller.
+** Otherwise, SQLITE_OK is returned.
+*/
+static int readDbPage(PgHdr *pPg){
+ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
+ Pgno pgno = pPg->pgno; /* Page number to read */
+ int rc = SQLITE_OK; /* Return code */
+ int isInWal = 0; /* True if page is in log file */
+ int pgsz = pPager->pageSize; /* Number of bytes to read */
+
+ assert( pPager->state>=PAGER_SHARED && !MEMDB );
+ assert( isOpen(pPager->fd) );
+
+ if( NEVER(!isOpen(pPager->fd)) ){
+ assert( pPager->tempFile );
+ memset(pPg->pData, 0, pPager->pageSize);
+ return SQLITE_OK;
+ }
+
+ if( pagerUseWal(pPager) ){
+ /* Try to pull the page from the write-ahead log. */
+ rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
+ }
+ if( rc==SQLITE_OK && !isInWal ){
+ i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
+ }
+
+ if( pgno==1 ){
+ if( rc ){
+ /* If the read is unsuccessful, set the dbFileVers[] to something
+ ** that will never be a valid file version. dbFileVers[] is a copy
+ ** of bytes 24..39 of the database. Bytes 28..31 should always be
+ ** zero or the size of the database in page. Bytes 32..35 and 35..39
+ ** should be page numbers which are never 0xffffffff. So filling
+ ** pPager->dbFileVers[] with all 0xff bytes should suffice.
+ **
+ ** For an encrypted database, the situation is more complex: bytes
+ ** 24..39 of the database are white noise. But the probability of
+ ** white noising equaling 16 bytes of 0xff is vanishingly small so
+ ** we should still be ok.
+ */
+ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
+ }else{
+ u8 *dbFileVers = &((u8*)pPg->pData)[24];
+ memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
+ }
+ }
+ CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
+
+ PAGER_INCR(sqlite3_pager_readdb_count);
+ PAGER_INCR(pPager->nRead);
+ IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
+ PAGERID(pPager), pgno, pager_pagehash(pPg)));
+
+ return rc;
+}
+
+#ifndef SQLITE_OMIT_WAL
+/*
+** This function is invoked once for each page that has already been
+** written into the log file when a WAL transaction is rolled back.
+** Parameter iPg is the page number of said page. The pCtx argument
+** is actually a pointer to the Pager structure.
+**
+** If page iPg is present in the cache, and has no outstanding references,
+** it is discarded. Otherwise, if there are one or more outstanding
+** references, the page content is reloaded from the database. If the
+** attempt to reload content from the database is required and fails,
+** return an SQLite error code. Otherwise, SQLITE_OK.
+*/
+static int pagerUndoCallback(void *pCtx, Pgno iPg){
+ int rc = SQLITE_OK;
+ Pager *pPager = (Pager *)pCtx;
+ PgHdr *pPg;
+
+ pPg = sqlite3PagerLookup(pPager, iPg);
+ if( pPg ){
+ if( sqlite3PcachePageRefcount(pPg)==1 ){
+ sqlite3PcacheDrop(pPg);
+ }else{
+ rc = readDbPage(pPg);
+ if( rc==SQLITE_OK ){
+ pPager->xReiniter(pPg);
+ }
+ sqlite3PagerUnref(pPg);
+ }
+ }
+
+ /* Normally, if a transaction is rolled back, any backup processes are
+ ** updated as data is copied out of the rollback journal and into the
+ ** database. This is not generally possible with a WAL database, as
+ ** rollback involves simply truncating the log file. Therefore, if one
+ ** or more frames have already been written to the log (and therefore
+ ** also copied into the backup databases) as part of this transaction,
+ ** the backups must be restarted.
+ */
+ sqlite3BackupRestart(pPager->pBackup);
+
+ return rc;
+}
+
+/*
+** This function is called to rollback a transaction on a WAL database.
+*/
+static int pagerRollbackWal(Pager *pPager){
+ int rc; /* Return Code */
+ PgHdr *pList; /* List of dirty pages to revert */
+
+ /* For all pages in the cache that are currently dirty or have already
+ ** been written (but not committed) to the log file, do one of the
+ ** following:
+ **
+ ** + Discard the cached page (if refcount==0), or
+ ** + Reload page content from the database (if refcount>0).
+ */
+ pPager->dbSize = pPager->dbOrigSize;
+ rc = sqlite3WalUndo(pPager->pWal, pagerUndoCallback, (void *)pPager);
+ pList = sqlite3PcacheDirtyList(pPager->pPCache);
+ while( pList && rc==SQLITE_OK ){
+ PgHdr *pNext = pList->pDirty;
+ rc = pagerUndoCallback((void *)pPager, pList->pgno);
+ pList = pNext;
+ }
+
+ return rc;
+}
+
+/*
+** This function is a wrapper around sqlite3WalFrames(). As well as logging
+** the contents of the list of pages headed by pList (connected by pDirty),
+** this function notifies any active backup processes that the pages have
+** changed.
+*/
+static int pagerWalFrames(
+ Pager *pPager, /* Pager object */
+ PgHdr *pList, /* List of frames to log */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Return code */
+
+ assert( pPager->pWal );
+ rc = sqlite3WalFrames(pPager->pWal,
+ pPager->pageSize, pList, nTruncate, isCommit, sync_flags
+ );
+ if( rc==SQLITE_OK && pPager->pBackup ){
+ PgHdr *p;
+ for(p=pList; p; p=p->pDirty){
+ sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
+ }
+ }
+ return rc;
+}
+
+/*
+** Begin a read transaction on the WAL.
+**
+** This routine used to be called "pagerOpenSnapshot()" because it essentially
+** makes a snapshot of the database at the current point in time and preserves
+** that snapshot for use by the reader in spite of concurrently changes by
+** other writers or checkpointers.
+*/
+static int pagerBeginReadTransaction(Pager *pPager){
+ int rc; /* Return code */
+ int changed = 0; /* True if cache must be reset */
+
+ assert( pagerUseWal(pPager) );
+
+ /* sqlite3WalEndReadTransaction() was not called for the previous
+ ** transaction in locking_mode=EXCLUSIVE. So call it now. If we
+ ** are in locking_mode=NORMAL and EndRead() was previously called,
+ ** the duplicate call is harmless.
+ */
+ sqlite3WalEndReadTransaction(pPager->pWal);
+
+ rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
+ if( rc==SQLITE_OK ){
+ int dummy;
+ if( changed ){
+ pager_reset(pPager);
+ assert( pPager->errCode || pPager->dbSizeValid==0 );
+ }
+ rc = sqlite3PagerPagecount(pPager, &dummy);
+ }
+ pPager->state = PAGER_SHARED;
+
+ return rc;
+}
+
+/*
+** Check if the *-wal file that corresponds to the database opened by pPager
+** exists if the database is not empy, or verify that the *-wal file does
+** not exist (by deleting it) if the database file is empty.
+**
+** If the database is not empty and the *-wal file exists, open the pager
+** in WAL mode. If the database is empty or if no *-wal file exists and
+** if no error occurs, make sure Pager.journalMode is not set to
+** PAGER_JOURNALMODE_WAL.
+**
+** Return SQLITE_OK or an error code.
+**
+** If the WAL file is opened, also open a snapshot (read transaction).
+**
+** The caller must hold a SHARED lock on the database file to call this
+** function. Because an EXCLUSIVE lock on the db file is required to delete
+** a WAL on a none-empty database, this ensures there is no race condition
+** between the xAccess() below and an xDelete() being executed by some
+** other connection.
+*/
+static int pagerOpenWalIfPresent(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !pPager->tempFile ){
+ int isWal; /* True if WAL file exists */
+ int nPage; /* Size of the database file */
+ assert( pPager->state>=SHARED_LOCK );
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ isWal = 0;
+ }else{
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+ );
+ }
+ if( rc==SQLITE_OK ){
+ if( isWal ){
+ pager_reset(pPager);
+ rc = sqlite3PagerOpenWal(pPager, 0);
+ if( rc==SQLITE_OK ){
+ rc = pagerBeginReadTransaction(pPager);
+ }
+ }else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
+ pPager->journalMode = PAGER_JOURNALMODE_DELETE;
+ }
+ }
+ }
+ return rc;
+}
+#endif
+
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
** the entire master journal file. The case pSavepoint==NULL occurs when
@@ -33530,12 +36169,17 @@
*/
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
+ if( !pSavepoint && pagerUseWal(pPager) ){
+ return pagerRollbackWal(pPager);
+ }
+
/* Use pPager->journalOff as the effective size of the main rollback
** journal. The actual file might be larger than this in
** PAGER_JOURNALMODE_TRUNCATE or PAGER_JOURNALMODE_PERSIST. But anything
** past pPager->journalOff is off-limits to us.
*/
szJ = pPager->journalOff;
+ assert( pagerUseWal(pPager)==0 || szJ==0 );
/* Begin by rolling back records from the main journal starting at
** PagerSavepoint.iOffset and continuing to the next journal header.
@@ -33544,11 +36188,11 @@
** will be skipped automatically. Pages are added to pDone as they
** are played back.
*/
- if( pSavepoint ){
+ if( pSavepoint && !pagerUseWal(pPager) ){
iHdrOff = pSavepoint->iHdrOffset ? pSavepoint->iHdrOffset : szJ;
pPager->journalOff = pSavepoint->iOffset;
while( rc==SQLITE_OK && pPager->journalOff<iHdrOff ){
- rc = pager_playback_one_page(pPager, 1, 0, &pPager->journalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}else{
@@ -33578,11 +36222,11 @@
nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
}
for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){
- rc = pager_playback_one_page(pPager, 1, 0, &pPager->journalOff, 1, pDone);
+ rc = pager_playback_one_page(pPager, &pPager->journalOff, pDone, 1, 1);
}
assert( rc!=SQLITE_DONE );
}
- assert( rc!=SQLITE_OK || pPager->journalOff==szJ );
+ assert( rc!=SQLITE_OK || pPager->journalOff>=szJ );
/* Finally, rollback pages from the sub-journal. Page that were
** previously rolled back out of the main journal (and are hence in pDone)
@@ -33591,9 +36235,13 @@
if( pSavepoint ){
u32 ii; /* Loop counter */
i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
+
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
+ }
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
assert( offset==ii*(4+pPager->pageSize) );
- rc = pager_playback_one_page(pPager, 0, 0, &offset, 1, pDone);
+ rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
}
assert( rc!=SQLITE_DONE );
}
@@ -33602,6 +36250,7 @@
if( rc==SQLITE_OK ){
pPager->journalOff = szJ;
}
+
return rc;
}
@@ -33720,21 +36369,6 @@
}
/*
-** Report the current page size and number of reserved bytes back
-** to the codec.
-*/
-#ifdef SQLITE_HAS_CODEC
-static void pagerReportSize(Pager *pPager){
- if( pPager->xCodecSizeChng ){
- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
- (int)pPager->nReserve);
- }
-}
-#else
-# define pagerReportSize(X) /* No-op if we do not support a codec */
-#endif
-
-/*
** Change the page size used by the Pager object. The new page size
** is passed in *pPageSize.
**
@@ -33814,10 +36448,14 @@
** Regardless of mxPage, return the current maximum page count.
*/
SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+ int nPage;
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
- sqlite3PagerPagecount(pPager, 0);
+ if( pPager->state!=PAGER_UNLOCK ){
+ sqlite3PagerPagecount(pPager, &nPage);
+ assert( (int)pPager->mxPgno>=nPage );
+ }
return pPager->mxPgno;
}
@@ -33863,6 +36501,13 @@
int rc = SQLITE_OK;
memset(pDest, 0, N);
assert( isOpen(pPager->fd) || pPager->tempFile );
+
+ /* This routine is only called by btree immediately after creating
+ ** the Pager object. There has not been an opportunity to transition
+ ** to WAL mode yet.
+ */
+ assert( !pagerUseWal(pPager) );
+
if( isOpen(pPager->fd) ){
IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
rc = sqlite3OsRead(pPager->fd, pDest, N, 0);
@@ -33889,12 +36534,7 @@
** and *pnPage is set to the number of pages in the database.
*/
SQLITE_PRIVATE int sqlite3PagerPagecount(Pager *pPager, int *pnPage){
- Pgno nPage; /* Value to return via *pnPage */
-
- /* If the pager is already in the error state, return the error code. */
- if( pPager->errCode ){
- return pPager->errCode;
- }
+ Pgno nPage = 0; /* Value to return via *pnPage */
/* Determine the number of pages in the file. Store this in nPage. */
if( pPager->dbSizeValid ){
@@ -33903,15 +36543,23 @@
int rc; /* Error returned by OsFileSize() */
i64 n = 0; /* File size in bytes returned by OsFileSize() */
- assert( isOpen(pPager->fd) || pPager->tempFile );
- if( isOpen(pPager->fd) && (0 != (rc = sqlite3OsFileSize(pPager->fd, &n))) ){
- pager_error(pPager, rc);
- return rc;
+ if( pagerUseWal(pPager) && pPager->state!=PAGER_UNLOCK ){
+ sqlite3WalDbsize(pPager->pWal, &nPage);
}
- if( n>0 && n<pPager->pageSize ){
- nPage = 1;
- }else{
- nPage = (Pgno)(n / pPager->pageSize);
+
+ if( nPage==0 ){
+ assert( isOpen(pPager->fd) || pPager->tempFile );
+ if( isOpen(pPager->fd) ){
+ if( SQLITE_OK!=(rc = sqlite3OsFileSize(pPager->fd, &n)) ){
+ pager_error(pPager, rc);
+ return rc;
+ }
+ }
+ if( n>0 && n<pPager->pageSize ){
+ nPage = 1;
+ }else{
+ nPage = (Pgno)(n / pPager->pageSize);
+ }
}
if( pPager->state!=PAGER_UNLOCK ){
pPager->dbSize = nPage;
@@ -33929,9 +36577,7 @@
}
/* Set the output variable and return SQLITE_OK */
- if( pnPage ){
- *pnPage = nPage;
- }
+ *pnPage = nPage;
return SQLITE_OK;
}
@@ -34036,6 +36682,32 @@
assertTruncateConstraint(pPager);
}
+
+/*
+** This function is called before attempting a hot-journal rollback. It
+** syncs the journal file to disk, then sets pPager->journalHdr to the
+** size of the journal file so that the pager_playback() routine knows
+** that the entire journal file has been synced.
+**
+** Syncing a hot-journal to disk before attempting to roll it back ensures
+** that if a power-failure occurs during the rollback, the process that
+** attempts rollback following system recovery sees the same journal
+** content as this process.
+**
+** If everything goes as planned, SQLITE_OK is returned. Otherwise,
+** an SQLite error code.
+*/
+static int pagerSyncHotJournal(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !pPager->noSync ){
+ rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_NORMAL);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr);
+ }
+ return rc;
+}
+
/*
** Shutdown the page cache. Free all memory and close all files.
**
@@ -34051,10 +36723,19 @@
** to the caller.
*/
SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
+ u8 *pTmp = (u8 *)pPager->pTmpSpace;
+
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
pPager->errCode = 0;
pPager->exclusiveMode = 0;
+#ifndef SQLITE_OMIT_WAL
+ sqlite3WalClose(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, pTmp
+ );
+ pPager->pWal = 0;
+#endif
pager_reset(pPager);
if( MEMDB ){
pager_unlock(pPager);
@@ -34065,15 +36746,18 @@
** be played back into the database. If a power failure occurs while
** this is happening, the database may become corrupt.
*/
- pPager->journalHdr = -1;
+ if( isOpen(pPager->jfd) ){
+ pPager->errCode = pagerSyncHotJournal(pPager);
+ }
pagerUnlockAndRollback(pPager);
}
sqlite3EndBenignMalloc();
enable_simulated_io_errors();
PAGERTRACE(("CLOSE %d\n", PAGERID(pPager)));
IOTRACE(("CLOSE %p\n", pPager))
+ sqlite3OsClose(pPager->jfd);
sqlite3OsClose(pPager->fd);
- sqlite3PageFree(pPager->pTmpSpace);
+ sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
#ifdef SQLITE_HAS_CODEC
@@ -34155,7 +36839,7 @@
** mode, then the journal file may at this point actually be larger
** than Pager.journalOff bytes. If the next thing in the journal
** file happens to be a journal-header (written as part of the
- ** previous connections transaction), and a crash or power-failure
+ ** previous connection's transaction), and a crash or power-failure
** occurs after nRec is updated but before this connection writes
** anything else to the journal file (or commits/rolls back its
** transaction), then SQLite may become confused when doing the
@@ -34174,10 +36858,10 @@
*/
i64 iNextHdrOffset;
u8 aMagic[8];
- u8 zHeader[sizeof(aJournalMagic)+4];
+ u8 zHeader[sizeof(aJournalMagic)+4];
- memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
- put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
+ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
+ put32bits(&zHeader[sizeof(aJournalMagic)], pPager->nRec);
iNextHdrOffset = journalHdrOffset(pPager);
rc = sqlite3OsRead(pPager->jfd, aMagic, 8, iNextHdrOffset);
@@ -34209,7 +36893,7 @@
IOTRACE(("JHDR %p %lld\n", pPager, pPager->journalHdr));
rc = sqlite3OsWrite(
pPager->jfd, zHeader, sizeof(zHeader), pPager->journalHdr
- );
+ );
if( rc!=SQLITE_OK ) return rc;
}
if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
@@ -34227,6 +36911,7 @@
*/
pPager->needSync = 0;
pPager->journalStarted = 1;
+ pPager->journalHdr = pPager->journalOff;
sqlite3PcacheClearSyncFlags(pPager->pPCache);
}
@@ -34265,13 +36950,9 @@
** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
** be obtained, SQLITE_BUSY is returned.
*/
-static int pager_write_pagelist(PgHdr *pList){
- Pager *pPager; /* Pager object */
+static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
int rc; /* Return code */
- if( NEVER(pList==0) ) return SQLITE_OK;
- pPager = pList->pPager;
-
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
** database file. If there is already an EXCLUSIVE lock, the following
** call is a no-op.
@@ -34288,6 +36969,7 @@
** EXCLUSIVE, it means the database file has been changed and any rollback
** will require a journal playback.
*/
+ assert( !pagerUseWal(pPager) );
assert( pPager->state>=PAGER_RESERVED );
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
@@ -34300,6 +36982,14 @@
rc = pagerOpentemp(pPager, pPager->fd, pPager->vfsFlags);
}
+ /* Before the first write, give the VFS a hint of what the final
+ ** file size will be.
+ */
+ if( pPager->dbSize > (pPager->dbOrigSize+1) && isOpen(pPager->fd) ){
+ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
+ sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
+ }
+
while( rc==SQLITE_OK && pList ){
Pgno pgno = pList->pgno;
@@ -34309,9 +36999,7 @@
** any such pages to the file.
**
** Also, do not write out any page that has the PGHDR_DONT_WRITE flag
- ** set (set by sqlite3PagerDontWrite()). Note that if compiled with
- ** SQLITE_SECURE_DELETE the PGHDR_DONT_WRITE bit is never set and so
- ** the second test is always true.
+ ** set (set by sqlite3PagerDontWrite()).
*/
if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
@@ -34355,6 +37043,26 @@
}
/*
+** Ensure that the sub-journal file is open. If it is already open, this
+** function is a no-op.
+**
+** SQLITE_OK is returned if everything goes according to plan. An
+** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
+** fails.
+*/
+static int openSubJournal(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( !isOpen(pPager->sjfd) ){
+ if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
+ sqlite3MemJournalOpen(pPager->sjfd);
+ }else{
+ rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
+ }
+ }
+ return rc;
+}
+
+/*
** Append a record of the current state of page pPg to the sub-journal.
** It is the callers responsibility to use subjRequiresPage() to check
** that it is really required before calling this function.
@@ -34370,18 +37078,31 @@
static int subjournalPage(PgHdr *pPg){
int rc = SQLITE_OK;
Pager *pPager = pPg->pPager;
- if( isOpen(pPager->sjfd) ){
- void *pData = pPg->pData;
- i64 offset = pPager->nSubRec*(4+pPager->pageSize);
- char *pData2;
+ if( pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
- PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
-
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
- rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ /* Open the sub-journal, if it has not already been opened */
+ assert( pPager->useJournal );
+ assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
+ assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
+ assert( pagerUseWal(pPager)
+ || pageInJournal(pPg)
+ || pPg->pgno>pPager->dbOrigSize
+ );
+ rc = openSubJournal(pPager);
+
+ /* If the sub-journal was opened successfully (or was already open),
+ ** write the journal record into the file. */
if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ void *pData = pPg->pData;
+ i64 offset = pPager->nSubRec*(4+pPager->pageSize);
+ char *pData2;
+
+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
+ rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ }
}
}
if( rc==SQLITE_OK ){
@@ -34392,7 +37113,6 @@
return rc;
}
-
/*
** This function is called by the pcache layer when it has reached some
** soft memory limit. The first argument is a pointer to a Pager object
@@ -34419,74 +37139,83 @@
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
- /* The doNotSync flag is set by the sqlite3PagerWrite() function while it
- ** is journalling a set of two or more database pages that are stored
- ** on the same disk sector. Syncing the journal is not allowed while
- ** this is happening as it is important that all members of such a
- ** set of pages are synced to disk together. So, if the page this function
- ** is trying to make clean will require a journal sync and the doNotSync
- ** flag is set, return without doing anything. The pcache layer will
- ** just have to go ahead and allocate a new page buffer instead of
- ** reusing pPg.
+ /* The doNotSyncSpill flag is set during times when doing a sync of
+ ** journal (and adding a new header) is not allowed. This occurs
+ ** during calls to sqlite3PagerWrite() while trying to journal multiple
+ ** pages belonging to the same sector.
**
- ** Similarly, if the pager has already entered the error state, do not
- ** try to write the contents of pPg to disk.
+ ** The doNotSpill flag inhibits all cache spilling regardless of whether
+ ** or not a sync is required. This is set during a rollback.
+ **
+ ** Spilling is also inhibited when in an error state.
*/
- if( NEVER(pPager->errCode)
- || (pPager->doNotSync && pPg->flags&PGHDR_NEED_SYNC)
- ){
+ if( pPager->errCode ) return SQLITE_OK;
+ if( pPager->doNotSpill ) return SQLITE_OK;
+ if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
return SQLITE_OK;
}
- /* Sync the journal file if required. */
- if( pPg->flags&PGHDR_NEED_SYNC ){
- rc = syncJournal(pPager);
- if( rc==SQLITE_OK && pPager->fullSync &&
- !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
- !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
- ){
- pPager->nRec = 0;
- rc = writeJournalHdr(pPager);
+ pPg->pDirty = 0;
+ if( pagerUseWal(pPager) ){
+ /* Write a single frame for this page to the log. */
+ if( subjRequiresPage(pPg) ){
+ rc = subjournalPage(pPg);
}
- }
-
- /* If the page number of this page is larger than the current size of
- ** the database image, it may need to be written to the sub-journal.
- ** This is because the call to pager_write_pagelist() below will not
- ** actually write data to the file in this case.
- **
- ** Consider the following sequence of events:
- **
- ** BEGIN;
- ** <journal page X>
- ** <modify page X>
- ** SAVEPOINT sp;
- ** <shrink database file to Y pages>
- ** pagerStress(page X)
- ** ROLLBACK TO sp;
- **
- ** If (X>Y), then when pagerStress is called page X will not be written
- ** out to the database file, but will be dropped from the cache. Then,
- ** following the "ROLLBACK TO sp" statement, reading page X will read
- ** data from the database file. This will be the copy of page X as it
- ** was when the transaction started, not as it was when "SAVEPOINT sp"
- ** was executed.
- **
- ** The solution is to write the current data for page X into the
- ** sub-journal file now (if it is not already there), so that it will
- ** be restored to its current value when the "ROLLBACK TO sp" is
- ** executed.
- */
- if( NEVER(
- rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
- ) ){
- rc = subjournalPage(pPg);
- }
-
- /* Write the contents of the page out to the database file. */
- if( rc==SQLITE_OK ){
- pPg->pDirty = 0;
- rc = pager_write_pagelist(pPg);
+ if( rc==SQLITE_OK ){
+ rc = pagerWalFrames(pPager, pPg, 0, 0, 0);
+ }
+ }else{
+
+ /* Sync the journal file if required. */
+ if( pPg->flags&PGHDR_NEED_SYNC ){
+ assert( !pPager->noSync );
+ rc = syncJournal(pPager);
+ if( rc==SQLITE_OK &&
+ !(pPager->journalMode==PAGER_JOURNALMODE_MEMORY) &&
+ !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+ ){
+ pPager->nRec = 0;
+ rc = writeJournalHdr(pPager);
+ }
+ }
+
+ /* If the page number of this page is larger than the current size of
+ ** the database image, it may need to be written to the sub-journal.
+ ** This is because the call to pager_write_pagelist() below will not
+ ** actually write data to the file in this case.
+ **
+ ** Consider the following sequence of events:
+ **
+ ** BEGIN;
+ ** <journal page X>
+ ** <modify page X>
+ ** SAVEPOINT sp;
+ ** <shrink database file to Y pages>
+ ** pagerStress(page X)
+ ** ROLLBACK TO sp;
+ **
+ ** If (X>Y), then when pagerStress is called page X will not be written
+ ** out to the database file, but will be dropped from the cache. Then,
+ ** following the "ROLLBACK TO sp" statement, reading page X will read
+ ** data from the database file. This will be the copy of page X as it
+ ** was when the transaction started, not as it was when "SAVEPOINT sp"
+ ** was executed.
+ **
+ ** The solution is to write the current data for page X into the
+ ** sub-journal file now (if it is not already there), so that it will
+ ** be restored to its current value when the "ROLLBACK TO sp" is
+ ** executed.
+ */
+ if( NEVER(
+ rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg)
+ ) ){
+ rc = subjournalPage(pPg);
+ }
+
+ /* Write the contents of the page out to the database file. */
+ if( rc==SQLITE_OK ){
+ rc = pager_write_pagelist(pPager, pPg);
+ }
}
/* Mark the page as clean. */
@@ -34625,6 +37354,9 @@
journalFileSize * 2 + /* The two journal files */
nPathname + 1 + /* zFilename */
nPathname + 8 + 1 /* zJournal */
+#ifndef SQLITE_OMIT_WAL
+ + nPathname + 4 + 1 /* zWal */
+#endif
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
@@ -34645,7 +37377,16 @@
memcpy(pPager->zFilename, zPathname, nPathname);
memcpy(pPager->zJournal, zPathname, nPathname);
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
- if( pPager->zFilename[0]==0 ) pPager->zJournal[0] = 0;
+ if( pPager->zFilename[0]==0 ){
+ pPager->zJournal[0] = 0;
+ }
+#ifndef SQLITE_OMIT_WAL
+ else{
+ pPager->zWal = &pPager->zJournal[nPathname+8+1];
+ memcpy(pPager->zWal, zPathname, nPathname);
+ memcpy(&pPager->zWal[nPathname], "-wal", 4);
+ }
+#endif
sqlite3_free(zPathname);
}
pPager->pVfs = pVfs;
@@ -34775,6 +37516,7 @@
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
+
*ppPager = pPager;
return SQLITE_OK;
}
@@ -34814,17 +37556,22 @@
*/
static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3_vfs * const pVfs = pPager->pVfs;
- int rc; /* Return code */
- int exists; /* True if a journal file is present */
+ int rc = SQLITE_OK; /* Return code */
+ int exists = 1; /* True if a journal file is present */
+ int jrnlOpen = !!isOpen(pPager->jfd);
assert( pPager!=0 );
assert( pPager->useJournal );
assert( isOpen(pPager->fd) );
- assert( !isOpen(pPager->jfd) );
assert( pPager->state <= PAGER_SHARED );
+ assert( jrnlOpen==0 || ( sqlite3OsDeviceCharacteristics(pPager->jfd) &
+ SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
+ ));
*pExists = 0;
- rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ if( !jrnlOpen ){
+ rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
+ }
if( rc==SQLITE_OK && exists ){
int locked; /* True if some process holds a RESERVED lock */
@@ -34862,15 +37609,19 @@
** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
- int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ if( !jrnlOpen ){
+ int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
+ rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
+ }
if( rc==SQLITE_OK ){
u8 first = 0;
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
- sqlite3OsClose(pPager->jfd);
+ if( !jrnlOpen ){
+ sqlite3OsClose(pPager->jfd);
+ }
*pExists = (first!=0);
}else if( rc==SQLITE_CANTOPEN ){
/* If we cannot open the rollback journal file in order to see if
@@ -34894,51 +37645,6 @@
}
/*
-** Read the content for page pPg out of the database file and into
-** pPg->pData. A shared lock or greater must be held on the database
-** file before this function is called.
-**
-** If page 1 is read, then the value of Pager.dbFileVers[] is set to
-** the value read from the database file.
-**
-** If an IO error occurs, then the IO error is returned to the caller.
-** Otherwise, SQLITE_OK is returned.
-*/
-static int readDbPage(PgHdr *pPg){
- Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
- int rc; /* Return code */
- i64 iOffset; /* Byte offset of file to read from */
-
- assert( pPager->state>=PAGER_SHARED && !MEMDB );
- assert( isOpen(pPager->fd) );
-
- if( NEVER(!isOpen(pPager->fd)) ){
- assert( pPager->tempFile );
- memset(pPg->pData, 0, pPager->pageSize);
- return SQLITE_OK;
- }
- iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
- if( rc==SQLITE_IOERR_SHORT_READ ){
- rc = SQLITE_OK;
- }
- if( pgno==1 ){
- u8 *dbFileVers = &((u8*)pPg->pData)[24];
- memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
- }
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
-
- PAGER_INCR(sqlite3_pager_readdb_count);
- PAGER_INCR(pPager->nRead);
- IOTRACE(("PGIN %p %d\n", pPager, pgno));
- PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
-
- return rc;
-}
-
-/*
** This function is called to obtain a shared lock on the database file.
** It is illegal to call sqlite3PagerAcquire() until after this function
** has been successfully called. If a shared-lock is already held when
@@ -34991,7 +37697,9 @@
pager_reset(pPager);
}
- if( pPager->state==PAGER_UNLOCK || isErrorReset ){
+ if( pagerUseWal(pPager) ){
+ rc = pagerBeginReadTransaction(pPager);
+ }else if( pPager->state==PAGER_UNLOCK || isErrorReset ){
sqlite3_vfs * const pVfs = pPager->pVfs;
int isHotJournal = 0;
assert( !MEMDB );
@@ -35074,19 +37782,28 @@
goto failed;
}
- /* TODO: Why are these cleared here? Is it necessary? */
+ /* Reset the journal status fields to indicates that we have no
+ ** rollback journal at this time. */
pPager->journalStarted = 0;
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
+ /* Make sure the journal file has been synced to disk. */
+
/* Playback and delete the journal. Drop the database write
** lock and reacquire the read lock. Purge the cache before
** playing back the hot-journal so that we don't end up with
- ** an inconsistent cache.
+ ** an inconsistent cache. Sync the hot journal before playing
+ ** it back since the process that crashed and left the hot journal
+ ** probably did not sync it and we are required to always sync
+ ** the journal before playing it back.
*/
if( isOpen(pPager->jfd) ){
- rc = pager_playback(pPager, 1);
+ rc = pagerSyncHotJournal(pPager);
+ if( rc==SQLITE_OK ){
+ rc = pager_playback(pPager, 1);
+ }
if( rc!=SQLITE_OK ){
rc = pager_error(pPager, rc);
goto failed;
@@ -35114,16 +37831,16 @@
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
+ int nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)];
- sqlite3PagerPagecount(pPager, 0);
+ sqlite3PagerPagecount(pPager, &nPage);
if( pPager->errCode ){
rc = pPager->errCode;
goto failed;
}
- assert( pPager->dbSizeValid );
- if( pPager->dbSize>0 ){
+ if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){
@@ -35138,6 +37855,11 @@
}
}
assert( pPager->exclusiveMode || pPager->state==PAGER_SHARED );
+
+ /* If there is a WAL file in the file-system, open this database in WAL
+ ** mode. Otherwise, the following function call is a no-op.
+ */
+ rc = pagerOpenWalIfPresent(pPager);
}
failed:
@@ -35192,7 +37914,7 @@
** a) When reading a free-list leaf page from the database, and
**
** b) When a savepoint is being rolled back and we need to load
-** a new page into the cache to populate with the data read
+** a new page into the cache to be filled with the data read
** from the savepoint journal.
**
** If noContent is true, then the data returned is zeroed instead of
@@ -35248,7 +37970,7 @@
assert( (*ppPage)->pgno==pgno );
assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 );
- if( (*ppPage)->pPager ){
+ if( (*ppPage)->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
@@ -35278,8 +38000,8 @@
if( MEMDB || nMax<(int)pgno || noContent || !isOpen(pPager->fd) ){
if( pgno>pPager->mxPgno ){
- rc = SQLITE_FULL;
- goto pager_acquire_err;
+ rc = SQLITE_FULL;
+ goto pager_acquire_err;
}
if( noContent ){
/* Failure to set the bits in the InJournal bit-vectors is benign.
@@ -35364,27 +38086,6 @@
}
/*
-** If the main journal file has already been opened, ensure that the
-** sub-journal file is open too. If the main journal is not open,
-** this function is a no-op.
-**
-** SQLITE_OK is returned if everything goes according to plan.
-** An SQLITE_IOERR_XXX error code is returned if a call to
-** sqlite3OsOpen() fails.
-*/
-static int openSubJournal(Pager *pPager){
- int rc = SQLITE_OK;
- if( isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ){
- if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
- sqlite3MemJournalOpen(pPager->sjfd);
- }else{
- rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
- }
- }
- return rc;
-}
-
-/*
** This function is called at the start of every write transaction.
** There must already be a RESERVED or EXCLUSIVE lock on the database
** file when this routine is called.
@@ -35408,6 +38109,7 @@
*/
static int pager_open_journal(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
+ int nPage; /* Size of database file */
sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */
assert( pPager->state>=PAGER_RESERVED );
@@ -35420,13 +38122,10 @@
** an error state. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
- /* TODO: Is it really possible to get here with dbSizeValid==0? If not,
- ** the call to PagerPagecount() can be removed.
- */
testcase( pPager->dbSizeValid==0 );
- sqlite3PagerPagecount(pPager, 0);
-
- pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ pPager->pInJournal = sqlite3BitvecCreate(nPage);
if( pPager->pInJournal==0 ){
return SQLITE_NOMEM;
}
@@ -35468,9 +38167,6 @@
pPager->journalHdr = 0;
rc = writeJournalHdr(pPager);
}
- if( rc==SQLITE_OK && pPager->nSavepoint ){
- rc = openSubJournal(pPager);
- }
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
@@ -35508,53 +38204,77 @@
int rc = SQLITE_OK;
assert( pPager->state!=PAGER_UNLOCK );
pPager->subjInMemory = (u8)subjInMemory;
+
if( pPager->state==PAGER_SHARED ){
assert( pPager->pInJournal==0 );
assert( !MEMDB && !pPager->tempFile );
- /* Obtain a RESERVED lock on the database file. If the exFlag parameter
- ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
- ** busy-handler callback can be used when upgrading to the EXCLUSIVE
- ** lock, but not when obtaining the RESERVED lock.
- */
- rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
- if( rc==SQLITE_OK ){
- pPager->state = PAGER_RESERVED;
- if( exFlag ){
- rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ if( pagerUseWal(pPager) ){
+ /* If the pager is configured to use locking_mode=exclusive, and an
+ ** exclusive lock on the database is not already held, obtain it now.
+ */
+ if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
+ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
+ pPager->state = PAGER_SHARED;
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ sqlite3WalExclusiveMode(pPager->pWal, 1);
+ }
+
+ /* Grab the write lock on the log file. If successful, upgrade to
+ ** PAGER_RESERVED state. Otherwise, return an error code to the caller.
+ ** The busy-handler is not invoked if another connection already
+ ** holds the write-lock. If possible, the upper layer will call it.
+ **
+ ** WAL mode sets Pager.state to PAGER_RESERVED when it has an open
+ ** transaction, but never to PAGER_EXCLUSIVE. This is because in
+ ** PAGER_EXCLUSIVE state the code to roll back savepoint transactions
+ ** may copy data from the sub-journal into the database file as well
+ ** as into the page cache. Which would be incorrect in WAL mode.
+ */
+ rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
+ if( rc==SQLITE_OK ){
+ pPager->dbOrigSize = pPager->dbSize;
+ pPager->state = PAGER_RESERVED;
+ pPager->journalOff = 0;
+ }
+
+ assert( rc!=SQLITE_OK || pPager->state==PAGER_RESERVED );
+ assert( rc==SQLITE_OK || pPager->state==PAGER_SHARED );
+ }else{
+ /* Obtain a RESERVED lock on the database file. If the exFlag parameter
+ ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
+ ** busy-handler callback can be used when upgrading to the EXCLUSIVE
+ ** lock, but not when obtaining the RESERVED lock.
+ */
+ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
+ if( rc==SQLITE_OK ){
+ pPager->state = PAGER_RESERVED;
+ if( exFlag ){
+ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ }
}
}
- /* If the required locks were successfully obtained, open the journal
- ** file and write the first journal-header to it.
+ /* No need to open the journal file at this time. It will be
+ ** opened before it is written to. If we defer opening the journal,
+ ** we might save the work of creating a file if the transaction
+ ** ends up being a no-op.
*/
- if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
- rc = pager_open_journal(pPager);
+
+ if( rc!=SQLITE_OK ){
+ assert( !pPager->dbModified );
+ /* Ignore any IO error that occurs within pager_end_transaction(). The
+ ** purpose of this call is to reset the internal state of the pager
+ ** sub-system. It doesn't matter if the journal-file is not properly
+ ** finalized at this point (since it is not a valid journal file anyway).
+ */
+ pager_end_transaction(pPager, 0);
}
- }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){
- /* This happens when the pager was in exclusive-access mode the last
- ** time a (read or write) transaction was successfully concluded
- ** by this connection. Instead of deleting the journal file it was
- ** kept open and either was truncated to 0 bytes or its header was
- ** overwritten with zeros.
- */
- assert( pPager->nRec==0 );
- assert( pPager->dbOrigSize==0 );
- assert( pPager->pInJournal==0 );
- rc = pager_open_journal(pPager);
}
PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager)));
- assert( !isOpen(pPager->jfd) || pPager->journalOff>0 || rc!=SQLITE_OK );
- if( rc!=SQLITE_OK ){
- assert( !pPager->dbModified );
- /* Ignore any IO error that occurs within pager_end_transaction(). The
- ** purpose of this call is to reset the internal state of the pager
- ** sub-system. It doesn't matter if the journal-file is not properly
- ** finalized at this point (since it is not a valid journal file anyway).
- */
- pager_end_transaction(pPager, 0);
- }
return rc;
}
@@ -35575,8 +38295,8 @@
*/
assert( pPager->state>=PAGER_RESERVED );
- /* If an error has been previously detected, we should not be
- ** calling this routine. Repeat the error for robustness.
+ /* If an error has been previously detected, report the same error
+ ** again.
*/
if( NEVER(pPager->errCode) ) return pPager->errCode;
@@ -35593,6 +38313,7 @@
*/
sqlite3PcacheMakeDirty(pPg);
if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){
+ assert( !pagerUseWal(pPager) );
pPager->dbModified = 1;
}else{
@@ -35601,14 +38322,14 @@
** or both.
**
** Higher level routines should have already started a transaction,
- ** which means they have acquired the necessary locks and opened
- ** a rollback journal. Double-check to makes sure this is the case.
+ ** which means they have acquired the necessary locks but the rollback
+ ** journal might not yet be open.
*/
- rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory);
- if( NEVER(rc!=SQLITE_OK) ){
- return rc;
- }
- if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
+ assert( pPager->state>=RESERVED_LOCK );
+ if( pPager->pInJournal==0
+ && pPager->journalMode!=PAGER_JOURNALMODE_OFF
+ && !pagerUseWal(pPager)
+ ){
assert( pPager->useJournal );
rc = pager_open_journal(pPager);
if( rc!=SQLITE_OK ) return rc;
@@ -35620,6 +38341,7 @@
** the transaction journal if it is not there already.
*/
if( !pageInJournal(pPg) && isOpen(pPager->jfd) ){
+ assert( !pagerUseWal(pPager) );
if( pPg->pgno<=pPager->dbOrigSize ){
u32 cksum;
char *pData2;
@@ -35628,6 +38350,8 @@
** contains the database locks. The following assert verifies
** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
+
+ assert( pPager->journalHdr <= pPager->journalOff );
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
cksum = pager_cksum(pPager, (u8*)pData2);
rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno);
@@ -35730,16 +38454,17 @@
if( nPagePerSector>1 ){
Pgno nPageCount; /* Total number of pages in database file */
Pgno pg1; /* First page of the sector pPg is located on. */
- int nPage; /* Number of pages starting at pg1 to journal */
+ int nPage = 0; /* Number of pages starting at pg1 to journal */
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
- /* Set the doNotSync flag to 1. This is because we cannot allow a journal
- ** header to be written between the pages journaled by this function.
+ /* Set the doNotSyncSpill flag to 1. This is because we cannot allow
+ ** a journal header to be written between the pages journaled by
+ ** this function.
*/
assert( !MEMDB );
- assert( pPager->doNotSync==0 );
- pPager->doNotSync = 1;
+ assert( pPager->doNotSyncSpill==0 );
+ pPager->doNotSyncSpill++;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
@@ -35747,17 +38472,19 @@
*/
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
- sqlite3PagerPagecount(pPager, (int *)&nPageCount);
- if( pPg->pgno>nPageCount ){
- nPage = (pPg->pgno - pg1)+1;
- }else if( (pg1+nPagePerSector-1)>nPageCount ){
- nPage = nPageCount+1-pg1;
- }else{
- nPage = nPagePerSector;
+ rc = sqlite3PagerPagecount(pPager, (int *)&nPageCount);
+ if( rc==SQLITE_OK ){
+ if( pPg->pgno>nPageCount ){
+ nPage = (pPg->pgno - pg1)+1;
+ }else if( (pg1+nPagePerSector-1)>nPageCount ){
+ nPage = nPageCount+1-pg1;
+ }else{
+ nPage = nPagePerSector;
+ }
+ assert(nPage>0);
+ assert(pg1<=pPg->pgno);
+ assert((pg1+nPage)>pPg->pgno);
}
- assert(nPage>0);
- assert(pg1<=pPg->pgno);
- assert((pg1+nPage)>pPg->pgno);
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
Pgno pg = pg1+ii;
@@ -35800,8 +38527,8 @@
assert(pPager->needSync);
}
- assert( pPager->doNotSync==1 );
- pPager->doNotSync = 0;
+ assert( pPager->doNotSyncSpill==1 );
+ pPager->doNotSyncSpill--;
}else{
rc = pager_write(pDbPage);
}
@@ -35819,7 +38546,6 @@
}
#endif
-#ifndef SQLITE_SECURE_DELETE
/*
** A call to this routine tells the pager that it is not necessary to
** write the information on page pPg back to the disk, even though
@@ -35845,7 +38571,6 @@
#endif
}
}
-#endif /* !defined(SQLITE_SECURE_DELETE) */
/*
** This routine is called to increment the value of the database file
@@ -35910,11 +38635,20 @@
change_counter++;
put32bits(((char*)pPgHdr->pData)+24, change_counter);
+ /* Also store the SQLite version number in bytes 96..99 and in
+ ** bytes 92..95 store the change counter for which the version number
+ ** is valid. */
+ put32bits(((char*)pPgHdr->pData)+92, change_counter);
+ put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
+
/* If running in direct mode, write the contents of page 1 to the file. */
if( DIRECT_MODE ){
- const void *zBuf = pPgHdr->pData;
+ const void *zBuf;
assert( pPager->dbFileSize>0 );
- rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
+ }
if( rc==SQLITE_OK ){
pPager->changeCountDone = 1;
}
@@ -35983,10 +38717,8 @@
/* The dbOrigSize is never set if journal_mode=OFF */
assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF || pPager->dbOrigSize==0 );
- /* If a prior error occurred, this routine should not be called. ROLLBACK
- ** is the appropriate response to an error, not COMMIT. Guard against
- ** coding errors by repeating the prior error. */
- if( NEVER(pPager->errCode) ) return pPager->errCode;
+ /* If a prior error occurred, report that error again. */
+ if( pPager->errCode ) return pPager->errCode;
PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
@@ -35998,129 +38730,143 @@
*/
sqlite3BackupRestart(pPager->pBackup);
}else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){
-
- /* The following block updates the change-counter. Exactly how it
- ** does this depends on whether or not the atomic-update optimization
- ** was enabled at compile time, and if this transaction meets the
- ** runtime criteria to use the operation:
- **
- ** * The file-system supports the atomic-write property for
- ** blocks of size page-size, and
- ** * This commit is not part of a multi-file transaction, and
- ** * Exactly one page has been modified and store in the journal file.
- **
- ** If the optimization was not enabled at compile time, then the
- ** pager_incr_changecounter() function is called to update the change
- ** counter in 'indirect-mode'. If the optimization is compiled in but
- ** is not applicable to this transaction, call sqlite3JournalCreate()
- ** to make sure the journal file has actually been created, then call
- ** pager_incr_changecounter() to update the change-counter in indirect
- ** mode.
- **
- ** Otherwise, if the optimization is both enabled and applicable,
- ** then call pager_incr_changecounter() to update the change-counter
- ** in 'direct' mode. In this case the journal file will never be
- ** created for this transaction.
- */
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
- PgHdr *pPg;
- assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbFileSize
- && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
- ){
- /* Update the db file change counter via the direct-write method. The
- ** following call will modify the in-memory representation of page 1
- ** to include the updated change counter and then write page 1
- ** directly to the database file. Because of the atomic-write
- ** property of the host file-system, this is safe.
- */
- rc = pager_incr_changecounter(pPager, 1);
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 0);
+ if( pagerUseWal(pPager) ){
+ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
+ if( pList ){
+ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
+ (pPager->fullSync ? pPager->sync_flags : 0)
+ );
}
- }
-#else
- rc = pager_incr_changecounter(pPager, 0);
-#endif
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file. This can only happen in auto-vacuum mode.
- **
- ** Before reading the pages with page numbers larger than the
- ** current value of Pager.dbSize, set dbSize back to the value
- ** that it took at the start of the transaction. Otherwise, the
- ** calls to sqlite3PagerGet() return zeroed pages instead of
- ** reading data from the database file.
- **
- ** When journal_mode==OFF the dbOrigSize is always zero, so this
- ** block never runs if journal_mode=OFF.
- */
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pPager->dbSize<pPager->dbOrigSize
- && ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
- ){
- Pgno i; /* Iterator variable */
- const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
- const Pgno dbSize = pPager->dbSize; /* Database image size */
- pPager->dbSize = pPager->dbOrigSize;
- for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
- if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
- PgHdr *pPage; /* Page to journal */
- rc = sqlite3PagerGet(pPager, i, &pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
- rc = sqlite3PagerWrite(pPage);
- sqlite3PagerUnref(pPage);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ if( rc==SQLITE_OK ){
+ sqlite3PcacheCleanAll(pPager->pPCache);
+ }
+ }else{
+ /* The following block updates the change-counter. Exactly how it
+ ** does this depends on whether or not the atomic-update optimization
+ ** was enabled at compile time, and if this transaction meets the
+ ** runtime criteria to use the operation:
+ **
+ ** * The file-system supports the atomic-write property for
+ ** blocks of size page-size, and
+ ** * This commit is not part of a multi-file transaction, and
+ ** * Exactly one page has been modified and store in the journal file.
+ **
+ ** If the optimization was not enabled at compile time, then the
+ ** pager_incr_changecounter() function is called to update the change
+ ** counter in 'indirect-mode'. If the optimization is compiled in but
+ ** is not applicable to this transaction, call sqlite3JournalCreate()
+ ** to make sure the journal file has actually been created, then call
+ ** pager_incr_changecounter() to update the change-counter in indirect
+ ** mode.
+ **
+ ** Otherwise, if the optimization is both enabled and applicable,
+ ** then call pager_incr_changecounter() to update the change-counter
+ ** in 'direct' mode. In this case the journal file will never be
+ ** created for this transaction.
+ */
+ #ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ PgHdr *pPg;
+ assert( isOpen(pPager->jfd)
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ if( !zMaster && isOpen(pPager->jfd)
+ && pPager->journalOff==jrnlBufferSize(pPager)
+ && pPager->dbSize>=pPager->dbFileSize
+ && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
+ ){
+ /* Update the db file change counter via the direct-write method. The
+ ** following call will modify the in-memory representation of page 1
+ ** to include the updated change counter and then write page 1
+ ** directly to the database file. Because of the atomic-write
+ ** property of the host file-system, this is safe.
+ */
+ rc = pager_incr_changecounter(pPager, 1);
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 0);
}
- }
- pPager->dbSize = dbSize;
- }
-#endif
-
- /* Write the master journal name into the journal file. If a master
- ** journal file name has already been written to the journal file,
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
- */
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Sync the journal file. If the atomic-update optimization is being
- ** used, this call will not create the journal file or perform any
- ** real IO.
- */
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Write all dirty pages to the database file. */
- rc = pager_write_pagelist(sqlite3PcacheDirtyList(pPager->pPCache));
- if( rc!=SQLITE_OK ){
- assert( rc!=SQLITE_IOERR_BLOCKED );
- goto commit_phase_one_exit;
- }
- sqlite3PcacheCleanAll(pPager->pPCache);
-
- /* If the file on disk is not the same size as the database image,
- ** then use pager_truncate to grow or shrink the file here.
- */
- if( pPager->dbSize!=pPager->dbFileSize ){
- Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
- assert( pPager->state>=PAGER_EXCLUSIVE );
- rc = pager_truncate(pPager, nNew);
+ }
+ #else
+ rc = pager_incr_changecounter(pPager, 0);
+ #endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* If this transaction has made the database smaller, then all pages
+ ** being discarded by the truncation must be written to the journal
+ ** file. This can only happen in auto-vacuum mode.
+ **
+ ** Before reading the pages with page numbers larger than the
+ ** current value of Pager.dbSize, set dbSize back to the value
+ ** that it took at the start of the transaction. Otherwise, the
+ ** calls to sqlite3PagerGet() return zeroed pages instead of
+ ** reading data from the database file.
+ **
+ ** When journal_mode==OFF the dbOrigSize is always zero, so this
+ ** block never runs if journal_mode=OFF.
+ */
+ #ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPager->dbSize<pPager->dbOrigSize
+ && ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF)
+ ){
+ Pgno i; /* Iterator variable */
+ const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
+ const Pgno dbSize = pPager->dbSize; /* Database image size */
+ pPager->dbSize = pPager->dbOrigSize;
+ for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
+ if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
+ PgHdr *pPage; /* Page to journal */
+ rc = sqlite3PagerGet(pPager, i, &pPage);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ rc = sqlite3PagerWrite(pPage);
+ sqlite3PagerUnref(pPage);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+ }
+ pPager->dbSize = dbSize;
+ }
+ #endif
+
+ /* Write the master journal name into the journal file. If a master
+ ** journal file name has already been written to the journal file,
+ ** or if zMaster is NULL (no master journal), then this call is a no-op.
+ */
+ rc = writeMasterJournal(pPager, zMaster);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* Sync the journal file. If the atomic-update optimization is being
+ ** used, this call will not create the journal file or perform any
+ ** real IO.
+ */
+ rc = syncJournal(pPager);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+
+ /* Write all dirty pages to the database file. */
+ rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+ if( rc!=SQLITE_OK ){
+ assert( rc!=SQLITE_IOERR_BLOCKED );
+ goto commit_phase_one_exit;
+ }
+ sqlite3PcacheCleanAll(pPager->pPCache);
+
+ /* If the file on disk is not the same size as the database image,
+ ** then use pager_truncate to grow or shrink the file here.
+ */
+ if( pPager->dbSize!=pPager->dbFileSize ){
+ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
+ assert( pPager->state>=PAGER_EXCLUSIVE );
+ rc = pager_truncate(pPager, nNew);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ }
+
+ /* Finally, sync the database file. */
+ if( !pPager->noSync && !noSync ){
+ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
+ }
+ IOTRACE(("DBSYNC %p\n", pPager))
}
- /* Finally, sync the database file. */
- if( !pPager->noSync && !noSync ){
- rc = sqlite3OsSync(pPager->fd, pPager->sync_flags);
- }
- IOTRACE(("DBSYNC %p\n", pPager))
-
pPager->state = PAGER_SYNCED;
}
@@ -36153,8 +38899,9 @@
if( NEVER(pPager->errCode) ) return pPager->errCode;
/* This function should not be called if the pager is not in at least
- ** PAGER_RESERVED state. And indeed SQLite never does this. But it is
- ** nice to have this defensive test here anyway.
+ ** PAGER_RESERVED state. **FIXME**: Make it so that this test always
+ ** fails - make it so that we never reach this point if we do not hold
+ ** all necessary locks.
*/
if( NEVER(pPager->state<PAGER_RESERVED) ) return SQLITE_ERROR;
@@ -36172,7 +38919,7 @@
if( pPager->dbModified==0 && pPager->exclusiveMode
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST
){
- assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
+ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
return SQLITE_OK;
}
@@ -36205,7 +38952,7 @@
** (i.e. either SQLITE_IOERR or SQLITE_CORRUPT).
**
** * If the pager is in PAGER_RESERVED state, then attempt (1). Whether
-** or not (1) is succussful, also attempt (2). If successful, return
+** or not (1) is successful, also attempt (2). If successful, return
** SQLITE_OK. Otherwise, enter the error state and return the first
** error code encountered.
**
@@ -36228,7 +38975,14 @@
SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
int rc = SQLITE_OK; /* Return code */
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
- if( !pPager->dbModified || !isOpen(pPager->jfd) ){
+ if( pagerUseWal(pPager) ){
+ int rc2;
+
+ rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
+ rc2 = pager_end_transaction(pPager, pPager->setMaster);
+ if( rc==SQLITE_OK ) rc = rc2;
+ rc = pager_error(pPager, rc);
+ }else if( !pPager->dbModified || !isOpen(pPager->jfd) ){
rc = pager_end_transaction(pPager, pPager->setMaster);
}else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
@@ -36276,6 +39030,16 @@
}
/*
+** Return the approximate number of bytes of memory currently
+** used by the pager and its associated cache.
+*/
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
+ int perPageSize = pPager->pageSize + pPager->nExtra + 20;
+ return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
+ + sqlite3MallocSize(pPager);
+}
+
+/*
** Return the number of references to the specified page.
*/
SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage *pPage){
@@ -36327,11 +39091,10 @@
if( nSavepoint>nCurrent && pPager->useJournal ){
int ii; /* Iterator variable */
PagerSavepoint *aNew; /* New Pager.aSavepoint array */
+ int nPage; /* Size of database file */
- /* Either there is no active journal or the sub-journal is open or
- ** the journal is always stored in memory */
- assert( pPager->nSavepoint==0 || isOpen(pPager->sjfd) ||
- pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
+ rc = sqlite3PagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
/* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
** if the allocation fails. Otherwise, zero the new portion in case a
@@ -36345,26 +39108,26 @@
}
memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
pPager->aSavepoint = aNew;
- pPager->nSavepoint = nSavepoint;
/* Populate the PagerSavepoint structures just allocated. */
for(ii=nCurrent; ii<nSavepoint; ii++){
- assert( pPager->dbSizeValid );
- aNew[ii].nOrig = pPager->dbSize;
- if( isOpen(pPager->jfd) && ALWAYS(pPager->journalOff>0) ){
+ aNew[ii].nOrig = nPage;
+ if( isOpen(pPager->jfd) && pPager->journalOff>0 ){
aNew[ii].iOffset = pPager->journalOff;
}else{
aNew[ii].iOffset = JOURNAL_HDR_SZ(pPager);
}
aNew[ii].iSubRec = pPager->nSubRec;
- aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
+ aNew[ii].pInSavepoint = sqlite3BitvecCreate(nPage);
if( !aNew[ii].pInSavepoint ){
return SQLITE_NOMEM;
}
+ if( pagerUseWal(pPager) ){
+ sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
+ }
+ pPager->nSavepoint = ii+1;
}
-
- /* Open the sub-journal, if it is not already opened. */
- rc = openSubJournal(pPager);
+ assert( pPager->nSavepoint==nSavepoint );
assertTruncateConstraint(pPager);
}
@@ -36428,6 +39191,7 @@
/* Only truncate if it is an in-memory sub-journal. */
if( sqlite3IsMemJournal(pPager->sjfd) ){
rc = sqlite3OsTruncate(pPager->sjfd, 0);
+ assert( rc==SQLITE_OK );
}
pPager->nSubRec = 0;
}
@@ -36437,7 +39201,7 @@
** not yet been opened. In this case there have been no changes to
** the database file, so the playback operation can be skipped.
*/
- else if( isOpen(pPager->jfd) ){
+ else if( pagerUseWal(pPager) || isOpen(pPager->jfd) ){
PagerSavepoint *pSavepoint = (nNew==0)?0:&pPager->aSavepoint[nNew-1];
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
@@ -36489,7 +39253,7 @@
/*
** Set or retrieve the codec for this pager
*/
-static void sqlite3PagerSetCodec(
+SQLITE_PRIVATE void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void (*xCodecSizeChng)(void*,int,int),
@@ -36503,7 +39267,7 @@
pPager->pCodec = pCodec;
pagerReportSize(pPager);
}
-static void *sqlite3PagerGetCodec(Pager *pPager){
+SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
return pPager->pCodec;
}
#endif
@@ -36706,49 +39470,132 @@
}
/*
-** Get/set the journal-mode for this pager. Parameter eMode must be one of:
+** Set the journal-mode for this pager. Parameter eMode must be one of:
**
-** PAGER_JOURNALMODE_QUERY
** PAGER_JOURNALMODE_DELETE
** PAGER_JOURNALMODE_TRUNCATE
** PAGER_JOURNALMODE_PERSIST
** PAGER_JOURNALMODE_OFF
** PAGER_JOURNALMODE_MEMORY
+** PAGER_JOURNALMODE_WAL
**
-** If the parameter is not _QUERY, then the journal_mode is set to the
-** value specified if the change is allowed. The change is disallowed
-** for the following reasons:
+** The journalmode is set to the value specified if the change is allowed.
+** The change may be disallowed for the following reasons:
**
** * An in-memory database can only have its journal_mode set to _OFF
** or _MEMORY.
**
-** * The journal mode may not be changed while a transaction is active.
+** * Temporary databases cannot have _WAL journalmode.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
-SQLITE_PRIVATE int sqlite3PagerJournalMode(Pager *pPager, int eMode){
- assert( eMode==PAGER_JOURNALMODE_QUERY
- || eMode==PAGER_JOURNALMODE_DELETE
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
+ u8 eOld = pPager->journalMode; /* Prior journalmode */
+
+ /* The eMode parameter is always valid */
+ assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
+ || eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
- assert( PAGER_JOURNALMODE_QUERY<0 );
- if( eMode>=0
- && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY
- || eMode==PAGER_JOURNALMODE_OFF)
- && !pPager->dbModified
- && (!isOpen(pPager->jfd) || 0==pPager->journalOff)
- ){
- if( isOpen(pPager->jfd) ){
+
+ /* Do not allow the journalmode of a TEMP database to be changed to WAL
+ */
+ if( pPager->tempFile && eMode==PAGER_JOURNALMODE_WAL ){
+ assert( eOld!=PAGER_JOURNALMODE_WAL );
+ eMode = eOld;
+ }
+
+ /* Do allow the journalmode of an in-memory database to be set to
+ ** anything other than MEMORY or OFF
+ */
+ if( MEMDB ){
+ assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
+ if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
+ eMode = eOld;
+ }
+ }
+
+ if( eMode!=eOld ){
+ /* When changing between rollback modes, close the journal file prior
+ ** to the change. But when changing from a rollback mode to WAL, keep
+ ** the journal open since there is a rollback-style transaction in play
+ ** used to convert the version numbers in the btree header.
+ */
+ if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
sqlite3OsClose(pPager->jfd);
}
+
+ /* Change the journal mode. */
pPager->journalMode = (u8)eMode;
+
+ /* When transistioning from TRUNCATE or PERSIST to any other journal
+ ** mode except WAL (and we are not in locking_mode=EXCLUSIVE) then
+ ** delete the journal file.
+ */
+ assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
+ assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
+ assert( (PAGER_JOURNALMODE_DELETE & 5)==0 );
+ assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 );
+ assert( (PAGER_JOURNALMODE_OFF & 5)==0 );
+ assert( (PAGER_JOURNALMODE_WAL & 5)==5 );
+
+ assert( isOpen(pPager->fd) || pPager->exclusiveMode );
+ if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
+
+ /* In this case we would like to delete the journal file. If it is
+ ** not possible, then that is not a problem. Deleting the journal file
+ ** here is an optimization only.
+ **
+ ** Before deleting the journal file, obtain a RESERVED lock on the
+ ** database file. This ensures that the journal file is not deleted
+ ** while it is in use by some other client.
+ */
+ int rc = SQLITE_OK;
+ int state = pPager->state;
+ if( state<PAGER_SHARED ){
+ rc = sqlite3PagerSharedLock(pPager);
+ }
+ if( pPager->state==PAGER_SHARED ){
+ assert( rc==SQLITE_OK );
+ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
+ }
+ if( rc==SQLITE_OK && state==PAGER_SHARED ){
+ sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
+ }else if( state==PAGER_UNLOCK ){
+ pager_unlock(pPager);
+ }
+ assert( state==pPager->state );
+ }
}
+
+ /* Return the new journal mode */
return (int)pPager->journalMode;
}
/*
+** Return the current journal mode.
+*/
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
+ return (int)pPager->journalMode;
+}
+
+/*
+** Return TRUE if the pager is in a state where it is OK to change the
+** journalmode. Journalmode changes can only happen when the database
+** is unmodified.
+*/
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
+ if( pPager->dbModified ) return 0;
+ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
+ return 1;
+}
+
+/*
** Get/set the size-limit used for persistent journal files.
**
** Setting the size limit to -1 means no limit is enforced.
@@ -36771,9 +39618,2790 @@
return &pPager->pBackup;
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** This function is called when the user invokes "PRAGMA checkpoint".
+*/
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager){
+ int rc = SQLITE_OK;
+ if( pPager->pWal ){
+ u8 *zBuf = (u8 *)pPager->pTmpSpace;
+ rc = sqlite3WalCheckpoint(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, zBuf
+ );
+ }
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
+ return sqlite3WalCallback(pPager->pWal);
+}
+
+/*
+** Return true if the underlying VFS for the given pager supports the
+** primitives necessary for write-ahead logging.
+*/
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
+ const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+ return pMethods->iVersion>=2 && pMethods->xShmOpen!=0;
+}
+
+/*
+** The caller must be holding a SHARED lock on the database file to call
+** this function.
+**
+** If the pager passed as the first argument is open on a real database
+** file (not a temp file or an in-memory database), and the WAL file
+** is not already open, make an attempt to open it now. If successful,
+** return SQLITE_OK. If an error occurs or the VFS used by the pager does
+** not support the xShmXXX() methods, return an error code. *pisOpen is
+** not modified in either case.
+**
+** If the pager is open on a temp-file (or in-memory database), or if
+** the WAL file is already open, set *pisOpen to 1 and return SQLITE_OK
+** without doing anything.
+*/
+SQLITE_PRIVATE int sqlite3PagerOpenWal(
+ Pager *pPager, /* Pager object */
+ int *pisOpen /* OUT: Set to true if call is a no-op */
+){
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pPager->state>=PAGER_SHARED );
+ assert( (pisOpen==0 && !pPager->tempFile && !pPager->pWal) || *pisOpen==0 );
+
+ if( !pPager->tempFile && !pPager->pWal ){
+ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN;
+
+ /* Open the connection to the log file. If this operation fails,
+ ** (e.g. due to malloc() failure), unlock the database file and
+ ** return an error code.
+ */
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, &pPager->pWal);
+ if( rc==SQLITE_OK ){
+ pPager->journalMode = PAGER_JOURNALMODE_WAL;
+ }
+ }else{
+ *pisOpen = 1;
+ }
+
+ return rc;
+}
+
+/*
+** This function is called to close the connection to the log file prior
+** to switching from WAL to rollback mode.
+**
+** Before closing the log file, this function attempts to take an
+** EXCLUSIVE lock on the database file. If this cannot be obtained, an
+** error (SQLITE_BUSY) is returned and the log connection is not closed.
+** If successful, the EXCLUSIVE lock is not released before returning.
+*/
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+ int rc = SQLITE_OK;
+
+ assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
+
+ /* If the log file is not already open, but does exist in the file-system,
+ ** it may need to be checkpointed before the connection can switch to
+ ** rollback mode. Open it now so this can happen.
+ */
+ if( !pPager->pWal ){
+ int logexists = 0;
+ rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
+ );
+ }
+ if( rc==SQLITE_OK && logexists ){
+ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
+ pPager->zWal, &pPager->pWal);
+ }
+ }
+
+ /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
+ ** the database file, the log and log-summary files will be deleted.
+ */
+ if( rc==SQLITE_OK && pPager->pWal ){
+ rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3WalClose(pPager->pWal,
+ (pPager->noSync ? 0 : pPager->sync_flags),
+ pPager->pageSize, (u8*)pPager->pTmpSpace
+ );
+ pPager->pWal = 0;
+ }else{
+ /* If we cannot get an EXCLUSIVE lock, downgrade the PENDING lock
+ ** that we did get back to SHARED. */
+ sqlite3OsUnlock(pPager->fd, SQLITE_LOCK_SHARED);
+ }
+ }
+ return rc;
+}
+
+#ifdef SQLITE_HAS_CODEC
+/*
+** This function is called by the wal module when writing page content
+** into the log file.
+**
+** This function returns a pointer to a buffer containing the encrypted
+** page content. If a malloc fails, this function may return NULL.
+*/
+SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
+ void *aData = 0;
+ CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
+ return aData;
+}
+#endif /* SQLITE_HAS_CODEC */
+
+#endif /* !SQLITE_OMIT_WAL */
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
+/************** Begin file wal.c *********************************************/
+/*
+** 2010 February 1
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains the implementation of a write-ahead log (WAL) used in
+** "journal_mode=WAL" mode.
+**
+** WRITE-AHEAD LOG (WAL) FILE FORMAT
+**
+** A WAL file consists of a header followed by zero or more "frames".
+** Each frame records the revised content of a single page from the
+** database file. All changes to the database are recorded by writing
+** frames into the WAL. Transactions commit when a frame is written that
+** contains a commit marker. A single WAL can and usually does record
+** multiple transactions. Periodically, the content of the WAL is
+** transferred back into the database file in an operation called a
+** "checkpoint".
+**
+** A single WAL file can be used multiple times. In other words, the
+** WAL can fill up with frames and then be checkpointed and then new
+** frames can overwrite the old ones. A WAL always grows from beginning
+** toward the end. Checksums and counters attached to each frame are
+** used to determine which frames within the WAL are valid and which
+** are leftovers from prior checkpoints.
+**
+** The WAL header is 32 bytes in size and consists of the following eight
+** big-endian 32-bit unsigned integer values:
+**
+** 0: Magic number. 0x377f0682 or 0x377f0683
+** 4: File format version. Currently 3007000
+** 8: Database page size. Example: 1024
+** 12: Checkpoint sequence number
+** 16: Salt-1, random integer incremented with each checkpoint
+** 20: Salt-2, a different random integer changing with each ckpt
+** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
+** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
+**
+** Immediately following the wal-header are zero or more frames. Each
+** frame consists of a 24-byte frame-header followed by a <page-size> bytes
+** of page data. The frame-header is six big-endian 32-bit unsigned
+** integer values, as follows:
+**
+** 0: Page number.
+** 4: For commit records, the size of the database image in pages
+** after the commit. For all other records, zero.
+** 8: Salt-1 (copied from the header)
+** 12: Salt-2 (copied from the header)
+** 16: Checksum-1.
+** 20: Checksum-2.
+**
+** A frame is considered valid if and only if the following conditions are
+** true:
+**
+** (1) The salt-1 and salt-2 values in the frame-header match
+** salt values in the wal-header
+**
+** (2) The checksum values in the final 8 bytes of the frame-header
+** exactly match the checksum computed consecutively on the
+** WAL header and the first 8 bytes and the content of all frames
+** up to and including the current frame.
+**
+** The checksum is computed using 32-bit big-endian integers if the
+** magic number in the first 4 bytes of the WAL is 0x377f0683 and it
+** is computed using little-endian if the magic number is 0x377f0682.
+** The checksum values are always stored in the frame header in a
+** big-endian format regardless of which byte order is used to compute
+** the checksum. The checksum is computed by interpreting the input as
+** an even number of unsigned 32-bit integers: x[0] through x[N]. The
+** algorithm used for the checksum is as follows:
+**
+** for i from 0 to n-1 step 2:
+** s0 += x[i] + s1;
+** s1 += x[i+1] + s0;
+** endfor
+**
+** Note that s0 and s1 are both weighted checksums using fibonacci weights
+** in reverse order (the largest fibonacci weight occurs on the first element
+** of the sequence being summed.) The s1 value spans all 32-bit
+** terms of the sequence whereas s0 omits the final term.
+**
+** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
+** WAL is transferred into the database, then the database is VFS.xSync-ed.
+** The VFS.xSync operations serve as write barriers - all writes launched
+** before the xSync must complete before any write that launches after the
+** xSync begins.
+**
+** After each checkpoint, the salt-1 value is incremented and the salt-2
+** value is randomized. This prevents old and new frames in the WAL from
+** being considered valid at the same time and being checkpointing together
+** following a crash.
+**
+** READER ALGORITHM
+**
+** To read a page from the database (call it page number P), a reader
+** first checks the WAL to see if it contains page P. If so, then the
+** last valid instance of page P that is a followed by a commit frame
+** or is a commit frame itself becomes the value read. If the WAL
+** contains no copies of page P that are valid and which are a commit
+** frame or are followed by a commit frame, then page P is read from
+** the database file.
+**
+** To start a read transaction, the reader records the index of the last
+** valid frame in the WAL. The reader uses this recorded "mxFrame" value
+** for all subsequent read operations. New transactions can be appended
+** to the WAL, but as long as the reader uses its original mxFrame value
+** and ignores the newly appended content, it will see a consistent snapshot
+** of the database from a single point in time. This technique allows
+** multiple concurrent readers to view different versions of the database
+** content simultaneously.
+**
+** The reader algorithm in the previous paragraphs works correctly, but
+** because frames for page P can appear anywhere within the WAL, the
+** reader has to scan the entire WAL looking for page P frames. If the
+** WAL is large (multiple megabytes is typical) that scan can be slow,
+** and read performance suffers. To overcome this problem, a separate
+** data structure called the wal-index is maintained to expedite the
+** search for frames of a particular page.
+**
+** WAL-INDEX FORMAT
+**
+** Conceptually, the wal-index is shared memory, though VFS implementations
+** might choose to implement the wal-index using a mmapped file. Because
+** the wal-index is shared memory, SQLite does not support journal_mode=WAL
+** on a network filesystem. All users of the database must be able to
+** share memory.
+**
+** The wal-index is transient. After a crash, the wal-index can (and should
+** be) reconstructed from the original WAL file. In fact, the VFS is required
+** to either truncate or zero the header of the wal-index when the last
+** connection to it closes. Because the wal-index is transient, it can
+** use an architecture-specific format; it does not have to be cross-platform.
+** Hence, unlike the database and WAL file formats which store all values
+** as big endian, the wal-index can store multi-byte values in the native
+** byte order of the host computer.
+**
+** The purpose of the wal-index is to answer this question quickly: Given
+** a page number P, return the index of the last frame for page P in the WAL,
+** or return NULL if there are no frames for page P in the WAL.
+**
+** The wal-index consists of a header region, followed by an one or
+** more index blocks.
+**
+** The wal-index header contains the total number of frames within the WAL
+** in the the mxFrame field.
+**
+** Each index block except for the first contains information on
+** HASHTABLE_NPAGE frames. The first index block contains information on
+** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
+** HASHTABLE_NPAGE are selected so that together the wal-index header and
+** first index block are the same size as all other index blocks in the
+** wal-index.
+**
+** Each index block contains two sections, a page-mapping that contains the
+** database page number associated with each wal frame, and a hash-table
+** that allows readers to query an index block for a specific page number.
+** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
+** for the first index block) 32-bit page numbers. The first entry in the
+** first index-block contains the database page number corresponding to the
+** first frame in the WAL file. The first entry in the second index block
+** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
+** the log, and so on.
+**
+** The last index block in a wal-index usually contains less than the full
+** complement of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE) page-numbers,
+** depending on the contents of the WAL file. This does not change the
+** allocated size of the page-mapping array - the page-mapping array merely
+** contains unused entries.
+**
+** Even without using the hash table, the last frame for page P
+** can be found by scanning the page-mapping sections of each index block
+** starting with the last index block and moving toward the first, and
+** within each index block, starting at the end and moving toward the
+** beginning. The first entry that equals P corresponds to the frame
+** holding the content for that page.
+**
+** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
+** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
+** hash table for each page number in the mapping section, so the hash
+** table is never more than half full. The expected number of collisions
+** prior to finding a match is 1. Each entry of the hash table is an
+** 1-based index of an entry in the mapping section of the same
+** index block. Let K be the 1-based index of the largest entry in
+** the mapping section. (For index blocks other than the last, K will
+** always be exactly HASHTABLE_NPAGE (4096) and for the last index block
+** K will be (mxFrame%HASHTABLE_NPAGE).) Unused slots of the hash table
+** contain a value of 0.
+**
+** To look for page P in the hash table, first compute a hash iKey on
+** P as follows:
+**
+** iKey = (P * 383) % HASHTABLE_NSLOT
+**
+** Then start scanning entries of the hash table, starting with iKey
+** (wrapping around to the beginning when the end of the hash table is
+** reached) until an unused hash slot is found. Let the first unused slot
+** be at index iUnused. (iUnused might be less than iKey if there was
+** wrap-around.) Because the hash table is never more than half full,
+** the search is guaranteed to eventually hit an unused entry. Let
+** iMax be the value between iKey and iUnused, closest to iUnused,
+** where aHash[iMax]==P. If there is no iMax entry (if there exists
+** no hash slot such that aHash[i]==p) then page P is not in the
+** current index block. Otherwise the iMax-th mapping entry of the
+** current index block corresponds to the last entry that references
+** page P.
+**
+** A hash search begins with the last index block and moves toward the
+** first index block, looking for entries corresponding to page P. On
+** average, only two or three slots in each index block need to be
+** examined in order to either find the last entry for page P, or to
+** establish that no such entry exists in the block. Each index block
+** holds over 4000 entries. So two or three index blocks are sufficient
+** to cover a typical 10 megabyte WAL file, assuming 1K pages. 8 or 10
+** comparisons (on average) suffice to either locate a frame in the
+** WAL or to establish that the frame does not exist in the WAL. This
+** is much faster than scanning the entire 10MB WAL.
+**
+** Note that entries are added in order of increasing K. Hence, one
+** reader might be using some value K0 and a second reader that started
+** at a later time (after additional transactions were added to the WAL
+** and to the wal-index) might be using a different value K1, where K1>K0.
+** Both readers can use the same hash table and mapping section to get
+** the correct result. There may be entries in the hash table with
+** K>K0 but to the first reader, those entries will appear to be unused
+** slots in the hash table and so the first reader will get an answer as
+** if no values greater than K0 had ever been inserted into the hash table
+** in the first place - which is what reader one wants. Meanwhile, the
+** second reader using K1 will see additional values that were inserted
+** later, which is exactly what reader two wants.
+**
+** When a rollback occurs, the value of K is decreased. Hash table entries
+** that correspond to frames greater than the new K value are removed
+** from the hash table at this point.
+*/
+#ifndef SQLITE_OMIT_WAL
+
+
+/*
+** Trace output macros
+*/
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3WalTrace = 0;
+# define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X
+#else
+# define WALTRACE(X)
+#endif
+
+/*
+** The maximum (and only) versions of the wal and wal-index formats
+** that may be interpreted by this version of SQLite.
+**
+** If a client begins recovering a WAL file and finds that (a) the checksum
+** values in the wal-header are correct and (b) the version field is not
+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
+**
+** Similarly, if a client successfully reads a wal-index header (i.e. the
+** checksum test is successful) and finds that the version field is not
+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
+** returns SQLITE_CANTOPEN.
+*/
+#define WAL_MAX_VERSION 3007000
+#define WALINDEX_MAX_VERSION 3007000
+
+/*
+** Indices of various locking bytes. WAL_NREADER is the number
+** of available reader locks and should be at least 3.
+*/
+#define WAL_WRITE_LOCK 0
+#define WAL_ALL_BUT_WRITE 1
+#define WAL_CKPT_LOCK 1
+#define WAL_RECOVER_LOCK 2
+#define WAL_READ_LOCK(I) (3+(I))
+#define WAL_NREADER (SQLITE_SHM_NLOCK-3)
+
+
+/* Object declarations */
+typedef struct WalIndexHdr WalIndexHdr;
+typedef struct WalIterator WalIterator;
+typedef struct WalCkptInfo WalCkptInfo;
+
+
+/*
+** The following object holds a copy of the wal-index header content.
+**
+** The actual header in the wal-index consists of two copies of this
+** object.
+*/
+struct WalIndexHdr {
+ u32 iVersion; /* Wal-index version */
+ u32 unused; /* Unused (padding) field */
+ u32 iChange; /* Counter incremented each transaction */
+ u8 isInit; /* 1 when initialized */
+ u8 bigEndCksum; /* True if checksums in WAL are big-endian */
+ u16 szPage; /* Database page size in bytes */
+ u32 mxFrame; /* Index of last valid frame in the WAL */
+ u32 nPage; /* Size of database in pages */
+ u32 aFrameCksum[2]; /* Checksum of last frame in log */
+ u32 aSalt[2]; /* Two salt values copied from WAL header */
+ u32 aCksum[2]; /* Checksum over all prior fields */
+};
+
+/*
+** A copy of the following object occurs in the wal-index immediately
+** following the second copy of the WalIndexHdr. This object stores
+** information used by checkpoint.
+**
+** nBackfill is the number of frames in the WAL that have been written
+** back into the database. (We call the act of moving content from WAL to
+** database "backfilling".) The nBackfill number is never greater than
+** WalIndexHdr.mxFrame. nBackfill can only be increased by threads
+** holding the WAL_CKPT_LOCK lock (which includes a recovery thread).
+** However, a WAL_WRITE_LOCK thread can move the value of nBackfill from
+** mxFrame back to zero when the WAL is reset.
+**
+** There is one entry in aReadMark[] for each reader lock. If a reader
+** holds read-lock K, then the value in aReadMark[K] is no greater than
+** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
+** for any aReadMark[] means that entry is unused. aReadMark[0] is
+** a special case; its value is never used and it exists as a place-holder
+** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
+** directly from the database.
+**
+** The value of aReadMark[K] may only be changed by a thread that
+** is holding an exclusive lock on WAL_READ_LOCK(K). Thus, the value of
+** aReadMark[K] cannot changed while there is a reader is using that mark
+** since the reader will be holding a shared lock on WAL_READ_LOCK(K).
+**
+** The checkpointer may only transfer frames from WAL to database where
+** the frame numbers are less than or equal to every aReadMark[] that is
+** in use (that is, every aReadMark[j] for which there is a corresponding
+** WAL_READ_LOCK(j)). New readers (usually) pick the aReadMark[] with the
+** largest value and will increase an unused aReadMark[] to mxFrame if there
+** is not already an aReadMark[] equal to mxFrame. The exception to the
+** previous sentence is when nBackfill equals mxFrame (meaning that everything
+** in the WAL has been backfilled into the database) then new readers
+** will choose aReadMark[0] which has value 0 and hence such reader will
+** get all their all content directly from the database file and ignore
+** the WAL.
+**
+** Writers normally append new frames to the end of the WAL. However,
+** if nBackfill equals mxFrame (meaning that all WAL content has been
+** written back into the database) and if no readers are using the WAL
+** (in other words, if there are no WAL_READ_LOCK(i) where i>0) then
+** the writer will first "reset" the WAL back to the beginning and start
+** writing new content beginning at frame 1.
+**
+** We assume that 32-bit loads are atomic and so no locks are needed in
+** order to read from any aReadMark[] entries.
+*/
+struct WalCkptInfo {
+ u32 nBackfill; /* Number of WAL frames backfilled into DB */
+ u32 aReadMark[WAL_NREADER]; /* Reader marks */
+};
+#define READMARK_NOT_USED 0xffffffff
+
+
+/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
+** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
+** only support mandatory file-locks, we do not read or write data
+** from the region of the file on which locks are applied.
+*/
+#define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2 + sizeof(WalCkptInfo))
+#define WALINDEX_LOCK_RESERVED 16
+#define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED)
+
+/* Size of header before each frame in wal */
+#define WAL_FRAME_HDRSIZE 24
+
+/* Size of write ahead log header, including checksum. */
+/* #define WAL_HDRSIZE 24 */
+#define WAL_HDRSIZE 32
+
+/* WAL magic value. Either this value, or the same value with the least
+** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
+** big-endian format in the first 4 bytes of a WAL file.
+**
+** If the LSB is set, then the checksums for each frame within the WAL
+** file are calculated by treating all data as an array of 32-bit
+** big-endian words. Otherwise, they are calculated by interpreting
+** all data as 32-bit little-endian words.
+*/
+#define WAL_MAGIC 0x377f0682
+
+/*
+** Return the offset of frame iFrame in the write-ahead log file,
+** assuming a database page size of szPage bytes. The offset returned
+** is to the start of the write-ahead log frame-header.
+*/
+#define walFrameOffset(iFrame, szPage) ( \
+ WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
+)
+
+/*
+** An open write-ahead log file is represented by an instance of the
+** following object.
+*/
+struct Wal {
+ sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
+ sqlite3_file *pDbFd; /* File handle for the database file */
+ sqlite3_file *pWalFd; /* File handle for WAL file */
+ u32 iCallback; /* Value to pass to log callback (or 0) */
+ int nWiData; /* Size of array apWiData */
+ volatile u32 **apWiData; /* Pointer to wal-index content in memory */
+ u16 szPage; /* Database page size */
+ i16 readLock; /* Which read lock is being held. -1 for none */
+ u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
+ u8 isWIndexOpen; /* True if ShmOpen() called on pDbFd */
+ u8 writeLock; /* True if in a write transaction */
+ u8 ckptLock; /* True if holding a checkpoint lock */
+ WalIndexHdr hdr; /* Wal-index header for current transaction */
+ const char *zWalName; /* Name of WAL file */
+ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_DEBUG
+ u8 lockError; /* True if a locking error has occurred */
+#endif
+};
+
+/*
+** Each page of the wal-index mapping contains a hash-table made up of
+** an array of HASHTABLE_NSLOT elements of the following type.
+*/
+typedef u16 ht_slot;
+
+/*
+** This structure is used to implement an iterator that loops through
+** all frames in the WAL in database page order. Where two or more frames
+** correspond to the same database page, the iterator visits only the
+** frame most recently written to the WAL (in other words, the frame with
+** the largest index).
+**
+** The internals of this structure are only accessed by:
+**
+** walIteratorInit() - Create a new iterator,
+** walIteratorNext() - Step an iterator,
+** walIteratorFree() - Free an iterator.
+**
+** This functionality is used by the checkpoint code (see walCheckpoint()).
+*/
+struct WalIterator {
+ int iPrior; /* Last result returned from the iterator */
+ int nSegment; /* Size of the aSegment[] array */
+ struct WalSegment {
+ int iNext; /* Next slot in aIndex[] not yet returned */
+ ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
+ u32 *aPgno; /* Array of page numbers. */
+ int nEntry; /* Max size of aPgno[] and aIndex[] arrays */
+ int iZero; /* Frame number associated with aPgno[0] */
+ } aSegment[1]; /* One for every 32KB page in the WAL */
+};
+
+/*
+** Define the parameters of the hash tables in the wal-index file. There
+** is a hash-table following every HASHTABLE_NPAGE page numbers in the
+** wal-index.
+**
+** Changing any of these constants will alter the wal-index format and
+** create incompatibilities.
+*/
+#define HASHTABLE_NPAGE 4096 /* Must be power of 2 */
+#define HASHTABLE_HASH_1 383 /* Should be prime */
+#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
+
+/*
+** The block of page numbers associated with the first hash-table in a
+** wal-index is smaller than usual. This is so that there is a complete
+** hash-table on each aligned 32KB page of the wal-index.
+*/
+#define HASHTABLE_NPAGE_ONE (HASHTABLE_NPAGE - (WALINDEX_HDR_SIZE/sizeof(u32)))
+
+/* The wal-index is divided into pages of WALINDEX_PGSZ bytes each. */
+#define WALINDEX_PGSZ ( \
+ sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
+)
+
+/*
+** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
+** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
+** numbered from zero.
+**
+** If this call is successful, *ppPage is set to point to the wal-index
+** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
+** then an SQLite error code is returned and *ppPage is set to 0.
+*/
+static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
+ int rc = SQLITE_OK;
+
+ /* Enlarge the pWal->apWiData[] array if required */
+ if( pWal->nWiData<=iPage ){
+ int nByte = sizeof(u32 *)*(iPage+1);
+ volatile u32 **apNew;
+ apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+ if( !apNew ){
+ *ppPage = 0;
+ return SQLITE_NOMEM;
+ }
+ memset((void *)&apNew[pWal->nWiData], 0, sizeof(u32 *)*(iPage+1-pWal->nWiData));
+ pWal->apWiData = apNew;
+ pWal->nWiData = iPage+1;
+ }
+
+ /* Request a pointer to the required page from the VFS */
+ if( pWal->apWiData[iPage]==0 ){
+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
+ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+ );
+ }
+
+ *ppPage = pWal->apWiData[iPage];
+ assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
+ return rc;
+}
+
+/*
+** Return a pointer to the WalCkptInfo structure in the wal-index.
+*/
+static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
+}
+
+/*
+** Return a pointer to the WalIndexHdr structure in the wal-index.
+*/
+static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ return (volatile WalIndexHdr*)pWal->apWiData[0];
+}
+
+/*
+** The argument to this macro must be of type u32. On a little-endian
+** architecture, it returns the u32 value that results from interpreting
+** the 4 bytes as a big-endian value. On a big-endian architecture, it
+** returns the value that would be produced by intepreting the 4 bytes
+** of the input value as a little-endian integer.
+*/
+#define BYTESWAP32(x) ( \
+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
+)
+
+/*
+** Generate or extend an 8 byte checksum based on the data in
+** array aByte[] and the initial values of aIn[0] and aIn[1] (or
+** initial values of 0 and 0 if aIn==NULL).
+**
+** The checksum is written back into aOut[] before returning.
+**
+** nByte must be a positive multiple of 8.
+*/
+static void walChecksumBytes(
+ int nativeCksum, /* True for native byte-order, false for non-native */
+ u8 *a, /* Content to be checksummed */
+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
+ const u32 *aIn, /* Initial checksum value input */
+ u32 *aOut /* OUT: Final checksum value output */
+){
+ u32 s1, s2;
+ u32 *aData = (u32 *)a;
+ u32 *aEnd = (u32 *)&a[nByte];
+
+ if( aIn ){
+ s1 = aIn[0];
+ s2 = aIn[1];
+ }else{
+ s1 = s2 = 0;
+ }
+
+ assert( nByte>=8 );
+ assert( (nByte&0x00000007)==0 );
+
+ if( nativeCksum ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ }while( aData<aEnd );
+ }else{
+ do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }
+
+ aOut[0] = s1;
+ aOut[1] = s2;
+}
+
+/*
+** Write the header information in pWal->hdr into the wal-index.
+**
+** The checksum on pWal->hdr is updated before it is written.
+*/
+static void walIndexWriteHdr(Wal *pWal){
+ volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
+ const int nCksum = offsetof(WalIndexHdr, aCksum);
+
+ assert( pWal->writeLock );
+ pWal->hdr.isInit = 1;
+ pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
+ walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+ memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+}
+
+/*
+** This function encodes a single frame header and writes it to a buffer
+** supplied by the caller. A frame-header is made up of a series of
+** 4-byte big-endian integers, as follows:
+**
+** 0: Page number.
+** 4: For commit records, the size of the database image in pages
+** after the commit. For all other records, zero.
+** 8: Salt-1 (copied from the wal-header)
+** 12: Salt-2 (copied from the wal-header)
+** 16: Checksum-1.
+** 20: Checksum-2.
+*/
+static void walEncodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 iPage, /* Database page number for frame */
+ u32 nTruncate, /* New db size (or 0 for non-commit frames) */
+ u8 *aData, /* Pointer to page data */
+ u8 *aFrame /* OUT: Write encoded frame here */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ assert( WAL_FRAME_HDRSIZE==24 );
+ sqlite3Put4byte(&aFrame[0], iPage);
+ sqlite3Put4byte(&aFrame[4], nTruncate);
+ memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
+
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+
+ sqlite3Put4byte(&aFrame[16], aCksum[0]);
+ sqlite3Put4byte(&aFrame[20], aCksum[1]);
+}
+
+/*
+** Check to see if the frame with header in aFrame[] and content
+** in aData[] is valid. If it is a valid frame, fill *piPage and
+** *pnTruncate and return true. Return if the frame is not valid.
+*/
+static int walDecodeFrame(
+ Wal *pWal, /* The write-ahead log */
+ u32 *piPage, /* OUT: Database page number for frame */
+ u32 *pnTruncate, /* OUT: New db size (or 0 if not commit) */
+ u8 *aData, /* Pointer to page data (for checksum) */
+ u8 *aFrame /* Frame data */
+){
+ int nativeCksum; /* True for native byte-order checksums */
+ u32 *aCksum = pWal->hdr.aFrameCksum;
+ u32 pgno; /* Page number of the frame */
+ assert( WAL_FRAME_HDRSIZE==24 );
+
+ /* A frame is only valid if the salt values in the frame-header
+ ** match the salt values in the wal-header.
+ */
+ if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if the page number is creater than zero.
+ */
+ pgno = sqlite3Get4byte(&aFrame[0]);
+ if( pgno==0 ){
+ return 0;
+ }
+
+ /* A frame is only valid if a checksum of the first 16 bytes
+ ** of the frame-header, and the frame-data matches
+ ** the checksum in the last 8 bytes of the frame-header.
+ */
+ nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+ walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+ walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
+ ){
+ /* Checksum failed. */
+ return 0;
+ }
+
+ /* If we reach this point, the frame is valid. Return the page number
+ ** and the new database size.
+ */
+ *piPage = pgno;
+ *pnTruncate = sqlite3Get4byte(&aFrame[4]);
+ return 1;
+}
+
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+/*
+** Names of locks. This routine is used to provide debugging output and is not
+** a part of an ordinary build.
+*/
+static const char *walLockName(int lockIdx){
+ if( lockIdx==WAL_WRITE_LOCK ){
+ return "WRITE-LOCK";
+ }else if( lockIdx==WAL_CKPT_LOCK ){
+ return "CKPT-LOCK";
+ }else if( lockIdx==WAL_RECOVER_LOCK ){
+ return "RECOVER-LOCK";
+ }else{
+ static char zName[15];
+ sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+ lockIdx-WAL_READ_LOCK(0));
+ return zName;
+ }
+}
+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+
+
+/*
+** Set or release locks on the WAL. Locks are either shared or exclusive.
+** A lock cannot be moved directly between shared and exclusive - it must go
+** through the unlocked state first.
+**
+** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
+*/
+static int walLockShared(Wal *pWal, int lockIdx){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
+ walLockName(lockIdx), rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockShared(Wal *pWal, int lockIdx){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+ WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
+}
+static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+ int rc;
+ if( pWal->exclusiveMode ) return SQLITE_OK;
+ rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
+ walLockName(lockIdx), n, rc ? "failed" : "ok"));
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ return rc;
+}
+static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
+ if( pWal->exclusiveMode ) return;
+ (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+ SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+ WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
+ walLockName(lockIdx), n));
+}
+
+/*
+** Compute a hash on a page number. The resulting hash value must land
+** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances
+** the hash to the next value in the event of a collision.
+*/
+static int walHash(u32 iPage){
+ assert( iPage>0 );
+ assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
+ return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
+}
+static int walNextHash(int iPriorHash){
+ return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
+}
+
+/*
+** Return pointers to the hash table and page number array stored on
+** page iHash of the wal-index. The wal-index is broken into 32KB pages
+** numbered starting from 0.
+**
+** Set output variable *paHash to point to the start of the hash table
+** in the wal-index file. Set *piZero to one less than the frame
+** number of the first frame indexed by this hash table. If a
+** slot in the hash table is set to N, it refers to frame number
+** (*piZero+N) in the log.
+**
+** Finally, set *paPgno so that *paPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (*piZero+1).
+*/
+static int walHashGet(
+ Wal *pWal, /* WAL handle */
+ int iHash, /* Find the iHash'th table */
+ volatile ht_slot **paHash, /* OUT: Pointer to hash index */
+ volatile u32 **paPgno, /* OUT: Pointer to page number array */
+ u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+){
+ int rc; /* Return code */
+ volatile u32 *aPgno;
+
+ rc = walIndexPage(pWal, iHash, &aPgno);
+ assert( rc==SQLITE_OK || iHash>0 );
+
+ if( rc==SQLITE_OK ){
+ u32 iZero;
+ volatile ht_slot *aHash;
+
+ aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+ if( iHash==0 ){
+ aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+ iZero = 0;
+ }else{
+ iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+ }
+
+ *paPgno = &aPgno[-1];
+ *paHash = aHash;
+ *piZero = iZero;
+ }
+ return rc;
+}
+
+/*
+** Return the number of the wal-index page that contains the hash-table
+** and page-number array that contain entries corresponding to WAL frame
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
+** are numbered starting from 0.
+*/
+static int walFramePage(u32 iFrame){
+ int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
+ assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
+ && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
+ && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
+ && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
+ && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
+ );
+ return iHash;
+}
+
+/*
+** Return the page number associated with frame iFrame in this WAL.
+*/
+static u32 walFramePgno(Wal *pWal, u32 iFrame){
+ int iHash = walFramePage(iFrame);
+ if( iHash==0 ){
+ return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
+ }
+ return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
+}
+
+/*
+** Remove entries from the hash table that point to WAL slots greater
+** than pWal->hdr.mxFrame.
+**
+** This function is called whenever pWal->hdr.mxFrame is decreased due
+** to a rollback or savepoint.
+**
+** At most only the hash table containing pWal->hdr.mxFrame needs to be
+** updated. Any later hash tables will be automatically cleared when
+** pWal->hdr.mxFrame advances to the point where those hash tables are
+** actually needed.
+*/
+static void walCleanupHash(Wal *pWal){
+ volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
+ volatile u32 *aPgno = 0; /* Page number array for hash table */
+ u32 iZero = 0; /* frame == (aHash[x]+iZero) */
+ int iLimit = 0; /* Zero values greater than this */
+ int nByte; /* Number of bytes to zero in aPgno[] */
+ int i; /* Used to iterate through aHash[] */
+
+ assert( pWal->writeLock );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
+ testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
+
+ if( pWal->hdr.mxFrame==0 ) return;
+
+ /* Obtain pointers to the hash-table and page-number array containing
+ ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
+ ** that the page said hash-table and array reside on is already mapped.
+ */
+ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
+ assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
+ walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+
+ /* Zero all hash-table entries that correspond to frame numbers greater
+ ** than pWal->hdr.mxFrame.
+ */
+ iLimit = pWal->hdr.mxFrame - iZero;
+ assert( iLimit>0 );
+ for(i=0; i<HASHTABLE_NSLOT; i++){
+ if( aHash[i]>iLimit ){
+ aHash[i] = 0;
+ }
+ }
+
+ /* Zero the entries in the aPgno array that correspond to frames with
+ ** frame numbers greater than pWal->hdr.mxFrame.
+ */
+ nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
+ memset((void *)&aPgno[iLimit+1], 0, nByte);
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the every entry in the mapping region is still reachable
+ ** via the hash table even after the cleanup.
+ */
+ if( iLimit ){
+ int i; /* Loop counter */
+ int iKey; /* Hash key */
+ for(i=1; i<=iLimit; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
+ }
+ assert( aHash[iKey]==i );
+ }
+ }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+}
+
+
+/*
+** Set an entry in the wal-index that will map database page number
+** pPage into WAL frame iFrame.
+*/
+static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+ int rc; /* Return code */
+ u32 iZero = 0; /* One less than frame number of aPgno[1] */
+ volatile u32 *aPgno = 0; /* Page number array */
+ volatile ht_slot *aHash = 0; /* Hash table */
+
+ rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+
+ /* Assuming the wal-index file was successfully mapped, populate the
+ ** page number array and hash table entry.
+ */
+ if( rc==SQLITE_OK ){
+ int iKey; /* Hash table key */
+ int idx; /* Value to write to hash-table slot */
+ TESTONLY( int nCollide = 0; /* Number of hash collisions */ )
+
+ idx = iFrame - iZero;
+ assert( idx <= HASHTABLE_NSLOT/2 + 1 );
+
+ /* If this is the first entry to be added to this hash-table, zero the
+ ** entire hash table and aPgno[] array before proceding.
+ */
+ if( idx==1 ){
+ int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
+ memset((void*)&aPgno[1], 0, nByte);
+ }
+
+ /* If the entry in aPgno[] is already set, then the previous writer
+ ** must have exited unexpectedly in the middle of a transaction (after
+ ** writing one or more dirty pages to the WAL to free up memory).
+ ** Remove the remnants of that writers uncommitted transaction from
+ ** the hash-table before writing any new entries.
+ */
+ if( aPgno[idx] ){
+ walCleanupHash(pWal);
+ assert( !aPgno[idx] );
+ }
+
+ /* Write the aPgno[] array entry and the hash-table slot. */
+ for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+ assert( nCollide++ < idx );
+ }
+ aPgno[idx] = iPage;
+ aHash[iKey] = (ht_slot)idx;
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* Verify that the number of entries in the hash table exactly equals
+ ** the number of entries in the mapping region.
+ */
+ {
+ int i; /* Loop counter */
+ int nEntry = 0; /* Number of entries in the hash table */
+ for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+ assert( nEntry==idx );
+ }
+
+ /* Verify that the every entry in the mapping region is reachable
+ ** via the hash table. This turns out to be a really, really expensive
+ ** thing to check, so only do this occasionally - not on every
+ ** iteration.
+ */
+ if( (idx&0x3ff)==0 ){
+ int i; /* Loop counter */
+ for(i=1; i<=idx; i++){
+ for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+ if( aHash[iKey]==i ) break;
+ }
+ assert( aHash[iKey]==i );
+ }
+ }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
+ }
+
+
+ return rc;
+}
+
+
+/*
+** Recover the wal-index by reading the write-ahead log file.
+**
+** This routine first tries to establish an exclusive lock on the
+** wal-index to prevent other threads/processes from doing anything
+** with the WAL or wal-index while recovery is running. The
+** WAL_RECOVER_LOCK is also held so that other threads will know
+** that this thread is running recovery. If unable to establish
+** the necessary locks, this routine returns SQLITE_BUSY.
+*/
+static int walIndexRecover(Wal *pWal){
+ int rc; /* Return Code */
+ i64 nSize; /* Size of log file */
+ u32 aFrameCksum[2] = {0, 0};
+ int iLock; /* Lock offset to lock for checkpoint */
+ int nLock; /* Number of locks to hold */
+
+ /* Obtain an exclusive lock on all byte in the locking range not already
+ ** locked by the caller. The caller is guaranteed to have locked the
+ ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
+ ** If successful, the same bytes that are locked here are unlocked before
+ ** this function returns.
+ */
+ assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
+ assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
+ assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
+ assert( pWal->writeLock );
+ iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
+ nLock = SQLITE_SHM_NLOCK - iLock;
+ rc = walLockExclusive(pWal, iLock, nLock);
+ if( rc ){
+ return rc;
+ }
+ WALTRACE(("WAL%p: recovery begin...\n", pWal));
+
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+
+ rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ if( nSize>WAL_HDRSIZE ){
+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+ int szFrame; /* Number of bytes in buffer aFrame[] */
+ u8 *aData; /* Pointer to data part of aFrame buffer */
+ int iFrame; /* Index of last frame read */
+ i64 iOffset; /* Next offset to read from log file */
+ int szPage; /* Page size according to the log */
+ u32 magic; /* Magic value read from WAL header */
+ u32 version; /* Magic value read from WAL header */
+
+ /* Read in the WAL header. */
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+ if( rc!=SQLITE_OK ){
+ goto recovery_error;
+ }
+
+ /* If the database page size is not a power of two, or is greater than
+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
+ ** data. Similarly, if the 'magic' value is invalid, ignore the whole
+ ** WAL file.
+ */
+ magic = sqlite3Get4byte(&aBuf[0]);
+ szPage = sqlite3Get4byte(&aBuf[8]);
+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
+ || szPage&(szPage-1)
+ || szPage>SQLITE_MAX_PAGE_SIZE
+ || szPage<512
+ ){
+ goto finished;
+ }
+ pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
+ pWal->szPage = (u16)szPage;
+ pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
+ memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
+
+ /* Verify that the WAL header checksum is correct */
+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
+ aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
+ );
+ if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+ || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+ ){
+ goto finished;
+ }
+
+ /* Verify that the version number on the WAL format is one that
+ ** are able to understand */
+ version = sqlite3Get4byte(&aBuf[4]);
+ if( version!=WAL_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ goto finished;
+ }
+
+ /* Malloc a buffer to read frames into. */
+ szFrame = szPage + WAL_FRAME_HDRSIZE;
+ aFrame = (u8 *)sqlite3_malloc(szFrame);
+ if( !aFrame ){
+ rc = SQLITE_NOMEM;
+ goto recovery_error;
+ }
+ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
+ /* Read all frames from the log file. */
+ iFrame = 0;
+ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
+ int isValid; /* True if this frame is valid */
+
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+ if( !isValid ) break;
+ rc = walIndexAppend(pWal, ++iFrame, pgno);
+ if( rc!=SQLITE_OK ) break;
+
+ /* If nTruncate is non-zero, this is a commit record. */
+ if( nTruncate ){
+ pWal->hdr.mxFrame = iFrame;
+ pWal->hdr.nPage = nTruncate;
+ pWal->hdr.szPage = (u16)szPage;
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+ }
+
+ sqlite3_free(aFrame);
+ }
+
+finished:
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo;
+ int i;
+ pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
+ pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
+ walIndexWriteHdr(pWal);
+
+ /* Reset the checkpoint-header. This is safe because this thread is
+ ** currently holding locks that exclude all other readers, writers and
+ ** checkpointers.
+ */
+ pInfo = walCkptInfo(pWal);
+ pInfo->nBackfill = 0;
+ pInfo->aReadMark[0] = 0;
+ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ }
+
+recovery_error:
+ WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
+ walUnlockExclusive(pWal, iLock, nLock);
+ return rc;
+}
+
+/*
+** Close an open wal-index.
+*/
+static void walIndexClose(Wal *pWal, int isDelete){
+ if( pWal->isWIndexOpen ){
+ sqlite3OsShmClose(pWal->pDbFd, isDelete);
+ pWal->isWIndexOpen = 0;
+ }
+}
+
+/*
+** Open a connection to the WAL file zWalName. The database file must
+** already be opened on connection pDbFd. The buffer that zWalName points
+** to must remain valid for the lifetime of the returned Wal* handle.
+**
+** A SHARED lock should be held on the database file when this function
+** is called. The purpose of this SHARED lock is to prevent any other
+** client from unlinking the WAL or wal-index file. If another process
+** were to do this just after this client opened one of these files, the
+** system would be badly broken.
+**
+** If the log file is successfully opened, SQLITE_OK is returned and
+** *ppWal is set to point to a new WAL handle. If an error occurs,
+** an SQLite error code is returned and *ppWal is left unmodified.
+*/
+SQLITE_PRIVATE int sqlite3WalOpen(
+ sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */
+ sqlite3_file *pDbFd, /* The open database file */
+ const char *zWalName, /* Name of the WAL file */
+ Wal **ppWal /* OUT: Allocated Wal handle */
+){
+ int rc; /* Return Code */
+ Wal *pRet; /* Object to allocate and return */
+ int flags; /* Flags passed to OsOpen() */
+
+ assert( zWalName && zWalName[0] );
+ assert( pDbFd );
+
+ /* In the amalgamation, the os_unix.c and os_win.c source files come before
+ ** this source file. Verify that the #defines of the locking byte offsets
+ ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
+ */
+#ifdef WIN_SHM_BASE
+ assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+#ifdef UNIX_SHM_BASE
+ assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+
+
+ /* Allocate an instance of struct Wal to return. */
+ *ppWal = 0;
+ pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
+ if( !pRet ){
+ return SQLITE_NOMEM;
+ }
+
+ pRet->pVfs = pVfs;
+ pRet->pWalFd = (sqlite3_file *)&pRet[1];
+ pRet->pDbFd = pDbFd;
+ pRet->readLock = -1;
+ sqlite3_randomness(8, &pRet->hdr.aSalt);
+ pRet->zWalName = zWalName;
+ rc = sqlite3OsShmOpen(pDbFd);
+
+ /* Open file handle on the write-ahead log file. */
+ if( rc==SQLITE_OK ){
+ pRet->isWIndexOpen = 1;
+ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MAIN_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
+ }
+
+ if( rc!=SQLITE_OK ){
+ walIndexClose(pRet, 0);
+ sqlite3OsClose(pRet->pWalFd);
+ sqlite3_free(pRet);
+ }else{
+ *ppWal = pRet;
+ WALTRACE(("WAL%d: opened\n", pRet));
+ }
+ return rc;
+}
+
+/*
+** Find the smallest page number out of all pages held in the WAL that
+** has not been returned by any prior invocation of this method on the
+** same WalIterator object. Write into *piFrame the frame index where
+** that page was last written into the WAL. Write into *piPage the page
+** number.
+**
+** Return 0 on success. If there are no pages in the WAL with a page
+** number larger than *piPage, then return 1.
+*/
+static int walIteratorNext(
+ WalIterator *p, /* Iterator */
+ u32 *piPage, /* OUT: The page number of the next page */
+ u32 *piFrame /* OUT: Wal frame index of next page */
+){
+ u32 iMin; /* Result pgno must be greater than iMin */
+ u32 iRet = 0xFFFFFFFF; /* 0xffffffff is never a valid page number */
+ int i; /* For looping through segments */
+
+ iMin = p->iPrior;
+ assert( iMin<0xffffffff );
+ for(i=p->nSegment-1; i>=0; i--){
+ struct WalSegment *pSegment = &p->aSegment[i];
+ while( pSegment->iNext<pSegment->nEntry ){
+ u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
+ if( iPg>iMin ){
+ if( iPg<iRet ){
+ iRet = iPg;
+ *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
+ }
+ break;
+ }
+ pSegment->iNext++;
+ }
+ }
+
+ *piPage = p->iPrior = iRet;
+ return (iRet==0xFFFFFFFF);
+}
+
+/*
+** This function merges two sorted lists into a single sorted list.
+*/
+static void walMerge(
+ u32 *aContent, /* Pages in wal */
+ ht_slot *aLeft, /* IN: Left hand input list */
+ int nLeft, /* IN: Elements in array *paLeft */
+ ht_slot **paRight, /* IN/OUT: Right hand input list */
+ int *pnRight, /* IN/OUT: Elements in *paRight */
+ ht_slot *aTmp /* Temporary buffer */
+){
+ int iLeft = 0; /* Current index in aLeft */
+ int iRight = 0; /* Current index in aRight */
+ int iOut = 0; /* Current index in output buffer */
+ int nRight = *pnRight;
+ ht_slot *aRight = *paRight;
+
+ assert( nLeft>0 && nRight>0 );
+ while( iRight<nRight || iLeft<nLeft ){
+ ht_slot logpage;
+ Pgno dbpage;
+
+ if( (iLeft<nLeft)
+ && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
+ ){
+ logpage = aLeft[iLeft++];
+ }else{
+ logpage = aRight[iRight++];
+ }
+ dbpage = aContent[logpage];
+
+ aTmp[iOut++] = logpage;
+ if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
+
+ assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
+ assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+ }
+
+ *paRight = aLeft;
+ *pnRight = iOut;
+ memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
+}
+
+/*
+** Sort the elements in list aList, removing any duplicates.
+*/
+static void walMergesort(
+ u32 *aContent, /* Pages in wal */
+ ht_slot *aBuffer, /* Buffer of at least *pnList items to use */
+ ht_slot *aList, /* IN/OUT: List to sort */
+ int *pnList /* IN/OUT: Number of elements in aList[] */
+){
+ struct Sublist {
+ int nList; /* Number of elements in aList */
+ ht_slot *aList; /* Pointer to sub-list content */
+ };
+
+ const int nList = *pnList; /* Size of input list */
+ int nMerge = 0; /* Number of elements in list aMerge */
+ ht_slot *aMerge = 0; /* List to be merged */
+ int iList; /* Index into input list */
+ int iSub = 0; /* Index into aSub array */
+ struct Sublist aSub[13]; /* Array of sub-lists */
+
+ memset(aSub, 0, sizeof(aSub));
+ assert( nList<=HASHTABLE_NPAGE && nList>0 );
+ assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
+
+ for(iList=0; iList<nList; iList++){
+ nMerge = 1;
+ aMerge = &aList[iList];
+ for(iSub=0; iList & (1<<iSub); iSub++){
+ struct Sublist *p = &aSub[iSub];
+ assert( p->aList && p->nList<=(1<<iSub) );
+ assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ aSub[iSub].aList = aMerge;
+ aSub[iSub].nList = nMerge;
+ }
+
+ for(iSub++; iSub<ArraySize(aSub); iSub++){
+ if( nList & (1<<iSub) ){
+ struct Sublist *p = &aSub[iSub];
+ assert( p->nList<=(1<<iSub) );
+ assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
+ walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+ }
+ }
+ assert( aMerge==aList );
+ *pnList = nMerge;
+
+#ifdef SQLITE_DEBUG
+ {
+ int i;
+ for(i=1; i<*pnList; i++){
+ assert( aContent[aList[i]] > aContent[aList[i-1]] );
+ }
+ }
+#endif
+}
+
+/*
+** Free an iterator allocated by walIteratorInit().
+*/
+static void walIteratorFree(WalIterator *p){
+ sqlite3ScratchFree(p);
+}
+
+/*
+** Construct a WalInterator object that can be used to loop over all
+** pages in the WAL in ascending order. The caller must hold the checkpoint
+**
+** On success, make *pp point to the newly allocated WalInterator object
+** return SQLITE_OK. Otherwise, return an error code. If this routine
+** returns an error, the value of *pp is undefined.
+**
+** The calling routine should invoke walIteratorFree() to destroy the
+** WalIterator object when it has finished with it.
+*/
+static int walIteratorInit(Wal *pWal, WalIterator **pp){
+ WalIterator *p; /* Return value */
+ int nSegment; /* Number of segments to merge */
+ u32 iLast; /* Last frame in log */
+ int nByte; /* Number of bytes to allocate */
+ int i; /* Iterator variable */
+ ht_slot *aTmp; /* Temp space used by merge-sort */
+ int rc = SQLITE_OK; /* Return Code */
+
+ /* This routine only runs while holding the checkpoint lock. And
+ ** it only runs if there is actually content in the log (mxFrame>0).
+ */
+ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+ iLast = pWal->hdr.mxFrame;
+
+ /* Allocate space for the WalIterator object. */
+ nSegment = walFramePage(iLast) + 1;
+ nByte = sizeof(WalIterator)
+ + (nSegment-1)*sizeof(struct WalSegment)
+ + iLast*sizeof(ht_slot);
+ p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+ if( !p ){
+ return SQLITE_NOMEM;
+ }
+ memset(p, 0, nByte);
+ p->nSegment = nSegment;
+
+ /* Allocate temporary space used by the merge-sort routine. This block
+ ** of memory will be freed before this function returns.
+ */
+ aTmp = (ht_slot *)sqlite3ScratchMalloc(
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
+ if( !aTmp ){
+ rc = SQLITE_NOMEM;
+ }
+
+ for(i=0; rc==SQLITE_OK && i<nSegment; i++){
+ volatile ht_slot *aHash;
+ u32 iZero;
+ volatile u32 *aPgno;
+
+ rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+ if( rc==SQLITE_OK ){
+ int j; /* Counter variable */
+ int nEntry; /* Number of entries in this segment */
+ ht_slot *aIndex; /* Sorted index for this segment */
+
+ aPgno++;
+ nEntry = (int)(((i+1)==nSegment)?(int)(iLast-iZero):(u32 *)aHash-(u32 *)aPgno);
+ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
+ iZero++;
+
+ for(j=0; j<nEntry; j++){
+ aIndex[j] = (ht_slot)j;
+ }
+ walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
+ p->aSegment[i].iZero = iZero;
+ p->aSegment[i].nEntry = nEntry;
+ p->aSegment[i].aIndex = aIndex;
+ p->aSegment[i].aPgno = (u32 *)aPgno;
+ }
+ }
+ sqlite3ScratchFree(aTmp);
+
+ if( rc!=SQLITE_OK ){
+ walIteratorFree(p);
+ }
+ *pp = p;
+ return rc;
+}
+
+/*
+** Copy as much content as we can from the WAL back into the database file
+** in response to an sqlite3_wal_checkpoint() request or the equivalent.
+**
+** The amount of information copies from WAL to database might be limited
+** by active readers. This routine will never overwrite a database page
+** that a concurrent reader might be using.
+**
+** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
+** checkpoints are always run by a background thread or background
+** process, foreground threads will never block on a lengthy fsync call.
+**
+** Fsync is called on the WAL before writing content out of the WAL and
+** into the database. This ensures that if the new content is persistent
+** in the WAL and can be recovered following a power-loss or hard reset.
+**
+** Fsync is also called on the database file if (and only if) the entire
+** WAL content is copied into the database file. This second fsync makes
+** it safe to delete the WAL since the new content will persist in the
+** database file.
+**
+** This routine uses and updates the nBackfill field of the wal-index header.
+** This is the only routine tha will increase the value of nBackfill.
+** (A WAL reset or recovery will revert nBackfill to zero, but not increase
+** its value.)
+**
+** The caller must be holding sufficient locks to ensure that no other
+** checkpoint is running (in any other thread or process) at the same
+** time.
+*/
+static int walCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int sync_flags, /* Flags for OsSync() (or 0) */
+ int nBuf, /* Size of zBuf in bytes */
+ u8 *zBuf /* Temporary buffer to use */
+){
+ int rc; /* Return code */
+ int szPage = pWal->hdr.szPage; /* Database page-size */
+ WalIterator *pIter = 0; /* Wal iterator context */
+ u32 iDbpage = 0; /* Next database page to write */
+ u32 iFrame = 0; /* Wal frame containing data for iDbpage */
+ u32 mxSafeFrame; /* Max frame that can be backfilled */
+ int i; /* Loop counter */
+ volatile WalCkptInfo *pInfo; /* The checkpoint status information */
+
+ if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
+
+ /* Allocate the iterator */
+ rc = walIteratorInit(pWal, &pIter);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ assert( pIter );
+
+ /*** TODO: Move this test out to the caller. Make it an assert() here ***/
+ if( pWal->hdr.szPage!=nBuf ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto walcheckpoint_out;
+ }
+
+ /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+ ** safe to write into the database. Frames beyond mxSafeFrame might
+ ** overwrite database pages that are in use by active readers and thus
+ ** cannot be backfilled from the WAL.
+ */
+ mxSafeFrame = pWal->hdr.mxFrame;
+ pInfo = walCkptInfo(pWal);
+ for(i=1; i<WAL_NREADER; i++){
+ u32 y = pInfo->aReadMark[i];
+ if( mxSafeFrame>=y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ }else{
+ goto walcheckpoint_out;
+ }
+ }
+ }
+
+ if( pInfo->nBackfill<mxSafeFrame
+ && (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK
+ ){
+ u32 nBackfill = pInfo->nBackfill;
+
+ /* Sync the WAL to disk */
+ if( sync_flags ){
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
+
+ /* Iterate through the contents of the WAL, copying data to the db file. */
+ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+ i64 iOffset;
+ assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( iFrame<=nBackfill || iFrame>mxSafeFrame ) continue;
+ iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ iOffset = (iDbpage-1)*(i64)szPage;
+ testcase( IS_BIG_INT(iOffset) );
+ rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ }
+
+ /* If work was actually accomplished... */
+ if( rc==SQLITE_OK ){
+ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+ i64 szDb = pWal->hdr.nPage*(i64)szPage;
+ testcase( IS_BIG_INT(szDb) );
+ rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+ if( rc==SQLITE_OK && sync_flags ){
+ rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pInfo->nBackfill = mxSafeFrame;
+ }
+ }
+
+ /* Release the reader lock held while backfilling */
+ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ }else if( rc==SQLITE_BUSY ){
+ /* Reset the return code so as not to report a checkpoint failure
+ ** just because active readers prevent any backfill.
+ */
+ rc = SQLITE_OK;
+ }
+
+ walcheckpoint_out:
+ walIteratorFree(pIter);
+ return rc;
+}
+
+/*
+** Close a connection to a log file.
+*/
+SQLITE_PRIVATE int sqlite3WalClose(
+ Wal *pWal, /* Wal to close */
+ int sync_flags, /* Flags to pass to OsSync() (or 0) */
+ int nBuf,
+ u8 *zBuf /* Buffer of at least nBuf bytes */
+){
+ int rc = SQLITE_OK;
+ if( pWal ){
+ int isDelete = 0; /* True to unlink wal and wal-index files */
+
+ /* If an EXCLUSIVE lock can be obtained on the database file (using the
+ ** ordinary, rollback-mode locking methods, this guarantees that the
+ ** connection associated with this log file is the only connection to
+ ** the database. In this case checkpoint the database and unlink both
+ ** the wal and wal-index files.
+ **
+ ** The EXCLUSIVE lock is not released before returning.
+ */
+ rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+ if( rc==SQLITE_OK ){
+ pWal->exclusiveMode = 1;
+ rc = sqlite3WalCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ if( rc==SQLITE_OK ){
+ isDelete = 1;
+ }
+ }
+
+ walIndexClose(pWal, isDelete);
+ sqlite3OsClose(pWal->pWalFd);
+ if( isDelete ){
+ sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+ }
+ WALTRACE(("WAL%p: closed\n", pWal));
+ sqlite3_free((void *)pWal->apWiData);
+ sqlite3_free(pWal);
+ }
+ return rc;
+}
+
+/*
+** Try to read the wal-index header. Return 0 on success and 1 if
+** there is a problem.
+**
+** The wal-index is in shared memory. Another thread or process might
+** be writing the header at the same time this procedure is trying to
+** read it, which might result in inconsistency. A dirty read is detected
+** by verifying that both copies of the header are the same and also by
+** a checksum on the header.
+**
+** If and only if the read is consistent and the header is different from
+** pWal->hdr, then pWal->hdr is updated to the content of the new header
+** and *pChanged is set to 1.
+**
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
+*/
+static int walIndexTryHdr(Wal *pWal, int *pChanged){
+ u32 aCksum[2]; /* Checksum on the header content */
+ WalIndexHdr h1, h2; /* Two copies of the header content */
+ WalIndexHdr volatile *aHdr; /* Header in shared memory */
+
+ /* The first page of the wal-index must be mapped at this point. */
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+
+ /* Read the header. This might happen currently with a write to the
+ ** same area of shared memory on a different CPU in a SMP,
+ ** meaning it is possible that an inconsistent snapshot is read
+ ** from the file. If this happens, return non-zero.
+ **
+ ** There are two copies of the header at the beginning of the wal-index.
+ ** When reading, read [0] first then [1]. Writes are in the reverse order.
+ ** Memory barriers are used to prevent the compiler or the hardware from
+ ** reordering the reads and writes.
+ */
+ aHdr = walIndexHdr(pWal);
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
+
+ if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+ return 1; /* Dirty read */
+ }
+ if( h1.isInit==0 ){
+ return 1; /* Malformed header - probably all zeros */
+ }
+ walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
+ if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
+ return 1; /* Checksum does not match */
+ }
+
+ if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+ *pChanged = 1;
+ memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
+ pWal->szPage = pWal->hdr.szPage;
+ }
+
+ /* The header was successfully read. Return zero. */
+ return 0;
+}
+
+/*
+** Read the wal-index header from the wal-index and into pWal->hdr.
+** If the wal-header appears to be corrupt, try to reconstruct the
+** wal-index from the WAL before returning.
+**
+** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
+** changed by this opertion. If pWal->hdr is unchanged, set *pChanged
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK.
+** Otherwise an SQLite error code.
+*/
+static int walIndexReadHdr(Wal *pWal, int *pChanged){
+ int rc; /* Return code */
+ int badHdr; /* True if a header read failed */
+ volatile u32 *page0; /* Chunk of wal-index containing header */
+
+ /* Ensure that page 0 of the wal-index (the page that contains the
+ ** wal-index header) is mapped. Return early if an error occurs here.
+ */
+ assert( pChanged );
+ rc = walIndexPage(pWal, 0, &page0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ };
+ assert( page0 || pWal->writeLock==0 );
+
+ /* If the first page of the wal-index has been mapped, try to read the
+ ** wal-index header immediately, without holding any lock. This usually
+ ** works, but may fail if the wal-index header is corrupt or currently
+ ** being modified by another thread or process.
+ */
+ badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+
+ /* If the first attempt failed, it might have been due to a race
+ ** with a writer. So get a WRITE lock and try again.
+ */
+ assert( badHdr==0 || pWal->writeLock==0 );
+ if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+ pWal->writeLock = 1;
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+ badHdr = walIndexTryHdr(pWal, pChanged);
+ if( badHdr ){
+ /* If the wal-index header is still malformed even while holding
+ ** a WRITE lock, it can only mean that the header is corrupted and
+ ** needs to be reconstructed. So run recovery to do exactly that.
+ */
+ rc = walIndexRecover(pWal);
+ *pChanged = 1;
+ }
+ }
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ }
+
+ /* If the header is read successfully, check the version number to make
+ ** sure the wal-index was not constructed with some future format that
+ ** this version of SQLite cannot understand.
+ */
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
+
+ return rc;
+}
+
+/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY (-1)
+
+/*
+** Attempt to start a read transaction. This might fail due to a race or
+** other transient condition. When that happens, it returns WAL_RETRY to
+** indicate to the caller that it is safe to retry immediately.
+**
+** On success return SQLITE_OK. On a permanent failure (such an
+** I/O error or an SQLITE_BUSY because another process is running
+** recovery) return a positive error code.
+**
+** The useWal parameter is true to force the use of the WAL and disable
+** the case where the WAL is bypassed because it has been completely
+** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
+** to make a copy of the wal-index header into pWal->hdr. If the
+** wal-index header has changed, *pChanged is set to 1 (as an indication
+** to the caller that the local paget cache is obsolete and needs to be
+** flushed.) When useWal==1, the wal-index header is assumed to already
+** be loaded and the pChanged parameter is unused.
+**
+** The caller must set the cnt parameter to the number of prior calls to
+** this routine during the current read attempt that returned WAL_RETRY.
+** This routine will start taking more aggressive measures to clear the
+** race conditions after multiple WAL_RETRY returns, and after an excessive
+** number of errors will ultimately return SQLITE_PROTOCOL. The
+** SQLITE_PROTOCOL return indicates that some other process has gone rogue
+** and is not honoring the locking protocol. There is a vanishingly small
+** chance that SQLITE_PROTOCOL could be returned because of a run of really
+** bad luck when there is lots of contention for the wal-index, but that
+** possibility is so small that it can be safely neglected, we believe.
+**
+** On success, this routine obtains a read lock on
+** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
+** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
+** that means the Wal does not hold any read lock. The reader must not
+** access any database page that is modified by a WAL frame up to and
+** including frame number aReadMark[pWal->readLock]. The reader will
+** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
+** Or if pWal->readLock==0, then the reader will ignore the WAL
+** completely and get all content directly from the database file.
+** If the useWal parameter is 1 then the WAL will never be ignored and
+** this routine will always set pWal->readLock>0 on success.
+** When the read transaction is completed, the caller must release the
+** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
+**
+** This routine uses the nBackfill and aReadMark[] fields of the header
+** to select a particular WAL_READ_LOCK() that strives to let the
+** checkpoint process do as much work as possible. This routine might
+** update values of the aReadMark[] array in the header, but if it does
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
+*/
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+ volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ int rc = SQLITE_OK; /* Return code */
+
+ assert( pWal->readLock<0 ); /* Not currently locked */
+
+ /* Take steps to avoid spinning forever if there is a protocol error. */
+ if( cnt>5 ){
+ if( cnt>100 ) return SQLITE_PROTOCOL;
+ sqlite3OsSleep(pWal->pVfs, 1);
+ }
+
+ if( !useWal ){
+ rc = walIndexReadHdr(pWal, pChanged);
+ if( rc==SQLITE_BUSY ){
+ /* If there is not a recovery running in another thread or process
+ ** then convert BUSY errors to WAL_RETRY. If recovery is known to
+ ** be running, convert BUSY to BUSY_RECOVERY. There is a race here
+ ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
+ ** would be technically correct. But the race is benign since with
+ ** WAL_RETRY this routine will be called again and will probably be
+ ** right on the second iteration.
+ */
+ rc = walLockShared(pWal, WAL_RECOVER_LOCK);
+ if( rc==SQLITE_OK ){
+ walUnlockShared(pWal, WAL_RECOVER_LOCK);
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = SQLITE_BUSY_RECOVERY;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+
+ pInfo = walCkptInfo(pWal);
+ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+ /* The WAL has been completely backfilled (or it is empty).
+ ** and can be safely ignored.
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ if( rc==SQLITE_OK ){
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
+ ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** happening, this is usually correct.
+ **
+ ** However, if frames have been appended to the log (or if the log
+ ** is wrapped and written for that matter) before the READ_LOCK(0)
+ ** is obtained, that is not necessarily true. A checkpointer may
+ ** have started to backfill the appended frames but crashed before
+ ** it finished. Leaving a corrupt image in the database file.
+ */
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ return WAL_RETRY;
+ }
+ pWal->readLock = 0;
+ return SQLITE_OK;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+
+ /* If we get this far, it means that the reader will want to use
+ ** the WAL to get at content from recent commits. The job now is
+ ** to select one of the aReadMark[] entries that is closest to
+ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+ */
+ mxReadMark = 0;
+ mxI = 0;
+ for(i=1; i<WAL_NREADER; i++){
+ u32 thisMark = pInfo->aReadMark[i];
+ if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
+ mxI = i;
+ }
+ }
+ if( mxI==0 ){
+ /* If we get here, it means that all of the aReadMark[] entries between
+ ** 1 and WAL_NREADER-1 are zero. Try to initialize aReadMark[1] to
+ ** be mxFrame, then retry.
+ */
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), 1);
+ rc = WAL_RETRY;
+ }else if( rc==SQLITE_BUSY ){
+ rc = WAL_RETRY;
+ }
+ return rc;
+ }else{
+ if( mxReadMark < pWal->hdr.mxFrame ){
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+ }
+
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** This does not guarantee that the copy of the wal-index header is up to
+ ** date before proceeding. That would not be possible without somehow
+ ** blocking writers. It only guarantees that a dangerous checkpoint or
+ ** log-wrap (either of which would require an exclusive lock on
+ ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+ */
+ sqlite3OsShmBarrier(pWal->pDbFd);
+ if( pInfo->aReadMark[mxI]!=mxReadMark
+ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
+ }
+ return rc;
+}
+
+/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time. The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning. The
+** Pager layer will use this to know that is cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc; /* Return code */
+ int cnt = 0; /* Number of TryBeginRead attempts */
+
+ do{
+ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ }while( rc==WAL_RETRY );
+ return rc;
+}
+
+/*
+** Finish with a read transaction. All this does is release the
+** read-lock.
+*/
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+ if( pWal->readLock>=0 ){
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->readLock = -1;
+ }
+}
+
+/*
+** Read a page from the WAL, if it is present in the WAL and if the
+** current read transaction is configured to use the WAL.
+**
+** The *pInWal is set to 1 if the requested page is in the WAL and
+** has been loaded. Or *pInWal is set to 0 if the page was not in
+** the WAL and needs to be read out of the database.
+*/
+SQLITE_PRIVATE int sqlite3WalRead(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ int *pInWal, /* OUT: True if data is read from WAL */
+ int nOut, /* Size of buffer pOut in bytes */
+ u8 *pOut /* Buffer to write page data to */
+){
+ u32 iRead = 0; /* If !=0, WAL frame to return data from */
+ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
+ int iHash; /* Used to loop through N hash tables */
+
+ /* This routine is only be called from within a read transaction. */
+ assert( pWal->readLock>=0 || pWal->lockError );
+
+ /* If the "last page" field of the wal-index header snapshot is 0, then
+ ** no data will be read from the wal under any circumstances. Return early
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
+ ** then the WAL is ignored by the reader so return early, as if the
+ ** WAL were empty.
+ */
+ if( iLast==0 || pWal->readLock==0 ){
+ *pInWal = 0;
+ return SQLITE_OK;
+ }
+
+ /* Search the hash table or tables for an entry matching page number
+ ** pgno. Each iteration of the following for() loop searches one
+ ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
+ **
+ ** This code might run concurrently to the code in walIndexAppend()
+ ** that adds entries to the wal-index (and possibly to this hash
+ ** table). This means the value just read from the hash
+ ** slot (aHash[iKey]) may have been added before or after the
+ ** current read transaction was opened. Values added after the
+ ** read transaction was opened may have been written incorrectly -
+ ** i.e. these slots may contain garbage data. However, we assume
+ ** that any slots written before the current read transaction was
+ ** opened remain unmodified.
+ **
+ ** For the reasons above, the if(...) condition featured in the inner
+ ** loop of the following block is more stringent that would be required
+ ** if we had exclusive access to the hash-table:
+ **
+ ** (aPgno[iFrame]==pgno):
+ ** This condition filters out normal hash-table collisions.
+ **
+ ** (iFrame<=iLast):
+ ** This condition filters out entries that were added to the hash
+ ** table after the current read-transaction had started.
+ */
+ for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+ volatile ht_slot *aHash; /* Pointer to hash table */
+ volatile u32 *aPgno; /* Pointer to array of page numbers */
+ u32 iZero; /* Frame number corresponding to aPgno[0] */
+ int iKey; /* Hash slot index */
+ int rc;
+
+ rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+ u32 iFrame = aHash[iKey] + iZero;
+ if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+ assert( iFrame>iRead );
+ iRead = iFrame;
+ }
+ }
+ }
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+ /* If expensive assert() statements are available, do a linear search
+ ** of the wal-index file content. Make sure the results agree with the
+ ** result obtained using the hash indexes above. */
+ {
+ u32 iRead2 = 0;
+ u32 iTest;
+ for(iTest=iLast; iTest>0; iTest--){
+ if( walFramePgno(pWal, iTest)==pgno ){
+ iRead2 = iTest;
+ break;
+ }
+ }
+ assert( iRead==iRead2 );
+ }
+#endif
+
+ /* If iRead is non-zero, then it is the log frame number that contains the
+ ** required page. Read and return data from the log file.
+ */
+ if( iRead ){
+ i64 iOffset = walFrameOffset(iRead, pWal->hdr.szPage) + WAL_FRAME_HDRSIZE;
+ *pInWal = 1;
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+ return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset);
+ }
+
+ *pInWal = 0;
+ return SQLITE_OK;
+}
+
+
+/*
+** Set *pPgno to the size of the database file (or zero, if unknown).
+*/
+SQLITE_PRIVATE void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno){
+ assert( pWal->readLock>=0 || pWal->lockError );
+ *pPgno = pWal->hdr.nPage;
+}
+
+
+/*
+** This function starts a write transaction on the WAL.
+**
+** A read transaction must have already been started by a prior call
+** to sqlite3WalBeginReadTransaction().
+**
+** If another thread or process has written into the database since
+** the read transaction was started, then it is not possible for this
+** thread to write as doing so would cause a fork. So this routine
+** returns SQLITE_BUSY in that case and no write transaction is started.
+**
+** There can only be a single writer active at a time.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+ int rc;
+
+ /* Cannot start a write transaction without first holding a read
+ ** transaction. */
+ assert( pWal->readLock>=0 );
+
+ /* Only one writer allowed at a time. Get the write lock. Return
+ ** SQLITE_BUSY if unable.
+ */
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ if( rc ){
+ return rc;
+ }
+ pWal->writeLock = 1;
+
+ /* If another connection has written to the database file since the
+ ** time the read transaction on this connection was started, then
+ ** the write is disallowed.
+ */
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ rc = SQLITE_BUSY;
+ }
+
+ return rc;
+}
+
+/*
+** End a write transaction. The commit has already been done. This
+** routine merely releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ return SQLITE_OK;
+}
+
+/*
+** If any data has been written (but not committed) to the log file, this
+** function moves the write-pointer back to the start of the transaction.
+**
+** Additionally, the callback function is invoked for each frame written
+** to the WAL since the start of the transaction. If the callback returns
+** other than SQLITE_OK, it is not invoked again and the error code is
+** returned to the caller.
+**
+** Otherwise, if the callback function does not return an error, this
+** function returns SQLITE_OK.
+*/
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+ int rc = SQLITE_OK;
+ if( pWal->writeLock ){
+ Pgno iMax = pWal->hdr.mxFrame;
+ Pgno iFrame;
+
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
+ */
+ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ for(iFrame=pWal->hdr.mxFrame+1;
+ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+ iFrame++
+ ){
+ /* This call cannot fail. Unless the page for which the page number
+ ** is passed as the second argument is (a) in the cache and
+ ** (b) has an outstanding reference, then xUndo is either a no-op
+ ** (if (a) is false) or simply expels the page from the cache (if (b)
+ ** is false).
+ **
+ ** If the upper layer is doing a rollback, it is guaranteed that there
+ ** are no outstanding references to any page other than page 1. And
+ ** page 1 is never written to the log until the transaction is
+ ** committed. As a result, the call to xUndo may not fail.
+ */
+ assert( walFramePgno(pWal, iFrame)!=1 );
+ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ }
+ walCleanupHash(pWal);
+ }
+ assert( rc==SQLITE_OK );
+ return rc;
+}
+
+/*
+** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
+** values. This function populates the array with values required to
+** "rollback" the write position of the WAL handle back to the current
+** point in the event of a savepoint rollback (via WalSavepointUndo()).
+*/
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
+ assert( pWal->writeLock );
+ aWalData[0] = pWal->hdr.mxFrame;
+ aWalData[1] = pWal->hdr.aFrameCksum[0];
+ aWalData[2] = pWal->hdr.aFrameCksum[1];
+ aWalData[3] = pWal->nCkpt;
+}
+
+/*
+** Move the write position of the WAL back to the point identified by
+** the values in the aWalData[] array. aWalData must point to an array
+** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
+** by a call to WalSavepoint().
+*/
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
+ int rc = SQLITE_OK;
+
+ assert( pWal->writeLock );
+ assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+
+ if( aWalData[3]!=pWal->nCkpt ){
+ /* This savepoint was opened immediately after the write-transaction
+ ** was started. Right after that, the writer decided to wrap around
+ ** to the start of the log. Update the savepoint values to match.
+ */
+ aWalData[0] = 0;
+ aWalData[3] = pWal->nCkpt;
+ }
+
+ if( aWalData[0]<pWal->hdr.mxFrame ){
+ pWal->hdr.mxFrame = aWalData[0];
+ pWal->hdr.aFrameCksum[0] = aWalData[1];
+ pWal->hdr.aFrameCksum[1] = aWalData[2];
+ walCleanupHash(pWal);
+ }
+
+ return rc;
+}
+
+/*
+** This function is called just before writing a set of frames to the log
+** file (see sqlite3WalFrames()). It checks to see if, instead of appending
+** to the current log file, it is possible to overwrite the start of the
+** existing log file with the new frames (i.e. "reset" the log). If so,
+** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
+** unchanged.
+**
+** SQLITE_OK is returned if no error is encountered (regardless of whether
+** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
+** if some error
+*/
+static int walRestartLog(Wal *pWal){
+ int rc = SQLITE_OK;
+ int cnt;
+
+ if( pWal->readLock==0 ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ assert( pInfo->nBackfill==pWal->hdr.mxFrame );
+ if( pInfo->nBackfill>0 ){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ if( rc==SQLITE_OK ){
+ /* If all readers are using WAL_READ_LOCK(0) (in other words if no
+ ** readers are currently using the WAL), then the transactions
+ ** frames will overwrite the start of the existing log. Update the
+ ** wal-index header to reflect this.
+ **
+ ** In theory it would be Ok to update the cache of the header only
+ ** at this point. But updating the actual wal-index header is also
+ ** safe and means there is no special case for sqlite3WalUndo()
+ ** to handle if this transaction is rolled back.
+ */
+ int i; /* Loop counter */
+ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
+ pWal->nCkpt++;
+ pWal->hdr.mxFrame = 0;
+ sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+ sqlite3_randomness(4, &aSalt[1]);
+ walIndexWriteHdr(pWal);
+ pInfo->nBackfill = 0;
+ for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+ assert( pInfo->aReadMark[0]==0 );
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+ }
+ }
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ pWal->readLock = -1;
+ cnt = 0;
+ do{
+ int notUsed;
+ rc = walTryBeginRead(pWal, ¬Used, 1, ++cnt);
+ }while( rc==WAL_RETRY );
+ }
+ return rc;
+}
+
+/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+*/
+SQLITE_PRIVATE int sqlite3WalFrames(
+ Wal *pWal, /* Wal handle to write to */
+ int szPage, /* Database page-size in bytes */
+ PgHdr *pList, /* List of dirty pages to write */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc; /* Used to catch return codes */
+ u32 iFrame; /* Next frame address */
+ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
+ PgHdr *p; /* Iterator to run through pList with. */
+ PgHdr *pLast = 0; /* Last frame in list */
+ int nLast = 0; /* Number of extra copies of last page */
+
+ assert( pList );
+ assert( pWal->writeLock );
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
+ WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+ pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+ }
+#endif
+
+ /* See if it is possible to write these frames into the start of the
+ ** log file, instead of appending to it at pWal->hdr.mxFrame.
+ */
+ if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+ return rc;
+ }
+
+ /* If this is the first frame written into the log, write the WAL
+ ** header to the start of the WAL file. See comments at the top of
+ ** this source file for a description of the WAL header format.
+ */
+ iFrame = pWal->hdr.mxFrame;
+ if( iFrame==0 ){
+ u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assemble wal-header in */
+ u32 aCksum[2]; /* Checksum for wal-header */
+
+ sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
+ sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
+ sqlite3Put4byte(&aWalHdr[8], szPage);
+ sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
+ memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+ walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+ sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+ sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+
+ pWal->szPage = (u16)szPage;
+ pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+ pWal->hdr.aFrameCksum[0] = aCksum[0];
+ pWal->hdr.aFrameCksum[1] = aCksum[1];
+
+ rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
+ WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+ assert( pWal->szPage==szPage );
+
+ /* Write the log file. */
+ for(p=pList; p; p=p->pDirty){
+ u32 nDbsize; /* Db-size field for frame header */
+ i64 iOffset; /* Write offset in log file */
+ void *pData;
+
+ iOffset = walFrameOffset(++iFrame, szPage);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+
+ /* Populate and write the frame header */
+ nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
+#else
+ pData = p->pData;
+#endif
+ walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+
+ /* Write the page data */
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset+sizeof(aFrame));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pLast = p;
+ }
+
+ /* Sync the log file if the 'isSync' flag was specified. */
+ if( sync_flags ){
+ i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
+ i64 iOffset = walFrameOffset(iFrame+1, szPage);
+
+ assert( isCommit );
+ assert( iSegment>0 );
+
+ iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
+ while( iOffset<iSegment ){
+ void *pData;
+#if defined(SQLITE_HAS_CODEC)
+ if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
+#else
+ pData = pLast->pData;
+#endif
+ walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
+ /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+ rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ iOffset += WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nLast++;
+ iOffset += szPage;
+ }
+
+ rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+ }
+
+ /* Append data to the wal-index. It is not necessary to lock the
+ ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+ ** guarantees that there are no other writers, and no data that may
+ ** be in use by existing readers is being overwritten.
+ */
+ iFrame = pWal->hdr.mxFrame;
+ for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+ iFrame++;
+ rc = walIndexAppend(pWal, iFrame, p->pgno);
+ }
+ while( nLast>0 && rc==SQLITE_OK ){
+ iFrame++;
+ nLast--;
+ rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Update the private copy of the header. */
+ pWal->hdr.szPage = (u16)szPage;
+ pWal->hdr.mxFrame = iFrame;
+ if( isCommit ){
+ pWal->hdr.iChange++;
+ pWal->hdr.nPage = nTruncate;
+ }
+ /* If this is a commit, update the wal-index header too. */
+ if( isCommit ){
+ walIndexWriteHdr(pWal);
+ pWal->iCallback = iFrame;
+ }
+ }
+
+ WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+ return rc;
+}
+
+/*
+** This routine is called to implement sqlite3_wal_checkpoint() and
+** related interfaces.
+**
+** Obtain a CHECKPOINT lock and then backfill as much information as
+** we can from WAL into the database.
+*/
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+ Wal *pWal, /* Wal connection */
+ int sync_flags, /* Flags to sync db file with (or 0) */
+ int nBuf, /* Size of temporary buffer */
+ u8 *zBuf /* Temporary buffer to use */
+){
+ int rc; /* Return code */
+ int isChanged = 0; /* True if a new wal-index header is loaded */
+
+ assert( pWal->ckptLock==0 );
+
+ WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ if( rc ){
+ /* Usually this is SQLITE_BUSY meaning that another thread or process
+ ** is already running a checkpoint, or maybe a recovery. But it might
+ ** also be SQLITE_IOERR. */
+ return rc;
+ }
+ pWal->ckptLock = 1;
+
+ /* Copy data from the log to the database file. */
+ rc = walIndexReadHdr(pWal, &isChanged);
+ if( rc==SQLITE_OK ){
+ rc = walCheckpoint(pWal, sync_flags, nBuf, zBuf);
+ }
+ if( isChanged ){
+ /* If a new wal-index header was loaded before the checkpoint was
+ ** performed, then the pager-cache associated with pWal is now
+ ** out of date. So zero the cached wal-index header to ensure that
+ ** next time the pager opens a snapshot on this database it knows that
+ ** the cache needs to be reset.
+ */
+ memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+ }
+
+ /* Release the locks. */
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ pWal->ckptLock = 0;
+ WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+ return rc;
+}
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called. If no commits have occurred since
+** the last call, then return 0.
+*/
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+ u32 ret = 0;
+ if( pWal ){
+ ret = pWal->iCallback;
+ pWal->iCallback = 0;
+ }
+ return (int)ret;
+}
+
+/*
+** This function is called to change the WAL subsystem into or out
+** of locking_mode=EXCLUSIVE.
+**
+** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+** into locking_mode=NORMAL. This means that we must acquire a lock
+** on the pWal->readLock byte. If the WAL is already in locking_mode=NORMAL
+** or if the acquisition of the lock fails, then return 0. If the
+** transition out of exclusive-mode is successful, return 1. This
+** operation must occur while the pager is still holding the exclusive
+** lock on the main database file.
+**
+** If op is one, then change from locking_mode=NORMAL into
+** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
+** be released. Return 1 if the transition is made and 0 if the
+** WAL is already in exclusive-locking mode - meaning that this
+** routine is a no-op. The pager must already hold the exclusive lock
+** on the main database file before invoking this operation.
+**
+** If op is negative, then do a dry-run of the op==1 case but do
+** not actually change anything. The pager uses this to see if it
+** should acquire the database exclusive lock prior to invoking
+** the op==1 case.
+*/
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+ int rc;
+ assert( pWal->writeLock==0 );
+
+ /* pWal->readLock is usually set, but might be -1 if there was a
+ ** prior error while attempting to acquire are read-lock. This cannot
+ ** happen if the connection is actually in exclusive mode (as no xShmLock
+ ** locks are taken in this case). Nor should the pager attempt to
+ ** upgrade to exclusive-mode following such an error.
+ */
+ assert( pWal->readLock>=0 || pWal->lockError );
+ assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+
+ if( op==0 ){
+ if( pWal->exclusiveMode ){
+ pWal->exclusiveMode = 0;
+ if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+ pWal->exclusiveMode = 1;
+ }
+ rc = pWal->exclusiveMode==0;
+ }else{
+ /* Already in locking_mode=NORMAL */
+ rc = 0;
+ }
+ }else if( op>0 ){
+ assert( pWal->exclusiveMode==0 );
+ assert( pWal->readLock>=0 );
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ pWal->exclusiveMode = 1;
+ rc = 1;
+ }else{
+ rc = pWal->exclusiveMode==0;
+ }
+ return rc;
+}
+
+#endif /* #ifndef SQLITE_OMIT_WAL */
+
+/************** End of wal.c *************************************************/
/************** Begin file btmutex.c *****************************************/
/*
** 2007 August 27
@@ -37202,6 +42830,8 @@
MemPage *pPage1; /* First page of the database */
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
+ u8 secureDelete; /* True if secure_delete is enabled */
+ u8 initiallyEmpty; /* Database is empty at start of transaction */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
@@ -37213,7 +42843,9 @@
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
u8 inTransaction; /* Transaction state */
+ u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
int nTransaction; /* Number of open transactions (read + write) */
+ u32 nPage; /* Number of pages in the database */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
@@ -38294,11 +43926,8 @@
static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
int rc = SQLITE_OK;
if( !pBt->pHasContent ){
- int nPage = 100;
- sqlite3PagerPagecount(pBt->pPager, &nPage);
- /* If sqlite3PagerPagecount() fails there is no harm because the
- ** nPage variable is unchanged from its default value of 100 */
- pBt->pHasContent = sqlite3BitvecCreate((u32)nPage);
+ assert( pgno<=pBt->nPage );
+ pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM;
}
@@ -39025,11 +44654,11 @@
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( size>=0 ); /* Minimum cell size is 4 */
-#ifdef SQLITE_SECURE_DELETE
- /* Overwrite deleted information with zeros when the SECURE_DELETE
- ** option is enabled at compile-time */
- memset(&data[start], 0, size);
-#endif
+ if( pPage->pBt->secureDelete ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[start], 0, size);
+ }
/* Add the space back into the linked list of freeblocks. Note that
** even though the freeblock list was checked by btreeInitPage(),
@@ -39261,9 +44890,9 @@
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
-#ifdef SQLITE_SECURE_DELETE
- memset(&data[hdr], 0, pBt->usableSize - hdr);
-#endif
+ if( pBt->secureDelete ){
+ memset(&data[hdr], 0, pBt->usableSize - hdr);
+ }
data[hdr] = (char)flags;
first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1:0);
memset(&data[hdr+1], 0, 4);
@@ -39341,13 +44970,13 @@
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
-static Pgno pagerPagecount(BtShared *pBt){
- int nPage = -1;
- int rc;
- assert( pBt->pPage1 );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- assert( rc==SQLITE_OK || nPage==-1 );
- return (Pgno)nPage;
+static Pgno btreePagecount(BtShared *pBt){
+ return pBt->nPage;
+}
+SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
+ assert( sqlite3BtreeHoldsMutex(p) );
+ assert( ((p->pBt->nPage)&0x8000000)==0 );
+ return (int)btreePagecount(p->pBt);
}
/*
@@ -39364,25 +44993,22 @@
MemPage **ppPage /* Write the page pointer here */
){
int rc;
- TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = btreeGetPage(pBt, pgno, ppPage, 0);
- if( rc==SQLITE_OK ){
- rc = btreeInitPage(*ppPage);
- if( rc!=SQLITE_OK ){
- releasePage(*ppPage);
+ if( pgno>btreePagecount(pBt) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeGetPage(pBt, pgno, ppPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = btreeInitPage(*ppPage);
+ if( rc!=SQLITE_OK ){
+ releasePage(*ppPage);
+ }
}
}
- /* If the requested page number was either 0 or greater than the page
- ** number of the last page in the database, this function should return
- ** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this
- ** is the case. */
- assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK );
testcase( pgno==0 );
- testcase( pgno==iLastPg );
-
+ assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
}
@@ -39583,6 +45209,9 @@
pBt->pCursor = 0;
pBt->pPage1 = 0;
pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
+#ifdef SQLITE_SECURE_DELETE
+ pBt->secureDelete = 1;
+#endif
pBt->pageSize = get2byte(&zDbHeader[16]);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@@ -39939,6 +45568,23 @@
sqlite3BtreeLeave(p);
return n;
}
+
+/*
+** Set the secureDelete flag if newFlag is 0 or 1. If newFlag is -1,
+** then make no changes. Always return the value of the secureDelete
+** setting after the change.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
+ int b;
+ if( p==0 ) return 0;
+ sqlite3BtreeEnter(p);
+ if( newFlag>=0 ){
+ p->pBt->secureDelete = (newFlag!=0) ? 1 : 0;
+ }
+ b = p->pBt->secureDelete;
+ sqlite3BtreeLeave(p);
+ return b;
+}
#endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */
/*
@@ -39998,9 +45644,11 @@
** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
- int rc;
- MemPage *pPage1;
- int nPage;
+ int rc; /* Result code from subfunctions */
+ MemPage *pPage1; /* Page 1 of the database file */
+ int nPage; /* Number of pages in the database */
+ int nPageFile = 0; /* Number of pages in the database file */
+ int nPageHeader; /* Number of pages in the database according to hdr */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pBt->pPage1==0 );
@@ -40012,10 +45660,14 @@
/* Do some checking to help insure the file we opened really is
** a valid database file.
*/
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK ){
+ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
+ if( (rc = sqlite3PagerPagecount(pBt->pPager, &nPageFile))!=SQLITE_OK ){;
goto page1_init_failed;
- }else if( nPage>0 ){
+ }
+ if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
+ nPage = nPageFile;
+ }
+ if( nPage>0 ){
int pageSize;
int usableSize;
u8 *page1 = pPage1->aData;
@@ -40023,12 +45675,42 @@
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
+
+#ifdef SQLITE_OMIT_WAL
if( page1[18]>1 ){
pBt->readOnly = 1;
}
if( page1[19]>1 ){
goto page1_init_failed;
}
+#else
+ if( page1[18]>2 ){
+ pBt->readOnly = 1;
+ }
+ if( page1[19]>2 ){
+ goto page1_init_failed;
+ }
+
+ /* If the write version is set to 2, this database should be accessed
+ ** in WAL mode. If the log is not already open, open it now. Then
+ ** return SQLITE_OK and return without populating BtShared.pPage1.
+ ** The caller detects this and calls this function again. This is
+ ** required as the version of page 1 currently in the page1 buffer
+ ** may not be the latest version - there may be a newer one in the log
+ ** file.
+ */
+ if( page1[19]==2 && pBt->doNotUseWAL==0 ){
+ int isOpen = 0;
+ rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
+ if( rc!=SQLITE_OK ){
+ goto page1_init_failed;
+ }else if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
+ }
+ rc = SQLITE_NOTADB;
+ }
+#endif
/* The maximum embedded fraction must be exactly 25%. And the minimum
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
@@ -40061,6 +45743,10 @@
pageSize-usableSize);
return rc;
}
+ if( nPageHeader>nPageFile ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto page1_init_failed;
+ }
if( usableSize<480 ){
goto page1_init_failed;
}
@@ -40091,6 +45777,7 @@
pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
+ pBt->nPage = nPage;
return SQLITE_OK;
page1_init_failed:
@@ -40128,12 +45815,10 @@
MemPage *pP1;
unsigned char *data;
int rc;
- int nPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
- if( rc!=SQLITE_OK || nPage>0 ){
- return rc;
+ if( pBt->nPage>0 ){
+ return SQLITE_OK;
}
pP1 = pBt->pPage1;
assert( pP1!=0 );
@@ -40159,6 +45844,8 @@
put4byte(&data[36 + 4*4], pBt->autoVacuum);
put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
+ pBt->nPage = 1;
+ data[31] = 1;
return SQLITE_OK;
}
@@ -40248,6 +45935,7 @@
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
+ pBt->initiallyEmpty = (u8)(pBt->nPage==0);
do {
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
@@ -40272,7 +45960,7 @@
if( rc!=SQLITE_OK ){
unlockBtreeIfUnused(pBt);
}
- }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
+ }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
if( rc==SQLITE_OK ){
@@ -40527,12 +46215,12 @@
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
Pgno nFreeList; /* Number of pages still on the free-list */
+ int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( iLastPg>nFin );
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
- int rc;
u8 eType;
Pgno iPtrPage;
@@ -40608,7 +46296,7 @@
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
MemPage *pPg;
- int rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
+ rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -40621,6 +46309,7 @@
iLastPg--;
}
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
+ pBt->nPage = iLastPg;
}
return SQLITE_OK;
}
@@ -40643,7 +46332,11 @@
rc = SQLITE_DONE;
}else{
invalidateAllOverflowCache(pBt);
- rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
+ rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ put4byte(&pBt->pPage1->aData[28], pBt->nPage);
+ }
}
sqlite3BtreeLeave(p);
return rc;
@@ -40674,7 +46367,7 @@
int nEntry; /* Number of entries on one ptrmap page */
Pgno nOrig; /* Database size before freeing */
- nOrig = pagerPagecount(pBt);
+ nOrig = btreePagecount(pBt);
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
/* It is not possible to create a database for which the final page
** is either a pointer-map page or the pending-byte page. If one
@@ -40699,11 +46392,12 @@
rc = incrVacuumStep(pBt, nFin, iFree);
}
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
- rc = SQLITE_OK;
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
+ put4byte(&pBt->pPage1->aData[28], nFin);
sqlite3PagerTruncateImage(pBt->pPager, nFin);
+ pBt->nPage = nFin;
}
if( rc!=SQLITE_OK ){
sqlite3PagerRollback(pPager);
@@ -40953,6 +46647,11 @@
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
+ int nPage = get4byte(28+(u8*)pPage1->aData);
+ testcase( nPage==0 );
+ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
+ testcase( pBt->nPage!=nPage );
+ pBt->nPage = nPage;
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -40990,17 +46689,13 @@
assert( pBt->readOnly==0 );
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
- if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
- rc = SQLITE_INTERNAL;
- }else{
- assert( pBt->inTransaction==TRANS_WRITE );
- /* At the pager level, a statement transaction is a savepoint with
- ** an index greater than all savepoints created explicitly using
- ** SQL statements. It is illegal to open, release or rollback any
- ** such savepoints while the statement transaction savepoint is active.
- */
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
- }
+ assert( pBt->inTransaction==TRANS_WRITE );
+ /* At the pager level, a statement transaction is a savepoint with
+ ** an index greater than all savepoints created explicitly using
+ ** SQL statements. It is illegal to open, release or rollback any
+ ** such savepoints while the statement transaction savepoint is active.
+ */
+ rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
sqlite3BtreeLeave(p);
return rc;
}
@@ -41026,7 +46721,12 @@
sqlite3BtreeEnter(p);
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
if( rc==SQLITE_OK ){
+ if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
rc = newDatabase(pBt);
+ pBt->nPage = get4byte(28 + pBt->pPage1->aData);
+ if( pBt->nPage==0 ){
+ sqlite3PagerPagecount(pBt->pPager, (int*)&pBt->nPage);
+ }
}
sqlite3BtreeLeave(p);
}
@@ -41092,7 +46792,7 @@
if( NEVER(wrFlag && pBt->readOnly) ){
return SQLITE_READONLY;
}
- if( iTable==1 && pagerPagecount(pBt)==0 ){
+ if( iTable==1 && btreePagecount(pBt)==0 ){
return SQLITE_EMPTY;
}
@@ -41363,7 +47063,7 @@
iGuess++;
}
- if( iGuess<=pagerPagecount(pBt) ){
+ if( iGuess<=btreePagecount(pBt) ){
rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
next = iGuess;
@@ -41958,7 +47658,6 @@
if( pCur->eState==CURSOR_INVALID ){
assert( pCur->apPage[pCur->iPage]->nCell==0 );
*pRes = 1;
- rc = SQLITE_OK;
}else{
assert( pCur->apPage[pCur->iPage]->nCell>0 );
*pRes = 0;
@@ -42395,7 +48094,7 @@
assert( sqlite3_mutex_held(pBt->mutex) );
pPage1 = pBt->pPage1;
- mxPage = pagerPagecount(pBt);
+ mxPage = btreePagecount(pBt);
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -42591,35 +48290,35 @@
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
- int nPage = pagerPagecount(pBt);
- *pPgno = nPage + 1;
-
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
- (*pPgno)++;
- }
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc ) return rc;
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
+ if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){
/* If *pPgno refers to a pointer-map page, allocate two new pages
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
- assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, &pPg, 0);
+ TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
+ rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
}
if( rc ) return rc;
- (*pPgno)++;
- if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
+ pBt->nPage++;
+ if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; }
}
#endif
+ put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
+ *pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = btreeGetPage(pBt, *pPgno, ppPage, 0);
+ rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -42682,17 +48381,17 @@
nFree = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], nFree+1);
-#ifdef SQLITE_SECURE_DELETE
- /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
- ** always fully overwrite deleted information with zeros.
- */
- if( (!pPage && (rc = btreeGetPage(pBt, iPage, &pPage, 0)))
- || (rc = sqlite3PagerWrite(pPage->pDbPage))
- ){
- goto freepage_out;
+ if( pBt->secureDelete ){
+ /* If the secure_delete option is enabled, then
+ ** always fully overwrite deleted information with zeros.
+ */
+ if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
+ || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
+ ){
+ goto freepage_out;
+ }
+ memset(pPage->aData, 0, pPage->pBt->pageSize);
}
- memset(pPage->aData, 0, pPage->pBt->pageSize);
-#endif
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
@@ -42743,11 +48442,9 @@
if( rc==SQLITE_OK ){
put4byte(&pTrunk->aData[4], nLeaf+1);
put4byte(&pTrunk->aData[8+nLeaf*4], iPage);
-#ifndef SQLITE_SECURE_DELETE
- if( pPage ){
+ if( pPage && !pBt->secureDelete ){
sqlite3PagerDontWrite(pPage->pDbPage);
}
-#endif
rc = btreeSetHasContent(pBt, iPage);
}
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
@@ -42811,7 +48508,7 @@
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
- if( ovflPgno<2 || ovflPgno>pagerPagecount(pBt) ){
+ if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
/* 0 is not a legal page number and page 1 cannot be an
** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
@@ -42821,7 +48518,25 @@
rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext);
if( rc ) return rc;
}
- rc = freePage2(pBt, pOvfl, ovflPgno);
+
+ if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
+ && sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
+ ){
+ /* There is no reason any cursor should have an outstanding reference
+ ** to an overflow page belonging to a cell that is being deleted/updated.
+ ** So if there exists more than one reference to this page, then it
+ ** must not really be an overflow page and the database must be corrupt.
+ ** It is helpful to detect this before calling freePage2(), as
+ ** freePage2() may zero the page contents if secure-delete mode is
+ ** enabled. If this 'overflow' page happens to be a page that the
+ ** caller is iterating through or using in some other way, this
+ ** can be problematic.
+ */
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = freePage2(pBt, pOvfl, ovflPgno);
+ }
+
if( pOvfl ){
sqlite3PagerUnref(pOvfl->pDbPage);
}
@@ -43065,7 +48780,7 @@
Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
int *pRC /* Read and write return code from here */
){
- int idx; /* Where to write new cell content in data[] */
+ int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
int end; /* First byte past the last cell pointer in data[] */
int ins; /* Index in data[] where new cell pointer is inserted */
@@ -43556,10 +49271,17 @@
** In this case, temporarily copy the cell into the aOvflSpace[]
** buffer. It will be copied out again as soon as the aSpace[] buffer
** is allocated. */
-#ifdef SQLITE_SECURE_DELETE
- memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]);
- apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
-#endif
+ if( pBt->secureDelete ){
+ int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
+ if( (iOff+szNew[i])>pBt->usableSize ){
+ rc = SQLITE_CORRUPT_BKPT;
+ memset(apOld, 0, (i+1)*sizeof(MemPage*));
+ goto balance_cleanup;
+ }else{
+ memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]);
+ apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
+ }
+ }
dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc);
}
}
@@ -44618,8 +50340,14 @@
releasePage(pRoot);
return rc;
}
+
+ /* When the new root page was allocated, page 1 was made writable in
+ ** order either to increase the database filesize, or to decrement the
+ ** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
+ */
+ assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) );
rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
- if( rc ){
+ if( NEVER(rc) ){
releasePage(pRoot);
return rc;
}
@@ -44659,7 +50387,7 @@
int i;
assert( sqlite3_mutex_held(pBt->mutex) );
- if( pgno>pagerPagecount(pBt) ){
+ if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -45410,7 +51138,7 @@
nRef = sqlite3PagerRefcount(pBt->pPager);
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = pagerPagecount(sCheck.pBt);
+ sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
@@ -45679,6 +51407,42 @@
}
#endif
+/*
+** Set both the "read version" (single byte at byte offset 18) and
+** "write version" (single byte at byte offset 19) fields in the database
+** header to iVersion.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
+ BtShared *pBt = pBtree->pBt;
+ int rc; /* Return code */
+
+ assert( pBtree->inTrans==TRANS_NONE );
+ assert( iVersion==1 || iVersion==2 );
+
+ /* If setting the version fields to 1, do not automatically open the
+ ** WAL connection, even if the version fields are currently set to 2.
+ */
+ pBt->doNotUseWAL = (u8)(iVersion==1);
+
+ rc = sqlite3BtreeBeginTrans(pBtree, 0);
+ if( rc==SQLITE_OK ){
+ u8 *aData = pBt->pPage1->aData;
+ if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
+ rc = sqlite3BtreeBeginTrans(pBtree, 2);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
+ if( rc==SQLITE_OK ){
+ aData[18] = (u8)iVersion;
+ aData[19] = (u8)iVersion;
+ }
+ }
+ }
+ }
+
+ pBt->doNotUseWAL = 0;
+ return rc;
+}
+
/************** End of btree.c ***********************************************/
/************** Begin file backup.c ******************************************/
/*
@@ -45898,7 +51662,7 @@
/* Catch the case where the destination is an in-memory database and the
** page sizes of the source and destination differ.
*/
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
+ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
rc = SQLITE_READONLY;
}
@@ -45968,6 +51732,9 @@
*/
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
+ int destMode; /* Destination journal mode */
+ int pgszSrc = 0; /* Source page size */
+ int pgszDest = 0; /* Destination page size */
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
@@ -46008,13 +51775,21 @@
rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
bCloseTrans = 1;
}
+
+ /* Do not allow backup if the destination database is in WAL mode
+ ** and the page sizes are different between source and destination */
+ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
+ pgszDest = sqlite3BtreeGetPageSize(p->pDest);
+ destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
+ if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ rc = SQLITE_READONLY;
+ }
/* Now that there is a read-lock on the source database, query the
** source pager for the number of pages in the database.
*/
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage);
- }
+ nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
+ assert( nSrcPage>=0 );
for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
@@ -46045,8 +51820,6 @@
if( rc==SQLITE_DONE
&& (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
){
- const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
- const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
int nDestTruncate;
if( p->pDestDb ){
@@ -46065,18 +51838,20 @@
** journalled by PagerCommitPhaseOne() before they are destroyed
** by the file truncation.
*/
- if( nSrcPagesize<nDestPagesize ){
- int ratio = nDestPagesize/nSrcPagesize;
+ assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
+ assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
+ if( pgszSrc<pgszDest ){
+ int ratio = pgszDest/pgszSrc;
nDestTruncate = (nSrcPage+ratio-1)/ratio;
if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
nDestTruncate--;
}
}else{
- nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
+ nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
- if( nSrcPagesize<nDestPagesize ){
+ if( pgszSrc<pgszDest ){
/* If the source page-size is smaller than the destination page-size,
** two extra things may need to happen:
**
@@ -46086,31 +51861,31 @@
** pending-byte page in the source database may need to be
** copied into the destination database.
*/
- const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
+ const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
assert( pFile );
- assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
+ assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
- && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
+ && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
&& SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
&& SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
){
i64 iOff;
- i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
+ i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
for(
- iOff=PENDING_BYTE+nSrcPagesize;
+ iOff=PENDING_BYTE+pgszSrc;
rc==SQLITE_OK && iOff<iEnd;
- iOff+=nSrcPagesize
+ iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
- const Pgno iSrcPg = (Pgno)((iOff/nSrcPagesize)+1);
+ const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
- rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
+ rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
}
sqlite3PagerUnref(pSrcPg);
}
@@ -46139,6 +51914,9 @@
assert( rc2==SQLITE_OK );
}
+ if( rc==SQLITE_IOERR_NOMEM ){
+ rc = SQLITE_NOMEM;
+ }
p->rc = rc;
}
if( p->pDestDb ){
@@ -46625,6 +52403,10 @@
** before attempting the conversion.
*/
static i64 doubleToInt64(double r){
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ /* When floating-point is omitted, double and int64 are the same thing */
+ return r;
+#else
/*
** Many compilers we encounter do not define constants for the
** minimum and maximum 64-bit integers, or they define them
@@ -46646,6 +52428,7 @@
}else{
return (i64)r;
}
+#endif
}
/*
@@ -46773,21 +52556,26 @@
/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
+**
+** Every effort is made to force the conversion, even if the input
+** is a string that does not look completely like a number. Convert
+** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
- double r1, r2;
- i64 i;
+ int rc;
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- r1 = sqlite3VdbeRealValue(pMem);
- i = doubleToInt64(r1);
- r2 = (double)i;
- if( r1==r2 ){
- sqlite3VdbeMemIntegerify(pMem);
+ rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
+ if( rc ) return rc;
+ rc = sqlite3VdbeMemNulTerminate(pMem);
+ if( rc ) return rc;
+ if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
+ MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->r = r1;
+ pMem->r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
+ sqlite3VdbeIntegerAffinity(pMem);
}
return SQLITE_OK;
}
@@ -46839,6 +52627,7 @@
pMem->type = SQLITE_INTEGER;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type REAL.
@@ -46853,6 +52642,7 @@
pMem->type = SQLITE_FLOAT;
}
}
+#endif
/*
** Delete any previous value and set the value of pMem to be an
@@ -46907,7 +52697,7 @@
sqlite3VdbeMemReleaseExternal(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->xDel = 0;
- if( (pFrom->flags&MEM_Dyn)!=0 || pFrom->z==pFrom->zMalloc ){
+ if( (pFrom->flags&MEM_Static)==0 ){
pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
assert( srcType==MEM_Ephem || srcType==MEM_Static );
pTo->flags |= srcType;
@@ -47313,9 +53103,16 @@
return SQLITE_OK;
}
op = pExpr->op;
- if( op==TK_REGISTER ){
- op = pExpr->op2; /* This only happens with SQLITE_ENABLE_STAT2 */
- }
+
+ /* op can only be TK_REGISTER is we have compiled with SQLITE_ENABLE_STAT2.
+ ** The ifdef here is to enable us to achieve 100% branch test coverage even
+ ** when SQLITE_ENABLE_STAT2 is omitted.
+ */
+#ifdef SQLITE_ENABLE_STAT2
+ if( op==TK_REGISTER ) op = pExpr->op2;
+#else
+ if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+#endif
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
pVal = sqlite3ValueNew(db);
@@ -47478,7 +53275,7 @@
*/
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe *)pStmt;
- return (p->isPrepareV2 ? p->zSql : 0);
+ return (p && p->isPrepareV2) ? p->zSql : 0;
}
/*
@@ -48155,7 +53952,7 @@
pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
u8 *aSortOrder;
- memcpy(pKeyInfo, zP4, nByte);
+ memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
@@ -48226,9 +54023,12 @@
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
-** is readable and writable, but it has no effect. The return of a dummy
-** opcode allows the call to continue functioning after a OOM fault without
-** having to check to see if the return from this routine is a valid pointer.
+** is readable but not writable, though it is cast to a writable value.
+** The return of a dummy opcode allows the call to continue functioning
+** after a OOM fault without having to check to see if the return from
+** this routine is a valid pointer. But because the dummy.opcode is 0,
+** dummy will never be written to. This is verified by code inspection and
+** by running with Valgrind.
**
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
@@ -48239,17 +54039,19 @@
** check the value of p->nOp-1 before continuing.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
- static VdbeOp dummy;
+ /* C89 specifies that the constant "dummy" will be initialized to all
+ ** zeros, which is correct. MSVC generates a warning, nevertheless. */
+ static const VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->magic==VDBE_MAGIC_INIT );
if( addr<0 ){
#ifdef SQLITE_OMIT_TRACE
- if( p->nOp==0 ) return &dummy;
+ if( p->nOp==0 ) return (VdbeOp*)&dummy;
#endif
addr = p->nOp - 1;
}
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
- return &dummy;
+ return (VdbeOp*)&dummy;
}else{
return &p->aOp[addr];
}
@@ -48362,6 +54164,11 @@
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
+**
+** The prepared statement has to know in advance which Btree objects
+** will be used so that it can acquire mutexes on them all in sorted
+** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
+** in order (and released in reverse order) to avoid deadlocks.
*/
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
int mask;
@@ -48861,6 +54668,7 @@
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->iStatement = 0;
+ p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
{
int i;
@@ -49539,15 +55347,27 @@
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
- ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then set the error
- ** code to the new value.
+ ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
+ ** current statement error code.
+ **
+ ** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
+ ** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
+ ** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
+ ** the following code.
*/
if( eStatementOp ){
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
- if( rc && (p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT) ){
- p->rc = rc;
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( rc ){
+ assert( eStatementOp==SAVEPOINT_ROLLBACK );
+ if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
+ p->rc = rc;
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
+ invalidateCursorsOnModifiedBtrees(db);
+ sqlite3RollbackAll(db);
+ sqlite3CloseSavepoints(db);
+ db->autoCommit = 1;
}
}
@@ -49749,6 +55569,7 @@
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p->pFree);
+ p->db = 0;
sqlite3DbFree(db, p);
}
@@ -50832,6 +56653,27 @@
}
/*
+** This function is called after a transaction has been committed. It
+** invokes callbacks registered with sqlite3_wal_hook() as required.
+*/
+static int doWalCallbacks(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_WAL
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
**
@@ -50846,21 +56688,23 @@
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
- sqlite3_log(SQLITE_MISUSE,
- "attempt to step a halted statement: [%s]", p->zSql);
- return SQLITE_MISUSE_BKPT;
+ /* We used to require that sqlite3_reset() be called before retrying
+ ** sqlite3_step() after any error. But after 3.6.23, we changed this
+ ** so that sqlite3_reset() would be called automatically instead of
+ ** throwing the error.
+ */
+ sqlite3_reset((sqlite3_stmt*)p);
}
- /* Assert that malloc() has not failed */
+ /* Check that malloc() has not failed. If it has, return early. */
db = p->db;
if( db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
if( p->pc<=0 && p->expired ){
- if( p->rc==SQLITE_OK ){
- p->rc = SQLITE_SCHEMA;
- }
+ p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
goto end_of_step;
}
@@ -50877,9 +56721,7 @@
#ifndef SQLITE_OMIT_TRACE
if( db->xProfile && !db->init.busy ){
- double rNow;
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}
#endif
@@ -50900,16 +56742,20 @@
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
- double rNow;
- u64 elapseTime;
-
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
- elapseTime -= p->startTime;
- db->xProfile(db->pProfileArg, p->zSql, elapseTime);
+ sqlite3_int64 iNow;
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
+ db->xProfile(db->pProfileArg, p->zSql, iNow - p->startTime);
}
#endif
+ if( rc==SQLITE_DONE ){
+ assert( p->rc==SQLITE_OK );
+ p->rc = doWalCallbacks(db);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ }
+ }
+
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
@@ -50959,7 +56805,7 @@
sqlite3_reset(pStmt);
v->expired = 0;
}
- if( rc2!=SQLITE_OK && v->isPrepareV2 && db->pErr ){
+ if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
/* This case occurs after failing to recompile an sql statement.
** The error message from the SQL compiler has already been loaded
** into the database handle. This block copies the error message
@@ -52163,17 +58009,30 @@
static void applyNumericAffinity(Mem *pRec){
if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
int realnum;
+ u8 enc = pRec->enc;
sqlite3VdbeMemNulTerminate(pRec);
- if( (pRec->flags&MEM_Str)
- && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){
+ if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
i64 value;
- sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
- if( !realnum && sqlite3Atoi64(pRec->z, &value) ){
+ char *zUtf8 = pRec->z;
+#ifndef SQLITE_OMIT_UTF16
+ if( enc!=SQLITE_UTF8 ){
+ assert( pRec->db );
+ zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
+ if( !zUtf8 ) return;
+ }
+#endif
+ if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
pRec->u.i = value;
MemSetTypeFlag(pRec, MEM_Int);
}else{
- sqlite3VdbeMemRealify(pRec);
+ sqlite3AtoF(zUtf8, &pRec->r);
+ MemSetTypeFlag(pRec, MEM_Real);
}
+#ifndef SQLITE_OMIT_UTF16
+ if( enc!=SQLITE_UTF8 ){
+ sqlite3DbFree(pRec->db, zUtf8);
+ }
+#endif
}
}
}
@@ -52480,22 +58339,6 @@
#define CHECK_FOR_INTERRUPT \
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
-#ifdef SQLITE_DEBUG
-static int fileExists(sqlite3 *db, const char *zFile){
- int res = 0;
- int rc = SQLITE_OK;
-#ifdef SQLITE_TEST
- /* If we are currently testing IO errors, then do not call OsAccess() to
- ** test for the presence of zFile. This is because any IO error that
- ** occurs here will not be reported, causing the test to fail.
- */
- extern int sqlite3_io_error_pending;
- if( sqlite3_io_error_pending<=0 )
-#endif
- rc = sqlite3OsAccess(db->pVfs, zFile, SQLITE_ACCESS_EXISTS, &res);
- return (res && rc==SQLITE_OK);
-}
-#endif
#ifndef NDEBUG
/*
@@ -52551,7 +58394,7 @@
SQLITE_PRIVATE int sqlite3VdbeExec(
Vdbe *p /* The VDBE */
){
- int pc; /* The program counter */
+ int pc=0; /* The program counter */
Op *aOp = p->aOp; /* Copy of p->aOp */
Op *pOp; /* Current operation */
int rc = SQLITE_OK; /* Value to return */
@@ -52586,9 +58429,6 @@
int pcDest;
} aa;
struct OP_Variable_stack_vars {
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
} ab;
struct OP_Move_stack_vars {
@@ -52625,6 +58465,8 @@
struct OP_Ge_stack_vars {
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
+ u16 flags1; /* Copy of initial value of pIn1->flags */
+ u16 flags3; /* Copy of initial value of pIn3->flags */
} ai;
struct OP_Compare_stack_vars {
int n;
@@ -52911,18 +58753,25 @@
struct OP_AggFinal_stack_vars {
Mem *pMem;
} cc;
+ struct OP_JournalMode_stack_vars {
+ Btree *pBt; /* Btree to change journal mode of */
+ Pager *pPager; /* Pager associated with pBt */
+ int eNew; /* New journal mode */
+ int eOld; /* The old journal mode */
+ const char *zFilename; /* Name of database file for pPager */
+ } cd;
struct OP_IncrVacuum_stack_vars {
Btree *pBt;
- } cd;
+ } ce;
struct OP_VBegin_stack_vars {
VTable *pVTab;
- } ce;
+ } cf;
struct OP_VOpen_stack_vars {
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
- } cf;
+ } cg;
struct OP_VFilter_stack_vars {
int nArg;
int iQuery;
@@ -52935,23 +58784,23 @@
int res;
int i;
Mem **apArg;
- } cg;
+ } ch;
struct OP_VColumn_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
- } ch;
+ } ci;
struct OP_VNext_stack_vars {
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
- } ci;
+ } cj;
struct OP_VRename_stack_vars {
sqlite3_vtab *pVtab;
Mem *pName;
- } cj;
+ } ck;
struct OP_VUpdate_stack_vars {
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
@@ -52960,11 +58809,6 @@
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
- } ck;
- struct OP_Pagecount_stack_vars {
- int p1;
- int nPage;
- Pager *pPager;
} cl;
struct OP_Trace_stack_vars {
char *zTrace;
@@ -52992,9 +58836,7 @@
#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
- if( p->pc==0
- && ((p->db->flags & SQLITE_VdbeListing) || fileExists(db, "vdbe_explain"))
- ){
+ if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
int i;
printf("VDBE Program Listing:\n");
sqlite3VdbePrintSql(p);
@@ -53002,9 +58844,6 @@
sqlite3VdbePrintOp(stdout, i, &aOp[i]);
}
}
- if( fileExists(db, "vdbe_trace") ){
- p->trace = stdout;
- }
sqlite3EndBenignMalloc();
#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){
@@ -53026,13 +58865,6 @@
}
sqlite3VdbePrintOp(p->trace, pc, pOp);
}
- if( p->trace==0 && pc==0 ){
- sqlite3BeginBenignMalloc();
- if( fileExists(db, "vdbe_sqltrace") ){
- sqlite3VdbePrintSql(p);
- }
- sqlite3EndBenignMalloc();
- }
#endif
@@ -53300,6 +59132,7 @@
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* Opcode: Real * P2 * P4 *
**
** P4 is a pointer to a 64-bit floating point value.
@@ -53311,6 +59144,7 @@
pOut->r = *pOp->p4.pReal;
break;
}
+#endif
/* Opcode: String8 * P2 * P4 *
**
@@ -53387,40 +59221,25 @@
break;
}
-/* Opcode: Variable P1 P2 P3 P4 *
+/* Opcode: Variable P1 P2 * P4 *
**
-** Transfer the values of bound parameters P1..P1+P3-1 into registers
-** P2..P2+P3-1.
+** Transfer the values of bound parameter P1 into register P2
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
-case OP_Variable: {
+case OP_Variable: { /* out2-prerelease */
#if 0 /* local variables moved into u.ab */
- int p1; /* Variable to copy from */
- int p2; /* Register to copy to */
- int n; /* Number of values left to copy */
Mem *pVar; /* Value being transferred */
#endif /* local variables moved into u.ab */
- u.ab.p1 = pOp->p1 - 1;
- u.ab.p2 = pOp->p2;
- u.ab.n = pOp->p3;
- assert( u.ab.p1>=0 && u.ab.p1+u.ab.n<=p->nVar );
- assert( u.ab.p2>=1 && u.ab.p2+u.ab.n-1<=p->nMem );
- assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
-
- while( u.ab.n-- > 0 ){
- u.ab.pVar = &p->aVar[u.ab.p1++];
- if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
- goto too_big;
- }
- pOut = &aMem[u.ab.p2++];
- sqlite3VdbeMemReleaseExternal(pOut);
- pOut->flags = MEM_Null;
- sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
- UPDATE_MAX_BLOBSIZE(pOut);
+ assert( pOp->p1>0 && pOp->p1<=p->nVar );
+ u.ab.pVar = &p->aVar[pOp->p1 - 1];
+ if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
+ goto too_big;
}
+ sqlite3VdbeMemShallowCopy(pOut, u.ab.pVar, MEM_Static);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -53721,6 +59540,10 @@
break;
}
}
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ pOut->u.i = u.af.rB;
+ MemSetTypeFlag(pOut, MEM_Int);
+#else
if( sqlite3IsNaN(u.af.rB) ){
goto arithmetic_result_is_null;
}
@@ -53729,6 +59552,7 @@
if( (u.af.flags & MEM_Real)==0 ){
sqlite3VdbeIntegerAffinity(pOut);
}
+#endif
}
break;
@@ -53788,7 +59612,7 @@
for(u.ag.i=0; u.ag.i<u.ag.n; u.ag.i++, u.ag.pArg++){
u.ag.apVal[u.ag.i] = u.ag.pArg;
sqlite3VdbeMemStoreType(u.ag.pArg);
- REGISTER_TRACE(pOp->p2, u.ag.pArg);
+ REGISTER_TRACE(pOp->p2+u.ag.i, u.ag.pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
@@ -53951,6 +59775,7 @@
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* Opcode: RealAffinity P1 * * * *
**
** If register P1 holds an integer convert it to a real value.
@@ -53967,6 +59792,7 @@
}
break;
}
+#endif
#ifndef SQLITE_OMIT_CAST
/* Opcode: ToText P1 * * * *
@@ -54050,7 +59876,7 @@
break;
}
-#ifndef SQLITE_OMIT_CAST
+#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
/* Opcode: ToReal P1 * * * *
**
** Force the value in register P1 to be a floating point number.
@@ -54067,7 +59893,7 @@
}
break;
}
-#endif /* SQLITE_OMIT_CAST */
+#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
/* Opcode: Lt P1 P2 P3 P4 P5
**
@@ -54150,10 +59976,14 @@
#if 0 /* local variables moved into u.ai */
int res; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
+ u16 flags1; /* Copy of initial value of pIn1->flags */
+ u16 flags3; /* Copy of initial value of pIn3->flags */
#endif /* local variables moved into u.ai */
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
+ u.ai.flags1 = pIn1->flags;
+ u.ai.flags3 = pIn3->flags;
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
/* One or both operands are NULL */
if( pOp->p5 & SQLITE_NULLEQ ){
@@ -54208,6 +60038,10 @@
}else if( u.ai.res ){
pc = pOp->p2-1;
}
+
+ /* Undo any changes made by applyAffinity() to the input registers. */
+ pIn1->flags = (pIn1->flags&~MEM_TypeMask) | (u.ai.flags1&MEM_TypeMask);
+ pIn3->flags = (pIn3->flags&~MEM_TypeMask) | (u.ai.flags3&MEM_TypeMask);
break;
}
@@ -55495,10 +61329,10 @@
**
** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
-** the main database is read-only. The transient or virtual
+** the main database is read-only. The ephemeral
** table is deleted automatically when the cursor is closed.
**
-** P2 is the number of columns in the virtual table.
+** P2 is the number of columns in the ephemeral table.
** The cursor points to a BTree table if P4==0 and to a BTree index
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
@@ -55509,6 +61343,14 @@
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/
+/* Opcode: OpenAutoindex P1 P2 * P4 *
+**
+** This opcode works the same as OP_OpenEphemeral. It has a
+** different name to distinguish its use. Tables created using
+** by this opcode will be used for automatically created transient
+** indices in joins.
+*/
+case OP_OpenAutoindex:
case OP_OpenEphemeral: {
#if 0 /* local variables moved into u.ax */
VdbeCursor *pCx;
@@ -55563,7 +61405,7 @@
** register P2. In other words, cursor P1 becomes an alias for the
** MEM_Blob content contained in register P2.
**
-** A pseudo-table created by this opcode is used to hold the a single
+** A pseudo-table created by this opcode is used to hold a single
** row output from the sorter so that the row can be decomposed into
** individual columns using the OP_Column opcode. The OP_Column opcode
** is the only cursor opcode that works with a pseudo-table.
@@ -56630,14 +62472,13 @@
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
u.bl.pC = p->apCsr[pOp->p1];
assert( u.bl.pC!=0 );
+ u.bl.res = 1;
if( (u.bl.pCrsr = u.bl.pC->pCursor)!=0 ){
rc = sqlite3BtreeFirst(u.bl.pCrsr, &u.bl.res);
u.bl.pC->atFirst = u.bl.res==0 ?1:0;
u.bl.pC->deferredMoveto = 0;
u.bl.pC->cacheStatus = CACHE_STALE;
u.bl.pC->rowidIsValid = 0;
- }else{
- u.bl.res = 1;
}
u.bl.pC->nullRow = (u8)u.bl.res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
@@ -56647,7 +62488,7 @@
break;
}
-/* Opcode: Next P1 P2 * * *
+/* Opcode: Next P1 P2 * * P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
@@ -56656,9 +62497,12 @@
**
** The P1 cursor must be for a real table, not a pseudo-table.
**
+** If P5 is positive and the jump is taken, then event counter
+** number P5-1 in the prepared statement is incremented.
+**
** See also: Prev
*/
-/* Opcode: Prev P1 P2 * * *
+/* Opcode: Prev P1 P2 * * P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
@@ -56666,6 +62510,9 @@
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.
+**
+** If P5 is positive and the jump is taken, then event counter
+** number P5-1 in the prepared statement is incremented.
*/
case OP_Prev: /* jump */
case OP_Next: { /* jump */
@@ -56677,6 +62524,7 @@
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p5<=ArraySize(p->aCounter) );
u.bm.pC = p->apCsr[pOp->p1];
if( u.bm.pC==0 ){
break; /* See ticket #2273 */
@@ -57073,7 +62921,7 @@
u.bu.initData.iDb = pOp->p1;
u.bu.initData.pzErrMsg = &p->zErrMsg;
u.bu.zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
+ "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
db->aDb[u.bu.iDb].zName, u.bu.zMaster, pOp->p4.z);
if( u.bu.zSql==0 ){
rc = SQLITE_NOMEM;
@@ -57662,6 +63510,147 @@
break;
}
+#ifndef SQLITE_OMIT_WAL
+/* Opcode: Checkpoint P1 * * * *
+**
+** Checkpoint database P1. This is a no-op if P1 is not currently in
+** WAL mode.
+*/
+case OP_Checkpoint: {
+ rc = sqlite3Checkpoint(db, pOp->p1);
+ break;
+};
+#endif
+
+#ifndef SQLITE_OMIT_PRAGMA
+/* Opcode: JournalMode P1 P2 P3 * P5
+**
+** Change the journal mode of database P1 to P3. P3 must be one of the
+** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
+** modes (delete, truncate, persist, off and memory), this is a simple
+** operation. No IO is required.
+**
+** If changing into or out of WAL mode the procedure is more complicated.
+**
+** Write a string containing the final journal-mode to register P2.
+**
+** If an attempt to change in to or out of WAL mode fails because another
+** connection also has the same database open, then an SQLITE_BUSY error
+** is raised if P5==0, or of P5!=0 the journal mode changed is skipped
+** without signaling the error.
+*/
+case OP_JournalMode: { /* out2-prerelease */
+#if 0 /* local variables moved into u.cd */
+ Btree *pBt; /* Btree to change journal mode of */
+ Pager *pPager; /* Pager associated with pBt */
+ int eNew; /* New journal mode */
+ int eOld; /* The old journal mode */
+ const char *zFilename; /* Name of database file for pPager */
+#endif /* local variables moved into u.cd */
+
+ u.cd.eNew = pOp->p3;
+ assert( u.cd.eNew==PAGER_JOURNALMODE_DELETE
+ || u.cd.eNew==PAGER_JOURNALMODE_TRUNCATE
+ || u.cd.eNew==PAGER_JOURNALMODE_PERSIST
+ || u.cd.eNew==PAGER_JOURNALMODE_OFF
+ || u.cd.eNew==PAGER_JOURNALMODE_MEMORY
+ || u.cd.eNew==PAGER_JOURNALMODE_WAL
+ || u.cd.eNew==PAGER_JOURNALMODE_QUERY
+ );
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+
+ /* This opcode is used in two places: PRAGMA journal_mode and ATTACH.
+ ** In PRAGMA journal_mode, the sqlite3VdbeUsesBtree() routine is called
+ ** when the statment is prepared and so p->aMutex.nMutex>0. All mutexes
+ ** are already acquired. But when used in ATTACH, sqlite3VdbeUsesBtree()
+ ** is not called when the statement is prepared because it requires the
+ ** iDb index of the database as a parameter, and the database has not
+ ** yet been attached so that index is unavailable. We have to wait
+ ** until runtime (now) to get the mutex on the newly attached database.
+ ** No other mutexes are required by the ATTACH command so this is safe
+ ** to do.
+ */
+ assert( (p->btreeMask & (1<<pOp->p1))!=0 || p->aMutex.nMutex==0 );
+ if( p->aMutex.nMutex==0 ){
+ /* This occurs right after ATTACH. Get a mutex on the newly ATTACHed
+ ** database. */
+ sqlite3VdbeUsesBtree(p, pOp->p1);
+ sqlite3VdbeMutexArrayEnter(p);
+ }
+
+ u.cd.pBt = db->aDb[pOp->p1].pBt;
+ u.cd.pPager = sqlite3BtreePager(u.cd.pBt);
+ u.cd.eOld = sqlite3PagerGetJournalMode(u.cd.pPager);
+ if( u.cd.eNew==PAGER_JOURNALMODE_QUERY ) u.cd.eNew = u.cd.eOld;
+ if( !sqlite3PagerOkToChangeJournalMode(u.cd.pPager) ) u.cd.eNew = u.cd.eOld;
+
+#ifndef SQLITE_OMIT_WAL
+ u.cd.zFilename = sqlite3PagerFilename(u.cd.pPager);
+
+ /* Do not allow a transition to journal_mode=WAL for a database
+ ** in temporary storage or if the VFS does not support xShmOpen.
+ */
+ if( u.cd.eNew==PAGER_JOURNALMODE_WAL
+ && (u.cd.zFilename[0]==0 /* Temp file */
+ || !sqlite3PagerWalSupported(u.cd.pPager)) /* No xShmOpen support */
+ ){
+ u.cd.eNew = u.cd.eOld;
+ }
+
+ if( (u.cd.eNew!=u.cd.eOld)
+ && (u.cd.eOld==PAGER_JOURNALMODE_WAL || u.cd.eNew==PAGER_JOURNALMODE_WAL)
+ ){
+ if( !db->autoCommit || db->activeVdbeCnt>1 ){
+ rc = SQLITE_ERROR;
+ sqlite3SetString(&p->zErrMsg, db,
+ "cannot change %s wal mode from within a transaction",
+ (u.cd.eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
+ );
+ break;
+ }else{
+
+ if( u.cd.eOld==PAGER_JOURNALMODE_WAL ){
+ /* If leaving WAL mode, close the log file. If successful, the call
+ ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
+ ** file. An EXCLUSIVE lock may still be held on the database file
+ ** after a successful return.
+ */
+ rc = sqlite3PagerCloseWal(u.cd.pPager);
+ if( rc==SQLITE_OK ){
+ sqlite3PagerSetJournalMode(u.cd.pPager, u.cd.eNew);
+ }
+ }else if( u.cd.eOld==PAGER_JOURNALMODE_MEMORY ){
+ /* Cannot transition directly from MEMORY to WAL. Use mode OFF
+ ** as an intermediate */
+ sqlite3PagerSetJournalMode(u.cd.pPager, PAGER_JOURNALMODE_OFF);
+ }
+
+ /* Open a transaction on the database file. Regardless of the journal
+ ** mode, this transaction always uses a rollback journal.
+ */
+ assert( sqlite3BtreeIsInTrans(u.cd.pBt)==0 );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeSetVersion(u.cd.pBt, (u.cd.eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
+ }
+ }
+ }
+#endif /* ifndef SQLITE_OMIT_WAL */
+
+ if( rc ){
+ if( rc==SQLITE_BUSY && pOp->p5!=0 ) rc = SQLITE_OK;
+ u.cd.eNew = u.cd.eOld;
+ }
+ u.cd.eNew = sqlite3PagerSetJournalMode(u.cd.pPager, u.cd.eNew);
+
+ pOut = &aMem[pOp->p2];
+ pOut->flags = MEM_Str|MEM_Static|MEM_Term;
+ pOut->z = (char *)sqlite3JournalModename(u.cd.eNew);
+ pOut->n = sqlite3Strlen30(pOut->z);
+ pOut->enc = SQLITE_UTF8;
+ sqlite3VdbeChangeEncoding(pOut, encoding);
+ break;
+};
+#endif /* SQLITE_OMIT_PRAGMA */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* Opcode: Vacuum * * * * *
@@ -57684,14 +63673,14 @@
** P2. Otherwise, fall through to the next instruction.
*/
case OP_IncrVacuum: { /* jump */
-#if 0 /* local variables moved into u.cd */
+#if 0 /* local variables moved into u.ce */
Btree *pBt;
-#endif /* local variables moved into u.cd */
+#endif /* local variables moved into u.ce */
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( (p->btreeMask & (1<<pOp->p1))!=0 );
- u.cd.pBt = db->aDb[pOp->p1].pBt;
- rc = sqlite3BtreeIncrVacuum(u.cd.pBt);
+ u.ce.pBt = db->aDb[pOp->p1].pBt;
+ rc = sqlite3BtreeIncrVacuum(u.ce.pBt);
if( rc==SQLITE_DONE ){
pc = pOp->p2 - 1;
rc = SQLITE_OK;
@@ -57761,15 +63750,15 @@
** code will be set to SQLITE_LOCKED.
*/
case OP_VBegin: {
-#if 0 /* local variables moved into u.ce */
+#if 0 /* local variables moved into u.cf */
VTable *pVTab;
-#endif /* local variables moved into u.ce */
- u.ce.pVTab = pOp->p4.pVtab;
- rc = sqlite3VtabBegin(db, u.ce.pVTab);
- if( u.ce.pVTab ){
+#endif /* local variables moved into u.cf */
+ u.cf.pVTab = pOp->p4.pVtab;
+ rc = sqlite3VtabBegin(db, u.cf.pVTab);
+ if( u.cf.pVTab ){
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ce.pVTab->pVtab->zErrMsg;
- u.ce.pVTab->pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cf.pVTab->pVtab->zErrMsg;
+ u.cf.pVTab->pVtab->zErrMsg = 0;
}
break;
}
@@ -57809,34 +63798,34 @@
** table and stores that cursor in P1.
*/
case OP_VOpen: {
-#if 0 /* local variables moved into u.cf */
+#if 0 /* local variables moved into u.cg */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVtabCursor;
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
-#endif /* local variables moved into u.cf */
+#endif /* local variables moved into u.cg */
- u.cf.pCur = 0;
- u.cf.pVtabCursor = 0;
- u.cf.pVtab = pOp->p4.pVtab->pVtab;
- u.cf.pModule = (sqlite3_module *)u.cf.pVtab->pModule;
- assert(u.cf.pVtab && u.cf.pModule);
- rc = u.cf.pModule->xOpen(u.cf.pVtab, &u.cf.pVtabCursor);
+ u.cg.pCur = 0;
+ u.cg.pVtabCursor = 0;
+ u.cg.pVtab = pOp->p4.pVtab->pVtab;
+ u.cg.pModule = (sqlite3_module *)u.cg.pVtab->pModule;
+ assert(u.cg.pVtab && u.cg.pModule);
+ rc = u.cg.pModule->xOpen(u.cg.pVtab, &u.cg.pVtabCursor);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cf.pVtab->zErrMsg;
- u.cf.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cg.pVtab->zErrMsg;
+ u.cg.pVtab->zErrMsg = 0;
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
- u.cf.pVtabCursor->pVtab = u.cf.pVtab;
+ u.cg.pVtabCursor->pVtab = u.cg.pVtab;
/* Initialise vdbe cursor object */
- u.cf.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
- if( u.cf.pCur ){
- u.cf.pCur->pVtabCursor = u.cf.pVtabCursor;
- u.cf.pCur->pModule = u.cf.pVtabCursor->pVtab->pModule;
+ u.cg.pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
+ if( u.cg.pCur ){
+ u.cg.pCur->pVtabCursor = u.cg.pVtabCursor;
+ u.cg.pCur->pModule = u.cg.pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
- u.cf.pModule->xClose(u.cf.pVtabCursor);
+ u.cg.pModule->xClose(u.cg.pVtabCursor);
}
}
break;
@@ -57863,7 +63852,7 @@
** A jump is made to P2 if the result set after filtering would be empty.
*/
case OP_VFilter: { /* jump */
-#if 0 /* local variables moved into u.cg */
+#if 0 /* local variables moved into u.ch */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@@ -57875,46 +63864,46 @@
int res;
int i;
Mem **apArg;
-#endif /* local variables moved into u.cg */
+#endif /* local variables moved into u.ch */
- u.cg.pQuery = &aMem[pOp->p3];
- u.cg.pArgc = &u.cg.pQuery[1];
- u.cg.pCur = p->apCsr[pOp->p1];
- REGISTER_TRACE(pOp->p3, u.cg.pQuery);
- assert( u.cg.pCur->pVtabCursor );
- u.cg.pVtabCursor = u.cg.pCur->pVtabCursor;
- u.cg.pVtab = u.cg.pVtabCursor->pVtab;
- u.cg.pModule = u.cg.pVtab->pModule;
+ u.ch.pQuery = &aMem[pOp->p3];
+ u.ch.pArgc = &u.ch.pQuery[1];
+ u.ch.pCur = p->apCsr[pOp->p1];
+ REGISTER_TRACE(pOp->p3, u.ch.pQuery);
+ assert( u.ch.pCur->pVtabCursor );
+ u.ch.pVtabCursor = u.ch.pCur->pVtabCursor;
+ u.ch.pVtab = u.ch.pVtabCursor->pVtab;
+ u.ch.pModule = u.ch.pVtab->pModule;
/* Grab the index number and argc parameters */
- assert( (u.cg.pQuery->flags&MEM_Int)!=0 && u.cg.pArgc->flags==MEM_Int );
- u.cg.nArg = (int)u.cg.pArgc->u.i;
- u.cg.iQuery = (int)u.cg.pQuery->u.i;
+ assert( (u.ch.pQuery->flags&MEM_Int)!=0 && u.ch.pArgc->flags==MEM_Int );
+ u.ch.nArg = (int)u.ch.pArgc->u.i;
+ u.ch.iQuery = (int)u.ch.pQuery->u.i;
/* Invoke the xFilter method */
{
- u.cg.res = 0;
- u.cg.apArg = p->apArg;
- for(u.cg.i = 0; u.cg.i<u.cg.nArg; u.cg.i++){
- u.cg.apArg[u.cg.i] = &u.cg.pArgc[u.cg.i+1];
- sqlite3VdbeMemStoreType(u.cg.apArg[u.cg.i]);
+ u.ch.res = 0;
+ u.ch.apArg = p->apArg;
+ for(u.ch.i = 0; u.ch.i<u.ch.nArg; u.ch.i++){
+ u.ch.apArg[u.ch.i] = &u.ch.pArgc[u.ch.i+1];
+ sqlite3VdbeMemStoreType(u.ch.apArg[u.ch.i]);
}
p->inVtabMethod = 1;
- rc = u.cg.pModule->xFilter(u.cg.pVtabCursor, u.cg.iQuery, pOp->p4.z, u.cg.nArg, u.cg.apArg);
+ rc = u.ch.pModule->xFilter(u.ch.pVtabCursor, u.ch.iQuery, pOp->p4.z, u.ch.nArg, u.ch.apArg);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cg.pVtab->zErrMsg;
- u.cg.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.ch.pVtab->zErrMsg;
+ u.ch.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK ){
- u.cg.res = u.cg.pModule->xEof(u.cg.pVtabCursor);
+ u.ch.res = u.ch.pModule->xEof(u.ch.pVtabCursor);
}
- if( u.cg.res ){
+ if( u.ch.res ){
pc = pOp->p2 - 1;
}
}
- u.cg.pCur->nullRow = 0;
+ u.ch.pCur->nullRow = 0;
break;
}
@@ -57928,52 +63917,52 @@
** P1 cursor is pointing to into register P3.
*/
case OP_VColumn: {
-#if 0 /* local variables moved into u.ch */
+#if 0 /* local variables moved into u.ci */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
-#endif /* local variables moved into u.ch */
+#endif /* local variables moved into u.ci */
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
- u.ch.pDest = &aMem[pOp->p3];
+ u.ci.pDest = &aMem[pOp->p3];
if( pCur->nullRow ){
- sqlite3VdbeMemSetNull(u.ch.pDest);
+ sqlite3VdbeMemSetNull(u.ci.pDest);
break;
}
- u.ch.pVtab = pCur->pVtabCursor->pVtab;
- u.ch.pModule = u.ch.pVtab->pModule;
- assert( u.ch.pModule->xColumn );
- memset(&u.ch.sContext, 0, sizeof(u.ch.sContext));
+ u.ci.pVtab = pCur->pVtabCursor->pVtab;
+ u.ci.pModule = u.ci.pVtab->pModule;
+ assert( u.ci.pModule->xColumn );
+ memset(&u.ci.sContext, 0, sizeof(u.ci.sContext));
/* The output cell may already have a buffer allocated. Move
- ** the current contents to u.ch.sContext.s so in case the user-function
+ ** the current contents to u.ci.sContext.s so in case the user-function
** can use the already allocated buffer instead of allocating a
** new one.
*/
- sqlite3VdbeMemMove(&u.ch.sContext.s, u.ch.pDest);
- MemSetTypeFlag(&u.ch.sContext.s, MEM_Null);
+ sqlite3VdbeMemMove(&u.ci.sContext.s, u.ci.pDest);
+ MemSetTypeFlag(&u.ci.sContext.s, MEM_Null);
- rc = u.ch.pModule->xColumn(pCur->pVtabCursor, &u.ch.sContext, pOp->p2);
+ rc = u.ci.pModule->xColumn(pCur->pVtabCursor, &u.ci.sContext, pOp->p2);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ch.pVtab->zErrMsg;
- u.ch.pVtab->zErrMsg = 0;
- if( u.ch.sContext.isError ){
- rc = u.ch.sContext.isError;
+ p->zErrMsg = u.ci.pVtab->zErrMsg;
+ u.ci.pVtab->zErrMsg = 0;
+ if( u.ci.sContext.isError ){
+ rc = u.ci.sContext.isError;
}
/* Copy the result of the function to the P3 register. We
** do this regardless of whether or not an error occurred to ensure any
- ** dynamic allocation in u.ch.sContext.s (a Mem struct) is released.
+ ** dynamic allocation in u.ci.sContext.s (a Mem struct) is released.
*/
- sqlite3VdbeChangeEncoding(&u.ch.sContext.s, encoding);
- sqlite3VdbeMemMove(u.ch.pDest, &u.ch.sContext.s);
- REGISTER_TRACE(pOp->p3, u.ch.pDest);
- UPDATE_MAX_BLOBSIZE(u.ch.pDest);
+ sqlite3VdbeChangeEncoding(&u.ci.sContext.s, encoding);
+ sqlite3VdbeMemMove(u.ci.pDest, &u.ci.sContext.s);
+ REGISTER_TRACE(pOp->p3, u.ci.pDest);
+ UPDATE_MAX_BLOBSIZE(u.ci.pDest);
- if( sqlite3VdbeMemTooBig(u.ch.pDest) ){
+ if( sqlite3VdbeMemTooBig(u.ci.pDest) ){
goto too_big;
}
break;
@@ -57988,22 +63977,22 @@
** the end of its result set, then fall through to the next instruction.
*/
case OP_VNext: { /* jump */
-#if 0 /* local variables moved into u.ci */
+#if 0 /* local variables moved into u.cj */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
VdbeCursor *pCur;
-#endif /* local variables moved into u.ci */
+#endif /* local variables moved into u.cj */
- u.ci.res = 0;
- u.ci.pCur = p->apCsr[pOp->p1];
- assert( u.ci.pCur->pVtabCursor );
- if( u.ci.pCur->nullRow ){
+ u.cj.res = 0;
+ u.cj.pCur = p->apCsr[pOp->p1];
+ assert( u.cj.pCur->pVtabCursor );
+ if( u.cj.pCur->nullRow ){
break;
}
- u.ci.pVtab = u.ci.pCur->pVtabCursor->pVtab;
- u.ci.pModule = u.ci.pVtab->pModule;
- assert( u.ci.pModule->xNext );
+ u.cj.pVtab = u.cj.pCur->pVtabCursor->pVtab;
+ u.cj.pModule = u.cj.pVtab->pModule;
+ assert( u.cj.pModule->xNext );
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
@@ -58012,16 +64001,16 @@
** some other method is next invoked on the save virtual table cursor.
*/
p->inVtabMethod = 1;
- rc = u.ci.pModule->xNext(u.ci.pCur->pVtabCursor);
+ rc = u.cj.pModule->xNext(u.cj.pCur->pVtabCursor);
p->inVtabMethod = 0;
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ci.pVtab->zErrMsg;
- u.ci.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cj.pVtab->zErrMsg;
+ u.cj.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK ){
- u.ci.res = u.ci.pModule->xEof(u.ci.pCur->pVtabCursor);
+ u.cj.res = u.cj.pModule->xEof(u.cj.pCur->pVtabCursor);
}
- if( !u.ci.res ){
+ if( !u.cj.res ){
/* If there is data, jump to P2 */
pc = pOp->p2 - 1;
}
@@ -58037,20 +64026,20 @@
** in register P1 is passed as the zName argument to the xRename method.
*/
case OP_VRename: {
-#if 0 /* local variables moved into u.cj */
+#if 0 /* local variables moved into u.ck */
sqlite3_vtab *pVtab;
Mem *pName;
-#endif /* local variables moved into u.cj */
+#endif /* local variables moved into u.ck */
- u.cj.pVtab = pOp->p4.pVtab->pVtab;
- u.cj.pName = &aMem[pOp->p1];
- assert( u.cj.pVtab->pModule->xRename );
- REGISTER_TRACE(pOp->p1, u.cj.pName);
- assert( u.cj.pName->flags & MEM_Str );
- rc = u.cj.pVtab->pModule->xRename(u.cj.pVtab, u.cj.pName->z);
+ u.ck.pVtab = pOp->p4.pVtab->pVtab;
+ u.ck.pName = &aMem[pOp->p1];
+ assert( u.ck.pVtab->pModule->xRename );
+ REGISTER_TRACE(pOp->p1, u.ck.pName);
+ assert( u.ck.pName->flags & MEM_Str );
+ rc = u.ck.pVtab->pModule->xRename(u.ck.pVtab, u.ck.pName->z);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.cj.pVtab->zErrMsg;
- u.cj.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.ck.pVtab->zErrMsg;
+ u.ck.pVtab->zErrMsg = 0;
break;
}
@@ -58081,7 +64070,7 @@
** is set to the value of the rowid for the row just inserted.
*/
case OP_VUpdate: {
-#if 0 /* local variables moved into u.ck */
+#if 0 /* local variables moved into u.cl */
sqlite3_vtab *pVtab;
sqlite3_module *pModule;
int nArg;
@@ -58089,27 +64078,27 @@
sqlite_int64 rowid;
Mem **apArg;
Mem *pX;
-#endif /* local variables moved into u.ck */
+#endif /* local variables moved into u.cl */
- u.ck.pVtab = pOp->p4.pVtab->pVtab;
- u.ck.pModule = (sqlite3_module *)u.ck.pVtab->pModule;
- u.ck.nArg = pOp->p2;
+ u.cl.pVtab = pOp->p4.pVtab->pVtab;
+ u.cl.pModule = (sqlite3_module *)u.cl.pVtab->pModule;
+ u.cl.nArg = pOp->p2;
assert( pOp->p4type==P4_VTAB );
- if( ALWAYS(u.ck.pModule->xUpdate) ){
- u.ck.apArg = p->apArg;
- u.ck.pX = &aMem[pOp->p3];
- for(u.ck.i=0; u.ck.i<u.ck.nArg; u.ck.i++){
- sqlite3VdbeMemStoreType(u.ck.pX);
- u.ck.apArg[u.ck.i] = u.ck.pX;
- u.ck.pX++;
+ if( ALWAYS(u.cl.pModule->xUpdate) ){
+ u.cl.apArg = p->apArg;
+ u.cl.pX = &aMem[pOp->p3];
+ for(u.cl.i=0; u.cl.i<u.cl.nArg; u.cl.i++){
+ sqlite3VdbeMemStoreType(u.cl.pX);
+ u.cl.apArg[u.cl.i] = u.cl.pX;
+ u.cl.pX++;
}
- rc = u.ck.pModule->xUpdate(u.ck.pVtab, u.ck.nArg, u.ck.apArg, &u.ck.rowid);
+ rc = u.cl.pModule->xUpdate(u.cl.pVtab, u.cl.nArg, u.cl.apArg, &u.cl.rowid);
sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = u.ck.pVtab->zErrMsg;
- u.ck.pVtab->zErrMsg = 0;
+ p->zErrMsg = u.cl.pVtab->zErrMsg;
+ u.cl.pVtab->zErrMsg = 0;
if( rc==SQLITE_OK && pOp->p1 ){
- assert( u.ck.nArg>1 && u.ck.apArg[0] && (u.ck.apArg[0]->flags&MEM_Null) );
- db->lastRowid = u.ck.rowid;
+ assert( u.cl.nArg>1 && u.cl.apArg[0] && (u.cl.apArg[0]->flags&MEM_Null) );
+ db->lastRowid = u.cl.rowid;
}
p->nChange++;
}
@@ -58123,21 +64112,7 @@
** Write the current number of pages in database P1 to memory cell P2.
*/
case OP_Pagecount: { /* out2-prerelease */
-#if 0 /* local variables moved into u.cl */
- int p1;
- int nPage;
- Pager *pPager;
-#endif /* local variables moved into u.cl */
-
- u.cl.p1 = pOp->p1;
- u.cl.pPager = sqlite3BtreePager(db->aDb[u.cl.p1].pBt);
- rc = sqlite3PagerPagecount(u.cl.pPager, &u.cl.nPage);
- /* OP_Pagecount is always called from within a read transaction. The
- ** page count has already been successfully read and cached. So the
- ** sqlite3PagerPagecount() call above cannot fail. */
- if( ALWAYS(rc==SQLITE_OK) ){
- pOut->u.i = u.cl.nPage;
- }
+ pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
break;
}
#endif
@@ -58183,6 +64158,7 @@
** the same as a no-op. This opcodesnever appears in a real VM program.
*/
default: { /* This is really OP_Noop and OP_Explain */
+ assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
break;
}
@@ -58234,7 +64210,9 @@
vdbe_error_halt:
assert( rc );
p->rc = rc;
- sqlite3_log(rc, "prepared statement aborts at %d: [%s]", pc, p->zSql);
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ sqlite3_log(rc, "statement aborts at %d: [%s] %s",
+ pc, p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
rc = SQLITE_ERROR;
@@ -58478,10 +64456,14 @@
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
+#ifdef SQLITE_OMIT_SHARED_CACHE
+ sqlite3VdbeChangeToNoop(v, 2, 1);
+#else
sqlite3VdbeChangeP1(v, 2, iDb);
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
sqlite3VdbeChangeP3(v, 2, flags);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
+#endif
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
@@ -58852,7 +64834,12 @@
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
- 0 /* xDeviceCharacteristics */
+ 0, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmLock */
+ 0, /* xShmMap */
+ 0, /* xShmBarrier */
+ 0 /* xShmClose */
};
/*
@@ -59102,11 +65089,10 @@
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
-static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
- UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
- assert( 0 ); /*NO_TEST*/
- return SQLITE_OK; /*NO_TEST*/
-} /*NO_TEST*/
+static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return SQLITE_OK;
+}
/*
** Query the size of the file in bytes.
@@ -59120,7 +65106,7 @@
/*
** Table of methods for MemJournal sqlite3_file object.
*/
-static struct sqlite3_io_methods MemJournalMethods = {
+static const struct sqlite3_io_methods MemJournalMethods = {
1, /* iVersion */
memjrnlClose, /* xClose */
memjrnlRead, /* xRead */
@@ -59133,7 +65119,12 @@
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
- 0 /* xDeviceCharacteristics */
+ 0, /* xDeviceCharacteristics */
+ 0, /* xShmOpen */
+ 0, /* xShmLock */
+ 0, /* xShmMap */
+ 0, /* xShmBarrier */
+ 0 /* xShmClose */
};
/*
@@ -59143,7 +65134,7 @@
MemJournal *p = (MemJournal *)pJfd;
assert( EIGHT_BYTE_ALIGNMENT(p) );
memset(p, 0, sqlite3MemJournalSize());
- p->pMethod = &MemJournalMethods;
+ p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
}
/*
@@ -59656,6 +65647,7 @@
}else{
sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
}
+ pParse->checkSchema = 1;
pTopNC->nErr++;
}
@@ -59702,7 +65694,7 @@
/*
** Allocate and return a pointer to an expression to load the column iCol
-** from datasource iSrc datasource in SrcList pSrc.
+** from datasource iSrc in SrcList pSrc.
*/
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
@@ -59714,6 +65706,8 @@
p->iColumn = -1;
}else{
p->iColumn = (ynVar)iCol;
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
}
ExprSetProperty(p, EP_Resolved);
@@ -59990,7 +65984,7 @@
** result-set entry.
*/
for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprCompare(pEList->a[i].pExpr, pE) ){
+ if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){
return i+1;
}
}
@@ -60750,10 +66744,6 @@
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
(void*)p4, P4_COLLSEQ);
sqlite3VdbeChangeP5(pParse->pVdbe, (u8)p5);
- if( (p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_NONE ){
- sqlite3ExprCacheAffinityChange(pParse, in1, 1);
- sqlite3ExprCacheAffinityChange(pParse, in2, 1);
- }
return addr;
}
@@ -62384,6 +68374,7 @@
return out;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Generate an instruction that will put the floating point
** value described by z[0..n-1] into register iMem.
@@ -62403,6 +68394,7 @@
sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
}
}
+#endif
/*
@@ -62413,7 +68405,8 @@
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
-static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
+static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
+ Vdbe *v = pParse->pVdbe;
if( pExpr->flags & EP_IntValue ){
int i = pExpr->u.iValue;
if( negFlag ) i = -i;
@@ -62429,7 +68422,11 @@
zV = dup8bytes(v, (char*)&value);
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
}else{
+#ifdef SQLITE_OMIT_FLOATING_POINT
+ sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
+#else
codeReal(v, z, negFlag, iMem);
+#endif
}
}
}
@@ -62582,6 +68579,27 @@
}
/*
+** Generate code to extract the value of the iCol-th column of a table.
+*/
+SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
+ Vdbe *v, /* The VDBE under construction */
+ Table *pTab, /* The table containing the value */
+ int iTabCur, /* The cursor for this table */
+ int iCol, /* Index of the column to extract */
+ int regOut /* Extract the valud into this register */
+){
+ if( iCol<0 || iCol==pTab->iPKey ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
+ }else{
+ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp3(v, op, iTabCur, iCol, regOut);
+ }
+ if( iCol>=0 ){
+ sqlite3ColumnDefault(v, pTab, iCol, regOut);
+ }
+}
+
+/*
** Generate code that will extract the iColumn-th column from
** table pTab and store the column value in a register. An effort
** is made to store the column value in register iReg, but this is
@@ -62609,13 +68627,7 @@
}
}
assert( v!=0 );
- if( iColumn<0 ){
- sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg);
- }else if( ALWAYS(pTab!=0) ){
- int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
- sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);
- sqlite3ColumnDefault(v, pTab, iColumn, iReg);
- }
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
return iReg;
}
@@ -62816,14 +68828,16 @@
break;
}
case TK_INTEGER: {
- codeInteger(v, pExpr, 0, target);
+ codeInteger(pParse, pExpr, 0, target);
break;
}
+#ifndef SQLITE_OMIT_FLOATING_POINT
case TK_FLOAT: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pExpr->u.zToken, 0, target);
break;
}
+#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
@@ -62850,27 +68864,12 @@
}
#endif
case TK_VARIABLE: {
- VdbeOp *pOp;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( pExpr->u.zToken!=0 );
assert( pExpr->u.zToken[0]!=0 );
- if( pExpr->u.zToken[1]==0
- && (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
- && pOp->p1+pOp->p3==pExpr->iColumn
- && pOp->p2+pOp->p3==target
- && pOp->p4.z==0
- ){
- /* If the previous instruction was a copy of the previous unnamed
- ** parameter into the previous register, then simply increment the
- ** repeat count on the prior instruction rather than making a new
- ** instruction.
- */
- pOp->p3++;
- }else{
- sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1);
- if( pExpr->u.zToken[1]!=0 ){
- sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
- }
+ sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
+ if( pExpr->u.zToken[1]!=0 ){
+ sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
}
break;
}
@@ -62993,11 +68992,13 @@
case TK_UMINUS: {
Expr *pLeft = pExpr->pLeft;
assert( pLeft );
- if( pLeft->op==TK_FLOAT ){
+ if( pLeft->op==TK_INTEGER ){
+ codeInteger(pParse, pLeft, 1, target);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ }else if( pLeft->op==TK_FLOAT ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pLeft->u.zToken, 1, target);
- }else if( pLeft->op==TK_INTEGER ){
- codeInteger(v, pLeft, 1, target);
+#endif
}else{
regFree1 = r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
@@ -63245,6 +69246,7 @@
target
));
+#ifndef SQLITE_OMIT_FLOATING_POINT
/* If the column has REAL affinity, it may currently be stored as an
** integer. Use OP_RealAffinity to make sure it is really real. */
if( pExpr->iColumn>=0
@@ -63252,6 +69254,7 @@
){
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
}
+#endif
break;
}
@@ -63917,59 +69920,76 @@
}
/*
-** Do a deep comparison of two expression trees. Return TRUE (non-zero)
-** if they are identical and return FALSE if they differ in any way.
+** Do a deep comparison of two expression trees. Return 0 if the two
+** expressions are completely identical. Return 1 if they differ only
+** by a COLLATE operator at the top level. Return 2 if there are differences
+** other than the top-level COLLATE operator.
**
-** Sometimes this routine will return FALSE even if the two expressions
+** Sometimes this routine will return 2 even if the two expressions
** really are equivalent. If we cannot prove that the expressions are
-** identical, we return FALSE just to be safe. So if this routine
-** returns false, then you do not really know for certain if the two
-** expressions are the same. But if you get a TRUE return, then you
+** identical, we return 2 just to be safe. So if this routine
+** returns 2, then you do not really know for certain if the two
+** expressions are the same. But if you get a 0 or 1 return, then you
** can be sure the expressions are the same. In the places where
-** this routine is used, it does not hurt to get an extra FALSE - that
+** this routine is used, it does not hurt to get an extra 2 - that
** just might result in some slightly slower code. But returning
-** an incorrect TRUE could lead to a malfunction.
+** an incorrect 0 or 1 could lead to a malfunction.
*/
SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB){
- int i;
if( pA==0||pB==0 ){
- return pB==pA;
+ return pB==pA ? 0 : 2;
}
assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
- return 0;
+ return 2;
}
- if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
- if( pA->op!=pB->op ) return 0;
- if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
- if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
-
- if( pA->x.pList && pB->x.pList ){
- if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 0;
- for(i=0; i<pA->x.pList->nExpr; i++){
- Expr *pExprA = pA->x.pList->a[i].pExpr;
- Expr *pExprB = pB->x.pList->a[i].pExpr;
- if( !sqlite3ExprCompare(pExprA, pExprB) ) return 0;
- }
- }else if( pA->x.pList || pB->x.pList ){
- return 0;
- }
-
- if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
+ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
+ if( pA->op!=pB->op ) return 2;
+ if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
+ if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
+ if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
+ if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
if( ExprHasProperty(pA, EP_IntValue) ){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
- return 0;
+ return 2;
}
}else if( pA->op!=TK_COLUMN && pA->u.zToken ){
- if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 0;
+ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){
- return 0;
+ return 2;
}
}
- return 1;
+ if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
+ if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
+ return 0;
}
+/*
+** Compare two ExprList objects. Return 0 if they are identical and
+** non-zero if they differ in any way.
+**
+** This routine might return non-zero for equivalent ExprLists. The
+** only consequence will be disabled optimizations. But this routine
+** must never return 0 if the two ExprList objects are different, or
+** a malfunction will result.
+**
+** Two NULL pointers are considered to be the same. But a NULL pointer
+** always differs from a non-NULL pointer.
+*/
+SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
+ int i;
+ if( pA==0 && pB==0 ) return 0;
+ if( pA==0 || pB==0 ) return 1;
+ if( pA->nExpr!=pB->nExpr ) return 1;
+ for(i=0; i<pA->nExpr; i++){
+ Expr *pExprA = pA->a[i].pExpr;
+ Expr *pExprB = pB->a[i].pExpr;
+ if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
+ if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
+ }
+ return 0;
+}
/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
@@ -64098,7 +70118,7 @@
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
+ if( sqlite3ExprCompare(pItem->pExpr, pExpr)==0 ){
break;
}
}
@@ -64466,17 +70486,23 @@
/*
** Register built-in functions used to help implement ALTER TABLE
*/
-SQLITE_PRIVATE void sqlite3AlterFunctions(sqlite3 *db){
- sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0,
- renameTableFunc, 0, 0);
+SQLITE_PRIVATE void sqlite3AlterFunctions(void){
+ static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
+ FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
- sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
- renameTriggerFunc, 0, 0);
+ FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0,
- renameParentFunc, 0, 0);
+ FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
+ };
+ int i;
+ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
+
+ for(i=0; i<ArraySize(aAlterTableFuncs); i++){
+ sqlite3FuncDefInsert(pHash, &aFunc[i]);
+ }
}
/*
@@ -64620,7 +70646,9 @@
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
-
+ int savedDbFlags; /* Saved value of db->flags */
+
+ savedDbFlags = db->flags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -64629,6 +70657,7 @@
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
+ db->flags |= SQLITE_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -64719,9 +70748,9 @@
** for which the renamed table is the parent table. */
if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
sqlite3NestedParse(pParse,
- "UPDATE sqlite_master SET "
+ "UPDATE \"%w\".%s SET "
"sql = sqlite_rename_parent(sql, %Q, %Q) "
- "WHERE %s;", zTabName, zName, zWhere);
+ "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
sqlite3DbFree(db, zWhere);
}
}
@@ -64796,6 +70825,7 @@
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
+ db->flags = savedDbFlags;
}
@@ -64915,9 +70945,11 @@
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
+ int savedDbFlags = db->flags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
+ db->flags |= SQLITE_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -64926,6 +70958,7 @@
zTab
);
sqlite3DbFree(db, zCol);
+ db->flags = savedDbFlags;
}
/* If the default value of the new column is NULL, then set the file
@@ -65071,7 +71104,7 @@
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
const char *zWhere /* Delete entries associated with this table */
){
- static struct {
+ static const struct {
const char *zName;
const char *zCols;
} aTable[] = {
@@ -65653,12 +71686,16 @@
n = 24;
}
pSample->nByte = (u8)n;
- pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
- if( pSample->u.z ){
- memcpy(pSample->u.z, z, n);
+ if( n < 1){
+ pSample->u.z = 0;
}else{
- db->mallocFailed = 1;
- break;
+ pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
+ if( pSample->u.z ){
+ memcpy(pSample->u.z, z, n);
+ }else{
+ db->mallocFailed = 1;
+ break;
+ }
}
}
}
@@ -65825,7 +71862,10 @@
}
pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
- sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
+ /* journal_mode set by the OP_JournalMode opcode that will following
+ ** the OP_Function opcode that invoked this function. */
+ sqlite3BtreeSecureDelete(aNew->pBt,
+ sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
@@ -65834,7 +71874,7 @@
}
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( rc==SQLITE_OK ){
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
@@ -65968,7 +72008,7 @@
static void codeAttach(
Parse *pParse, /* The parser context */
int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */
- FuncDef *pFunc, /* FuncDef wrapper for detachFunc() or attachFunc() */
+ FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */
Expr *pAuthArg, /* Expression to pass to authorization callback */
Expr *pFilename, /* Name of database file */
Expr *pDbname, /* Name of the database to use internally */
@@ -66019,6 +72059,17 @@
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
+ if( type==SQLITE_ATTACH ){
+ /* On an attach, also set the journal mode. Note that
+ ** sqlite3VdbeUsesBtree() is not call here since the iDb index
+ ** will be out of range prior to the new database being attached.
+ ** The OP_JournalMode opcode will all sqlite3VdbeUsesBtree() for us.
+ */
+ sqlite3VdbeAddOp3(v, OP_JournalMode, db->nDb, regArgs+3,
+ db->dfltJournalMode);
+ sqlite3VdbeChangeP5(v, 1);
+ }
+
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
@@ -66038,7 +72089,7 @@
** DETACH pDbname
*/
SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
- static FuncDef detach_func = {
+ static const FuncDef detach_func = {
1, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
@@ -66059,7 +72110,7 @@
** ATTACH p AS pDbname KEY pKey
*/
SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
- static FuncDef attach_func = {
+ static const FuncDef attach_func = {
3, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
@@ -66674,7 +72725,7 @@
pParse->isMultiWrite && pParse->mayAbort);
pParse->rc = SQLITE_DONE;
pParse->colNamesSet = 0;
- }else if( pParse->rc==SQLITE_OK ){
+ }else{
pParse->rc = SQLITE_ERROR;
}
pParse->nTab = 0;
@@ -69086,6 +75137,7 @@
if( j>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "table %s has no column named %s",
pTab->zName, zColName);
+ pParse->checkSchema = 1;
goto exit_create_index;
}
pIndex->aiColumn[i] = j;
@@ -69854,7 +75906,7 @@
if( zName ){
Vdbe *v = sqlite3GetVdbe(pParse);
#ifndef SQLITE_OMIT_AUTHORIZATION
- static const char *az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
+ static const char * const az[] = { "BEGIN", "RELEASE", "ROLLBACK" };
assert( !SAVEPOINT_BEGIN && SAVEPOINT_RELEASE==1 && SAVEPOINT_ROLLBACK==2 );
#endif
if( !v || sqlite3AuthCheck(pParse, SQLITE_SAVEPOINT, az[op], zName, 0) ){
@@ -69873,6 +75925,7 @@
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt==0 && !pParse->explain ){
int rc;
+ Btree *pBt;
static const int flags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
@@ -69880,17 +75933,20 @@
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TEMP_DB;
- rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags,
- &db->aDb[1].pBt);
+ rc = sqlite3BtreeFactory(db, 0, 0, SQLITE_DEFAULT_CACHE_SIZE, flags, &pBt);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
pParse->rc = rc;
return 1;
}
+ db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
- sqlite3PagerJournalMode(sqlite3BtreePager(db->aDb[1].pBt),
- db->dfltJournalMode);
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
+ db->mallocFailed = 1;
+ return 1;
+ }
+ sqlite3PagerSetJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
}
return 0;
}
@@ -70530,14 +76586,19 @@
/* If no match is found, search the built-in functions.
**
+ ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** functions even if a prior app-defined function was found. And give
+ ** priority to built-in functions.
+ **
** Except, if createFlag is true, that means that we are trying to
** install a new function. Whatever FuncDef structure is returned will
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
- if( !createFlag && !pBest ){
+ if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
+ bestScore = 0;
p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
@@ -71137,9 +77198,7 @@
sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld);
for(iCol=0; iCol<pTab->nCol; iCol++){
if( mask==0xffffffff || mask&(1<<iCol) ){
- int iTarget = iOld + iCol + 1;
- sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget);
- sqlite3ColumnDefault(v, pTab, iCol, iTarget);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1);
}
}
@@ -71535,14 +77594,24 @@
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
r = sqlite3_value_double(argv[0]);
- zBuf = sqlite3_mprintf("%.*f",n,r);
- if( zBuf==0 ){
- sqlite3_result_error_nomem(context);
+ /* If Y==0 and X will fit in a 64-bit int,
+ ** handle the rounding directly,
+ ** otherwise use printf.
+ */
+ if( n==0 && r>=0 && r<LARGEST_INT64-1 ){
+ r = (double)((sqlite_int64)(r+0.5));
+ }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){
+ r = -(double)((sqlite_int64)((-r)+0.5));
}else{
+ zBuf = sqlite3_mprintf("%.*f",n,r);
+ if( zBuf==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
sqlite3AtoF(zBuf, &r);
sqlite3_free(zBuf);
- sqlite3_result_double(context, r);
}
+ sqlite3_result_double(context, r);
}
#endif
@@ -71704,12 +77773,18 @@
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ /* IMP: R-51513-12026 The last_insert_rowid() SQL function is a
+ ** wrapper around the sqlite3_last_insert_rowid() C/C++ interface
+ ** function. */
sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
}
/*
-** Implementation of the changes() SQL function. The return value is the
-** same as the sqlite3_changes() API function.
+** Implementation of the changes() SQL function.
+**
+** IMP: R-62073-11209 The changes() SQL function is a wrapper
+** around the sqlite3_changes() C/C++ function and hence follows the same
+** rules for counting changes.
*/
static void changes(
sqlite3_context *context,
@@ -71732,6 +77807,8 @@
){
sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ /* IMP: R-52756-41993 This function is a wrapper around the
+ ** sqlite3_total_changes() C/C++ interface. */
sqlite3_result_int(context, sqlite3_total_changes(db));
}
@@ -71999,7 +78076,9 @@
sqlite3_value **NotUsed2
){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
+ /* IMP: R-48699-48617 This function is an SQL wrapper around the
+ ** sqlite3_libversion() C-interface. */
+ sqlite3_result_text(context, sqlite3_libversion(), -1, SQLITE_STATIC);
}
/*
@@ -72013,9 +78092,54 @@
sqlite3_value **NotUsed2
){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- sqlite3_result_text(context, SQLITE_SOURCE_ID, -1, SQLITE_STATIC);
+ /* IMP: R-24470-31136 This function is an SQL wrapper around the
+ ** sqlite3_sourceid() C interface. */
+ sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
}
+/*
+** Implementation of the sqlite_compileoption_used() function.
+** The result is an integer that identifies if the compiler option
+** was used to build SQLite.
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+static void compileoptionusedFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zOptName;
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ /* IMP: R-xxxx This function is an SQL wrapper around the
+ ** sqlite3_compileoption_used() C interface. */
+ if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){
+ sqlite3_result_int(context, sqlite3_compileoption_used(zOptName));
+ }
+}
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+/*
+** Implementation of the sqlite_compileoption_get() function.
+** The result is a string that identifies the compiler options
+** used to build SQLite.
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+static void compileoptiongetFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int n;
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ /* IMP: R-xxxx This function is an SQL wrapper around the
+ ** sqlite3_compileoption_get() C interface. */
+ n = sqlite3_value_int(argv[0]);
+ sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC);
+}
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
/* Array for converting from half-bytes (nybbles) into ASCII hex
** digits. */
static const char hexdigits[] = {
@@ -72142,7 +78266,7 @@
if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
}else{
- sqlite3_result_zeroblob(context, (int)n);
+ sqlite3_result_zeroblob(context, (int)n); /* IMP: R-00293-64994 */
}
}
@@ -72610,20 +78734,15 @@
}
/*
-** This function registered all of the above C functions as SQL
-** functions. This should be the only routine in this file with
-** external linkage.
+** This routine does per-connection function registration. Most
+** of the built-in functions above are part of the global function set.
+** This routine only deals with those that are not global.
*/
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
-#ifndef SQLITE_OMIT_ALTERTABLE
- sqlite3AlterFunctions(db);
-#endif
- if( !db->mallocFailed ){
- int rc = sqlite3_overload_function(db, "MATCH", 2);
- assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
- if( rc==SQLITE_NOMEM ){
- db->mallocFailed = 1;
- }
+ int rc = sqlite3_overload_function(db, "MATCH", 2);
+ assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
+ if( rc==SQLITE_NOMEM ){
+ db->mallocFailed = 1;
}
}
@@ -72747,6 +78866,10 @@
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
+ FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
FUNCTION(changes, 0, 0, 0, changes ),
@@ -72787,6 +78910,9 @@
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
+#ifndef SQLITE_OMIT_ALTERTABLE
+ sqlite3AlterFunctions();
+#endif
}
/************** End of func.c ************************************************/
@@ -74712,7 +80838,7 @@
}else{
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
pTabList, 0, pColumn->a[i].zName);
- pParse->nErr++;
+ pParse->checkSchema = 1;
goto insert_cleanup;
}
}
@@ -74831,7 +80957,7 @@
if( pColumn->a[j].idx==i ) break;
}
}
- if( pColumn && j>=pColumn->nId ){
+ if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
}else if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
@@ -75246,19 +81372,33 @@
** the triggers and remove both the table and index b-tree entries.
**
** Otherwise, if there are no triggers or the recursive-triggers
- ** flag is not set, call GenerateRowIndexDelete(). This removes
- ** the index b-tree entries only. The table b-tree entry will be
- ** replaced by the new entry when it is inserted. */
+ ** flag is not set, but the table has one or more indexes, call
+ ** GenerateRowIndexDelete(). This removes the index b-tree entries
+ ** only. The table b-tree entry will be replaced by the new entry
+ ** when it is inserted.
+ **
+ ** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
+ ** also invoke MultiWrite() to indicate that this VDBE may require
+ ** statement rollback (if the statement is aborted after the delete
+ ** takes place). Earlier versions called sqlite3MultiWrite() regardless,
+ ** but being more selective here allows statements like:
+ **
+ ** REPLACE INTO t(rowid) VALUES($newrowid)
+ **
+ ** to run without a statement journal if there are no indexes on the
+ ** table.
+ */
Trigger *pTrigger = 0;
if( pParse->db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
- sqlite3MultiWrite(pParse);
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
+ sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(
pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace
);
- }else{
+ }else if( pTab->pIndex ){
+ sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
}
seenReplace = 1;
@@ -75700,7 +81840,7 @@
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
+ if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
@@ -75843,6 +81983,7 @@
int nRetry = 0; /* Number of retry attempts */
int callbackIsInit; /* True if callback data is initialized */
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
if( zSql==0 ) zSql = "";
sqlite3_mutex_enter(db->mutex);
@@ -77112,6 +83253,9 @@
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+ { "automatic_index", SQLITE_AutoIndex },
+#endif
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
@@ -77193,6 +83337,31 @@
}
#endif
+
+/*
+** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
+** defined in pager.h. This function returns the associated lowercase
+** journal-mode name.
+*/
+SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
+ static char * const azModeName[] = {
+ "delete", "persist", "off", "truncate", "memory"
+#ifndef SQLITE_OMIT_WAL
+ , "wal"
+#endif
+ };
+ assert( PAGER_JOURNALMODE_DELETE==0 );
+ assert( PAGER_JOURNALMODE_PERSIST==1 );
+ assert( PAGER_JOURNALMODE_OFF==2 );
+ assert( PAGER_JOURNALMODE_TRUNCATE==3 );
+ assert( PAGER_JOURNALMODE_MEMORY==4 );
+ assert( PAGER_JOURNALMODE_WAL==5 );
+ assert( eMode>=0 && eMode<=ArraySize(azModeName) );
+
+ if( eMode==ArraySize(azModeName) ) return 0;
+ return azModeName[eMode];
+}
+
/*
** Process a pragma statement.
**
@@ -77265,11 +83434,11 @@
** page cache size value and the persistent page cache size value
** stored in the database file.
**
- ** The default cache size is stored in meta-value 2 of page 1 of the
- ** database file. The cache size is actually the absolute value of
- ** this memory location. The sign of meta-value 2 determines the
- ** synchronous setting. A negative value means synchronous is off
- ** and a positive value means synchronous is on.
+ ** Older versions of SQLite would set the default cache size to a
+ ** negative number to indicate synchronous=OFF. These days, synchronous
+ ** is always on by default regardless of the sign of the default cache
+ ** size. But continue to take the absolute value of the default cache
+ ** size of historical compatibility.
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
@@ -77298,10 +83467,6 @@
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
- sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
- addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
- sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
- sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -77357,6 +83522,31 @@
}else
/*
+ ** PRAGMA [database.]secure_delete
+ ** PRAGMA [database.]secure_delete=ON/OFF
+ **
+ ** The first form reports the current setting for the
+ ** secure_delete flag. The second form changes the secure_delete
+ ** flag setting and reports thenew value.
+ */
+ if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
+ Btree *pBt = pDb->pBt;
+ int b = -1;
+ assert( pBt!=0 );
+ if( zRight ){
+ b = getBoolean(zRight);
+ }
+ if( pId2->n==0 && b>=0 ){
+ int ii;
+ for(ii=0; ii<db->nDb; ii++){
+ sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
+ }
+ }
+ b = sqlite3BtreeSecureDelete(pBt, b);
+ returnSingleInt(pParse, "secure_delete", b);
+ }else
+
+ /*
** PRAGMA [database.]page_count
**
** Return the number of pages in the specified database.
@@ -77421,21 +83611,29 @@
/*
** PRAGMA [database.]journal_mode
- ** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
+ ** PRAGMA [database.]journal_mode =
+ ** (delete|persist|off|truncate|memory|wal|off)
*/
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
- int eMode;
- static char * const azModeName[] = {
- "delete", "persist", "off", "truncate", "memory"
- };
+ int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
+
+ if( sqlite3ReadSchema(pParse) ){
+ goto pragma_out;
+ }
+
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
if( zRight==0 ){
eMode = PAGER_JOURNALMODE_QUERY;
}else{
+ const char *zMode;
int n = sqlite3Strlen30(zRight);
- eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
- while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
- eMode--;
+ for(eMode=0; (zMode = sqlite3JournalModename(eMode))!=0; eMode++){
+ if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
+ }
+ if( !zMode ){
+ eMode = PAGER_JOURNALMODE_QUERY;
}
}
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
@@ -77444,39 +83642,31 @@
** the journal-mode of the main database).
*/
eMode = db->dfltJournalMode;
+ sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
+ sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
}else{
- Pager *pPager;
+ int ii;
+
if( pId2->n==0 ){
- /* This indicates that no database name was specified as part
- ** of the PRAGMA command. In this case the journal-mode must be
- ** set on all attached databases, as well as the main db file.
+ /* When there is no database name before the "journal_mode" keyword
+ ** in the PRAGMA, then the journal-mode will be set on
+ ** all attached databases, as well as the main db file.
**
** Also, the sqlite3.dfltJournalMode variable is set so that
** any subsequently attached databases also use the specified
** journal mode.
*/
- int ii;
- assert(pDb==&db->aDb[0]);
- for(ii=1; ii<db->nDb; ii++){
- if( db->aDb[ii].pBt ){
- pPager = sqlite3BtreePager(db->aDb[ii].pBt);
- sqlite3PagerJournalMode(pPager, eMode);
- }
- }
db->dfltJournalMode = (u8)eMode;
}
- pPager = sqlite3BtreePager(pDb->pBt);
- eMode = sqlite3PagerJournalMode(pPager, eMode);
+
+ for(ii=db->nDb-1; ii>=0; ii--){
+ if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
+ sqlite3VdbeUsesBtree(v, ii);
+ sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
+ }
+ }
}
- assert( eMode==PAGER_JOURNALMODE_DELETE
- || eMode==PAGER_JOURNALMODE_TRUNCATE
- || eMode==PAGER_JOURNALMODE_PERSIST
- || eMode==PAGER_JOURNALMODE_OFF
- || eMode==PAGER_JOURNALMODE_MEMORY );
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
- sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
- azModeName[eMode], P4_STATIC);
+
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else
@@ -78274,6 +84464,56 @@
}else
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ /*
+ ** PRAGMA compile_options
+ **
+ ** Return the names of all compile-time options used in this build,
+ ** one option per row.
+ */
+ if( sqlite3StrICmp(zLeft, "compile_options")==0 ){
+ int i = 0;
+ const char *zOpt;
+ sqlite3VdbeSetNumCols(v, 1);
+ pParse->nMem = 1;
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "compile_option", SQLITE_STATIC);
+ while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+ }
+ }else
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+#ifndef SQLITE_OMIT_WAL
+ /*
+ ** PRAGMA [database.]wal_checkpoint
+ **
+ ** Checkpoint the database.
+ */
+ if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){
+ if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+ sqlite3VdbeAddOp3(v, OP_Checkpoint, pId2->z?iDb:SQLITE_MAX_ATTACHED, 0, 0);
+ }else
+
+ /*
+ ** PRAGMA wal_autocheckpoint
+ ** PRAGMA wal_autocheckpoint = N
+ **
+ ** Configure a database connection to automatically checkpoint a database
+ ** after accumulating N frames in the log. Or query for the current value
+ ** of N.
+ */
+ if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
+ if( zRight ){
+ int nAuto = atoi(zRight);
+ sqlite3_wal_autocheckpoint(db, nAuto);
+ }
+ returnSingleInt(pParse, "wal_autocheckpoint",
+ db->xWalCallback==sqlite3WalDefaultHook ?
+ SQLITE_PTR_TO_INT(db->pWalArg) : 0);
+ }else
+#endif
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
@@ -78308,7 +84548,7 @@
}else
#endif
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( sqlite3StrICmp(zLeft, "key")==0 && zRight ){
sqlite3_key(db, zRight, sqlite3Strlen30(zRight));
}else
@@ -78331,17 +84571,15 @@
}
}else
#endif
-#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
+#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
-#if SQLITE_HAS_CODEC
+#ifdef SQLITE_HAS_CODEC
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
- extern void sqlite3_activate_see(const char*);
sqlite3_activate_see(&zRight[4]);
}
#endif
#ifdef SQLITE_ENABLE_CEROD
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
- extern void sqlite3_activate_cerod(const char*);
sqlite3_activate_cerod(&zRight[6]);
}
#endif
@@ -78444,15 +84682,18 @@
** or executed. All the parser does is build the internal data
** structures that describe the table, index, or view.
*/
- char *zErr;
int rc;
+ sqlite3_stmt *pStmt;
+ TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
+
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
db->init.orphanTrigger = 0;
- rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+ TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
+ rc = db->errCode;
+ assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = 0;
- assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -78460,12 +84701,12 @@
pData->rc = rc;
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
- }else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
- corruptSchema(pData, argv[0], zErr);
+ }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
+ corruptSchema(pData, argv[0], sqlite3_errmsg(db));
}
}
- sqlite3DbFree(db, zErr);
}
+ sqlite3_finalize(pStmt);
}else if( argv[0]==0 ){
corruptSchema(pData, 0, 0);
}else{
@@ -78684,7 +84925,7 @@
{
char *zSql;
zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM '%q'.%s",
+ "SELECT name, rootpage, sql FROM '%q'.%s ORDER BY rowid",
db->aDb[iDb].zName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
@@ -78950,6 +85191,7 @@
sqlite3VtabUnlockList(db);
pParse->db = db;
+ pParse->nQueryLoop = (double)1;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@@ -78971,6 +85213,7 @@
}else{
sqlite3RunParser(pParse, zSql, &zErrMsg);
}
+ assert( 1==(int)pParse->nQueryLoop );
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
@@ -79171,7 +85414,7 @@
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
- zSql8 = sqlite3Utf16to8(db, zSql, nBytes);
+ zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
if( zSql8 ){
rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
}
@@ -81755,8 +87998,8 @@
** (14) The subquery does not use OFFSET
**
** (15) The outer query is not part of a compound select or the
-** subquery does not have both an ORDER BY and a LIMIT clause.
-** (See ticket #2339)
+** subquery does not have a LIMIT clause.
+** (See ticket #2339 and ticket [02a8e81d44]).
**
** (16) The outer query is not an aggregate or the subquery does
** not contain ORDER BY. (Ticket #2942) This used to not matter
@@ -81839,7 +88082,7 @@
** and (14). */
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
if( pSub->pOffset ) return 0; /* Restriction (14) */
- if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){
+ if( p->pRightmost && pSub->pLimit ){
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
@@ -82249,6 +88492,7 @@
);
if( !pIdx ){
sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0);
+ pParse->checkSchema = 1;
return SQLITE_ERROR;
}
pFrom->pIndex = pIdx;
@@ -82556,18 +88800,19 @@
struct SrcList_item *pFrom;
assert( p->selFlags & SF_Resolved );
- assert( (p->selFlags & SF_HasTypeInfo)==0 );
- p->selFlags |= SF_HasTypeInfo;
- pParse = pWalker->pParse;
- pTabList = p->pSrc;
- for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
- Table *pTab = pFrom->pTab;
- if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
- /* A sub-query in the FROM clause of a SELECT */
- Select *pSel = pFrom->pSelect;
- assert( pSel );
- while( pSel->pPrior ) pSel = pSel->pPrior;
- selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
+ if( (p->selFlags & SF_HasTypeInfo)==0 ){
+ p->selFlags |= SF_HasTypeInfo;
+ pParse = pWalker->pParse;
+ pTabList = p->pSrc;
+ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ Table *pTab = pFrom->pTab;
+ if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ /* A sub-query in the FROM clause of a SELECT */
+ Select *pSel = pFrom->pSelect;
+ assert( pSel );
+ while( pSel->pPrior ) pSel = pSel->pPrior;
+ selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSel);
+ }
}
}
return WRC_Continue;
@@ -82726,6 +88971,18 @@
sqlite3ExprCacheClear(pParse);
}
}
+
+ /* Before populating the accumulator registers, clear the column cache.
+ ** Otherwise, if any of the required column values are already present
+ ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
+ ** to pC->iMem. But by the time the value is used, the original register
+ ** may have been used, invalidating the underlying buffer holding the
+ ** text or blob value. See ticket [883034dcb5].
+ **
+ ** Another solution would be to change the OP_SCopy used to copy cached
+ ** values to an OP_Copy.
+ */
+ sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
@@ -82934,6 +89191,18 @@
isDistinct = 0;
}
+ /* If there is both a GROUP BY and an ORDER BY clause and they are
+ ** identical, then disable the ORDER BY clause since the GROUP BY
+ ** will cause elements to come out in the correct order. This is
+ ** an optimization - the correct answer should result regardless.
+ ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
+ ** to disable this optimization for testing purposes.
+ */
+ if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
+ && (db->flags & SQLITE_GroupByOrder)==0 ){
+ pOrderBy = 0;
+ }
+
/* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
@@ -83839,7 +90108,8 @@
goto trigger_cleanup;
}
pTab = sqlite3SrcListLookup(pParse, pTableName);
- if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){
+ if( db->init.busy==0 && pName2->n==0 && pTab
+ && pTab->pSchema==db->aDb[1].pSchema ){
iDb = 1;
}
@@ -83967,12 +90237,12 @@
TriggerStep *pStepList, /* The triggered program */
Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
- Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
- char *zName; /* Name of trigger */
- sqlite3 *db = pParse->db; /* The database */
- DbFixer sFix;
- int iDb; /* Database containing the trigger */
- Token nameToken; /* Trigger name for error reporting */
+ Trigger *pTrig = pParse->pNewTrigger; /* Trigger being finished */
+ char *zName; /* Name of trigger */
+ sqlite3 *db = pParse->db; /* The database */
+ DbFixer sFix; /* Fixer object */
+ int iDb; /* Database containing the trigger */
+ Token nameToken; /* Trigger name for error reporting */
pTrig = pParse->pNewTrigger;
pParse->pNewTrigger = 0;
@@ -83991,7 +90261,7 @@
goto triggerfinish_cleanup;
}
- /* if we are not initializing, and this trigger is not on a TEMP table,
+ /* if we are not initializing,
** build the sqlite_master entry
*/
if( !db->init.busy ){
@@ -84208,6 +90478,7 @@
if( !noErr ){
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
}
+ pParse->checkSchema = 1;
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger);
@@ -84538,6 +90809,7 @@
pSubParse->pToplevel = pTop;
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
+ pSubParse->nQueryLoop = pParse->nQueryLoop;
v = sqlite3GetVdbe(pSubParse);
if( v ){
@@ -84814,7 +91086,7 @@
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
-*************************************************************************
+sqlite*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
*/
@@ -85017,6 +91289,7 @@
pRowidExpr = pChanges->a[i].pExpr;
}else{
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
+ pParse->checkSchema = 1;
goto update_cleanup;
}
}
@@ -85201,8 +91474,7 @@
);
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
- sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i);
- sqlite3ColumnDefault(v, pTab, i, regOld+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
}
@@ -85575,7 +91847,8 @@
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
- int nRes;
+ int nRes; /* Bytes of reserved space at the end of each page */
+ int nDb; /* Number of attached databases */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -85589,8 +91862,8 @@
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_xTrace = db->xTrace;
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
- db->flags &= ~SQLITE_ForeignKeys;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
db->xTrace = 0;
pMain = db->aDb[0].pBt;
@@ -85610,15 +91883,18 @@
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
+ nDb = db->nDb;
if( sqlite3TempInMemory(db) ){
zSql = "ATTACH ':memory:' AS vacuum_db;";
}else{
zSql = "ATTACH '' AS vacuum_db;";
}
rc = execSql(db, pzErrMsg, zSql);
+ if( db->nDb>nDb ){
+ pDb = &db->aDb[db->nDb-1];
+ assert( strcmp(pDb->zName,"vacuum_db")==0 );
+ }
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- pDb = &db->aDb[db->nDb-1];
- assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
/* The call to execSql() to attach the temp database has left the file
@@ -85640,6 +91916,12 @@
}
#endif
+ /* Do not attempt to change the page size for a WAL database */
+ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
+ ==PAGER_JOURNALMODE_WAL ){
+ db->nextPagesize = 0;
+ }
+
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
@@ -85776,6 +92058,7 @@
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
db->xTrace = saved_xTrace;
+ sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
@@ -86458,6 +92741,7 @@
}else{
pParse->declareVtab = 1;
pParse->db = db;
+ pParse->nQueryLoop = 1;
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
&& pParse->pNewTable
@@ -86978,6 +93262,7 @@
#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
+#define WHERE_NOT_FULLSCAN 0x000f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
@@ -86987,6 +93272,7 @@
#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
+#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
/*
** Initialize a preallocated WhereClause structure.
@@ -87396,7 +93682,7 @@
}
assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
pColl = sqlite3ExprCollSeq(pParse, pLeft);
- assert( pColl!=0 ); /* Every non-IPK column has a collating sequence */
+ if( pColl==0 ) return 0; /* Happens when LHS has an undefined collation */
if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
/* IMP: R-09003-32046 For the GLOB operator, the column must use the
@@ -87839,7 +94125,7 @@
Expr *pExpr; /* The expression to be analyzed */
Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
Bitmask prereqAll; /* Prerequesites of pExpr */
- Bitmask extraRight = 0; /* */
+ Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
int noCase = 0; /* LIKE/GLOB distinguishes case */
@@ -87911,7 +94197,8 @@
pLeft = pDup->pLeft;
pNew->leftCursor = pLeft->iTable;
pNew->u.leftColumn = pLeft->iColumn;
- pNew->prereqRight = prereqLeft;
+ testcase( (prereqLeft | extraRight) != prereqLeft );
+ pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
pNew->eOperator = operatorMask(pDup->op);
}
@@ -88315,6 +94602,11 @@
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
WhereTerm *pTerm; /* A single term of the WHERE clause */
+ /* No OR-clause optimization allowed if the NOT INDEXED clause is used */
+ if( pSrc->notIndexed ){
+ return;
+ }
+
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR
@@ -88357,8 +94649,9 @@
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
if( pOrderBy!=0 ){
+ WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
+ rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow);
- WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal));
}
/* If the cost of scanning using this OR term for optimization is
@@ -88377,6 +94670,247 @@
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
}
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Return TRUE if the WHERE clause term pTerm is of a form where it
+** could be used with an index to access pSrc, assuming an appropriate
+** index existed.
+*/
+static int termCanDriveIndex(
+ WhereTerm *pTerm, /* WHERE clause term to check */
+ struct SrcList_item *pSrc, /* Table we are trying to access */
+ Bitmask notReady /* Tables in outer loops of the join */
+){
+ char aff;
+ if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
+ if( pTerm->eOperator!=WO_EQ ) return 0;
+ if( (pTerm->prereqRight & notReady)!=0 ) return 0;
+ aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
+ if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
+ return 1;
+}
+#endif
+
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** If the query plan for pSrc specified in pCost is a full table scan
+** and indexing is allows (if there is no NOT INDEXED clause) and it
+** possible to construct a transient index that would perform better
+** than a full table scan even when the cost of constructing the index
+** is taken into account, then alter the query plan to use the
+** transient index.
+*/
+static void bestAutomaticIndex(
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause */
+ struct SrcList_item *pSrc, /* The FROM clause term to search */
+ Bitmask notReady, /* Mask of cursors that are not available */
+ WhereCost *pCost /* Lowest cost query plan */
+){
+ double nTableRow; /* Rows in the input table */
+ double logN; /* log(nTableRow) */
+ double costTempIdx; /* per-query cost of the transient index */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pWCEnd; /* End of pWC->a[] */
+ Table *pTable; /* Table tht might be indexed */
+
+ if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
+ /* Automatic indices are disabled at run-time */
+ return;
+ }
+ if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
+ /* We already have some kind of index in use for this query. */
+ return;
+ }
+ if( pSrc->notIndexed ){
+ /* The NOT INDEXED clause appears in the SQL. */
+ return;
+ }
+
+ assert( pParse->nQueryLoop >= (double)1 );
+ pTable = pSrc->pTab;
+ nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
+ logN = estLog(nTableRow);
+ costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
+ if( costTempIdx>=pCost->rCost ){
+ /* The cost of creating the transient table would be greater than
+ ** doing the full table scan */
+ return;
+ }
+
+ /* Search for any equality comparison term */
+ pWCEnd = &pWC->a[pWC->nTerm];
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
+ pCost->rCost, costTempIdx));
+ pCost->rCost = costTempIdx;
+ pCost->nRow = logN + 1;
+ pCost->plan.wsFlags = WHERE_TEMP_INDEX;
+ pCost->used = pTerm->prereqRight;
+ break;
+ }
+ }
+}
+#else
+# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
+
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+/*
+** Generate code to construct the Index object for an automatic index
+** and to set up the WhereLevel object pLevel so that the code generator
+** makes use of the automatic index.
+*/
+static void constructAutomaticIndex(
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause */
+ struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
+ Bitmask notReady, /* Mask of cursors that are not available */
+ WhereLevel *pLevel /* Write new index here */
+){
+ int nColumn; /* Number of columns in the constructed index */
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
+ WhereTerm *pWCEnd; /* End of pWC->a[] */
+ int nByte; /* Byte of memory needed for pIdx */
+ Index *pIdx; /* Object describing the transient index */
+ Vdbe *v; /* Prepared statement under construction */
+ int regIsInit; /* Register set by initialization */
+ int addrInit; /* Address of the initialization bypass jump */
+ Table *pTable; /* The table being indexed */
+ KeyInfo *pKeyinfo; /* Key information for the index */
+ int addrTop; /* Top of the index fill loop */
+ int regRecord; /* Register holding an index record */
+ int n; /* Column counter */
+ int i; /* Loop counter */
+ int mxBitCol; /* Maximum column in pSrc->colUsed */
+ CollSeq *pColl; /* Collating sequence to on a column */
+ Bitmask idxCols; /* Bitmap of columns used for indexing */
+ Bitmask extraCols; /* Bitmap of additional columns */
+
+ /* Generate code to skip over the creation and initialization of the
+ ** transient index on 2nd and subsequent iterations of the loop. */
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ regIsInit = ++pParse->nMem;
+ addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
+
+ /* Count the number of columns that will be added to the index
+ ** and used to match WHERE clause constraints */
+ nColumn = 0;
+ pTable = pSrc->pTab;
+ pWCEnd = &pWC->a[pWC->nTerm];
+ idxCols = 0;
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ int iCol = pTerm->u.leftColumn;
+ Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
+ if( (idxCols & cMask)==0 ){
+ nColumn++;
+ idxCols |= cMask;
+ }
+ }
+ }
+ assert( nColumn>0 );
+ pLevel->plan.nEq = nColumn;
+
+ /* Count the number of additional columns needed to create a
+ ** covering index. A "covering index" is an index that contains all
+ ** columns that are needed by the query. With a covering index, the
+ ** original table never needs to be accessed. Automatic indices must
+ ** be a covering index because the index will not be updated if the
+ ** original table changes and the index and table cannot both be used
+ ** if they go out of sync.
+ */
+ extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1)));
+ mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
+ testcase( pTable->nCol==BMS-1 );
+ testcase( pTable->nCol==BMS-2 );
+ for(i=0; i<mxBitCol; i++){
+ if( extraCols & (((Bitmask)1)<<i) ) nColumn++;
+ }
+ if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
+ nColumn += pTable->nCol - BMS + 1;
+ }
+ pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ;
+
+ /* Construct the Index object to describe this index */
+ nByte = sizeof(Index);
+ nByte += nColumn*sizeof(int); /* Index.aiColumn */
+ nByte += nColumn*sizeof(char*); /* Index.azColl */
+ nByte += nColumn; /* Index.aSortOrder */
+ pIdx = sqlite3DbMallocZero(pParse->db, nByte);
+ if( pIdx==0 ) return;
+ pLevel->plan.u.pIdx = pIdx;
+ pIdx->azColl = (char**)&pIdx[1];
+ pIdx->aiColumn = (int*)&pIdx->azColl[nColumn];
+ pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn];
+ pIdx->zName = "auto-index";
+ pIdx->nColumn = nColumn;
+ pIdx->pTable = pTable;
+ n = 0;
+ idxCols = 0;
+ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
+ if( termCanDriveIndex(pTerm, pSrc, notReady) ){
+ int iCol = pTerm->u.leftColumn;
+ Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
+ if( (idxCols & cMask)==0 ){
+ Expr *pX = pTerm->pExpr;
+ idxCols |= cMask;
+ pIdx->aiColumn[n] = pTerm->u.leftColumn;
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
+ pIdx->azColl[n] = pColl->zName;
+ n++;
+ }
+ }
+ }
+ assert( (u32)n==pLevel->plan.nEq );
+
+ /* Add additional columns needed to make the automatic index into
+ ** a covering index */
+ for(i=0; i<mxBitCol; i++){
+ if( extraCols & (((Bitmask)1)<<i) ){
+ pIdx->aiColumn[n] = i;
+ pIdx->azColl[n] = "BINARY";
+ n++;
+ }
+ }
+ if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
+ for(i=BMS-1; i<pTable->nCol; i++){
+ pIdx->aiColumn[n] = i;
+ pIdx->azColl[n] = "BINARY";
+ n++;
+ }
+ }
+ assert( n==nColumn );
+
+ /* Create the automatic index */
+ pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx);
+ assert( pLevel->iIdxCur>=0 );
+ sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
+ (char*)pKeyinfo, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "for %s", pTable->zName));
+
+ /* Fill the automatic index with content */
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
+ regRecord = sqlite3GetTempReg(pParse);
+ sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
+ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
+ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
+ sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
+ sqlite3VdbeJumpHere(v, addrTop);
+ sqlite3ReleaseTempReg(pParse, regRecord);
+
+ /* Jump here when skipping the initialization */
+ sqlite3VdbeJumpHere(v, addrInit);
+}
+#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allocate and populate an sqlite3_index_info structure. It is the
@@ -88561,6 +95095,7 @@
WhereTerm *pTerm;
int i, j;
int nOrderBy;
+ double rCost;
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -88647,6 +95182,15 @@
}
}
+ /* If there is an ORDER BY clause, and the selected virtual table index
+ ** does not satisfy it, increase the cost of the scan accordingly. This
+ ** matches the processing for non-virtual tables in bestBtreeIndex().
+ */
+ rCost = pIdxInfo->estimatedCost;
+ if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
+ rCost += estLog(rCost)*rCost;
+ }
+
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
** inital value of lowestCost in this loop. If it is, then the
** (cost<lowestCost) test below will never be true.
@@ -88654,10 +95198,10 @@
** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT
** is defined.
*/
- if( (SQLITE_BIG_DBL/((double)2))<pIdxInfo->estimatedCost ){
+ if( (SQLITE_BIG_DBL/((double)2))<rCost ){
pCost->rCost = (SQLITE_BIG_DBL/((double)2));
}else{
- pCost->rCost = pIdxInfo->estimatedCost;
+ pCost->rCost = rCost;
}
pCost->plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
@@ -89058,14 +95602,14 @@
** Set to true if there was at least one "x IN (SELECT ...)" term used
** in determining the value of nInMul.
**
- ** nBound:
+ ** estBound:
** An estimate on the amount of the table that must be searched. A
** value of 100 means the entire table is searched. Range constraints
** might reduce this to a value less than 100 to indicate that only
** a fraction of the table needs searching. In the absence of
** sqlite_stat2 ANALYZE data, a single inequality reduces the search
** space to 1/3rd its original size. So an x>? constraint reduces
- ** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11.
+ ** estBound to 33. Two constraints (x>? AND x<?) reduce estBound to 11.
**
** bSort:
** Boolean. True if there is an ORDER BY clause that will require an
@@ -89087,13 +95631,14 @@
int nEq;
int bInEst = 0;
int nInMul = 1;
- int nBound = 100;
+ int estBound = 100;
+ int nBound = 0; /* Number of range constraints seen */
int bSort = 0;
int bLookup = 0;
+ WhereTerm *pTerm; /* A single term of the WHERE clause */
/* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; nEq++){
- WhereTerm *pTerm; /* A single term of the WHERE clause */
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
@@ -89113,18 +95658,20 @@
used |= pTerm->prereqRight;
}
- /* Determine the value of nBound. */
+ /* Determine the value of estBound. */
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
- whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
+ whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound);
if( pTop ){
+ nBound = 1;
wsFlags |= WHERE_TOP_LIMIT;
used |= pTop->prereqRight;
}
if( pBtm ){
+ nBound++;
wsFlags |= WHERE_BTM_LIMIT;
used |= pBtm->prereqRight;
}
@@ -89155,7 +95702,7 @@
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
- ** seeking to entries in the main table (i.e. if the index is a covering
+ ** using the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
** wsFlags. Otherwise, set the bLookup variable to true. */
if( pIdx && wsFlags ){
@@ -89174,8 +95721,7 @@
}
}
- /**** Begin adding up the cost of using this index (Needs improvements)
- **
+ /*
** Estimate the number of rows of output. For an IN operator,
** do not let the estimate exceed half the rows in the table.
*/
@@ -89194,8 +95740,8 @@
/* Adjust the number of rows and the cost downward to reflect rows
** that are excluded by range constraints.
*/
- nRow = (nRow * (double)nBound) / (double)100;
- cost = (cost * (double)nBound) / (double)100;
+ nRow = (nRow * (double)estBound) / (double)100;
+ cost = (cost * (double)estBound) / (double)100;
/* Add in the estimated cost of sorting the result
*/
@@ -89212,17 +95758,75 @@
}
/**** Cost of using this index has now been computed ****/
+ /* If there are additional constraints on this table that cannot
+ ** be used with the current index, but which might lower the number
+ ** of output rows, adjust the nRow value accordingly. This only
+ ** matters if the current index is the least costly, so do not bother
+ ** with this step if we already know this index will not be chosen.
+ ** Also, never reduce the output row count below 2 using this step.
+ **
+ ** Do not reduce the output row count if pSrc is the only table that
+ ** is notReady; if notReady is a power of two. This will be the case
+ ** when the main sqlite3WhereBegin() loop is scanning for a table with
+ ** and "optimal" index, and on such a scan the output row count
+ ** reduction is not valid because it does not update the "pCost->used"
+ ** bitmap. The notReady bitmap will also be a power of two when we
+ ** are scanning for the last table in a 64-way join. We are willing
+ ** to bypass this optimization in that corner case.
+ */
+ if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
+ int k; /* Loop counter */
+ int nSkipEq = nEq; /* Number of == constraints to skip */
+ int nSkipRange = nBound; /* Number of < constraints to skip */
+ Bitmask thisTab; /* Bitmap for pSrc */
+
+ thisTab = getMask(pWC->pMaskSet, iCur);
+ for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
+ if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
+ if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
+ if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
+ if( nSkipEq ){
+ /* Ignore the first nEq equality matches since the index
+ ** has already accounted for these */
+ nSkipEq--;
+ }else{
+ /* Assume each additional equality match reduces the result
+ ** set size by a factor of 10 */
+ nRow /= 10;
+ }
+ }else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
+ if( nSkipRange ){
+ /* Ignore the first nBound range constraints since the index
+ ** has already accounted for these */
+ nSkipRange--;
+ }else{
+ /* Assume each additional range constraint reduces the result
+ ** set size by a factor of 3 */
+ nRow /= 3;
+ }
+ }else{
+ /* Any other expression lowers the output row count by half */
+ nRow /= 2;
+ }
+ }
+ if( nRow<2 ) nRow = 2;
+ }
+
+
WHERETRACE((
- "tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
- " wsFlags=%d (nRow=%.2f cost=%.2f)\n",
+ "%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
+ " notReady=0x%llx nRow=%.2f cost=%.2f used=0x%llx\n",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
- nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
+ nEq, nInMul, estBound, bSort, bLookup, wsFlags,
+ notReady, nRow, cost, used
));
/* If this index is the best we have seen so far, then record this
** index and its cost in the pCost structure.
*/
- if( (!pIdx || wsFlags) && cost<pCost->rCost ){
+ if( (!pIdx || wsFlags)
+ && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
+ ){
pCost->rCost = cost;
pCost->nRow = nRow;
pCost->used = used;
@@ -89257,10 +95861,12 @@
);
WHERETRACE(("best index is: %s\n",
- (pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
+ ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
+ pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
+ bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
pCost->plan.wsFlags |= eqTermMask;
}
@@ -89318,7 +95924,7 @@
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm
- && ALWAYS((pTerm->wtFlags & TERM_CODED)==0)
+ && (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
pTerm->wtFlags |= TERM_CODED;
@@ -89516,7 +96122,9 @@
int k = pIdx->aiColumn[j];
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
if( NEVER(pTerm==0) ) break;
- assert( (pTerm->wtFlags & TERM_CODED)==0 );
+ /* The following true for indices with redundant columns.
+ ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
+ testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
@@ -89730,7 +96338,11 @@
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iCur;
pLevel->p2 = start;
- pLevel->p5 = (pStart==0 && pEnd==0) ?1:0;
+ if( pStart==0 && pEnd==0 ){
+ pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ }else{
+ assert( pLevel->p5==0 );
+ }
if( testOp!=OP_Noop ){
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
@@ -89799,7 +96411,8 @@
int iIdxCur; /* The VDBE cursor for the index */
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
- char *zAff;
+ char *zStartAff; /* Affinity for start of range constraint */
+ char *zEndAff; /* Affinity for end of range constraint */
pIdx = pLevel->plan.u.pIdx;
iIdxCur = pLevel->iIdxCur;
@@ -89840,15 +96453,16 @@
** starting at regBase.
*/
regBase = codeAllEqualityTerms(
- pParse, pLevel, pWC, notReady, nExtraReg, &zAff
+ pParse, pLevel, pWC, notReady, nExtraReg, &zStartAff
);
+ zEndAff = sqlite3DbStrDup(pParse->db, zStartAff);
addrNxt = pLevel->addrNxt;
/* If we are doing a reverse order scan on an ascending index, or
** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd).
*/
- if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
+ if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
}
@@ -89866,15 +96480,15 @@
Expr *pRight = pRangeStart->pExpr->pRight;
sqlite3ExprCode(pParse, pRight, regBase+nEq);
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
- if( zAff ){
- if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
+ if( zStartAff ){
+ if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
/* Since the comparison is to be performed with no conversions
** applied to the operands, set the affinity to apply to pRight to
** SQLITE_AFF_NONE. */
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ zStartAff[nEq] = SQLITE_AFF_NONE;
}
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
+ zStartAff[nEq] = SQLITE_AFF_NONE;
}
}
nConstraint++;
@@ -89884,7 +96498,7 @@
startEq = 0;
start_constraints = 1;
}
- codeApplyAffinity(pParse, regBase, nConstraint, zAff);
+ codeApplyAffinity(pParse, regBase, nConstraint, zStartAff);
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
testcase( op==OP_Rewind );
@@ -89904,21 +96518,22 @@
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
sqlite3ExprCode(pParse, pRight, regBase+nEq);
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
- if( zAff ){
- if( sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE){
+ if( zEndAff ){
+ if( sqlite3CompareAffinity(pRight, zEndAff[nEq])==SQLITE_AFF_NONE){
/* Since the comparison is to be performed with no conversions
** applied to the operands, set the affinity to apply to pRight to
** SQLITE_AFF_NONE. */
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ zEndAff[nEq] = SQLITE_AFF_NONE;
}
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[nConstraint]) ){
- zAff[nConstraint] = SQLITE_AFF_NONE;
+ if( sqlite3ExprNeedsNoAffinityChange(pRight, zEndAff[nEq]) ){
+ zEndAff[nEq] = SQLITE_AFF_NONE;
}
}
- codeApplyAffinity(pParse, regBase, nEq+1, zAff);
+ codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
nConstraint++;
}
- sqlite3DbFree(pParse->db, zAff);
+ sqlite3DbFree(pParse->db, zStartAff);
+ sqlite3DbFree(pParse->db, zEndAff);
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -90188,7 +96803,7 @@
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
- if( pWInfo ){
+ if( ALWAYS(pWInfo) ){
int i;
for(i=0; i<pWInfo->nLevel; i++){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
@@ -90199,6 +96814,13 @@
}
sqlite3DbFree(db, pInfo);
}
+ if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){
+ Index *pIdx = pWInfo->a[i].plan.u.pIdx;
+ if( pIdx ){
+ sqlite3DbFree(db, pIdx->zColAff);
+ sqlite3DbFree(db, pIdx);
+ }
+ }
}
whereClauseClear(pWInfo->pWC);
sqlite3DbFree(db, pWInfo);
@@ -90318,6 +96940,7 @@
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
+ testcase( pTabList->nSrc==BMS );
if( pTabList->nSrc>BMS ){
sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
return 0;
@@ -90345,6 +96968,8 @@
sizeof(WhereMaskSet)
);
if( db->mallocFailed ){
+ sqlite3DbFree(db, pWInfo);
+ pWInfo = 0;
goto whereBeginError;
}
pWInfo->nLevel = nTabList;
@@ -90353,6 +96978,7 @@
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
+ pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1];
/* Split the WHERE clause into separate subexpressions where each
@@ -90454,20 +97080,25 @@
bestPlan.rCost = SQLITE_BIG_DBL;
/* Loop through the remaining entries in the FROM clause to find the
- ** next nested loop. The FROM clause entries may be iterated through
+ ** next nested loop. The loop tests all FROM clause entries
** either once or twice.
**
- ** The first iteration, which is always performed, searches for the
- ** FROM clause entry that permits the lowest-cost, "optimal" scan. In
+ ** The first test is always performed if there are two or more entries
+ ** remaining and never performed if there is only one FROM clause entry
+ ** to choose from. The first test looks for an "optimal" scan. In
** this context an optimal scan is one that uses the same strategy
** for the given FROM clause entry as would be selected if the entry
** were used as the innermost nested loop. In other words, a table
** is chosen such that the cost of running that table cannot be reduced
- ** by waiting for other tables to run first.
+ ** by waiting for other tables to run first. This "optimal" test works
+ ** by first assuming that the FROM clause is on the inner loop and finding
+ ** its query plan, then checking to see if that query plan uses any
+ ** other FROM clause terms that are notReady. If no notReady terms are
+ ** used then the "optimal" query plan works.
**
- ** The second iteration is only performed if no optimal scan strategies
- ** were found by the first. This iteration is used to search for the
- ** lowest cost scan overall.
+ ** The second loop iteration is only performed if no optimal scan
+ ** strategies were found by the first loop. This 2nd iteration is used to
+ ** search for the lowest cost scan overall.
**
** Previous versions of SQLite performed only the second iteration -
** the next outermost loop was always that with the lowest overall
@@ -90485,9 +97116,8 @@
** algorithm may choose to use t2 for the outer loop, which is a much
** costlier approach.
*/
- for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
- Bitmask mask = (isOptimal ? 0 : notReady);
- assert( (nTabList-iFrom)>1 || isOptimal );
+ for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
+ Bitmask mask; /* Mask of tables not yet ready */
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
@@ -90500,6 +97130,7 @@
if( j==iFrom ) iFrom++;
continue;
}
+ mask = (isOptimal ? m : notReady);
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
assert( pTabItem->pTab );
@@ -90515,8 +97146,11 @@
assert( isOptimal || (sCost.used¬Ready)==0 );
if( (sCost.used¬Ready)==0
- && (j==iFrom || sCost.rCost<bestPlan.rCost)
+ && (bestJ<0 || sCost.rCost<bestPlan.rCost
+ || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
){
+ WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
+ sCost.rCost, sCost.nRow));
bestPlan = sCost;
bestJ = j;
}
@@ -90532,13 +97166,16 @@
}
andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan;
- if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
+ testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
+ testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
+ if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
pLevel->iIdxCur = pParse->nTab++;
}else{
pLevel->iIdxCur = -1;
}
notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
+ if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
/* Check that if the table scanned by this loop iteration had an
** INDEXED BY clause attached to it, that the named index is being
@@ -90585,6 +97222,7 @@
** searching those tables.
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
+ notReady = ~(Bitmask)0;
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
@@ -90597,7 +97235,9 @@
if( pItem->zAlias ){
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
}
- if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
+ zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
+ }else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
zMsg, pLevel->plan.u.pIdx->zName);
}else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -90620,8 +97260,11 @@
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
+ pLevel->iTabCur = pTabItem->iCursor;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
+ /* Do nothing */
+ }else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
@@ -90633,6 +97276,8 @@
&& (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
+ testcase( pTab->nCol==BMS-1 );
+ testcase( pTab->nCol==BMS );
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
Bitmask b = pTabItem->colUsed;
int n = 0;
@@ -90644,7 +97289,11 @@
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
- pLevel->iTabCur = pTabItem->iCursor;
+#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+ if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
+ constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
+ }else
+#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
Index *pIx = pLevel->plan.u.pIdx;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
@@ -90656,8 +97305,10 @@
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
+ notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
+ if( db->mallocFailed ) goto whereBeginError;
/* Generate the code to do the search. Each iteration of the for
** loop below generates code for a single nested loop of the VM
@@ -90725,7 +97376,10 @@
/* Jump here if malloc fails */
whereBeginError:
- whereInfoFree(db, pWInfo);
+ if( pWInfo ){
+ pParse->nQueryLoop = pWInfo->savedNQueryLoop;
+ whereInfoFree(db, pWInfo);
+ }
return 0;
}
@@ -90795,12 +97449,15 @@
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
- if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
- if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
- if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
+ if( (pTab->tabFlags & TF_Ephemeral)==0
+ && pTab->pSelect==0
+ && (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0
+ ){
+ int ws = pLevel->plan.wsFlags;
+ if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
- if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
+ if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
}
@@ -90848,6 +97505,7 @@
/* Final cleanup
*/
+ pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
return;
}
@@ -91134,7 +97792,7 @@
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
*/
-#define YY_ACTTAB_COUNT (1543)
+#define YY_ACTTAB_COUNT (1550)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 313, 49, 556, 46, 147, 172, 628, 598, 55, 55,
/* 10 */ 55, 55, 302, 53, 53, 53, 53, 52, 52, 51,
@@ -91284,13 +97942,13 @@
/* 1450 */ 249, 389, 487, 486, 314, 164, 602, 79, 310, 240,
/* 1460 */ 414, 373, 480, 163, 262, 371, 414, 162, 369, 602,
/* 1470 */ 78, 212, 478, 26, 477, 602, 9, 161, 467, 363,
- /* 1480 */ 141, 122, 339, 187, 119, 457, 348, 117, 347, 116,
- /* 1490 */ 115, 114, 448, 112, 182, 320, 22, 433, 19, 432,
- /* 1500 */ 431, 63, 428, 610, 193, 298, 597, 574, 572, 404,
- /* 1510 */ 555, 552, 290, 281, 510, 499, 498, 497, 495, 380,
- /* 1520 */ 356, 460, 256, 250, 345, 447, 306, 5, 570, 550,
- /* 1530 */ 299, 211, 370, 401, 550, 508, 502, 501, 490, 527,
- /* 1540 */ 525, 483, 238,
+ /* 1480 */ 141, 122, 339, 187, 119, 457, 348, 347, 117, 116,
+ /* 1490 */ 115, 112, 114, 448, 182, 22, 320, 433, 432, 431,
+ /* 1500 */ 19, 428, 610, 597, 574, 193, 572, 63, 298, 404,
+ /* 1510 */ 555, 552, 290, 281, 510, 460, 498, 499, 495, 447,
+ /* 1520 */ 356, 497, 256, 380, 306, 570, 5, 250, 345, 238,
+ /* 1530 */ 299, 550, 527, 490, 508, 525, 502, 401, 501, 963,
+ /* 1540 */ 211, 963, 483, 963, 963, 963, 963, 963, 963, 370,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 19, 222, 223, 224, 225, 24, 1, 26, 77, 78,
@@ -91441,18 +98099,18 @@
/* 1450 */ 107, 150, 176, 176, 111, 156, 174, 175, 179, 116,
/* 1460 */ 165, 18, 157, 156, 238, 157, 165, 156, 45, 174,
/* 1470 */ 175, 157, 157, 135, 239, 174, 175, 156, 189, 157,
- /* 1480 */ 68, 189, 139, 219, 22, 199, 157, 192, 18, 192,
- /* 1490 */ 192, 192, 199, 189, 219, 157, 243, 40, 243, 157,
- /* 1500 */ 157, 246, 38, 153, 196, 198, 166, 233, 233, 228,
- /* 1510 */ 177, 177, 209, 177, 182, 177, 166, 177, 166, 178,
- /* 1520 */ 242, 199, 242, 209, 209, 199, 148, 196, 166, 208,
- /* 1530 */ 195, 236, 237, 191, 208, 183, 183, 183, 186, 174,
- /* 1540 */ 174, 186, 92,
+ /* 1480 */ 68, 189, 139, 219, 22, 199, 157, 18, 192, 192,
+ /* 1490 */ 192, 189, 192, 199, 219, 243, 157, 40, 157, 157,
+ /* 1500 */ 243, 38, 153, 166, 233, 196, 233, 246, 198, 228,
+ /* 1510 */ 177, 177, 209, 177, 182, 199, 166, 177, 166, 199,
+ /* 1520 */ 242, 177, 242, 178, 148, 166, 196, 209, 209, 92,
+ /* 1530 */ 195, 208, 174, 186, 183, 174, 183, 191, 183, 253,
+ /* 1540 */ 236, 253, 186, 253, 253, 253, 253, 253, 253, 237,
};
#define YY_SHIFT_USE_DFLT (-90)
#define YY_SHIFT_COUNT (418)
#define YY_SHIFT_MIN (-89)
-#define YY_SHIFT_MAX (1470)
+#define YY_SHIFT_MAX (1469)
static const short yy_shift_ofst[] = {
/* 0 */ 993, 1114, 1343, 1114, 1213, 1213, 90, 90, 0, -19,
/* 10 */ 1213, 1213, 1213, 1213, 1213, 352, 517, 721, 1091, 1213,
@@ -91467,7 +98125,7 @@
/* 100 */ 1017, -69, -69, -69, -69, -1, -1, 58, 138, -44,
/* 110 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
/* 120 */ 517, 517, 517, 517, 517, 517, 202, 579, 517, 517,
- /* 130 */ 517, 517, 517, 382, 885, 1450, -90, -90, -90, 1293,
+ /* 130 */ 517, 517, 517, 382, 885, 1437, -90, -90, -90, 1293,
/* 140 */ 73, 272, 272, 309, 311, 297, 282, 216, 602, 538,
/* 150 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
/* 160 */ 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
@@ -91478,8 +98136,8 @@
/* 210 */ 149, 604, 516, 149, 149, 508, 3, 299, 677, 871,
/* 220 */ 613, 613, 879, 871, 879, 144, 382, 226, 382, 226,
/* 230 */ 564, 226, 613, 226, 226, 404, 625, 625, 382, 426,
- /* 240 */ -89, 801, 1464, 1244, 1244, 1457, 1457, 1244, 1462, 1412,
- /* 250 */ 1188, 1470, 1470, 1470, 1470, 1244, 1188, 1462, 1412, 1412,
+ /* 240 */ -89, 801, 1463, 1244, 1244, 1457, 1457, 1244, 1462, 1412,
+ /* 250 */ 1188, 1469, 1469, 1469, 1469, 1244, 1188, 1462, 1412, 1412,
/* 260 */ 1244, 1443, 1338, 1423, 1244, 1244, 1443, 1244, 1443, 1244,
/* 270 */ 1443, 1414, 1306, 1306, 1306, 1365, 1348, 1348, 1414, 1306,
/* 280 */ 1317, 1306, 1365, 1306, 1306, 1267, 1268, 1267, 1268, 1267,
@@ -91500,7 +98158,7 @@
#define YY_REDUCE_USE_DFLT (-222)
#define YY_REDUCE_COUNT (312)
#define YY_REDUCE_MIN (-221)
-#define YY_REDUCE_MAX (1378)
+#define YY_REDUCE_MAX (1376)
static const short yy_reduce_ofst[] = {
/* 0 */ 310, 994, 1134, 221, 169, 157, 89, 18, 83, 301,
/* 10 */ 377, 316, 312, 16, 295, 238, 249, 391, 1301, 1295,
@@ -91521,13 +98179,13 @@
/* 160 */ 1084, 1066, 1049, 1011, 1010, 1006, 1002, 999, 998, 973,
/* 170 */ 972, 970, 966, 964, 895, 894, 892, 833, 822, 762,
/* 180 */ 761, 229, 811, 804, 803, 389, 688, 808, 807, 737,
- /* 190 */ 460, 464, 572, 584, 1355, 1366, 1365, 1352, 1354, 1353,
- /* 200 */ 1352, 1326, 1335, 1342, 1335, 1335, 1335, 1335, 1335, 1335,
- /* 210 */ 1335, 1295, 1295, 1335, 1335, 1321, 1362, 1331, 1378, 1326,
- /* 220 */ 1315, 1314, 1280, 1322, 1278, 1341, 1352, 1340, 1350, 1338,
- /* 230 */ 1332, 1336, 1303, 1334, 1333, 1281, 1275, 1274, 1340, 1307,
- /* 240 */ 1308, 1350, 1255, 1343, 1342, 1255, 1253, 1338, 1275, 1304,
- /* 250 */ 1293, 1299, 1298, 1297, 1295, 1329, 1286, 1264, 1292, 1289,
+ /* 190 */ 460, 464, 572, 584, 1356, 1361, 1358, 1347, 1355, 1353,
+ /* 200 */ 1351, 1323, 1335, 1346, 1335, 1335, 1335, 1335, 1335, 1335,
+ /* 210 */ 1335, 1312, 1304, 1335, 1335, 1323, 1359, 1330, 1376, 1320,
+ /* 220 */ 1319, 1318, 1280, 1316, 1278, 1345, 1352, 1344, 1350, 1340,
+ /* 230 */ 1332, 1336, 1303, 1334, 1333, 1281, 1273, 1271, 1337, 1310,
+ /* 240 */ 1309, 1349, 1261, 1342, 1341, 1257, 1252, 1339, 1275, 1302,
+ /* 250 */ 1294, 1300, 1298, 1297, 1296, 1329, 1286, 1264, 1292, 1289,
/* 260 */ 1322, 1321, 1235, 1226, 1315, 1314, 1311, 1308, 1307, 1305,
/* 270 */ 1299, 1279, 1277, 1276, 1270, 1258, 1211, 1209, 1250, 1259,
/* 280 */ 1255, 1242, 1243, 1241, 1201, 1200, 1184, 1186, 1182, 1178,
@@ -95827,7 +102485,12 @@
** NULL.
*/
case SQLITE_CONFIG_LOG: {
- sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
+ /* MSVC is picky about pulling func ptrs from va lists.
+ ** http://support.microsoft.com/kb/47961
+ ** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
+ */
+ typedef void(*LOGFUNC_t)(void*,int,const char*);
+ sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
break;
}
@@ -96214,7 +102877,7 @@
/* SQLITE_NOTFOUND */ 0,
/* SQLITE_FULL */ "database or disk is full",
/* SQLITE_CANTOPEN */ "unable to open database file",
- /* SQLITE_PROTOCOL */ 0,
+ /* SQLITE_PROTOCOL */ "locking protocol",
/* SQLITE_EMPTY */ "table contains no data",
/* SQLITE_SCHEMA */ "database schema has changed",
/* SQLITE_TOOBIG */ "string or blob too big",
@@ -96488,7 +103151,7 @@
char *zFunc8;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1);
+ zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xFunc, xStep, xFinal);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
@@ -96624,6 +103287,145 @@
return pRet;
}
+#ifndef SQLITE_OMIT_WAL
+/*
+** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
+** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
+** is greater than sqlite3.pWalArg cast to an integer (the value configured by
+** wal_autocheckpoint()).
+*/
+SQLITE_PRIVATE int sqlite3WalDefaultHook(
+ void *pClientData, /* Argument */
+ sqlite3 *db, /* Connection */
+ const char *zDb, /* Database */
+ int nFrame /* Size of WAL */
+){
+ if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){
+ sqlite3BeginBenignMalloc();
+ sqlite3_wal_checkpoint(db, zDb);
+ sqlite3EndBenignMalloc();
+ }
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OMIT_WAL */
+
+/*
+** Configure an sqlite3_wal_hook() callback to automatically checkpoint
+** a database after committing a transaction if there are nFrame or
+** more frames in the log file. Passing zero or a negative value as the
+** nFrame parameter disables automatic checkpoints entirely.
+**
+** The callback registered by this function replaces any existing callback
+** registered using sqlite3_wal_hook(). Likewise, registering a callback
+** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
+** configured by this function.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
+#ifndef SQLITE_OMIT_WAL
+ if( nFrame>0 ){
+ sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
+ }else{
+ sqlite3_wal_hook(db, 0, 0);
+ }
+#endif
+ return SQLITE_OK;
+}
+
+/*
+** Register a callback to be invoked each time a transaction is written
+** into the write-ahead-log by this database connection.
+*/
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3 *db, /* Attach the hook to this db handle */
+ int(*xCallback)(void *, sqlite3*, const char*, int),
+ void *pArg /* First argument passed to xCallback() */
+){
+#ifndef SQLITE_OMIT_WAL
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pWalArg;
+ db->xWalCallback = xCallback;
+ db->pWalArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return pRet;
+#else
+ return 0;
+#endif
+}
+
+
+/*
+** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
+** to contains a zero-length string, all attached databases are
+** checkpointed.
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
+#ifdef SQLITE_OMIT_WAL
+ return SQLITE_OK;
+#else
+ int rc; /* Return code */
+ int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
+
+ sqlite3_mutex_enter(db->mutex);
+ if( zDb && zDb[0] ){
+ iDb = sqlite3FindDbName(db, zDb);
+ }
+ if( iDb<0 ){
+ rc = SQLITE_ERROR;
+ sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
+ }else{
+ rc = sqlite3Checkpoint(db, iDb);
+ sqlite3Error(db, rc, 0);
+ }
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+#endif
+}
+
+#ifndef SQLITE_OMIT_WAL
+/*
+** Run a checkpoint on database iDb. This is a no-op if database iDb is
+** not currently open in WAL mode.
+**
+** If a transaction is open on the database being checkpointed, this
+** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
+** an error occurs while running the checkpoint, an SQLite error code is
+** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
+**
+** The mutex on database handle db should be held by the caller. The mutex
+** associated with the specific b-tree being checkpointed is taken by
+** this function while the checkpoint is running.
+**
+** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
+** checkpointed. If an error is encountered it is returned immediately -
+** no attempt is made to checkpoint any remaining databases.
+*/
+SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb){
+ int rc = SQLITE_OK; /* Return code */
+ int i; /* Used to iterate through attached dbs */
+
+ assert( sqlite3_mutex_held(db->mutex) );
+
+ for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
+ if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ if( sqlite3BtreeIsInReadTrans(pBt) ){
+ rc = SQLITE_LOCKED;
+ }else{
+ sqlite3BtreeEnter(pBt);
+ rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
+ sqlite3BtreeLeave(pBt);
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+#endif /* SQLITE_OMIT_WAL */
+
/*
** This function returns true if main-memory should be used instead of
** a temporary file for transient pager files and statement journals.
@@ -97046,7 +103848,7 @@
db->autoCommit = 1;
db->nextAutovac = -1;
db->nextPagesize = 0;
- db->flags |= SQLITE_ShortColNames
+ db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
@@ -97184,6 +103986,8 @@
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
+ sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
+
opendb_out:
if( db ){
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
@@ -97311,7 +104115,7 @@
char *zName8;
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
- zName8 = sqlite3Utf16to8(db, zName, -1);
+ zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
if( zName8 ){
rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
sqlite3DbFree(db, zName8);
@@ -97358,7 +104162,6 @@
}
#endif /* SQLITE_OMIT_UTF16 */
-#ifndef SQLITE_OMIT_GLOBALRECOVER
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -97368,7 +104171,6 @@
return SQLITE_OK;
}
#endif
-#endif
/*
** Test to see whether or not the database connection is in autocommit
@@ -97396,17 +104198,22 @@
SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_CORRUPT,
- "database corruption found by source line %d", lineno);
+ "database corruption at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_CORRUPT;
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_MISUSE, "misuse detected by source line %d", lineno);
+ sqlite3_log(SQLITE_MISUSE,
+ "misuse at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_MISUSE;
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_CANTOPEN, "cannot open file at source line %d", lineno);
+ sqlite3_log(SQLITE_CANTOPEN,
+ "cannot open file at line %d of [%.10s]",
+ lineno, 20+sqlite3_sourceid());
return SQLITE_CANTOPEN;
}
@@ -97678,9 +104485,13 @@
** dileterious behavior.
*/
case SQLITE_TESTCTRL_PENDING_BYTE: {
- unsigned int newVal = va_arg(ap, unsigned int);
- rc = sqlite3PendingByte;
- if( newVal ) sqlite3PendingByte = newVal;
+ rc = PENDING_BYTE;
+#ifndef SQLITE_OMIT_WSD
+ {
+ unsigned int newVal = va_arg(ap, unsigned int);
+ if( newVal ) sqlite3PendingByte = newVal;
+ }
+#endif
break;
}
@@ -97784,6 +104595,15 @@
}
#endif
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PGHDRSZ)
+ **
+ ** Return the size of a pcache header in bytes.
+ */
+ case SQLITE_TESTCTRL_PGHDRSZ: {
+ rc = sizeof(PgHdr);
+ break;
+ }
+
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
@@ -97949,6 +104769,7 @@
if( xNotify==0 ){
removeFromBlockedList(db);
+ db->pBlockingConnection = 0;
db->pUnlockConnection = 0;
db->xUnlockNotify = 0;
db->pUnlockArg = 0;
@@ -98149,9 +104970,6 @@
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/
-/* TODO(shess) Consider exporting this comment to an HTML file or the
-** wiki.
-*/
/* The full-text index is stored in a series of b+tree (-like)
** structures called segments which map terms to doclists. The
** structures are like b+trees in layout, but are constructed from the
@@ -98174,30 +104992,40 @@
** 21 bits - BBA
** and so on.
**
-** This is identical to how sqlite encodes varints (see util.c).
+** This is similar in concept to how sqlite encodes "varints" but
+** the encoding is not the same. SQLite varints are big-endian
+** are are limited to 9 bytes in length whereas FTS3 varints are
+** little-endian and can be up to 10 bytes in length (in theory).
+**
+** Example encodings:
+**
+** 1: 0x01
+** 127: 0x7f
+** 128: 0x81 0x00
**
**
**** Document lists ****
** A doclist (document list) holds a docid-sorted list of hits for a
-** given term. Doclists hold docids, and can optionally associate
-** token positions and offsets with docids.
+** given term. Doclists hold docids and associated token positions.
+** A docid is the unique integer identifier for a single document.
+** A position is the index of a word within the document. The first
+** word of the document has a position of 0.
**
-** A DL_POSITIONS_OFFSETS doclist is stored like this:
+** FTS3 used to optionally store character offsets using a compile-time
+** option. But that functionality is no longer supported.
+**
+** A doclist is stored like this:
**
** array {
** varint docid;
** array { (position list for column 0)
-** varint position; (delta from previous position plus POS_BASE)
-** varint startOffset; (delta from previous startOffset)
-** varint endOffset; (delta from startOffset)
+** varint position; (2 more than the delta from previous position)
** }
** array {
** varint POS_COLUMN; (marks start of position list for new column)
** varint column; (index of new column)
** array {
-** varint position; (delta from previous position plus POS_BASE)
-** varint startOffset;(delta from previous startOffset)
-** varint endOffset; (delta from startOffset)
+** varint position; (2 more than the delta from previous position)
** }
** }
** varint POS_END; (marks end of positions for this document.
@@ -98205,19 +105033,32 @@
**
** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream
-** generated by the tokenizer, while an "offset" is a byte offset,
-** both based at 0. Note that POS_END and POS_COLUMN occur in the
-** same logical place as the position element, and act as sentinals
-** ending a position list array.
+** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
+** in the same logical place as the position element, and act as sentinals
+** ending a position list array. POS_END is 0. POS_COLUMN is 1.
+** The positions numbers are not stored literally but rather as two more
+** than the difference from the prior position, or the just the position plus
+** 2 for the first position. Example:
**
-** A DL_POSITIONS doclist omits the startOffset and endOffset
-** information. A DL_DOCIDS doclist omits both the position and
-** offset information, becoming an array of varint-encoded docids.
+** label: A B C D E F G H I J K
+** value: 123 5 9 1 1 14 35 0 234 72 0
**
-** On-disk data is stored as type DL_DEFAULT, so we don't serialize
-** the type. Due to how deletion is implemented in the segmentation
-** system, on-disk doclists MUST store at least positions.
+** The 123 value is the first docid. For column zero in this document
+** there are two matches at positions 3 and 10 (5-2 and 9-2+3). The 1
+** at D signals the start of a new column; the 1 at E indicates that the
+** new column is column number 1. There are two positions at 12 and 45
+** (14-2 and 35-2+12). The 0 at H indicate the end-of-document. The
+** 234 at I is the next docid. It has one position 72 (72-2) and then
+** terminates with the 0 at K.
**
+** A "position-list" is the list of positions for multiple columns for
+** a single docid. A "column-list" is the set of positions for a single
+** column. Hence, a position-list consists of one or more column-lists,
+** a document record consists of a docid followed by a position-list and
+** a doclist consists of one or more document records.
+**
+** A bare doclist omits the position information, becoming an
+** array of varint-encoded docids.
**
**** Segment leaf nodes ****
** Segment leaf nodes store terms and doclists, ordered by term. Leaf
@@ -98732,6 +105573,20 @@
#define FTS3_VARINT_MAX 10
/*
+** The testcase() macro is only used by the amalgamation. If undefined,
+** make it a no-op.
+*/
+#ifndef testcase
+# define testcase(X)
+#endif
+
+/*
+** Terminator values for position-lists and column-lists.
+*/
+#define POS_COLUMN (1) /* Column-list terminator */
+#define POS_END (0) /* Position-list terminator */
+
+/*
** This section provides definitions to allow the
** FTS3 extension to be compiled outside of the
** amalgamation.
@@ -98782,7 +105637,7 @@
/* Precompiled statements used by the implementation. Each of these
** statements is run and reset within a single virtual table API call.
*/
- sqlite3_stmt *aStmt[18];
+ sqlite3_stmt *aStmt[25];
/* Pointer to string containing the SQL:
**
@@ -98796,6 +105651,8 @@
sqlite3_stmt **aLeavesStmt; /* Array of prepared zSelectLeaves stmts */
int nNodeSize; /* Soft limit for node size */
+ u8 bHasContent; /* True if %_content table exists */
+ u8 bHasDocsize; /* True if %_docsize table exists */
/* The following hash table is used to buffer pending index updates during
** transactions. Variable nPendingData estimates the memory size of the
@@ -98826,8 +105683,8 @@
char *pNextId; /* Pointer into the body of aDoclist */
char *aDoclist; /* List of docids for full-text queries */
int nDoclist; /* Size of buffer at aDoclist */
- int isMatchinfoOk; /* True when aMatchinfo[] matches iPrevId */
- u32 *aMatchinfo;
+ int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
+ u32 *aMatchinfo; /* Information about most recent match */
};
/*
@@ -98933,6 +105790,8 @@
);
SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char const**, int*);
SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
@@ -98957,6 +105816,7 @@
SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
+SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -98967,10 +105827,7 @@
/* fts3_snippet.c */
SQLITE_PRIVATE void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
-SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context*, Fts3Cursor*,
- const char *, const char *, const char *
-);
-SQLITE_PRIVATE void sqlite3Fts3Snippet2(sqlite3_context *, Fts3Cursor *, const char *,
+SQLITE_PRIVATE void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
const char *, const char *, int, int
);
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
@@ -99040,8 +105897,7 @@
}
/*
-** Return the number of bytes required to store the value passed as the
-** first argument in varint form.
+** Return the number of bytes required to encode v as a varint
*/
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64 v){
int i = 0;
@@ -99090,12 +105946,23 @@
}
}
+/*
+** Read a single varint from the doclist at *pp and advance *pp to point
+** to the first byte past the end of the varint. Add the value of the varint
+** to *pVal.
+*/
static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
sqlite3_int64 iVal;
*pp += sqlite3Fts3GetVarint(*pp, &iVal);
*pVal += iVal;
}
+/*
+** As long as *pp has not reached its end (pEnd), then do the same
+** as fts3GetDeltaVarint(): read a single varint and add it to *pVal.
+** But if we have reached the end of the varint, just set *pp=0 and
+** leave *pVal unchanged.
+*/
static void fts3GetDeltaVarint2(char **pp, char *pEnd, sqlite3_int64 *pVal){
if( *pp>=pEnd ){
*pp = 0;
@@ -99131,29 +105998,46 @@
}
/*
+** Construct one or more SQL statements from the format string given
+** and then evaluate those statements. The success code is writting
+** into *pRc.
+**
+** If *pRc is initially non-zero then this routine is a no-op.
+*/
+static void fts3DbExec(
+ int *pRc, /* Success code */
+ sqlite3 *db, /* Database in which to run SQL */
+ const char *zFormat, /* Format string for SQL */
+ ... /* Arguments to the format string */
+){
+ va_list ap;
+ char *zSql;
+ if( *pRc ) return;
+ va_start(ap, zFormat);
+ zSql = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ if( zSql==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ *pRc = sqlite3_exec(db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ }
+}
+
+/*
** The xDestroy() virtual table method.
*/
static int fts3DestroyMethod(sqlite3_vtab *pVtab){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
Fts3Table *p = (Fts3Table *)pVtab;
+ sqlite3 *db = p->db;
- /* Create a script to drop the underlying three storage tables. */
- char *zSql = sqlite3_mprintf(
- "DROP TABLE IF EXISTS %Q.'%q_content';"
- "DROP TABLE IF EXISTS %Q.'%q_segments';"
- "DROP TABLE IF EXISTS %Q.'%q_segdir';",
- p->zDb, p->zName, p->zDb, p->zName, p->zDb, p->zName
- );
-
- /* If malloc has failed, set rc to SQLITE_NOMEM. Otherwise, try to
- ** execute the SQL script created above.
- */
- if( zSql ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_free(zSql);
- }else{
- rc = SQLITE_NOMEM;
- }
+ /* Drop the shadow tables */
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName);
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName);
/* If everything has worked, invoke fts3DisconnectMethod() to free the
** memory associated with the Fts3Table structure and return SQLITE_OK.
@@ -99200,24 +106084,39 @@
** Create the backing store tables (%_content, %_segments and %_segdir)
** required by the FTS3 table passed as the only argument. This is done
** as part of the vtab xCreate() method.
+**
+** If the p->bHasDocsize boolean is true (indicating that this is an
+** FTS4 table, not an FTS3 table) then also create the %_docsize and
+** %_stat tables required by FTS4.
*/
static int fts3CreateTables(Fts3Table *p){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
char *zContentCols; /* Columns of %_content table */
- char *zSql; /* SQL script to create required tables */
+ sqlite3 *db = p->db; /* The database connection */
/* Create a list of user columns for the content table */
- zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
- for(i=0; zContentCols && i<p->nColumn; i++){
- char *z = p->azColumn[i];
- zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
- }
+ if( p->bHasContent ){
+ zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
+ for(i=0; zContentCols && i<p->nColumn; i++){
+ char *z = p->azColumn[i];
+ zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
+ }
+ if( zContentCols==0 ) rc = SQLITE_NOMEM;
- /* Create the whole SQL script */
- zSql = sqlite3_mprintf(
- "CREATE TABLE %Q.'%q_content'(%s);"
- "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);"
+ /* Create the content table */
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_content'(%s)",
+ p->zDb, p->zName, zContentCols
+ );
+ sqlite3_free(zContentCols);
+ }
+ /* Create other tables */
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
+ p->zDb, p->zName
+ );
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_segdir'("
"level INTEGER,"
"idx INTEGER,"
@@ -99227,30 +106126,64 @@
"root BLOB,"
"PRIMARY KEY(level, idx)"
");",
- p->zDb, p->zName, zContentCols, p->zDb, p->zName, p->zDb, p->zName
+ p->zDb, p->zName
);
-
- /* Unless a malloc() failure has occurred, execute the SQL script to
- ** create the tables used to store data for this FTS3 virtual table.
- */
- if( zContentCols==0 || zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
+ if( p->bHasDocsize ){
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
+ p->zDb, p->zName
+ );
+ fts3DbExec(&rc, db,
+ "CREATE TABLE %Q.'%q_stat'(id INTEGER PRIMARY KEY, value BLOB);",
+ p->zDb, p->zName
+ );
}
-
- sqlite3_free(zSql);
- sqlite3_free(zContentCols);
return rc;
}
/*
+** An sqlite3_exec() callback for fts3TableExists.
+*/
+static int fts3TableExistsCallback(void *pArg, int n, char **pp1, char **pp2){
+ UNUSED_PARAMETER(n);
+ UNUSED_PARAMETER(pp1);
+ UNUSED_PARAMETER(pp2);
+ *(int*)pArg = 1;
+ return 1;
+}
+
+/*
+** Determine if a table currently exists in the database.
+*/
+static void fts3TableExists(
+ int *pRc, /* Success code */
+ sqlite3 *db, /* The database connection to test */
+ const char *zDb, /* ATTACHed database within the connection */
+ const char *zName, /* Name of the FTS3 table */
+ const char *zSuffix, /* Shadow table extension */
+ u8 *pResult /* Write results here */
+){
+ int rc = SQLITE_OK;
+ int res = 0;
+ char *zSql;
+ if( *pRc ) return;
+ zSql = sqlite3_mprintf(
+ "SELECT 1 FROM %Q.sqlite_master WHERE name='%q%s'",
+ zDb, zName, zSuffix
+ );
+ rc = sqlite3_exec(db, zSql, fts3TableExistsCallback, &res, 0);
+ sqlite3_free(zSql);
+ *pResult = (u8)(res & 0xff);
+ if( rc!=SQLITE_ABORT ) *pRc = rc;
+}
+
+/*
** This function is the implementation of both the xConnect and xCreate
** methods of the FTS3 virtual table.
**
** The argv[] array contains the following:
**
-** argv[0] -> module name
+** argv[0] -> module name ("fts3" or "fts4")
** argv[1] -> database name
** argv[2] -> table name
** argv[...] -> "column name" and other module argument fields.
@@ -99269,12 +106202,12 @@
int rc; /* Return code */
int i; /* Iterator variable */
int nByte; /* Size of allocation used for *p */
- int iCol;
- int nString = 0;
- int nCol = 0;
- char *zCsr;
- int nDb;
- int nName;
+ int iCol; /* Column index */
+ int nString = 0; /* Bytes required to hold all column names */
+ int nCol = 0; /* Number of columns in the FTS table */
+ char *zCsr; /* Space for holding column names */
+ int nDb; /* Bytes required to hold database name */
+ int nName; /* Bytes required to hold table name */
const char *zTokenizer = 0; /* Name of tokenizer to use */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
@@ -99360,9 +106293,15 @@
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
+ p->bHasContent = 1;
+ p->bHasDocsize = argv[0][3]=='4';
rc = fts3CreateTables(p);
- if( rc!=SQLITE_OK ) goto fts3_init_out;
+ }else{
+ rc = SQLITE_OK;
+ fts3TableExists(&rc, db, argv[1], argv[2], "_content", &p->bHasContent);
+ fts3TableExists(&rc, db, argv[1], argv[2], "_docsize", &p->bHasDocsize);
}
+ if( rc!=SQLITE_OK ) goto fts3_init_out;
rc = fts3DeclareVtab(p);
if( rc!=SQLITE_OK ) goto fts3_init_out;
@@ -99484,12 +106423,6 @@
return SQLITE_OK;
}
-/****************************************************************/
-/****************************************************************/
-/****************************************************************/
-/****************************************************************/
-
-
/*
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
@@ -99504,6 +106437,11 @@
return SQLITE_OK;
}
+/*
+** Position the pCsr->pStmt statement so that it is on the row
+** of the %_content table that contains the last match. Return
+** SQLITE_OK on success.
+*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
if( pCsr->isRequireSeek ){
pCsr->isRequireSeek = 0;
@@ -99530,6 +106468,17 @@
}
}
+/*
+** Advance the cursor to the next row in the %_content table that
+** matches the search criteria. For a MATCH search, this will be
+** the next row that matches. For a full-table scan, this will be
+** simply the next row in the %_content table. For a docid lookup,
+** this routine simply sets the EOF flag.
+**
+** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
+** even if we reach end-of-file. The fts3EofMethod() will be called
+** subsequently to determine whether or not an EOF was hit.
+*/
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
int rc = SQLITE_OK; /* Return code */
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
@@ -99545,7 +106494,7 @@
sqlite3_reset(pCsr->pStmt);
fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
pCsr->isRequireSeek = 1;
- pCsr->isMatchinfoOk = 1;
+ pCsr->isMatchinfoNeeded = 1;
}
return rc;
}
@@ -99663,24 +106612,37 @@
/*
** When this function is called, *ppPoslist is assumed to point to the
-** start of a position-list.
+** start of a position-list. After it returns, *ppPoslist points to the
+** first byte after the position-list.
+**
+** A position list is list of positions (delta encoded) and columns for
+** a single document record of a doclist. So, in other words, this
+** routine advances *ppPoslist so that it points to the next docid in
+** the doclist, or to the first byte past the end of the doclist.
+**
+** If pp is not NULL, then the contents of the position list are copied
+** to *pp. *pp is set to point to the first byte past the last byte copied
+** before this function returns.
*/
static void fts3PoslistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
/* The end of a position list is marked by a zero encoded as an FTS3
- ** varint. A single 0x00 byte. Except, if the 0x00 byte is preceded by
+ ** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
** of some other, multi-byte, value.
**
- ** The following block moves pEnd to point to the first byte that is not
+ ** The following while-loop moves pEnd to point to the first byte that is not
** immediately preceded by a byte with the 0x80 bit set. Then increments
** pEnd once more so that it points to the byte immediately following the
** last byte in the position-list.
*/
- while( *pEnd | c ) c = *pEnd++ & 0x80;
- pEnd++;
+ while( *pEnd | c ){
+ c = *pEnd++ & 0x80;
+ testcase( c!=0 && (*pEnd)==0 );
+ }
+ pEnd++; /* Advance past the POS_END terminator byte */
if( pp ){
int n = (int)(pEnd - *ppPoslist);
@@ -99692,12 +106654,34 @@
*ppPoslist = pEnd;
}
+/*
+** When this function is called, *ppPoslist is assumed to point to the
+** start of a column-list. After it returns, *ppPoslist points to the
+** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
+**
+** A column-list is list of delta-encoded positions for a single column
+** within a single document within a doclist.
+**
+** The column-list is terminated either by a POS_COLUMN varint (1) or
+** a POS_END varint (0). This routine leaves *ppPoslist pointing to
+** the POS_COLUMN or POS_END that terminates the column-list.
+**
+** If pp is not NULL, then the contents of the column-list are copied
+** to *pp. *pp is set to point to the first byte past the last byte copied
+** before this function returns. The POS_COLUMN or POS_END terminator
+** is not copied into *pp.
+*/
static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
- /* A column-list is terminated by either a 0x01 or 0x00. */
- while( 0xFE & (*pEnd | c) ) c = *pEnd++ & 0x80;
+ /* A column-list is terminated by either a 0x01 or 0x00 byte that is
+ ** not part of a multi-byte varint.
+ */
+ while( 0xFE & (*pEnd | c) ){
+ c = *pEnd++ & 0x80;
+ testcase( c!=0 && ((*pEnd)&0xfe)==0 );
+ }
if( pp ){
int n = (int)(pEnd - *ppPoslist);
char *p = *pp;
@@ -99709,37 +106693,45 @@
}
/*
-** Value used to signify the end of an offset-list. This is safe because
+** Value used to signify the end of an position-list. This is safe because
** it is not possible to have a document with 2^31 terms.
*/
-#define OFFSET_LIST_END 0x7fffffff
+#define POSITION_LIST_END 0x7fffffff
/*
-** This function is used to help parse offset-lists. When this function is
-** called, *pp may point to the start of the next varint in the offset-list
-** being parsed, or it may point to 1 byte past the end of the offset-list
-** (in which case **pp will be 0x00 or 0x01).
+** This function is used to help parse position-lists. When this function is
+** called, *pp may point to the start of the next varint in the position-list
+** being parsed, or it may point to 1 byte past the end of the position-list
+** (in which case **pp will be a terminator bytes POS_END (0) or
+** (1)).
**
-** If *pp points past the end of the current offset list, set *pi to
-** OFFSET_LIST_END and return. Otherwise, read the next varint from *pp,
+** If *pp points past the end of the current position-list, set *pi to
+** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
** increment the current value of *pi by the value read, and set *pp to
** point to the next value before returning.
+**
+** Before calling this routine *pi must be initialized to the value of
+** the previous position, or zero if we are reading the first position
+** in the position-list. Because positions are delta-encoded, the value
+** of the previous position is needed in order to compute the value of
+** the next position.
*/
static void fts3ReadNextPos(
- char **pp, /* IN/OUT: Pointer into offset-list buffer */
- sqlite3_int64 *pi /* IN/OUT: Value read from offset-list */
+ char **pp, /* IN/OUT: Pointer into position-list buffer */
+ sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
- if( **pp&0xFE ){
+ if( (**pp)&0xFE ){
fts3GetDeltaVarint(pp, pi);
*pi -= 2;
}else{
- *pi = OFFSET_LIST_END;
+ *pi = POSITION_LIST_END;
}
}
/*
-** If parameter iCol is not 0, write an 0x01 byte followed by the value of
-** iCol encoded as a varint to *pp.
+** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by
+** the value of iCol encoded as a varint to *pp. This will start a new
+** column list.
**
** Set *pp to point to the byte just after the last byte written before
** returning (do not modify it if iCol==0). Return the total number of bytes
@@ -99757,7 +106749,11 @@
}
/*
-**
+** Compute the union of two position lists. The output written
+** into *pp contains all positions of both *pp1 and *pp2 in sorted
+** order and with any duplicates removed. All pointers are
+** updated appropriately. The caller is responsible for insuring
+** that there is enough space in *pp to hold the complete output.
*/
static void fts3PoslistMerge(
char **pp, /* Output buffer */
@@ -99769,32 +106765,33 @@
char *p2 = *pp2;
while( *p1 || *p2 ){
- int iCol1;
- int iCol2;
+ int iCol1; /* The current column index in pp1 */
+ int iCol2; /* The current column index in pp2 */
- if( *p1==0x01 ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
- else if( *p1==0x00 ) iCol1 = OFFSET_LIST_END;
+ if( *p1==POS_COLUMN ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
+ else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
else iCol1 = 0;
- if( *p2==0x01 ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
- else if( *p2==0x00 ) iCol2 = OFFSET_LIST_END;
+ if( *p2==POS_COLUMN ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
+ else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
else iCol2 = 0;
if( iCol1==iCol2 ){
- sqlite3_int64 i1 = 0;
- sqlite3_int64 i2 = 0;
+ sqlite3_int64 i1 = 0; /* Last position from pp1 */
+ sqlite3_int64 i2 = 0; /* Last position from pp2 */
sqlite3_int64 iPrev = 0;
int n = fts3PutColNumber(&p, iCol1);
p1 += n;
p2 += n;
- /* At this point, both p1 and p2 point to the start of offset-lists.
- ** An offset-list is a list of non-negative delta-encoded varints, each
- ** incremented by 2 before being stored. Each list is terminated by a 0
- ** or 1 value (0x00 or 0x01). The following block merges the two lists
+ /* At this point, both p1 and p2 point to the start of column-lists
+ ** for the same column (the column with index iCol1 and iCol2).
+ ** A column-list is a list of non-negative delta-encoded varints, each
+ ** incremented by 2 before being stored. Each list is terminated by a
+ ** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
** and writes the results to buffer p. p is left pointing to the byte
- ** after the list written. No terminator (0x00 or 0x01) is written to
- ** the output.
+ ** after the list written. No terminator (POS_END or POS_COLUMN) is
+ ** written to the output.
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
@@ -99809,7 +106806,7 @@
}else{
fts3ReadNextPos(&p2, &i2);
}
- }while( i1!=OFFSET_LIST_END || i2!=OFFSET_LIST_END );
+ }while( i1!=POSITION_LIST_END || i2!=POSITION_LIST_END );
}else if( iCol1<iCol2 ){
p1 += fts3PutColNumber(&p, iCol1);
fts3ColumnlistCopy(&p, &p1);
@@ -99819,7 +106816,7 @@
}
}
- *p++ = '\0';
+ *p++ = POS_END;
*pp = p;
*pp1 = p1 + 1;
*pp2 = p2 + 1;
@@ -99842,11 +106839,11 @@
int iCol1 = 0;
int iCol2 = 0;
assert( *p1!=0 && *p2!=0 );
- if( *p1==0x01 ){
+ if( *p1==POS_COLUMN ){
p1++;
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
}
- if( *p2==0x01 ){
+ if( *p2==POS_COLUMN ){
p2++;
p2 += sqlite3Fts3GetVarint32(p2, &iCol2);
}
@@ -99859,11 +106856,12 @@
sqlite3_int64 iPos2 = 0;
if( pp && iCol1 ){
- *p++ = 0x01;
+ *p++ = POS_COLUMN;
p += sqlite3Fts3PutVarint(p, iCol1);
}
- assert( *p1!=0x00 && *p2!=0x00 && *p1!=0x01 && *p2!=0x01 );
+ assert( *p1!=POS_END && *p1!=POS_COLUMN );
+ assert( *p2!=POS_END && *p2!=POS_COLUMN );
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
@@ -100115,6 +107113,7 @@
default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); {
char *aTmp = 0;
char **ppPos = 0;
+
if( mergetype==MERGE_POS_NEAR ){
ppPos = &p;
aTmp = sqlite3_malloc(2*(n1+n2+1));
@@ -100219,9 +107218,9 @@
**
** The returned doclist may be in one of two formats, depending on the
** value of parameter isReqPos. If isReqPos is zero, then the doclist is
-** a sorted list of delta-compressed docids. If isReqPos is non-zero,
-** then the returned list is in the same format as is stored in the
-** database without the found length specifier at the start of on-disk
+** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
+** is non-zero, then the returned list is in the same format as is stored
+** in the database without the found length specifier at the start of on-disk
** doclists.
*/
static int fts3TermSelect(
@@ -100411,9 +107410,79 @@
return rc;
}
+static int fts3NearMerge(
+ int mergetype, /* MERGE_POS_NEAR or MERGE_NEAR */
+ int nNear, /* Parameter to NEAR operator */
+ int nTokenLeft, /* Number of tokens in LHS phrase arg */
+ char *aLeft, /* Doclist for LHS (incl. positions) */
+ int nLeft, /* Size of LHS doclist in bytes */
+ int nTokenRight, /* As nTokenLeft */
+ char *aRight, /* As aLeft */
+ int nRight, /* As nRight */
+ char **paOut, /* OUT: Results of merge (malloced) */
+ int *pnOut /* OUT: Sized of output buffer */
+){
+ char *aOut;
+ int rc;
+
+ assert( mergetype==MERGE_POS_NEAR || MERGE_NEAR );
+
+ aOut = sqlite3_malloc(nLeft+nRight+1);
+ if( aOut==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = fts3DoclistMerge(mergetype, nNear+nTokenRight, nNear+nTokenLeft,
+ aOut, pnOut, aLeft, nLeft, aRight, nRight
+ );
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(aOut);
+ aOut = 0;
+ }
+ }
+
+ *paOut = aOut;
+ return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
+ int rc;
+ if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
+ sqlite3_free(pLeft->aDoclist);
+ sqlite3_free(pRight->aDoclist);
+ pRight->aDoclist = 0;
+ pLeft->aDoclist = 0;
+ rc = SQLITE_OK;
+ }else{
+ char *aOut;
+ int nOut;
+
+ rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
+ pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
+ pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
+ &aOut, &nOut
+ );
+ if( rc!=SQLITE_OK ) return rc;
+ sqlite3_free(pRight->aDoclist);
+ pRight->aDoclist = aOut;
+ pRight->nDoclist = nOut;
+
+ rc = fts3NearMerge(MERGE_POS_NEAR, nNear,
+ pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
+ pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
+ &aOut, &nOut
+ );
+ sqlite3_free(pLeft->aDoclist);
+ pLeft->aDoclist = aOut;
+ pLeft->nDoclist = nOut;
+ }
+ return rc;
+}
+
/*
** Evaluate the full-text expression pExpr against fts3 table pTab. Store
-** the resulting doclist in *paOut and *pnOut.
+** the resulting doclist in *paOut and *pnOut. This routine mallocs for
+** the space needed to store the output. The caller is responsible for
+** freeing the space when it has finished.
*/
static int evalFts3Expr(
Fts3Table *p, /* Virtual table handle */
@@ -100455,9 +107524,6 @@
Fts3Expr *pLeft;
Fts3Expr *pRight;
int mergetype = isReqPos ? MERGE_POS_NEAR : MERGE_NEAR;
- int nParam1;
- int nParam2;
- char *aBuffer;
if( pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR ){
mergetype = MERGE_POS_NEAR;
@@ -100470,17 +107536,11 @@
assert( pRight->eType==FTSQUERY_PHRASE );
assert( pLeft->eType==FTSQUERY_PHRASE );
- nParam1 = pExpr->nNear+1;
- nParam2 = nParam1+pLeft->pPhrase->nToken+pRight->pPhrase->nToken-2;
- aBuffer = sqlite3_malloc(nLeft+nRight+1);
- rc = fts3DoclistMerge(mergetype, nParam1, nParam2, aBuffer,
- pnOut, aLeft, nLeft, aRight, nRight
+ rc = fts3NearMerge(mergetype, pExpr->nNear,
+ pLeft->pPhrase->nToken, aLeft, nLeft,
+ pRight->pPhrase->nToken, aRight, nRight,
+ paOut, pnOut
);
- if( rc!=SQLITE_OK ){
- sqlite3_free(aBuffer);
- }else{
- *paOut = aBuffer;
- }
sqlite3_free(aLeft);
break;
}
@@ -100595,7 +107655,13 @@
rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn,
iCol, zQuery, -1, &pCsr->pExpr
);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_ERROR ){
+ p->base.zErrMsg = sqlite3_mprintf("malformed MATCH expression: [%s]",
+ zQuery);
+ }
+ return rc;
+ }
rc = evalFts3Expr(p, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
pCsr->pNextId = pCsr->aDoclist;
@@ -100731,7 +107797,7 @@
/*
** After ExprLoadDoclist() (see above) has been called, this function is
-** used to iterate through the position lists that make up the doclist
+** used to iterate/search through the position lists that make up the doclist
** stored in pExpr->aDoclist.
*/
SQLITE_PRIVATE char *sqlite3Fts3FindPositions(
@@ -100748,7 +107814,9 @@
while( pCsr<pEnd ){
if( pExpr->iCurrent<iDocid ){
fts3PoslistCopy(0, &pCsr);
- fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
+ if( pCsr<pEnd ){
+ fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
+ }
pExpr->pCurrent = pCsr;
}else{
if( pExpr->iCurrent==iDocid ){
@@ -100766,7 +107834,7 @@
pCsr++;
pCsr += sqlite3Fts3GetVarint32(pCsr, &iThis);
}
- if( iCol==iThis ) return pCsr;
+ if( iCol==iThis && (*pCsr&0xFE) ) return pCsr;
}
return 0;
}
@@ -100818,45 +107886,8 @@
const char *zStart = "<b>";
const char *zEnd = "</b>";
const char *zEllipsis = "<b>...</b>";
-
- /* There must be at least one argument passed to this function (otherwise
- ** the non-overloaded version would have been called instead of this one).
- */
- assert( nVal>=1 );
-
- if( nVal>4 ){
- sqlite3_result_error(pContext,
- "wrong number of arguments to function snippet()", -1);
- return;
- }
- if( fts3FunctionArg(pContext, "snippet", apVal[0], &pCsr) ) return;
-
- switch( nVal ){
- case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
- case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
- case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
- }
- if( !zEllipsis || !zEnd || !zStart ){
- sqlite3_result_error_nomem(pContext);
- }else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){
- sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis);
- }
-}
-
-/*
-** Implementation of the snippet2() function for FTS3
-*/
-static void fts3Snippet2Func(
- sqlite3_context *pContext, /* SQLite function call context */
- int nVal, /* Size of apVal[] array */
- sqlite3_value **apVal /* Array of arguments */
-){
- Fts3Cursor *pCsr; /* Cursor handle passed through apVal[0] */
- const char *zStart = "<b>";
- const char *zEnd = "</b>";
- const char *zEllipsis = "<b>...</b>";
int iCol = -1;
- int nToken = 10;
+ int nToken = 15; /* Default number of tokens in snippet */
/* There must be at least one argument passed to this function (otherwise
** the non-overloaded version would have been called instead of this one).
@@ -100880,7 +107911,7 @@
if( !zEllipsis || !zEnd || !zStart ){
sqlite3_result_error_nomem(pContext);
}else if( SQLITE_OK==fts3CursorSeek(pContext, pCsr) ){
- sqlite3Fts3Snippet2(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken);
+ sqlite3Fts3Snippet(pContext, pCsr, zStart, zEnd, zEllipsis, iCol, nToken);
}
}
@@ -100981,7 +108012,6 @@
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aOverload[] = {
{ "snippet", fts3SnippetFunc },
- { "snippet2", fts3Snippet2Func },
{ "offsets", fts3OffsetsFunc },
{ "optimize", fts3OptimizeFunc },
{ "matchinfo", fts3MatchinfoFunc },
@@ -101010,22 +108040,35 @@
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
- Fts3Table *p = (Fts3Table *)pVtab;
- int rc = SQLITE_NOMEM; /* Return Code */
- char *zSql; /* SQL script to run to rename tables */
+ Fts3Table *p = (Fts3Table *)pVtab;
+ sqlite3 *db; /* Database connection */
+ int rc; /* Return Code */
- zSql = sqlite3_mprintf(
- "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';"
- "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';"
- "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';"
- , p->zDb, p->zName, zName
- , p->zDb, p->zName, zName
- , p->zDb, p->zName, zName
+ db = p->db;
+ rc = SQLITE_OK;
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
+ p->zDb, p->zName, zName
);
- if( zSql ){
- rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
- sqlite3_free(zSql);
+ if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
+ if( p->bHasDocsize ){
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
+ p->zDb, p->zName, zName
+ );
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_stat' RENAME TO '%q_stat';",
+ p->zDb, p->zName, zName
+ );
}
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';",
+ p->zDb, p->zName, zName
+ );
+ fts3DbExec(&rc, db,
+ "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
+ p->zDb, p->zName, zName
+ );
return rc;
}
@@ -101131,14 +108174,19 @@
if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
- && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet2", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
){
- return sqlite3_create_module_v2(
+ rc = sqlite3_create_module_v2(
db, "fts3", &fts3Module, (void *)pHash, hashDestroy
);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module_v2(
+ db, "fts4", &fts3Module, (void *)pHash, 0
+ );
+ }
+ return rc;
}
/* An error has occurred. Delete the hash table and return the error code. */
@@ -103068,9 +110116,11 @@
if( c->iOffset>iStartOffset ){
int n = c->iOffset-iStartOffset;
if( n>c->nAllocated ){
+ char *pNew;
c->nAllocated = n+20;
- c->zToken = sqlite3_realloc(c->zToken, c->nAllocated);
- if( c->zToken==NULL ) return SQLITE_NOMEM;
+ pNew = sqlite3_realloc(c->zToken, c->nAllocated);
+ if( !pNew ) return SQLITE_NOMEM;
+ c->zToken = pNew;
}
porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes);
*pzToken = c->zToken;
@@ -103781,9 +110831,11 @@
if( c->iOffset>iStartOffset ){
int i, n = c->iOffset-iStartOffset;
if( n>c->nTokenAllocated ){
+ char *pNew;
c->nTokenAllocated = n+20;
- c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated);
- if( c->pToken==NULL ) return SQLITE_NOMEM;
+ pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
+ if( !pNew ) return SQLITE_NOMEM;
+ c->pToken = pNew;
}
for(i=0; i<n; i++){
/* TODO(shess) This needs expansion to handle UTF-8
@@ -103967,19 +111019,26 @@
#define SQL_DELETE_ALL_CONTENT 2
#define SQL_DELETE_ALL_SEGMENTS 3
#define SQL_DELETE_ALL_SEGDIR 4
-#define SQL_SELECT_CONTENT_BY_ROWID 5
-#define SQL_NEXT_SEGMENT_INDEX 6
-#define SQL_INSERT_SEGMENTS 7
-#define SQL_NEXT_SEGMENTS_ID 8
-#define SQL_INSERT_SEGDIR 9
-#define SQL_SELECT_LEVEL 10
-#define SQL_SELECT_ALL_LEVEL 11
-#define SQL_SELECT_LEVEL_COUNT 12
-#define SQL_SELECT_SEGDIR_COUNT_MAX 13
-#define SQL_DELETE_SEGDIR_BY_LEVEL 14
-#define SQL_DELETE_SEGMENTS_RANGE 15
-#define SQL_CONTENT_INSERT 16
-#define SQL_GET_BLOCK 17
+#define SQL_DELETE_ALL_DOCSIZE 5
+#define SQL_DELETE_ALL_STAT 6
+#define SQL_SELECT_CONTENT_BY_ROWID 7
+#define SQL_NEXT_SEGMENT_INDEX 8
+#define SQL_INSERT_SEGMENTS 9
+#define SQL_NEXT_SEGMENTS_ID 10
+#define SQL_INSERT_SEGDIR 11
+#define SQL_SELECT_LEVEL 12
+#define SQL_SELECT_ALL_LEVEL 13
+#define SQL_SELECT_LEVEL_COUNT 14
+#define SQL_SELECT_SEGDIR_COUNT_MAX 15
+#define SQL_DELETE_SEGDIR_BY_LEVEL 16
+#define SQL_DELETE_SEGMENTS_RANGE 17
+#define SQL_CONTENT_INSERT 18
+#define SQL_GET_BLOCK 19
+#define SQL_DELETE_DOCSIZE 20
+#define SQL_REPLACE_DOCSIZE 21
+#define SQL_SELECT_DOCSIZE 22
+#define SQL_SELECT_DOCTOTAL 23
+#define SQL_REPLACE_DOCTOTAL 24
/*
** This function is used to obtain an SQLite prepared statement handle
@@ -104004,25 +111063,32 @@
/* 2 */ "DELETE FROM %Q.'%q_content'",
/* 3 */ "DELETE FROM %Q.'%q_segments'",
/* 4 */ "DELETE FROM %Q.'%q_segdir'",
-/* 5 */ "SELECT * FROM %Q.'%q_content' WHERE rowid=?",
-/* 6 */ "SELECT coalesce(max(idx)+1, 0) FROM %Q.'%q_segdir' WHERE level=?",
-/* 7 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
-/* 8 */ "SELECT coalesce(max(blockid)+1, 1) FROM %Q.'%q_segments'",
-/* 9 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
+/* 5 */ "DELETE FROM %Q.'%q_docsize'",
+/* 6 */ "DELETE FROM %Q.'%q_stat'",
+/* 7 */ "SELECT * FROM %Q.'%q_content' WHERE rowid=?",
+/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
+/* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
+/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
+/* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
/* Return segments in order from oldest to newest.*/
-/* 10 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
+/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC",
-/* 11 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
+/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' ORDER BY level DESC, idx ASC",
-/* 12 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
-/* 13 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'",
+/* 14 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
+/* 15 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'",
-/* 14 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
-/* 15 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
-/* 16 */ "INSERT INTO %Q.'%q_content' VALUES(%z)",
-/* 17 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
+/* 16 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
+/* 17 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
+/* 18 */ "INSERT INTO %Q.'%q_content' VALUES(%z)",
+/* 19 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?",
+/* 20 */ "DELETE FROM %Q.'%q_docsize' WHERE docid = ?",
+/* 21 */ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",
+/* 22 */ "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
+/* 23 */ "SELECT value FROM %Q.'%q_stat' WHERE id=0",
+/* 24 */ "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
};
int rc = SQLITE_OK;
sqlite3_stmt *pStmt;
@@ -104079,14 +111145,21 @@
** Returns SQLITE_OK if the statement is successfully executed, or an
** SQLite error code otherwise.
*/
-static int fts3SqlExec(Fts3Table *p, int eStmt, sqlite3_value **apVal){
+static void fts3SqlExec(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* The FTS3 table */
+ int eStmt, /* Index of statement to evaluate */
+ sqlite3_value **apVal /* Parameters to bind */
+){
sqlite3_stmt *pStmt;
- int rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
+ int rc;
+ if( *pRC ) return;
+ rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
if( rc==SQLITE_OK ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
}
- return rc;
+ *pRC = rc;
}
@@ -104266,11 +111339,17 @@
**
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
-static int fts3PendingTermsAdd(Fts3Table *p, const char *zText, int iCol){
+static int fts3PendingTermsAdd(
+ Fts3Table *p, /* FTS table into which text will be inserted */
+ const char *zText, /* Text of document to be inseted */
+ int iCol, /* Column number into which text is inserted */
+ u32 *pnWord /* OUT: Number of tokens inserted */
+){
int rc;
int iStart;
int iEnd;
int iPos;
+ int nWord = 0;
char const *zToken;
int nToken;
@@ -104294,6 +111373,8 @@
&& SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos))
){
PendingList *pList;
+
+ if( iPos>=nWord ) nWord = iPos+1;
/* Positions cannot be negative; we use -1 as a terminator internally.
** Tokens must have a non-zero length.
@@ -104323,6 +111404,7 @@
}
pModule->xClose(pCsr);
+ *pnWord = nWord;
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
}
@@ -104363,12 +111445,12 @@
** Argument apVal is the same as the similarly named argument passed to
** fts3InsertData(). Parameter iDocid is the docid of the new row.
*/
-static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal){
+static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
int i; /* Iterator variable */
for(i=2; i<p->nColumn+2; i++){
const char *zText = (const char *)sqlite3_value_text(apVal[i]);
if( zText ){
- int rc = fts3PendingTermsAdd(p, zText, i-2);
+ int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -104449,18 +111531,18 @@
** pending terms.
*/
static int fts3DeleteAll(Fts3Table *p){
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
/* Discard the contents of the pending-terms hash table. */
sqlite3Fts3PendingTermsClear(p);
/* Delete everything from the %_content, %_segments and %_segdir tables. */
- rc = fts3SqlExec(p, SQL_DELETE_ALL_CONTENT, 0);
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGMENTS, 0);
- }
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGDIR, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_STAT, 0);
}
return rc;
}
@@ -104470,20 +111552,27 @@
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
-static int fts3DeleteTerms(Fts3Table *p, sqlite3_value **apVal){
+static void fts3DeleteTerms(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* The FTS table to delete from */
+ sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */
+ u32 *aSz /* Sizes of deleted document written here */
+){
int rc;
sqlite3_stmt *pSelect;
+ if( *pRC ) return;
rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pSelect) ){
int i;
for(i=1; i<=p->nColumn; i++){
const char *zText = (const char *)sqlite3_column_text(pSelect, i);
- rc = fts3PendingTermsAdd(p, zText, -1);
+ rc = fts3PendingTermsAdd(p, zText, -1, &aSz[i-1]);
if( rc!=SQLITE_OK ){
sqlite3_reset(pSelect);
- return rc;
+ *pRC = rc;
+ return;
}
}
}
@@ -104491,7 +111580,7 @@
}else{
sqlite3_reset(pSelect);
}
- return rc;
+ *pRC = rc;
}
/*
@@ -105611,7 +112700,7 @@
rc = sqlite3_reset(pDelete);
}
}else{
- rc = fts3SqlExec(p, SQL_DELETE_ALL_SEGDIR, 0);
+ fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
}
return rc;
@@ -106040,6 +113129,211 @@
}
/*
+** Encode N integers as varints into a blob.
+*/
+static void fts3EncodeIntArray(
+ int N, /* The number of integers to encode */
+ u32 *a, /* The integer values */
+ char *zBuf, /* Write the BLOB here */
+ int *pNBuf /* Write number of bytes if zBuf[] used here */
+){
+ int i, j;
+ for(i=j=0; i<N; i++){
+ j += sqlite3Fts3PutVarint(&zBuf[j], (sqlite3_int64)a[i]);
+ }
+ *pNBuf = j;
+}
+
+/*
+** Decode a blob of varints into N integers
+*/
+static void fts3DecodeIntArray(
+ int N, /* The number of integers to decode */
+ u32 *a, /* Write the integer values */
+ const char *zBuf, /* The BLOB containing the varints */
+ int nBuf /* size of the BLOB */
+){
+ int i, j;
+ UNUSED_PARAMETER(nBuf);
+ for(i=j=0; i<N; i++){
+ sqlite3_int64 x;
+ j += sqlite3Fts3GetVarint(&zBuf[j], &x);
+ assert(j<=nBuf);
+ a[i] = (u32)(x & 0xffffffff);
+ }
+}
+
+/*
+** Fill in the document size auxiliary information for the matchinfo
+** structure. The auxiliary information is:
+**
+** N Total number of documents in the full-text index
+** a0 Average length of column 0 over the whole index
+** n0 Length of column 0 on the matching row
+** ...
+** aM Average length of column M over the whole index
+** nM Length of column M on the matching row
+**
+** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
+** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
+*/
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
+ const char *pBlob; /* The BLOB holding %_docsize info */
+ int nBlob; /* Size of the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i, j; /* Loop counters */
+ sqlite3_int64 x; /* Varint value */
+ int rc; /* Result code from subfunctions */
+ Fts3Table *p; /* The FTS table */
+
+ p = (Fts3Table*)pCur->base.pVtab;
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
+ if( rc ){
+ return rc;
+ }
+ sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ nBlob = sqlite3_column_bytes(pStmt, 0);
+ pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
+ for(i=j=0; i<p->nColumn && j<nBlob; i++){
+ j = sqlite3Fts3GetVarint(&pBlob[j], &x);
+ a[2+i*2] = (u32)(x & 0xffffffff);
+ }
+ }
+ sqlite3_reset(pStmt);
+ return SQLITE_OK;
+}
+SQLITE_PRIVATE int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
+ const char *pBlob; /* The BLOB holding %_stat info */
+ int nBlob; /* Size of the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i, j; /* Loop counters */
+ sqlite3_int64 x; /* Varint value */
+ int nDoc; /* Number of documents */
+ int rc; /* Result code from subfunctions */
+ Fts3Table *p; /* The FTS table */
+
+ p = (Fts3Table*)pCur->base.pVtab;
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ return rc;
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ nBlob = sqlite3_column_bytes(pStmt, 0);
+ pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
+ j = sqlite3Fts3GetVarint(pBlob, &x);
+ a[0] = nDoc = (u32)(x & 0xffffffff);
+ for(i=0; i<p->nColumn && j<nBlob; i++){
+ j = sqlite3Fts3GetVarint(&pBlob[j], &x);
+ a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
+ }
+ }
+ sqlite3_reset(pStmt);
+ return SQLITE_OK;
+}
+
+/*
+** Insert the sizes (in tokens) for each column of the document
+** with docid equal to p->iPrevDocid. The sizes are encoded as
+** a blob of varints.
+*/
+static void fts3InsertDocsize(
+ int *pRC, /* Result code */
+ Fts3Table *p, /* Table into which to insert */
+ u32 *aSz /* Sizes of each column */
+){
+ char *pBlob; /* The BLOB encoding of the document size */
+ int nBlob; /* Number of bytes in the BLOB */
+ sqlite3_stmt *pStmt; /* Statement used to insert the encoding */
+ int rc; /* Result code from subfunctions */
+
+ if( *pRC ) return;
+ pBlob = sqlite3_malloc( 10*p->nColumn );
+ if( pBlob==0 ){
+ *pRC = SQLITE_NOMEM;
+ return;
+ }
+ fts3EncodeIntArray(p->nColumn, aSz, pBlob, &nBlob);
+ rc = fts3SqlStmt(p, SQL_REPLACE_DOCSIZE, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(pBlob);
+ *pRC = rc;
+ return;
+ }
+ sqlite3_bind_int64(pStmt, 1, p->iPrevDocid);
+ sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, sqlite3_free);
+ sqlite3_step(pStmt);
+ *pRC = sqlite3_reset(pStmt);
+}
+
+/*
+** Update the 0 record of the %_stat table so that it holds a blob
+** which contains the document count followed by the cumulative
+** document sizes for all columns.
+*/
+static void fts3UpdateDocTotals(
+ int *pRC, /* The result code */
+ Fts3Table *p, /* Table being updated */
+ u32 *aSzIns, /* Size increases */
+ u32 *aSzDel, /* Size decreases */
+ int nChng /* Change in the number of documents */
+){
+ char *pBlob; /* Storage for BLOB written into %_stat */
+ int nBlob; /* Size of BLOB written into %_stat */
+ u32 *a; /* Array of integers that becomes the BLOB */
+ sqlite3_stmt *pStmt; /* Statement for reading and writing */
+ int i; /* Loop counter */
+ int rc; /* Result code from subfunctions */
+
+ if( *pRC ) return;
+ a = sqlite3_malloc( (sizeof(u32)+10)*(p->nColumn+1) );
+ if( a==0 ){
+ *pRC = SQLITE_NOMEM;
+ return;
+ }
+ pBlob = (char*)&a[p->nColumn+1];
+ rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(a);
+ *pRC = rc;
+ return;
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ fts3DecodeIntArray(p->nColumn+1, a,
+ sqlite3_column_blob(pStmt, 0),
+ sqlite3_column_bytes(pStmt, 0));
+ }else{
+ memset(a, 0, sizeof(u32)*(p->nColumn+1) );
+ }
+ sqlite3_reset(pStmt);
+ if( nChng<0 && a[0]<(u32)(-nChng) ){
+ a[0] = 0;
+ }else{
+ a[0] += nChng;
+ }
+ for(i=0; i<p->nColumn; i++){
+ u32 x = a[i+1];
+ if( x+aSzIns[i] < aSzDel[i] ){
+ x = 0;
+ }else{
+ x = x + aSzIns[i] - aSzDel[i];
+ }
+ a[i+1] = x;
+ }
+ fts3EncodeIntArray(p->nColumn+1, a, pBlob, &nBlob);
+ rc = fts3SqlStmt(p, SQL_REPLACE_DOCTOTAL, &pStmt, 0);
+ if( rc ){
+ sqlite3_free(a);
+ *pRC = rc;
+ return;
+ }
+ sqlite3_bind_blob(pStmt, 1, pBlob, nBlob, SQLITE_STATIC);
+ sqlite3_step(pStmt);
+ *pRC = sqlite3_reset(pStmt);
+ sqlite3_free(a);
+}
+
+/*
** Handle a 'special' INSERT of the form:
**
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
@@ -106090,8 +113384,17 @@
int rc = SQLITE_OK; /* Return Code */
int isRemove = 0; /* True for an UPDATE or DELETE */
sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */
+ u32 *aSzIns; /* Sizes of inserted documents */
+ u32 *aSzDel; /* Sizes of deleted documents */
+ int nChng = 0; /* Net change in number of documents */
+ /* Allocate space to hold the change in document sizes */
+ aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*p->nColumn*2 );
+ if( aSzIns==0 ) return SQLITE_NOMEM;
+ aSzDel = &aSzIns[p->nColumn];
+ memset(aSzIns, 0, sizeof(aSzIns[0])*p->nColumn*2);
+
/* If this is a DELETE or UPDATE operation, remove the old record. */
if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
int isEmpty;
@@ -106107,15 +113410,16 @@
isRemove = 1;
iRemove = sqlite3_value_int64(apVal[0]);
rc = fts3PendingTermsDocid(p, iRemove);
- if( rc==SQLITE_OK ){
- rc = fts3DeleteTerms(p, apVal);
- if( rc==SQLITE_OK ){
- rc = fts3SqlExec(p, SQL_DELETE_CONTENT, apVal);
- }
+ fts3DeleteTerms(&rc, p, apVal, aSzDel);
+ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
+ if( p->bHasDocsize ){
+ fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
+ nChng--;
}
}
}
}else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
+ sqlite3_free(aSzIns);
return fts3SpecialInsert(p, apVal[p->nColumn+2]);
}
@@ -106126,10 +113430,19 @@
rc = fts3PendingTermsDocid(p, *pRowid);
}
if( rc==SQLITE_OK ){
- rc = fts3InsertTerms(p, apVal);
+ rc = fts3InsertTerms(p, apVal, aSzIns);
+ }
+ if( p->bHasDocsize ){
+ nChng++;
+ fts3InsertDocsize(&rc, p, aSzIns);
}
}
+ if( p->bHasDocsize ){
+ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
+ }
+
+ sqlite3_free(aSzIns);
return rc;
}
@@ -106176,727 +113489,97 @@
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-typedef struct Snippet Snippet;
/*
-** An instance of the following structure keeps track of generated
-** matching-word offset information and snippets.
+** Used as an fts3ExprIterate() context when loading phrase doclists to
+** Fts3Expr.aDoclist[]/nDoclist.
*/
-struct Snippet {
- int nMatch; /* Total number of matches */
- int nAlloc; /* Space allocated for aMatch[] */
- struct snippetMatch { /* One entry for each matching term */
- char snStatus; /* Status flag for use while constructing snippets */
- short int nByte; /* Number of bytes in the term */
- short int iCol; /* The column that contains the match */
- short int iTerm; /* The index in Query.pTerms[] of the matching term */
- int iToken; /* The index of the matching document token */
- int iStart; /* The offset to the first character of the term */
- } *aMatch; /* Points to space obtained from malloc */
- char *zOffset; /* Text rendering of aMatch[] */
- int nOffset; /* strlen(zOffset) */
- char *zSnippet; /* Snippet text */
- int nSnippet; /* strlen(zSnippet) */
+typedef struct LoadDoclistCtx LoadDoclistCtx;
+struct LoadDoclistCtx {
+ Fts3Table *pTab; /* FTS3 Table */
+ int nPhrase; /* Number of phrases seen so far */
+ int nToken; /* Number of tokens seen so far */
+};
+
+/*
+** The following types are used as part of the implementation of the
+** fts3BestSnippet() routine.
+*/
+typedef struct SnippetIter SnippetIter;
+typedef struct SnippetPhrase SnippetPhrase;
+typedef struct SnippetFragment SnippetFragment;
+
+struct SnippetIter {
+ Fts3Cursor *pCsr; /* Cursor snippet is being generated from */
+ int iCol; /* Extract snippet from this column */
+ int nSnippet; /* Requested snippet length (in tokens) */
+ int nPhrase; /* Number of phrases in query */
+ SnippetPhrase *aPhrase; /* Array of size nPhrase */
+ int iCurrent; /* First token of current snippet */
+};
+
+struct SnippetPhrase {
+ int nToken; /* Number of tokens in phrase */
+ char *pList; /* Pointer to start of phrase position list */
+ int iHead; /* Next value in position list */
+ char *pHead; /* Position list data following iHead */
+ int iTail; /* Next value in trailing position list */
+ char *pTail; /* Position list data following iTail */
+};
+
+struct SnippetFragment {
+ int iCol; /* Column snippet is extracted from */
+ int iPos; /* Index of first token in snippet */
+ u64 covered; /* Mask of query phrases covered */
+ u64 hlmask; /* Mask of snippet terms to highlight */
+};
+
+/*
+** This type is used as an fts3ExprIterate() context object while
+** accumulating the data returned by the matchinfo() function.
+*/
+typedef struct MatchInfo MatchInfo;
+struct MatchInfo {
+ Fts3Cursor *pCursor; /* FTS3 Cursor */
+ int nCol; /* Number of columns in table */
+ u32 *aMatchinfo; /* Pre-allocated buffer */
};
-/* It is not safe to call isspace(), tolower(), or isalnum() on
-** hi-bit-set characters. This is the same solution used in the
-** tokenizer.
+
+/*
+** The snippet() and offsets() functions both return text values. An instance
+** of the following structure is used to accumulate those values while the
+** functions are running. See fts3StringAppend() for details.
*/
-static int fts3snippetIsspace(char c){
- return (c&0x80)==0 ? isspace(c) : 0;
-}
+typedef struct StrBuffer StrBuffer;
+struct StrBuffer {
+ char *z; /* Pointer to buffer containing string */
+ int n; /* Length of z in bytes (excl. nul-term) */
+ int nAlloc; /* Allocated size of buffer z in bytes */
+};
/*
-** A StringBuffer object holds a zero-terminated string that grows
-** arbitrarily by appending. Space to hold the string is obtained
-** from sqlite3_malloc(). After any memory allocation failure,
-** StringBuffer.z is set to NULL and no further allocation is attempted.
-*/
-typedef struct StringBuffer {
- char *z; /* Text of the string. Space from malloc. */
- int nUsed; /* Number bytes of z[] used, not counting \000 terminator */
- int nAlloc; /* Bytes allocated for z[] */
-} StringBuffer;
-
-
-/*
-** Initialize a new StringBuffer.
-*/
-static void fts3SnippetSbInit(StringBuffer *p){
- p->nAlloc = 100;
- p->nUsed = 0;
- p->z = sqlite3_malloc( p->nAlloc );
-}
-
-/*
-** Append text to the string buffer.
-*/
-static void fts3SnippetAppend(StringBuffer *p, const char *zNew, int nNew){
- if( p->z==0 ) return;
- if( nNew<0 ) nNew = (int)strlen(zNew);
- if( p->nUsed + nNew >= p->nAlloc ){
- int nAlloc;
- char *zNew;
-
- nAlloc = p->nUsed + nNew + p->nAlloc;
- zNew = sqlite3_realloc(p->z, nAlloc);
- if( zNew==0 ){
- sqlite3_free(p->z);
- p->z = 0;
- return;
- }
- p->z = zNew;
- p->nAlloc = nAlloc;
- }
- memcpy(&p->z[p->nUsed], zNew, nNew);
- p->nUsed += nNew;
- p->z[p->nUsed] = 0;
-}
-
-/* If the StringBuffer ends in something other than white space, add a
-** single space character to the end.
-*/
-static void fts3SnippetAppendWhiteSpace(StringBuffer *p){
- if( p->z && p->nUsed && !fts3snippetIsspace(p->z[p->nUsed-1]) ){
- fts3SnippetAppend(p, " ", 1);
- }
-}
-
-/* Remove white space from the end of the StringBuffer */
-static void fts3SnippetTrimWhiteSpace(StringBuffer *p){
- if( p->z ){
- while( p->nUsed && fts3snippetIsspace(p->z[p->nUsed-1]) ){
- p->nUsed--;
- }
- p->z[p->nUsed] = 0;
- }
-}
-
-/*
-** Release all memory associated with the Snippet structure passed as
-** an argument.
-*/
-static void fts3SnippetFree(Snippet *p){
- if( p ){
- sqlite3_free(p->aMatch);
- sqlite3_free(p->zOffset);
- sqlite3_free(p->zSnippet);
- sqlite3_free(p);
- }
-}
-
-/*
-** Append a single entry to the p->aMatch[] log.
-*/
-static int snippetAppendMatch(
- Snippet *p, /* Append the entry to this snippet */
- int iCol, int iTerm, /* The column and query term */
- int iToken, /* Matching token in document */
- int iStart, int nByte /* Offset and size of the match */
-){
- int i;
- struct snippetMatch *pMatch;
- if( p->nMatch+1>=p->nAlloc ){
- struct snippetMatch *pNew;
- p->nAlloc = p->nAlloc*2 + 10;
- pNew = sqlite3_realloc(p->aMatch, p->nAlloc*sizeof(p->aMatch[0]) );
- if( pNew==0 ){
- p->aMatch = 0;
- p->nMatch = 0;
- p->nAlloc = 0;
- return SQLITE_NOMEM;
- }
- p->aMatch = pNew;
- }
- i = p->nMatch++;
- pMatch = &p->aMatch[i];
- pMatch->iCol = (short)iCol;
- pMatch->iTerm = (short)iTerm;
- pMatch->iToken = iToken;
- pMatch->iStart = iStart;
- pMatch->nByte = (short)nByte;
- return SQLITE_OK;
-}
-
-/*
-** Sizing information for the circular buffer used in snippetOffsetsOfColumn()
-*/
-#define FTS3_ROTOR_SZ (32)
-#define FTS3_ROTOR_MASK (FTS3_ROTOR_SZ-1)
-
-/*
-** Function to iterate through the tokens of a compiled expression.
+** This function is used to help iterate through a position-list. A position
+** list is a list of unique integers, sorted from smallest to largest. Each
+** element of the list is represented by an FTS3 varint that takes the value
+** of the difference between the current element and the previous one plus
+** two. For example, to store the position-list:
**
-** Except, skip all tokens on the right-hand side of a NOT operator.
-** This function is used to find tokens as part of snippet and offset
-** generation and we do nt want snippets and offsets to report matches
-** for tokens on the RHS of a NOT.
-*/
-static int fts3NextExprToken(Fts3Expr **ppExpr, int *piToken){
- Fts3Expr *p = *ppExpr;
- int iToken = *piToken;
- if( iToken<0 ){
- /* In this case the expression p is the root of an expression tree.
- ** Move to the first token in the expression tree.
- */
- while( p->pLeft ){
- p = p->pLeft;
- }
- iToken = 0;
- }else{
- assert(p && p->eType==FTSQUERY_PHRASE );
- if( iToken<(p->pPhrase->nToken-1) ){
- iToken++;
- }else{
- iToken = 0;
- while( p->pParent && p->pParent->pLeft!=p ){
- assert( p->pParent->pRight==p );
- p = p->pParent;
- }
- p = p->pParent;
- if( p ){
- assert( p->pRight!=0 );
- p = p->pRight;
- while( p->pLeft ){
- p = p->pLeft;
- }
- }
- }
- }
-
- *ppExpr = p;
- *piToken = iToken;
- return p?1:0;
-}
-
-/*
-** Return TRUE if the expression node pExpr is located beneath the
-** RHS of a NOT operator.
-*/
-static int fts3ExprBeneathNot(Fts3Expr *p){
- Fts3Expr *pParent;
- while( p ){
- pParent = p->pParent;
- if( pParent && pParent->eType==FTSQUERY_NOT && pParent->pRight==p ){
- return 1;
- }
- p = pParent;
- }
- return 0;
-}
-
-/*
-** Add entries to pSnippet->aMatch[] for every match that occurs against
-** document zDoc[0..nDoc-1] which is stored in column iColumn.
-*/
-static int snippetOffsetsOfColumn(
- Fts3Cursor *pCur, /* The fulltest search cursor */
- Snippet *pSnippet, /* The Snippet object to be filled in */
- int iColumn, /* Index of fulltext table column */
- const char *zDoc, /* Text of the fulltext table column */
- int nDoc /* Length of zDoc in bytes */
-){
- const sqlite3_tokenizer_module *pTModule; /* The tokenizer module */
- sqlite3_tokenizer *pTokenizer; /* The specific tokenizer */
- sqlite3_tokenizer_cursor *pTCursor; /* Tokenizer cursor */
- Fts3Table *pVtab; /* The full text index */
- int nColumn; /* Number of columns in the index */
- int i, j; /* Loop counters */
- int rc; /* Return code */
- unsigned int match, prevMatch; /* Phrase search bitmasks */
- const char *zToken; /* Next token from the tokenizer */
- int nToken; /* Size of zToken */
- int iBegin, iEnd, iPos; /* Offsets of beginning and end */
-
- /* The following variables keep a circular buffer of the last
- ** few tokens */
- unsigned int iRotor = 0; /* Index of current token */
- int iRotorBegin[FTS3_ROTOR_SZ]; /* Beginning offset of token */
- int iRotorLen[FTS3_ROTOR_SZ]; /* Length of token */
-
- pVtab = (Fts3Table *)pCur->base.pVtab;
- nColumn = pVtab->nColumn;
- pTokenizer = pVtab->pTokenizer;
- pTModule = pTokenizer->pModule;
- rc = pTModule->xOpen(pTokenizer, zDoc, nDoc, &pTCursor);
- if( rc ) return rc;
- pTCursor->pTokenizer = pTokenizer;
-
- prevMatch = 0;
- while( (rc = pTModule->xNext(pTCursor, &zToken, &nToken,
- &iBegin, &iEnd, &iPos))==SQLITE_OK ){
- Fts3Expr *pIter = pCur->pExpr;
- int iIter = -1;
- iRotorBegin[iRotor&FTS3_ROTOR_MASK] = iBegin;
- iRotorLen[iRotor&FTS3_ROTOR_MASK] = iEnd-iBegin;
- match = 0;
- for(i=0; i<(FTS3_ROTOR_SZ-1) && fts3NextExprToken(&pIter, &iIter); i++){
- int nPhrase; /* Number of tokens in current phrase */
- struct PhraseToken *pToken; /* Current token */
- int iCol; /* Column index */
-
- if( fts3ExprBeneathNot(pIter) ) continue;
- nPhrase = pIter->pPhrase->nToken;
- pToken = &pIter->pPhrase->aToken[iIter];
- iCol = pIter->pPhrase->iColumn;
- if( iCol>=0 && iCol<nColumn && iCol!=iColumn ) continue;
- if( pToken->n>nToken ) continue;
- if( !pToken->isPrefix && pToken->n<nToken ) continue;
- assert( pToken->n<=nToken );
- if( memcmp(pToken->z, zToken, pToken->n) ) continue;
- if( iIter>0 && (prevMatch & (1<<i))==0 ) continue;
- match |= 1<<i;
- if( i==(FTS3_ROTOR_SZ-2) || nPhrase==iIter+1 ){
- for(j=nPhrase-1; j>=0; j--){
- int k = (iRotor-j) & FTS3_ROTOR_MASK;
- rc = snippetAppendMatch(pSnippet, iColumn, i-j, iPos-j,
- iRotorBegin[k], iRotorLen[k]);
- if( rc ) goto end_offsets_of_column;
- }
- }
- }
- prevMatch = match<<1;
- iRotor++;
- }
-end_offsets_of_column:
- pTModule->xClose(pTCursor);
- return rc==SQLITE_DONE ? SQLITE_OK : rc;
-}
-
-/*
-** Remove entries from the pSnippet structure to account for the NEAR
-** operator. When this is called, pSnippet contains the list of token
-** offsets produced by treating all NEAR operators as AND operators.
-** This function removes any entries that should not be present after
-** accounting for the NEAR restriction. For example, if the queried
-** document is:
+** 4 9 113
**
-** "A B C D E A"
+** the three varints:
**
-** and the query is:
-**
-** A NEAR/0 E
+** 6 7 106
**
-** then when this function is called the Snippet contains token offsets
-** 0, 4 and 5. This function removes the "0" entry (because the first A
-** is not near enough to an E).
+** are encoded.
**
-** When this function is called, the value pointed to by parameter piLeft is
-** the integer id of the left-most token in the expression tree headed by
-** pExpr. This function increments *piLeft by the total number of tokens
-** in the expression tree headed by pExpr.
-**
-** Return 1 if any trimming occurs. Return 0 if no trimming is required.
+** When this function is called, *pp points to the start of an element of
+** the list. *piPos contains the value of the previous entry in the list.
+** After it returns, *piPos contains the value of the next element of the
+** list and *pp is advanced to the following varint.
*/
-static int trimSnippetOffsets(
- Fts3Expr *pExpr, /* The search expression */
- Snippet *pSnippet, /* The set of snippet offsets to be trimmed */
- int *piLeft /* Index of left-most token in pExpr */
-){
- if( pExpr ){
- if( trimSnippetOffsets(pExpr->pLeft, pSnippet, piLeft) ){
- return 1;
- }
-
- switch( pExpr->eType ){
- case FTSQUERY_PHRASE:
- *piLeft += pExpr->pPhrase->nToken;
- break;
- case FTSQUERY_NEAR: {
- /* The right-hand-side of a NEAR operator is always a phrase. The
- ** left-hand-side is either a phrase or an expression tree that is
- ** itself headed by a NEAR operator. The following initializations
- ** set local variable iLeft to the token number of the left-most
- ** token in the right-hand phrase, and iRight to the right most
- ** token in the same phrase. For example, if we had:
- **
- ** <col> MATCH '"abc def" NEAR/2 "ghi jkl"'
- **
- ** then iLeft will be set to 2 (token number of ghi) and nToken will
- ** be set to 4.
- */
- Fts3Expr *pLeft = pExpr->pLeft;
- Fts3Expr *pRight = pExpr->pRight;
- int iLeft = *piLeft;
- int nNear = pExpr->nNear;
- int nToken = pRight->pPhrase->nToken;
- int jj, ii;
- if( pLeft->eType==FTSQUERY_NEAR ){
- pLeft = pLeft->pRight;
- }
- assert( pRight->eType==FTSQUERY_PHRASE );
- assert( pLeft->eType==FTSQUERY_PHRASE );
- nToken += pLeft->pPhrase->nToken;
-
- for(ii=0; ii<pSnippet->nMatch; ii++){
- struct snippetMatch *p = &pSnippet->aMatch[ii];
- if( p->iTerm==iLeft ){
- int isOk = 0;
- /* Snippet ii is an occurence of query term iLeft in the document.
- ** It occurs at position (p->iToken) of the document. We now
- ** search for an instance of token (iLeft-1) somewhere in the
- ** range (p->iToken - nNear)...(p->iToken + nNear + nToken) within
- ** the set of snippetMatch structures. If one is found, proceed.
- ** If one cannot be found, then remove snippets ii..(ii+N-1)
- ** from the matching snippets, where N is the number of tokens
- ** in phrase pRight->pPhrase.
- */
- for(jj=0; isOk==0 && jj<pSnippet->nMatch; jj++){
- struct snippetMatch *p2 = &pSnippet->aMatch[jj];
- if( p2->iTerm==(iLeft-1) ){
- if( p2->iToken>=(p->iToken-nNear-1)
- && p2->iToken<(p->iToken+nNear+nToken)
- ){
- isOk = 1;
- }
- }
- }
- if( !isOk ){
- int kk;
- for(kk=0; kk<pRight->pPhrase->nToken; kk++){
- pSnippet->aMatch[kk+ii].iTerm = -2;
- }
- return 1;
- }
- }
- if( p->iTerm==(iLeft-1) ){
- int isOk = 0;
- for(jj=0; isOk==0 && jj<pSnippet->nMatch; jj++){
- struct snippetMatch *p2 = &pSnippet->aMatch[jj];
- if( p2->iTerm==iLeft ){
- if( p2->iToken<=(p->iToken+nNear+1)
- && p2->iToken>(p->iToken-nNear-nToken)
- ){
- isOk = 1;
- }
- }
- }
- if( !isOk ){
- int kk;
- for(kk=0; kk<pLeft->pPhrase->nToken; kk++){
- pSnippet->aMatch[ii-kk].iTerm = -2;
- }
- return 1;
- }
- }
- }
- break;
- }
- }
-
- if( trimSnippetOffsets(pExpr->pRight, pSnippet, piLeft) ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** Compute all offsets for the current row of the query.
-** If the offsets have already been computed, this routine is a no-op.
-*/
-static int snippetAllOffsets(Fts3Cursor *pCsr, Snippet **ppSnippet){
- Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; /* The FTS3 virtual table */
- int nColumn; /* Number of columns. Docid does count */
- int iColumn; /* Index of of a column */
- int i; /* Loop index */
- int iFirst; /* First column to search */
- int iLast; /* Last coumn to search */
- int iTerm = 0;
- Snippet *pSnippet;
- int rc = SQLITE_OK;
-
- if( pCsr->pExpr==0 ){
- return SQLITE_OK;
- }
-
- pSnippet = (Snippet *)sqlite3_malloc(sizeof(Snippet));
- *ppSnippet = pSnippet;
- if( !pSnippet ){
- return SQLITE_NOMEM;
- }
- memset(pSnippet, 0, sizeof(Snippet));
-
- nColumn = p->nColumn;
- iColumn = (pCsr->eSearch - 2);
- if( iColumn<0 || iColumn>=nColumn ){
- /* Look for matches over all columns of the full-text index */
- iFirst = 0;
- iLast = nColumn-1;
- }else{
- /* Look for matches in the iColumn-th column of the index only */
- iFirst = iColumn;
- iLast = iColumn;
- }
- for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
- const char *zDoc;
- int nDoc;
- zDoc = (const char*)sqlite3_column_text(pCsr->pStmt, i+1);
- nDoc = sqlite3_column_bytes(pCsr->pStmt, i+1);
- if( zDoc==0 && sqlite3_column_type(pCsr->pStmt, i+1)!=SQLITE_NULL ){
- rc = SQLITE_NOMEM;
- }else{
- rc = snippetOffsetsOfColumn(pCsr, pSnippet, i, zDoc, nDoc);
- }
- }
-
- while( trimSnippetOffsets(pCsr->pExpr, pSnippet, &iTerm) ){
- iTerm = 0;
- }
-
- return rc;
-}
-
-/*
-** Convert the information in the aMatch[] array of the snippet
-** into the string zOffset[0..nOffset-1]. This string is used as
-** the return of the SQL offsets() function.
-*/
-static void snippetOffsetText(Snippet *p){
- int i;
- int cnt = 0;
- StringBuffer sb;
- char zBuf[200];
- if( p->zOffset ) return;
- fts3SnippetSbInit(&sb);
- for(i=0; i<p->nMatch; i++){
- struct snippetMatch *pMatch = &p->aMatch[i];
- if( pMatch->iTerm>=0 ){
- /* If snippetMatch.iTerm is less than 0, then the match was
- ** discarded as part of processing the NEAR operator (see the
- ** trimSnippetOffsetsForNear() function for details). Ignore
- ** it in this case
- */
- zBuf[0] = ' ';
- sqlite3_snprintf(sizeof(zBuf)-1, &zBuf[cnt>0], "%d %d %d %d",
- pMatch->iCol, pMatch->iTerm, pMatch->iStart, pMatch->nByte);
- fts3SnippetAppend(&sb, zBuf, -1);
- cnt++;
- }
- }
- p->zOffset = sb.z;
- p->nOffset = sb.z ? sb.nUsed : 0;
-}
-
-/*
-** zDoc[0..nDoc-1] is phrase of text. aMatch[0..nMatch-1] are a set
-** of matching words some of which might be in zDoc. zDoc is column
-** number iCol.
-**
-** iBreak is suggested spot in zDoc where we could begin or end an
-** excerpt. Return a value similar to iBreak but possibly adjusted
-** to be a little left or right so that the break point is better.
-*/
-static int wordBoundary(
- int iBreak, /* The suggested break point */
- const char *zDoc, /* Document text */
- int nDoc, /* Number of bytes in zDoc[] */
- struct snippetMatch *aMatch, /* Matching words */
- int nMatch, /* Number of entries in aMatch[] */
- int iCol /* The column number for zDoc[] */
-){
- int i;
- if( iBreak<=10 ){
- return 0;
- }
- if( iBreak>=nDoc-10 ){
- return nDoc;
- }
- for(i=0; ALWAYS(i<nMatch) && aMatch[i].iCol<iCol; i++){}
- while( i<nMatch && aMatch[i].iStart+aMatch[i].nByte<iBreak ){ i++; }
- if( i<nMatch ){
- if( aMatch[i].iStart<iBreak+10 ){
- return aMatch[i].iStart;
- }
- if( i>0 && aMatch[i-1].iStart+aMatch[i-1].nByte>=iBreak ){
- return aMatch[i-1].iStart;
- }
- }
- for(i=1; i<=10; i++){
- if( fts3snippetIsspace(zDoc[iBreak-i]) ){
- return iBreak - i + 1;
- }
- if( fts3snippetIsspace(zDoc[iBreak+i]) ){
- return iBreak + i + 1;
- }
- }
- return iBreak;
-}
-
-
-
-/*
-** Allowed values for Snippet.aMatch[].snStatus
-*/
-#define SNIPPET_IGNORE 0 /* It is ok to omit this match from the snippet */
-#define SNIPPET_DESIRED 1 /* We want to include this match in the snippet */
-
-/*
-** Generate the text of a snippet.
-*/
-static void snippetText(
- Fts3Cursor *pCursor, /* The cursor we need the snippet for */
- Snippet *pSnippet,
- const char *zStartMark, /* Markup to appear before each match */
- const char *zEndMark, /* Markup to appear after each match */
- const char *zEllipsis /* Ellipsis mark */
-){
- int i, j;
- struct snippetMatch *aMatch;
- int nMatch;
- int nDesired;
- StringBuffer sb;
- int tailCol;
- int tailOffset;
- int iCol;
- int nDoc;
- const char *zDoc;
- int iStart, iEnd;
- int tailEllipsis = 0;
- int iMatch;
-
-
- sqlite3_free(pSnippet->zSnippet);
- pSnippet->zSnippet = 0;
- aMatch = pSnippet->aMatch;
- nMatch = pSnippet->nMatch;
- fts3SnippetSbInit(&sb);
-
- for(i=0; i<nMatch; i++){
- aMatch[i].snStatus = SNIPPET_IGNORE;
- }
- nDesired = 0;
- for(i=0; i<FTS3_ROTOR_SZ; i++){
- for(j=0; j<nMatch; j++){
- if( aMatch[j].iTerm==i ){
- aMatch[j].snStatus = SNIPPET_DESIRED;
- nDesired++;
- break;
- }
- }
- }
-
- iMatch = 0;
- tailCol = -1;
- tailOffset = 0;
- for(i=0; i<nMatch && nDesired>0; i++){
- if( aMatch[i].snStatus!=SNIPPET_DESIRED ) continue;
- nDesired--;
- iCol = aMatch[i].iCol;
- zDoc = (const char*)sqlite3_column_text(pCursor->pStmt, iCol+1);
- nDoc = sqlite3_column_bytes(pCursor->pStmt, iCol+1);
- iStart = aMatch[i].iStart - 40;
- iStart = wordBoundary(iStart, zDoc, nDoc, aMatch, nMatch, iCol);
- if( iStart<=10 ){
- iStart = 0;
- }
- if( iCol==tailCol && iStart<=tailOffset+20 ){
- iStart = tailOffset;
- }
- if( (iCol!=tailCol && tailCol>=0) || iStart!=tailOffset ){
- fts3SnippetTrimWhiteSpace(&sb);
- fts3SnippetAppendWhiteSpace(&sb);
- fts3SnippetAppend(&sb, zEllipsis, -1);
- fts3SnippetAppendWhiteSpace(&sb);
- }
- iEnd = aMatch[i].iStart + aMatch[i].nByte + 40;
- iEnd = wordBoundary(iEnd, zDoc, nDoc, aMatch, nMatch, iCol);
- if( iEnd>=nDoc-10 ){
- iEnd = nDoc;
- tailEllipsis = 0;
- }else{
- tailEllipsis = 1;
- }
- while( iMatch<nMatch && aMatch[iMatch].iCol<iCol ){ iMatch++; }
- while( iStart<iEnd ){
- while( iMatch<nMatch && aMatch[iMatch].iStart<iStart
- && aMatch[iMatch].iCol<=iCol ){
- iMatch++;
- }
- if( iMatch<nMatch && aMatch[iMatch].iStart<iEnd
- && aMatch[iMatch].iCol==iCol ){
- fts3SnippetAppend(&sb, &zDoc[iStart], aMatch[iMatch].iStart - iStart);
- iStart = aMatch[iMatch].iStart;
- fts3SnippetAppend(&sb, zStartMark, -1);
- fts3SnippetAppend(&sb, &zDoc[iStart], aMatch[iMatch].nByte);
- fts3SnippetAppend(&sb, zEndMark, -1);
- iStart += aMatch[iMatch].nByte;
- for(j=iMatch+1; j<nMatch; j++){
- if( aMatch[j].iTerm==aMatch[iMatch].iTerm
- && aMatch[j].snStatus==SNIPPET_DESIRED ){
- nDesired--;
- aMatch[j].snStatus = SNIPPET_IGNORE;
- }
- }
- }else{
- fts3SnippetAppend(&sb, &zDoc[iStart], iEnd - iStart);
- iStart = iEnd;
- }
- }
- tailCol = iCol;
- tailOffset = iEnd;
- }
- fts3SnippetTrimWhiteSpace(&sb);
- if( tailEllipsis ){
- fts3SnippetAppendWhiteSpace(&sb);
- fts3SnippetAppend(&sb, zEllipsis, -1);
- }
- pSnippet->zSnippet = sb.z;
- pSnippet->nSnippet = sb.z ? sb.nUsed : 0;
-}
-
-SQLITE_PRIVATE void sqlite3Fts3Offsets(
- sqlite3_context *pCtx, /* SQLite function call context */
- Fts3Cursor *pCsr /* Cursor object */
-){
- Snippet *p; /* Snippet structure */
- int rc = snippetAllOffsets(pCsr, &p);
- if( rc==SQLITE_OK ){
- snippetOffsetText(p);
- if( p->zOffset ){
- sqlite3_result_text(pCtx, p->zOffset, p->nOffset, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- fts3SnippetFree(p);
-}
-
-SQLITE_PRIVATE void sqlite3Fts3Snippet(
- sqlite3_context *pCtx, /* SQLite function call context */
- Fts3Cursor *pCsr, /* Cursor object */
- const char *zStart, /* Snippet start text - "<b>" */
- const char *zEnd, /* Snippet end text - "</b>" */
- const char *zEllipsis /* Snippet ellipsis text - "<b>...</b>" */
-){
- Snippet *p; /* Snippet structure */
- int rc = snippetAllOffsets(pCsr, &p);
- if( rc==SQLITE_OK ){
- snippetText(pCsr, p, zStart, zEnd, zEllipsis);
- if( p->zSnippet ){
- sqlite3_result_text(pCtx, p->zSnippet, p->nSnippet, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- fts3SnippetFree(p);
-}
-
-/*************************************************************************
-** Below this point is the alternative, experimental snippet() implementation.
-*/
-
-#define SNIPPET_BUFFER_CHUNK 64
-#define SNIPPET_BUFFER_SIZE SNIPPET_BUFFER_CHUNK*4
-#define SNIPPET_BUFFER_MASK (SNIPPET_BUFFER_SIZE-1)
-
static void fts3GetDeltaPosition(char **pp, int *piPos){
int iVal;
*pp += sqlite3Fts3GetVarint32(*pp, &iVal);
@@ -106904,6 +113587,31 @@
}
/*
+** Helper function for fts3ExprIterate() (see below).
+*/
+static int fts3ExprIterate2(
+ Fts3Expr *pExpr, /* Expression to iterate phrases of */
+ int *piPhrase, /* Pointer to phrase counter */
+ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
+ void *pCtx /* Second argument to pass to callback */
+){
+ int rc; /* Return code */
+ int eType = pExpr->eType; /* Type of expression node pExpr */
+
+ if( eType!=FTSQUERY_PHRASE ){
+ assert( pExpr->pLeft && pExpr->pRight );
+ rc = fts3ExprIterate2(pExpr->pLeft, piPhrase, x, pCtx);
+ if( rc==SQLITE_OK && eType!=FTSQUERY_NOT ){
+ rc = fts3ExprIterate2(pExpr->pRight, piPhrase, x, pCtx);
+ }
+ }else{
+ rc = x(pExpr, *piPhrase, pCtx);
+ (*piPhrase)++;
+ }
+ return rc;
+}
+
+/*
** Iterate through all phrase nodes in an FTS3 query, except those that
** are part of a sub-tree that is the right-hand-side of a NOT operator.
** For each phrase node found, the supplied callback function is invoked.
@@ -106915,285 +113623,387 @@
*/
static int fts3ExprIterate(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
- int (*x)(Fts3Expr *, void *), /* Callback function to invoke for phrases */
+ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
void *pCtx /* Second argument to pass to callback */
){
- int rc;
- int eType = pExpr->eType;
- if( eType==FTSQUERY_NOT ){
- rc = SQLITE_OK;
- }else if( eType!=FTSQUERY_PHRASE ){
- assert( pExpr->pLeft && pExpr->pRight );
- rc = fts3ExprIterate(pExpr->pLeft, x, pCtx);
- if( rc==SQLITE_OK ){
- rc = fts3ExprIterate(pExpr->pRight, x, pCtx);
- }
- }else{
- rc = x(pExpr, pCtx);
- }
- return rc;
+ int iPhrase = 0; /* Variable used as the phrase counter */
+ return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
}
-typedef struct LoadDoclistCtx LoadDoclistCtx;
-struct LoadDoclistCtx {
- Fts3Table *pTab; /* FTS3 Table */
- int nPhrase; /* Number of phrases so far */
-};
-
-static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, void *ctx){
+/*
+** The argument to this function is always a phrase node. Its doclist
+** (Fts3Expr.aDoclist[]) and the doclists associated with all phrase nodes
+** to the left of this one in the query tree have already been loaded.
+**
+** If this phrase node is part of a series of phrase nodes joined by
+** NEAR operators (and is not the left-most of said series), then elements are
+** removed from the phrases doclist consistent with the NEAR restriction. If
+** required, elements may be removed from the doclists of phrases to the
+** left of this one that are part of the same series of NEAR operator
+** connected phrases.
+**
+** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
+*/
+static int fts3ExprNearTrim(Fts3Expr *pExpr){
int rc = SQLITE_OK;
- LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
- p->nPhrase++;
- if( pExpr->isLoaded==0 ){
- rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
- pExpr->isLoaded = 1;
- if( rc==SQLITE_OK && pExpr->aDoclist ){
- pExpr->pCurrent = pExpr->aDoclist;
- pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
- }
- }
- return rc;
-}
+ Fts3Expr *pParent = pExpr->pParent;
-static int fts3ExprLoadDoclists(Fts3Cursor *pCsr, int *pnPhrase){
- int rc;
- LoadDoclistCtx sCtx = {0, 0};
- sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
- *pnPhrase = sCtx.nPhrase;
+ assert( pExpr->eType==FTSQUERY_PHRASE );
+ while( rc==SQLITE_OK
+ && pParent
+ && pParent->eType==FTSQUERY_NEAR
+ && pParent->pRight==pExpr
+ ){
+ /* This expression (pExpr) is the right-hand-side of a NEAR operator.
+ ** Find the expression to the left of the same operator.
+ */
+ int nNear = pParent->nNear;
+ Fts3Expr *pLeft = pParent->pLeft;
+
+ if( pLeft->eType!=FTSQUERY_PHRASE ){
+ assert( pLeft->eType==FTSQUERY_NEAR );
+ assert( pLeft->pRight->eType==FTSQUERY_PHRASE );
+ pLeft = pLeft->pRight;
+ }
+
+ rc = sqlite3Fts3ExprNearTrim(pLeft, pExpr, nNear);
+
+ pExpr = pLeft;
+ pParent = pExpr->pParent;
+ }
+
return rc;
}
/*
-** Each call to this function populates a chunk of a snippet-buffer
-** SNIPPET_BUFFER_CHUNK bytes in size.
-**
-** Return true if the end of the data has been reached (and all subsequent
-** calls to fts3LoadSnippetBuffer() with the same arguments will be no-ops),
-** or false otherwise.
+** This is an fts3ExprIterate() callback used while loading the doclists
+** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** fts3ExprLoadDoclists().
*/
-static int fts3LoadSnippetBuffer(
- int iPos, /* Document token offset to load data for */
- u8 *aBuffer, /* Circular snippet buffer to populate */
- int nList, /* Number of position lists in appList */
- char **apList, /* IN/OUT: nList position list pointers */
- int *aiPrev /* IN/OUT: Previous positions read */
-){
- int i;
- int nFin = 0;
+static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ int rc = SQLITE_OK;
+ LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
- assert( (iPos&(SNIPPET_BUFFER_CHUNK-1))==0 );
+ UNUSED_PARAMETER(iPhrase);
- memset(&aBuffer[iPos&SNIPPET_BUFFER_MASK], 0, SNIPPET_BUFFER_CHUNK);
+ p->nPhrase++;
+ p->nToken += pExpr->pPhrase->nToken;
- for(i=0; i<nList; i++){
- int iPrev = aiPrev[i];
- char *pList = apList[i];
-
- if( !pList ){
- nFin++;
- continue;
+ if( pExpr->isLoaded==0 ){
+ rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
+ pExpr->isLoaded = 1;
+ if( rc==SQLITE_OK ){
+ rc = fts3ExprNearTrim(pExpr);
}
-
- while( iPrev<(iPos+SNIPPET_BUFFER_CHUNK) ){
- if( iPrev>=iPos ){
- aBuffer[iPrev&SNIPPET_BUFFER_MASK] = (u8)(i+1);
- }
- if( 0==((*pList)&0xFE) ){
- nFin++;
- break;
- }
- fts3GetDeltaPosition(&pList, &iPrev);
- }
-
- aiPrev[i] = iPrev;
- apList[i] = pList;
}
- return (nFin==nList);
+ return rc;
}
-typedef struct SnippetCtx SnippetCtx;
-struct SnippetCtx {
- Fts3Cursor *pCsr;
- int iCol;
- int iPhrase;
- int *aiPrev;
- int *anToken;
- char **apList;
-};
-
-static int fts3SnippetFindPositions(Fts3Expr *pExpr, void *ctx){
- SnippetCtx *p = (SnippetCtx *)ctx;
- int iPhrase = p->iPhrase++;
- char *pCsr;
-
- p->anToken[iPhrase] = pExpr->pPhrase->nToken;
- pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
-
- if( pCsr ){
- int iVal;
- pCsr += sqlite3Fts3GetVarint32(pCsr, &iVal);
- p->apList[iPhrase] = pCsr;
- p->aiPrev[iPhrase] = iVal-2;
+/*
+** This is an fts3ExprIterate() callback used while loading the doclists
+** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** fts3ExprLoadDoclists().
+*/
+static int fts3ExprLoadDoclistsCb2(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ UNUSED_PARAMETER(iPhrase);
+ UNUSED_PARAMETER(ctx);
+ if( pExpr->aDoclist ){
+ pExpr->pCurrent = pExpr->aDoclist;
+ pExpr->iCurrent = 0;
+ pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent, &pExpr->iCurrent);
}
return SQLITE_OK;
}
-static void fts3SnippetCnt(
- int iIdx,
- int nSnippet,
- int *anCnt,
- u8 *aBuffer,
- int *anToken,
- u64 *pHlmask
+/*
+** Load the doclists for each phrase in the query associated with FTS3 cursor
+** pCsr.
+**
+** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
+** phrases in the expression (all phrases except those directly or
+** indirectly descended from the right-hand-side of a NOT operator). If
+** pnToken is not NULL, then it is set to the number of tokens in all
+** matchable phrases of the expression.
+*/
+static int fts3ExprLoadDoclists(
+ Fts3Cursor *pCsr, /* Fts3 cursor for current query */
+ int *pnPhrase, /* OUT: Number of phrases in query */
+ int *pnToken /* OUT: Number of tokens in query */
){
- int iSub = (iIdx-1)&SNIPPET_BUFFER_MASK;
- int iAdd = (iIdx+nSnippet-1)&SNIPPET_BUFFER_MASK;
- int iSub2 = (iIdx+(nSnippet/3)-1)&SNIPPET_BUFFER_MASK;
- int iAdd2 = (iIdx+(nSnippet*2/3)-1)&SNIPPET_BUFFER_MASK;
+ int rc; /* Return Code */
+ LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
+ sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
+ rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
+ if( rc==SQLITE_OK ){
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
+ }
+ if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
+ if( pnToken ) *pnToken = sCtx.nToken;
+ return rc;
+}
- u64 h = *pHlmask;
+/*
+** Advance the position list iterator specified by the first two
+** arguments so that it points to the first element with a value greater
+** than or equal to parameter iNext.
+*/
+static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
+ char *pIter = *ppIter;
+ if( pIter ){
+ int iIter = *piIter;
- anCnt[ aBuffer[iSub] ]--;
- anCnt[ aBuffer[iSub2] ]--;
- anCnt[ aBuffer[iAdd] ]++;
- anCnt[ aBuffer[iAdd2] ]++;
+ while( iIter<iNext ){
+ if( 0==(*pIter & 0xFE) ){
+ iIter = -1;
+ pIter = 0;
+ break;
+ }
+ fts3GetDeltaPosition(&pIter, &iIter);
+ }
- h = h >> 1;
- if( aBuffer[iAdd] ){
- int j;
- for(j=anToken[aBuffer[iAdd]-1]; j>=1; j--){
- h |= (u64)1 << (nSnippet-j);
+ *piIter = iIter;
+ *ppIter = pIter;
+ }
+}
+
+/*
+** Advance the snippet iterator to the next candidate snippet.
+*/
+static int fts3SnippetNextCandidate(SnippetIter *pIter){
+ int i; /* Loop counter */
+
+ if( pIter->iCurrent<0 ){
+ /* The SnippetIter object has just been initialized. The first snippet
+ ** candidate always starts at offset 0 (even if this candidate has a
+ ** score of 0.0).
+ */
+ pIter->iCurrent = 0;
+
+ /* Advance the 'head' iterator of each phrase to the first offset that
+ ** is greater than or equal to (iNext+nSnippet).
+ */
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, pIter->nSnippet);
+ }
+ }else{
+ int iStart;
+ int iEnd = 0x7FFFFFFF;
+
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ if( pPhrase->pHead && pPhrase->iHead<iEnd ){
+ iEnd = pPhrase->iHead;
+ }
+ }
+ if( iEnd==0x7FFFFFFF ){
+ return 1;
+ }
+
+ pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ fts3SnippetAdvance(&pPhrase->pHead, &pPhrase->iHead, iEnd+1);
+ fts3SnippetAdvance(&pPhrase->pTail, &pPhrase->iTail, iStart);
}
}
- *pHlmask = h;
+
+ return 0;
}
-static int fts3SnippetScore(int n, int *anCnt){
- int j;
- int iScore = 0;
- for(j=1; j<=n; j++){
- int nCnt = anCnt[j];
- iScore += nCnt + (nCnt ? 1000 : 0);
+/*
+** Retrieve information about the current candidate snippet of snippet
+** iterator pIter.
+*/
+static void fts3SnippetDetails(
+ SnippetIter *pIter, /* Snippet iterator */
+ u64 mCovered, /* Bitmask of phrases already covered */
+ int *piToken, /* OUT: First token of proposed snippet */
+ int *piScore, /* OUT: "Score" for this snippet */
+ u64 *pmCover, /* OUT: Bitmask of phrases covered */
+ u64 *pmHighlight /* OUT: Bitmask of terms to highlight */
+){
+ int iStart = pIter->iCurrent; /* First token of snippet */
+ int iScore = 0; /* Score of this snippet */
+ int i; /* Loop counter */
+ u64 mCover = 0; /* Mask of phrases covered by this snippet */
+ u64 mHighlight = 0; /* Mask of tokens to highlight in snippet */
+
+ for(i=0; i<pIter->nPhrase; i++){
+ SnippetPhrase *pPhrase = &pIter->aPhrase[i];
+ if( pPhrase->pTail ){
+ char *pCsr = pPhrase->pTail;
+ int iCsr = pPhrase->iTail;
+
+ while( iCsr<(iStart+pIter->nSnippet) ){
+ int j;
+ u64 mPhrase = (u64)1 << i;
+ u64 mPos = (u64)1 << (iCsr - iStart);
+ assert( iCsr>=iStart );
+ if( (mCover|mCovered)&mPhrase ){
+ iScore++;
+ }else{
+ iScore += 1000;
+ }
+ mCover |= mPhrase;
+
+ for(j=0; j<pPhrase->nToken; j++){
+ mHighlight |= (mPos>>j);
+ }
+
+ if( 0==(*pCsr & 0x0FE) ) break;
+ fts3GetDeltaPosition(&pCsr, &iCsr);
+ }
+ }
}
- return iScore;
+
+ /* Set the output variables before returning. */
+ *piToken = iStart;
+ *piScore = iScore;
+ *pmCover = mCover;
+ *pmHighlight = mHighlight;
}
+/*
+** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
+** Each invocation populates an element of the SnippetIter.aPhrase[] array.
+*/
+static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ SnippetIter *p = (SnippetIter *)ctx;
+ SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
+ char *pCsr;
+
+ pPhrase->nToken = pExpr->pPhrase->nToken;
+
+ pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
+ if( pCsr ){
+ int iFirst = 0;
+ pPhrase->pList = pCsr;
+ fts3GetDeltaPosition(&pCsr, &iFirst);
+ pPhrase->pHead = pCsr;
+ pPhrase->pTail = pCsr;
+ pPhrase->iHead = iFirst;
+ pPhrase->iTail = iFirst;
+ }else{
+ assert( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 );
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Select the fragment of text consisting of nFragment contiguous tokens
+** from column iCol that represent the "best" snippet. The best snippet
+** is the snippet with the highest score, where scores are calculated
+** by adding:
+**
+** (a) +1 point for each occurence of a matchable phrase in the snippet.
+**
+** (b) +1000 points for the first occurence of each matchable phrase in
+** the snippet for which the corresponding mCovered bit is not set.
+**
+** The selected snippet parameters are stored in structure *pFragment before
+** returning. The score of the selected snippet is stored in *piScore
+** before returning.
+*/
static int fts3BestSnippet(
int nSnippet, /* Desired snippet length */
Fts3Cursor *pCsr, /* Cursor to create snippet for */
int iCol, /* Index of column to create snippet from */
- int *piPos, /* OUT: Starting token for best snippet */
- u64 *pHlmask /* OUT: Highlight mask for best snippet */
+ u64 mCovered, /* Mask of phrases already covered */
+ u64 *pmSeen, /* IN/OUT: Mask of phrases seen */
+ SnippetFragment *pFragment, /* OUT: Best snippet found */
+ int *piScore /* OUT: Score of snippet pFragment */
){
int rc; /* Return Code */
- u8 aBuffer[SNIPPET_BUFFER_SIZE];/* Circular snippet buffer */
- int *aiPrev; /* Used by fts3LoadSnippetBuffer() */
- int *anToken; /* Number of tokens in each phrase */
- char **apList; /* Array of position lists */
- int *anCnt; /* Running totals of phrase occurences */
- int nList;
+ int nList; /* Number of phrases in expression */
+ SnippetIter sIter; /* Iterates through snippet candidates */
+ int nByte; /* Number of bytes of space to allocate */
+ int iBestScore = -1; /* Best snippet score found so far */
+ int i; /* Loop counter */
- int i;
-
- u64 hlmask = 0; /* Current mask of highlighted terms */
- u64 besthlmask = 0; /* Mask of highlighted terms for iBestPos */
- int iBestPos = 0; /* Starting position of 'best' snippet */
- int iBestScore = 0; /* Score of best snippet higher->better */
- SnippetCtx sCtx;
+ memset(&sIter, 0, sizeof(sIter));
/* Iterate through the phrases in the expression to count them. The same
** callback makes sure the doclists are loaded for each phrase.
*/
- rc = fts3ExprLoadDoclists(pCsr, &nList);
+ rc = fts3ExprLoadDoclists(pCsr, &nList, 0);
if( rc!=SQLITE_OK ){
return rc;
}
/* Now that it is known how many phrases there are, allocate and zero
- ** the required arrays using malloc().
+ ** the required space using malloc().
*/
- apList = sqlite3_malloc(
- sizeof(u8*)*nList + /* apList */
- sizeof(int)*(nList) + /* anToken */
- sizeof(int)*nList + /* aiPrev */
- sizeof(int)*(nList+1) /* anCnt */
- );
- if( !apList ){
+ nByte = sizeof(SnippetPhrase) * nList;
+ sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
+ if( !sIter.aPhrase ){
return SQLITE_NOMEM;
}
- memset(apList, 0, sizeof(u8*)*nList+sizeof(int)*nList+sizeof(int)*nList);
- anToken = (int *)&apList[nList];
- aiPrev = &anToken[nList];
- anCnt = &aiPrev[nList];
+ memset(sIter.aPhrase, 0, nByte);
- /* Initialize the contents of the aiPrev and aiList arrays. */
- sCtx.pCsr = pCsr;
- sCtx.iCol = iCol;
- sCtx.apList = apList;
- sCtx.aiPrev = aiPrev;
- sCtx.anToken = anToken;
- sCtx.iPhrase = 0;
- (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sCtx);
+ /* Initialize the contents of the SnippetIter object. Then iterate through
+ ** the set of phrases in the expression to populate the aPhrase[] array.
+ */
+ sIter.pCsr = pCsr;
+ sIter.iCol = iCol;
+ sIter.nSnippet = nSnippet;
+ sIter.nPhrase = nList;
+ sIter.iCurrent = -1;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
- /* Load the first two chunks of data into the buffer. */
- memset(aBuffer, 0, SNIPPET_BUFFER_SIZE);
- fts3LoadSnippetBuffer(0, aBuffer, nList, apList, aiPrev);
- fts3LoadSnippetBuffer(SNIPPET_BUFFER_CHUNK, aBuffer, nList, apList, aiPrev);
-
- /* Set the initial contents of the highlight-mask and anCnt[] array. */
- for(i=1-nSnippet; i<=0; i++){
- fts3SnippetCnt(i, nSnippet, anCnt, aBuffer, anToken, &hlmask);
+ /* Set the *pmSeen output variable. */
+ for(i=0; i<nList; i++){
+ if( sIter.aPhrase[i].pHead ){
+ *pmSeen |= (u64)1 << i;
+ }
}
- iBestScore = fts3SnippetScore(nList, anCnt);
- besthlmask = hlmask;
- iBestPos = 0;
- for(i=1; 1; i++){
+ /* Loop through all candidate snippets. Store the best snippet in
+ ** *pFragment. Store its associated 'score' in iBestScore.
+ */
+ pFragment->iCol = iCol;
+ while( !fts3SnippetNextCandidate(&sIter) ){
+ int iPos;
int iScore;
-
- if( 0==(i&(SNIPPET_BUFFER_CHUNK-1)) ){
- int iLoad = i + SNIPPET_BUFFER_CHUNK;
- if( fts3LoadSnippetBuffer(iLoad, aBuffer, nList, apList, aiPrev) ) break;
- }
-
- /* Figure out how highly a snippet starting at token offset i scores
- ** according to fts3SnippetScore(). If it is higher than any previously
- ** considered position, save the current position, score and hlmask as
- ** the best snippet candidate found so far.
- */
- fts3SnippetCnt(i, nSnippet, anCnt, aBuffer, anToken, &hlmask);
- iScore = fts3SnippetScore(nList, anCnt);
+ u64 mCover;
+ u64 mHighlight;
+ fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight);
+ assert( iScore>=0 );
if( iScore>iBestScore ){
- iBestPos = i;
+ pFragment->iPos = iPos;
+ pFragment->hlmask = mHighlight;
+ pFragment->covered = mCover;
iBestScore = iScore;
- besthlmask = hlmask;
}
}
- sqlite3_free(apList);
- *piPos = iBestPos;
- *pHlmask = besthlmask;
+ sqlite3_free(sIter.aPhrase);
+ *piScore = iBestScore;
return SQLITE_OK;
}
-typedef struct StrBuffer StrBuffer;
-struct StrBuffer {
- char *z;
- int n;
- int nAlloc;
-};
+/*
+** Append a string to the string-buffer passed as the first argument.
+**
+** If nAppend is negative, then the length of the string zAppend is
+** determined using strlen().
+*/
static int fts3StringAppend(
- StrBuffer *pStr,
- const char *zAppend,
- int nAppend
+ StrBuffer *pStr, /* Buffer to append to */
+ const char *zAppend, /* Pointer to data to append to buffer */
+ int nAppend /* Size of zAppend in bytes (or -1) */
){
if( nAppend<0 ){
nAppend = (int)strlen(zAppend);
}
+ /* If there is insufficient space allocated at StrBuffer.z, use realloc()
+ ** to grow the buffer until so that it is big enough to accomadate the
+ ** appended data.
+ */
if( pStr->n+nAppend+1>=pStr->nAlloc ){
int nAlloc = pStr->nAlloc+nAppend+100;
char *zNew = sqlite3_realloc(pStr->z, nAlloc);
@@ -107204,6 +114014,7 @@
pStr->nAlloc = nAlloc;
}
+ /* Append the data to the string buffer. */
memcpy(&pStr->z[pStr->n], zAppend, nAppend);
pStr->n += nAppend;
pStr->z[pStr->n] = '\0';
@@ -107211,126 +114022,201 @@
return SQLITE_OK;
}
+/*
+** The fts3BestSnippet() function often selects snippets that end with a
+** query term. That is, the final term of the snippet is always a term
+** that requires highlighting. For example, if 'X' is a highlighted term
+** and '.' is a non-highlighted term, BestSnippet() may select:
+**
+** ........X.....X
+**
+** This function "shifts" the beginning of the snippet forward in the
+** document so that there are approximately the same number of
+** non-highlighted terms to the right of the final highlighted term as there
+** are to the left of the first highlighted term. For example, to this:
+**
+** ....X.....X....
+**
+** This is done as part of extracting the snippet text, not when selecting
+** the snippet. Snippet selection is done based on doclists only, so there
+** is no way for fts3BestSnippet() to know whether or not the document
+** actually contains terms that follow the final highlighted term.
+*/
+static int fts3SnippetShift(
+ Fts3Table *pTab, /* FTS3 table snippet comes from */
+ int nSnippet, /* Number of tokens desired for snippet */
+ const char *zDoc, /* Document text to extract snippet from */
+ int nDoc, /* Size of buffer zDoc in bytes */
+ int *piPos, /* IN/OUT: First token of snippet */
+ u64 *pHlmask /* IN/OUT: Mask of tokens to highlight */
+){
+ u64 hlmask = *pHlmask; /* Local copy of initial highlight-mask */
+
+ if( hlmask ){
+ int nLeft; /* Tokens to the left of first highlight */
+ int nRight; /* Tokens to the right of last highlight */
+ int nDesired; /* Ideal number of tokens to shift forward */
+
+ for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++);
+ for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++);
+ nDesired = (nLeft-nRight)/2;
+
+ /* Ideally, the start of the snippet should be pushed forward in the
+ ** document nDesired tokens. This block checks if there are actually
+ ** nDesired tokens to the right of the snippet. If so, *piPos and
+ ** *pHlMask are updated to shift the snippet nDesired tokens to the
+ ** right. Otherwise, the snippet is shifted by the number of tokens
+ ** available.
+ */
+ if( nDesired>0 ){
+ int nShift; /* Number of tokens to shift snippet by */
+ int iCurrent = 0; /* Token counter */
+ int rc; /* Return Code */
+ sqlite3_tokenizer_module *pMod;
+ sqlite3_tokenizer_cursor *pC;
+ pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
+
+ /* Open a cursor on zDoc/nDoc. Check if there are (nSnippet+nDesired)
+ ** or more tokens in zDoc/nDoc.
+ */
+ rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pC->pTokenizer = pTab->pTokenizer;
+ while( rc==SQLITE_OK && iCurrent<(nSnippet+nDesired) ){
+ const char *ZDUMMY; int DUMMY1, DUMMY2, DUMMY3;
+ rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
+ }
+ pMod->xClose(pC);
+ if( rc!=SQLITE_OK && rc!=SQLITE_DONE ){ return rc; }
+
+ nShift = (rc==SQLITE_DONE)+iCurrent-nSnippet;
+ assert( nShift<=nDesired );
+ if( nShift>0 ){
+ *piPos += nShift;
+ *pHlmask = hlmask >> nShift;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Extract the snippet text for fragment pFragment from cursor pCsr and
+** append it to string buffer pOut.
+*/
static int fts3SnippetText(
Fts3Cursor *pCsr, /* FTS3 Cursor */
- const char *zDoc, /* Document to extract snippet from */
- int nDoc, /* Size of zDoc in bytes */
+ SnippetFragment *pFragment, /* Snippet to extract */
+ int iFragment, /* Fragment number */
+ int isLast, /* True for final fragment in snippet */
int nSnippet, /* Number of tokens in extracted snippet */
- int iPos, /* Index of first document token in snippet */
- u64 hlmask, /* Bitmask of terms to highlight in snippet */
const char *zOpen, /* String inserted before highlighted term */
const char *zClose, /* String inserted after highlighted term */
- const char *zEllipsis,
- char **pzSnippet /* OUT: Snippet text */
+ const char *zEllipsis, /* String inserted between snippets */
+ StrBuffer *pOut /* Write output here */
){
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
int rc; /* Return code */
- int iCurrent = 0;
- int iStart = 0;
- int iEnd;
-
+ const char *zDoc; /* Document text to extract snippet from */
+ int nDoc; /* Size of zDoc in bytes */
+ int iCurrent = 0; /* Current token number of document */
+ int iEnd = 0; /* Byte offset of end of current token */
+ int isShiftDone = 0; /* True after snippet is shifted */
+ int iPos = pFragment->iPos; /* First token of snippet */
+ u64 hlmask = pFragment->hlmask; /* Highlight-mask for snippet */
+ int iCol = pFragment->iCol+1; /* Query column to extract text from */
sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
- const char *ZDUMMY; /* Dummy arguments used with tokenizer */
- int DUMMY1, DUMMY2, DUMMY3; /* Dummy arguments used with tokenizer */
+ const char *ZDUMMY; /* Dummy argument used with tokenizer */
+ int DUMMY1; /* Dummy argument used with tokenizer */
+
+ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
+ if( zDoc==0 ){
+ if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){
+ return SQLITE_NOMEM;
+ }
+ return SQLITE_OK;
+ }
+ nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol);
- StrBuffer res = {0, 0, 0}; /* Result string */
-
- /* Open a token cursor on the document. Read all tokens up to and
- ** including token iPos (the first token of the snippet). Set variable
- ** iStart to the byte offset in zDoc of the start of token iPos.
- */
+ /* Open a token cursor on the document. */
pMod = (sqlite3_tokenizer_module *)pTab->pTokenizer->pModule;
rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
- while( rc==SQLITE_OK && iCurrent<iPos ){
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iStart, &DUMMY2, &iCurrent);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
- iEnd = iStart;
-
- if( rc==SQLITE_OK && iStart>0 ){
- rc = fts3StringAppend(&res, zEllipsis, -1);
- }
+ pC->pTokenizer = pTab->pTokenizer;
while( rc==SQLITE_OK ){
- int iBegin;
- int iFin;
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
+ int iBegin; /* Offset in zDoc of start of token */
+ int iFin; /* Offset in zDoc of end of token */
+ int isHighlight; /* True for highlighted terms */
- if( rc==SQLITE_OK ){
- if( iCurrent>=(iPos+nSnippet) ){
- rc = SQLITE_DONE;
- }else{
- iEnd = iFin;
- if( hlmask & ((u64)1 << (iCurrent-iPos)) ){
- if( fts3StringAppend(&res, &zDoc[iStart], iBegin-iStart)
- || fts3StringAppend(&res, zOpen, -1)
- || fts3StringAppend(&res, &zDoc[iBegin], iEnd-iBegin)
- || fts3StringAppend(&res, zClose, -1)
- ){
- rc = SQLITE_NOMEM;
- }
- iStart = iEnd;
- }
+ rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &iBegin, &iFin, &iCurrent);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ /* Special case - the last token of the snippet is also the last token
+ ** of the column. Append any punctuation that occurred between the end
+ ** of the previous token and the end of the document to the output.
+ ** Then break out of the loop. */
+ rc = fts3StringAppend(pOut, &zDoc[iEnd], -1);
}
+ break;
}
- }
- assert( rc!=SQLITE_OK );
- if( rc==SQLITE_DONE ){
- rc = fts3StringAppend(&res, &zDoc[iStart], iEnd-iStart);
- if( rc==SQLITE_OK ){
- rc = pMod->xNext(pC, &ZDUMMY, &DUMMY1, &DUMMY2, &DUMMY3, &iCurrent);
- if( rc==SQLITE_OK ){
- rc = fts3StringAppend(&res, zEllipsis, -1);
- }else if( rc==SQLITE_DONE ){
- rc = fts3StringAppend(&res, &zDoc[iEnd], -1);
+ if( iCurrent<iPos ){ continue; }
+
+ if( !isShiftDone ){
+ int n = nDoc - iBegin;
+ rc = fts3SnippetShift(pTab, nSnippet, &zDoc[iBegin], n, &iPos, &hlmask);
+ isShiftDone = 1;
+
+ /* Now that the shift has been done, check if the initial "..." are
+ ** required. They are required if (a) this is not the first fragment,
+ ** or (b) this fragment does not begin at position 0 of its column.
+ */
+ if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
}
+ if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
}
+
+ if( iCurrent>=(iPos+nSnippet) ){
+ if( isLast ){
+ rc = fts3StringAppend(pOut, zEllipsis, -1);
+ }
+ break;
+ }
+
+ /* Set isHighlight to true if this term should be highlighted. */
+ isHighlight = (hlmask & ((u64)1 << (iCurrent-iPos)))!=0;
+
+ if( iCurrent>iPos ) rc = fts3StringAppend(pOut, &zDoc[iEnd], iBegin-iEnd);
+ if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zOpen, -1);
+ if( rc==SQLITE_OK ) rc = fts3StringAppend(pOut, &zDoc[iBegin], iFin-iBegin);
+ if( rc==SQLITE_OK && isHighlight ) rc = fts3StringAppend(pOut, zClose, -1);
+
+ iEnd = iFin;
}
pMod->xClose(pC);
- if( rc!=SQLITE_OK ){
- sqlite3_free(res.z);
- }else{
- *pzSnippet = res.z;
- }
return rc;
}
/*
-** An instance of this structure is used to collect the 'global' part of
-** the matchinfo statistics. The 'global' part consists of the following:
+** This function is used to count the entries in a column-list (a
+** delta-encoded list of term offsets within a single column of a single
+** row). When this function is called, *ppCollist should point to the
+** beginning of the first varint in the column-list (the varint that
+** contains the position of the first matching term in the column data).
+** Before returning, *ppCollist is set to point to the first byte after
+** the last varint in the column-list (either the 0x00 signifying the end
+** of the position-list, or the 0x01 that precedes the column number of
+** the next column in the position-list).
**
-** 1. The number of phrases in the query (nPhrase).
-**
-** 2. The number of columns in the FTS3 table (nCol).
-**
-** 3. A matrix of (nPhrase*nCol) integers containing the sum of the
-** number of hits for each phrase in each column across all rows
-** of the table.
-**
-** The total size of the global matchinfo array, assuming the number of
-** columns is N and the number of phrases is P is:
-**
-** 2 + P*(N+1)
-**
-** The number of hits for the 3rd phrase in the second column is found
-** using the expression:
-**
-** aGlobal[2 + P*(1+2) + 1]
-*/
-typedef struct MatchInfo MatchInfo;
-struct MatchInfo {
- Fts3Table *pTab; /* FTS3 Table */
- Fts3Cursor *pCursor; /* FTS3 Cursor */
- int iPhrase; /* Number of phrases so far */
- int nCol; /* Number of columns in table */
- u32 *aGlobal; /* Pre-allocated buffer */
-};
-
-/*
-** This function is used to count the entries in a column-list (delta-encoded
-** list of term offsets within a single column of a single row).
+** The number of elements in the column-list is returned.
*/
static int fts3ColumnlistCount(char **ppCollist){
char *pEnd = *ppCollist;
@@ -107347,15 +114233,21 @@
return nEntry;
}
-static void fts3LoadColumnlistCounts(char **pp, u32 *aOut){
+static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
char *pCsr = *pp;
while( *pCsr ){
+ int nHit;
sqlite3_int64 iCol = 0;
if( *pCsr==0x01 ){
pCsr++;
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
}
- aOut[iCol] += fts3ColumnlistCount(&pCsr);
+ nHit = fts3ColumnlistCount(&pCsr);
+ assert( nHit>0 );
+ if( isGlobal ){
+ aOut[iCol*3+1]++;
+ }
+ aOut[iCol*3] += nHit;
}
pCsr++;
*pp = pCsr;
@@ -107363,16 +114255,18 @@
/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query.
+** for a single query. The "global" stats are those elements of the matchinfo
+** array that are constant for all rows returned by the current query.
*/
static int fts3ExprGlobalMatchinfoCb(
Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number (numbered from zero) */
void *pCtx /* Pointer to MatchInfo structure */
){
MatchInfo *p = (MatchInfo *)pCtx;
char *pCsr;
char *pEnd;
- const int iStart = 2 + p->nCol*p->iPhrase;
+ const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;
assert( pExpr->isLoaded );
@@ -107380,84 +114274,108 @@
pCsr = pExpr->aDoclist;
pEnd = &pExpr->aDoclist[pExpr->nDoclist];
while( pCsr<pEnd ){
- while( *pCsr++ & 0x80 );
- fts3LoadColumnlistCounts(&pCsr, &p->aGlobal[iStart]);
- }
-
- p->iPhrase++;
- return SQLITE_OK;
-}
-
-static int fts3ExprLocalMatchinfoCb(
- Fts3Expr *pExpr, /* Phrase expression node */
- void *pCtx /* Pointer to MatchInfo structure */
-){
- MatchInfo *p = (MatchInfo *)pCtx;
- int iPhrase = p->iPhrase++;
-
- if( pExpr->aDoclist ){
- char *pCsr;
- int iOffset = 2 + p->nCol*(p->aGlobal[0]+iPhrase);
-
- memset(&p->aGlobal[iOffset], 0, p->nCol*sizeof(u32));
- pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
- if( pCsr ) fts3LoadColumnlistCounts(&pCsr, &p->aGlobal[iOffset]);
+ while( *pCsr++ & 0x80 ); /* Skip past docid. */
+ fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 1);
}
return SQLITE_OK;
}
/*
-** Populate pCsr->aMatchinfo[] with data for the current row. The 'matchinfo'
-** data is an array of 32-bit unsigned integers (C type u32).
+** fts3ExprIterate() callback used to collect the "local" matchinfo stats
+** for a single query. The "local" stats are those elements of the matchinfo
+** array that are different for each row returned by the query.
*/
-static int fts3GetMatchinfo(Fts3Cursor *pCsr){
- MatchInfo g;
- Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
- if( pCsr->aMatchinfo==0 ){
- int rc;
- int nPhrase;
- int nMatchinfo;
+static int fts3ExprLocalMatchinfoCb(
+ Fts3Expr *pExpr, /* Phrase expression node */
+ int iPhrase, /* Phrase number */
+ void *pCtx /* Pointer to MatchInfo structure */
+){
+ MatchInfo *p = (MatchInfo *)pCtx;
- g.pTab = pTab;
- g.nCol = pTab->nColumn;
- g.iPhrase = 0;
- rc = fts3ExprLoadDoclists(pCsr, &nPhrase);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( pExpr->aDoclist ){
+ char *pCsr;
+ int iStart = 2 + (iPhrase * p->nCol * 3);
+ int i;
+
+ for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
+
+ pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
+ if( pCsr ){
+ fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
}
-
- nMatchinfo = 2 + 2*g.nCol*nPhrase;
-
- g.iPhrase = 0;
- g.aGlobal = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
- if( !g.aGlobal ){
- return SQLITE_NOMEM;
- }
- memset(g.aGlobal, 0, sizeof(u32)*nMatchinfo);
-
- g.aGlobal[0] = nPhrase;
- g.aGlobal[1] = g.nCol;
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb, (void *)&g);
-
- pCsr->aMatchinfo = g.aGlobal;
- }
-
- g.pTab = pTab;
- g.pCursor = pCsr;
- g.nCol = pTab->nColumn;
- g.iPhrase = 0;
- g.aGlobal = pCsr->aMatchinfo;
-
- if( pCsr->isMatchinfoOk ){
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void *)&g);
- pCsr->isMatchinfoOk = 0;
}
return SQLITE_OK;
}
-SQLITE_PRIVATE void sqlite3Fts3Snippet2(
+/*
+** Populate pCsr->aMatchinfo[] with data for the current row. The
+** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
+*/
+static int fts3GetMatchinfo(Fts3Cursor *pCsr){
+ MatchInfo sInfo;
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ int rc = SQLITE_OK;
+
+ sInfo.pCursor = pCsr;
+ sInfo.nCol = pTab->nColumn;
+
+ if( pCsr->aMatchinfo==0 ){
+ /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
+ ** matchinfo function has been called for this query. In this case
+ ** allocate the array used to accumulate the matchinfo data and
+ ** initialize those elements that are constant for every row.
+ */
+ int nPhrase; /* Number of phrases */
+ int nMatchinfo; /* Number of u32 elements in match-info */
+
+ /* Load doclists for each phrase in the query. */
+ rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
+ if( pTab->bHasDocsize ){
+ nMatchinfo += 1 + 2*pTab->nColumn;
+ }
+
+ sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
+ if( !sInfo.aMatchinfo ){
+ return SQLITE_NOMEM;
+ }
+ memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);
+
+
+ /* First element of match-info is the number of phrases in the query */
+ sInfo.aMatchinfo[0] = nPhrase;
+ sInfo.aMatchinfo[1] = sInfo.nCol;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
+ if( pTab->bHasDocsize ){
+ int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
+ rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
+ }
+ pCsr->aMatchinfo = sInfo.aMatchinfo;
+ pCsr->isMatchinfoNeeded = 1;
+ }
+
+ sInfo.aMatchinfo = pCsr->aMatchinfo;
+ if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
+ if( pTab->bHasDocsize ){
+ int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
+ rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
+ }
+ pCsr->isMatchinfoNeeded = 0;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of snippet() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3Snippet(
sqlite3_context *pCtx, /* SQLite function call context */
Fts3Cursor *pCsr, /* Cursor object */
const char *zStart, /* Snippet start text - "<b>" */
@@ -107466,35 +114384,292 @@
int iCol, /* Extract snippet from this column */
int nToken /* Approximate number of tokens in snippet */
){
- int rc;
- int iPos = 0;
- u64 hlmask = 0;
- char *z = 0;
- int nDoc;
- const char *zDoc;
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ int rc = SQLITE_OK;
+ int i;
+ StrBuffer res = {0, 0, 0};
- rc = fts3BestSnippet(nToken, pCsr, iCol, &iPos, &hlmask);
+ /* The returned text includes up to four fragments of text extracted from
+ ** the data in the current row. The first iteration of the for(...) loop
+ ** below attempts to locate a single fragment of text nToken tokens in
+ ** size that contains at least one instance of all phrases in the query
+ ** expression that appear in the current row. If such a fragment of text
+ ** cannot be found, the second iteration of the loop attempts to locate
+ ** a pair of fragments, and so on.
+ */
+ int nSnippet = 0; /* Number of fragments in this snippet */
+ SnippetFragment aSnippet[4]; /* Maximum of 4 fragments per snippet */
+ int nFToken = -1; /* Number of tokens in each fragment */
- nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
- zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
-
- if( rc==SQLITE_OK ){
- rc = fts3SnippetText(
- pCsr, zDoc, nDoc, nToken, iPos, hlmask, zStart, zEnd, zEllipsis, &z);
+ if( !pCsr->pExpr ){
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
+ return;
}
+
+ for(nSnippet=1; 1; nSnippet++){
+
+ int iSnip; /* Loop counter 0..nSnippet-1 */
+ u64 mCovered = 0; /* Bitmask of phrases covered by snippet */
+ u64 mSeen = 0; /* Bitmask of phrases seen by BestSnippet() */
+
+ if( nToken>=0 ){
+ nFToken = (nToken+nSnippet-1) / nSnippet;
+ }else{
+ nFToken = -1 * nToken;
+ }
+
+ for(iSnip=0; iSnip<nSnippet; iSnip++){
+ int iBestScore = -1; /* Best score of columns checked so far */
+ int iRead; /* Used to iterate through columns */
+ SnippetFragment *pFragment = &aSnippet[iSnip];
+
+ memset(pFragment, 0, sizeof(*pFragment));
+
+ /* Loop through all columns of the table being considered for snippets.
+ ** If the iCol argument to this function was negative, this means all
+ ** columns of the FTS3 table. Otherwise, only column iCol is considered.
+ */
+ for(iRead=0; iRead<pTab->nColumn; iRead++){
+ SnippetFragment sF;
+ int iS;
+ if( iCol>=0 && iRead!=iCol ) continue;
+
+ /* Find the best snippet of nFToken tokens in column iRead. */
+ rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS);
+ if( rc!=SQLITE_OK ){
+ goto snippet_out;
+ }
+ if( iS>iBestScore ){
+ *pFragment = sF;
+ iBestScore = iS;
+ }
+ }
+
+ mCovered |= pFragment->covered;
+ }
+
+ /* If all query phrases seen by fts3BestSnippet() are present in at least
+ ** one of the nSnippet snippet fragments, break out of the loop.
+ */
+ assert( (mCovered&mSeen)==mCovered );
+ if( mSeen==mCovered || nSnippet==SizeofArray(aSnippet) ) break;
+ }
+
+ assert( nFToken>0 );
+
+ for(i=0; i<nSnippet && rc==SQLITE_OK; i++){
+ rc = fts3SnippetText(pCsr, &aSnippet[i],
+ i, (i==nSnippet-1), nFToken, zStart, zEnd, zEllipsis, &res
+ );
+ }
+
+ snippet_out:
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pCtx, rc);
+ sqlite3_free(res.z);
}else{
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ sqlite3_result_text(pCtx, res.z, -1, sqlite3_free);
}
}
+
+typedef struct TermOffset TermOffset;
+typedef struct TermOffsetCtx TermOffsetCtx;
+
+struct TermOffset {
+ char *pList; /* Position-list */
+ int iPos; /* Position just read from pList */
+ int iOff; /* Offset of this term from read positions */
+};
+
+struct TermOffsetCtx {
+ int iCol; /* Column of table to populate aTerm for */
+ int iTerm;
+ sqlite3_int64 iDocid;
+ TermOffset *aTerm;
+};
+
+/*
+** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets().
+*/
+static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ TermOffsetCtx *p = (TermOffsetCtx *)ctx;
+ int nTerm; /* Number of tokens in phrase */
+ int iTerm; /* For looping through nTerm phrase terms */
+ char *pList; /* Pointer to position list for phrase */
+ int iPos = 0; /* First position in position-list */
+
+ UNUSED_PARAMETER(iPhrase);
+ pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol);
+ nTerm = pExpr->pPhrase->nToken;
+ if( pList ){
+ fts3GetDeltaPosition(&pList, &iPos);
+ assert( iPos>=0 );
+ }
+
+ for(iTerm=0; iTerm<nTerm; iTerm++){
+ TermOffset *pT = &p->aTerm[p->iTerm++];
+ pT->iOff = nTerm-iTerm-1;
+ pT->pList = pList;
+ pT->iPos = iPos;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of offsets() function.
+*/
+SQLITE_PRIVATE void sqlite3Fts3Offsets(
+ sqlite3_context *pCtx, /* SQLite function call context */
+ Fts3Cursor *pCsr /* Cursor object */
+){
+ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+ sqlite3_tokenizer_module const *pMod = pTab->pTokenizer->pModule;
+ const char *ZDUMMY; /* Dummy argument used with xNext() */
+ int NDUMMY; /* Dummy argument used with xNext() */
+ int rc; /* Return Code */
+ int nToken; /* Number of tokens in query */
+ int iCol; /* Column currently being processed */
+ StrBuffer res = {0, 0, 0}; /* Result string */
+ TermOffsetCtx sCtx; /* Context for fts3ExprTermOffsetInit() */
+
+ if( !pCsr->pExpr ){
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
+ return;
+ }
+
+ memset(&sCtx, 0, sizeof(sCtx));
+ assert( pCsr->isRequireSeek==0 );
+
+ /* Count the number of terms in the query */
+ rc = fts3ExprLoadDoclists(pCsr, 0, &nToken);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+
+ /* Allocate the array of TermOffset iterators. */
+ sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
+ if( 0==sCtx.aTerm ){
+ rc = SQLITE_NOMEM;
+ goto offsets_out;
+ }
+ sCtx.iDocid = pCsr->iPrevId;
+
+ /* Loop through the table columns, appending offset information to
+ ** string-buffer res for each column.
+ */
+ for(iCol=0; iCol<pTab->nColumn; iCol++){
+ sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor */
+ int iStart;
+ int iEnd;
+ int iCurrent;
+ const char *zDoc;
+ int nDoc;
+
+ /* Initialize the contents of sCtx.aTerm[] for column iCol. There is
+ ** no way that this operation can fail, so the return code from
+ ** fts3ExprIterate() can be discarded.
+ */
+ sCtx.iCol = iCol;
+ sCtx.iTerm = 0;
+ (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void *)&sCtx);
+
+ /* Retreive the text stored in column iCol. If an SQL NULL is stored
+ ** in column iCol, jump immediately to the next iteration of the loop.
+ ** If an OOM occurs while retrieving the data (this can happen if SQLite
+ ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
+ ** to the caller.
+ */
+ zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
+ nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+ if( zDoc==0 ){
+ if( sqlite3_column_type(pCsr->pStmt, iCol+1)==SQLITE_NULL ){
+ continue;
+ }
+ rc = SQLITE_NOMEM;
+ goto offsets_out;
+ }
+
+ /* Initialize a tokenizer iterator to iterate through column iCol. */
+ rc = pMod->xOpen(pTab->pTokenizer, zDoc, nDoc, &pC);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+ pC->pTokenizer = pTab->pTokenizer;
+
+ rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
+ while( rc==SQLITE_OK ){
+ int i; /* Used to loop through terms */
+ int iMinPos = 0x7FFFFFFF; /* Position of next token */
+ TermOffset *pTerm = 0; /* TermOffset associated with next token */
+
+ for(i=0; i<nToken; i++){
+ TermOffset *pT = &sCtx.aTerm[i];
+ if( pT->pList && (pT->iPos-pT->iOff)<iMinPos ){
+ iMinPos = pT->iPos-pT->iOff;
+ pTerm = pT;
+ }
+ }
+
+ if( !pTerm ){
+ /* All offsets for this column have been gathered. */
+ break;
+ }else{
+ assert( iCurrent<=iMinPos );
+ if( 0==(0xFE&*pTerm->pList) ){
+ pTerm->pList = 0;
+ }else{
+ fts3GetDeltaPosition(&pTerm->pList, &pTerm->iPos);
+ }
+ while( rc==SQLITE_OK && iCurrent<iMinPos ){
+ rc = pMod->xNext(pC, &ZDUMMY, &NDUMMY, &iStart, &iEnd, &iCurrent);
+ }
+ if( rc==SQLITE_OK ){
+ char aBuffer[64];
+ sqlite3_snprintf(sizeof(aBuffer), aBuffer,
+ "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
+ );
+ rc = fts3StringAppend(&res, aBuffer, -1);
+ }else if( rc==SQLITE_DONE ){
+ rc = SQLITE_CORRUPT;
+ }
+ }
+ }
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ }
+
+ pMod->xClose(pC);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+ }
+
+ offsets_out:
+ sqlite3_free(sCtx.aTerm);
+ assert( rc!=SQLITE_DONE );
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pCtx, rc);
+ sqlite3_free(res.z);
+ }else{
+ sqlite3_result_text(pCtx, res.z, res.n-1, sqlite3_free);
+ }
+ return;
+}
+
+/*
+** Implementation of matchinfo() function.
+*/
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
- int rc = fts3GetMatchinfo(pCsr);
+ int rc;
+ if( !pCsr->pExpr ){
+ sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
+ return;
+ }
+ rc = fts3GetMatchinfo(pCsr);
if( rc!=SQLITE_OK ){
sqlite3_result_error_code(pContext, rc);
}else{
- int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*2);
+ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
+ int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
+ if( pTab->bHasDocsize ){
+ n += sizeof(u32)*(1 + 2*pTab->nColumn);
+ }
sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
}
}
@@ -107924,6 +115099,7 @@
rc = sqlite3_step(pRtree->pReadNode);
if( rc==SQLITE_ROW ){
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
+ assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
nodeReference(pParent);
}else{
@@ -109983,6 +117159,7 @@
}
rc = sqlite3_reset(pRtree->pReadRowid);
}
+ *pRowid = cell.iRowid;
if( rc==SQLITE_OK ){
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
@@ -110120,31 +117297,69 @@
}
/*
-** This routine queries database handle db for the page-size used by
-** database zDb. If successful, the page-size in bytes is written to
-** *piPageSize and SQLITE_OK returned. Otherwise, and an SQLite error
-** code is returned.
+** The second argument to this function contains the text of an SQL statement
+** that returns a single integer value. The statement is compiled and executed
+** using database connection db. If successful, the integer value returned
+** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
+** code is returned and the value of *piVal after returning is not defined.
*/
-static int getPageSize(sqlite3 *db, const char *zDb, int *piPageSize){
+static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
int rc = SQLITE_NOMEM;
+ if( zSql ){
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ *piVal = sqlite3_column_int(pStmt, 0);
+ }
+ rc = sqlite3_finalize(pStmt);
+ }
+ }
+ return rc;
+}
+
+/*
+** This function is called from within the xConnect() or xCreate() method to
+** determine the node-size used by the rtree table being created or connected
+** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
+** Otherwise, an SQLite error code is returned.
+**
+** If this function is being called as part of an xConnect(), then the rtree
+** table already exists. In this case the node-size is determined by inspecting
+** the root node of the tree.
+**
+** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
+** This ensures that each node is stored on a single database page. If the
+** database page-size is so large that more than RTREE_MAXCELLS entries
+** would fit in a single node, use a smaller node-size.
+*/
+static int getNodeSize(
+ sqlite3 *db, /* Database handle */
+ Rtree *pRtree, /* Rtree handle */
+ int isCreate /* True for xCreate, false for xConnect */
+){
+ int rc;
char *zSql;
- sqlite3_stmt *pStmt = 0;
-
- zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
- if( !zSql ){
- return SQLITE_NOMEM;
+ if( isCreate ){
+ int iPageSize;
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
+ rc = getIntFromStmt(db, zSql, &iPageSize);
+ if( rc==SQLITE_OK ){
+ pRtree->iNodeSize = iPageSize-64;
+ if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
+ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
+ }
+ }
+ }else{
+ zSql = sqlite3_mprintf(
+ "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
+ pRtree->zDb, pRtree->zName
+ );
+ rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
}
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- *piPageSize = sqlite3_column_int(pStmt, 0);
- }
- return sqlite3_finalize(pStmt);
+ return rc;
}
/*
@@ -110165,7 +117380,6 @@
int isCreate /* True for xCreate, false for xConnect */
){
int rc = SQLITE_OK;
- int iPageSize = 0;
Rtree *pRtree;
int nDb; /* Length of string argv[1] */
int nName; /* Length of string argv[2] */
@@ -110184,11 +117398,6 @@
return SQLITE_ERROR;
}
- rc = getPageSize(db, argv[1], &iPageSize);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
@@ -110207,44 +117416,37 @@
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
- /* Figure out the node size to use. By default, use 64 bytes less than
- ** the database page-size. This ensures that each node is stored on
- ** a single database page.
- **
- ** If the databasd page-size is so large that more than RTREE_MAXCELLS
- ** entries would fit in a single node, use a smaller node-size.
- */
- pRtree->iNodeSize = iPageSize-64;
- if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
- pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
- }
+ /* Figure out the node size to use. */
+ rc = getNodeSize(db, pRtree, isCreate);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
- if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
- *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- }else{
- char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
- char *zTmp;
- int ii;
- for(ii=4; zSql && ii<argc; ii++){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
- sqlite3_free(zTmp);
- }
- if( zSql ){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s);", zTmp);
- sqlite3_free(zTmp);
- }
- if( !zSql ){
- rc = SQLITE_NOMEM;
- }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ if( rc==SQLITE_OK ){
+ if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }else{
+ char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
+ char *zTmp;
+ int ii;
+ for(ii=4; zSql && ii<argc; ii++){
+ zTmp = zSql;
+ zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
+ sqlite3_free(zTmp);
+ }
+ if( zSql ){
+ zTmp = zSql;
+ zSql = sqlite3_mprintf("%s);", zTmp);
+ sqlite3_free(zTmp);
+ }
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ sqlite3_free(zSql);
}
- sqlite3_free(zSql);
}
if( rc==SQLITE_OK ){
diff --git a/dist/sqlite3.h b/dist/sqlite3.h
index a275b00..9268b20 100644
--- a/dist/sqlite3.h
+++ b/dist/sqlite3.h
@@ -107,13 +107,13 @@
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.6.22"
-#define SQLITE_VERSION_NUMBER 3006022
-#define SQLITE_SOURCE_ID "2010-03-22 23:55:10 82dd61fccff3e4c77e060e5734cd4b4e2eeb7c32"
+#define SQLITE_VERSION "3.7.0"
+#define SQLITE_VERSION_NUMBER 3007000
+#define SQLITE_SOURCE_ID "2010-07-07 14:45:41 8eefc287265443ec043bdab629597e79c9d22006"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version
+** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -135,9 +135,9 @@
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function a pointer
-** to a string constant whose value is the same as the [SQLITE_SOURCE_ID]
-** C preprocessor macro.
+** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
+** [SQLITE_SOURCE_ID] C preprocessor macro.
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -147,6 +147,33 @@
SQLITE_API int sqlite3_libversion_number(void);
/*
+** CAPI3REF: Run-Time Library Compilation Options Diagnostics
+**
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
+**
+** ^The sqlite3_compileoption_get() function allows interating
+** over the list of options that were defined at compile time by
+** returning the N-th compile time option string. ^If N is out of range,
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get().
+**
+** ^Support for the diagnostic functions sqlite3_compileoption_used()
+** and sqlite3_compileoption_get() may be omitted by specifing the
+** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
+**
+** See also: SQL functions [sqlite_compileoption_used()] and
+** [sqlite_compileoption_get()] and the [compile_options pragma].
+*/
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *sqlite3_compileoption_get(int N);
+#endif
+
+/*
** CAPI3REF: Test To See If The Library Is Threadsafe
**
** ^The sqlite3_threadsafe() function returns zero if and only if
@@ -366,7 +393,7 @@
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
@@ -422,7 +449,12 @@
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
-#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
+#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
+#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
+#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
+#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
+#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -437,6 +469,7 @@
#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
+#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
@@ -469,17 +502,18 @@
** information is written to disk in the same order as calls
** to xWrite().
*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_ATOMIC 0x00000001
+#define SQLITE_IOCAP_ATOMIC512 0x00000002
+#define SQLITE_IOCAP_ATOMIC1K 0x00000004
+#define SQLITE_IOCAP_ATOMIC2K 0x00000008
+#define SQLITE_IOCAP_ATOMIC4K 0x00000010
+#define SQLITE_IOCAP_ATOMIC8K 0x00000020
+#define SQLITE_IOCAP_ATOMIC16K 0x00000040
+#define SQLITE_IOCAP_ATOMIC32K 0x00000080
+#define SQLITE_IOCAP_ATOMIC64K 0x00000100
+#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
+#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
+#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
@@ -630,6 +664,13 @@
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
+ /* Methods above are valid for version 1 */
+ int (*xShmOpen)(sqlite3_file*);
+ int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
+ int (*xShmMap)(sqlite3_file*, int iPage, int pgsz, int, void volatile**);
+ void (*xShmBarrier)(sqlite3_file*);
+ int (*xShmClose)(sqlite3_file*, int deleteFlag);
+ /* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -647,11 +688,19 @@
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
+**
+** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
+** layer a hint of how large the database file will grow to be during the
+** current transaction. This hint is not guaranteed to be accurate but it
+** is often close. The underlying VFS might choose to preallocate database
+** file space based on this hint in order to help writes to the database
+** file run faster.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
+#define SQLITE_FCNTL_SIZE_HINT 5
/*
** CAPI3REF: Mutex Handle
@@ -783,20 +832,27 @@
** handled as a fatal error by SQLite, vfs implementations should endeavor
** to prevent this by setting mxPathname to a sufficiently large value.
**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
+** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
+** interfaces are not strictly a part of the filesystem, but they are
** included in the VFS structure for completeness.
** The xRandomness() function attempts to return nBytes bytes
** of good-quality randomness into zOut. The return value is
** the actual number of bytes of randomness obtained.
** The xSleep() method causes the calling thread to sleep for at
** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and time.
-**
+** method returns a Julian Day Number for the current date and time as
+** a floating point value.
+** The xCurrentTimeInt64() method returns, as an integer, the Julian
+** Day Number multipled by 86400000 (the number of milliseconds in
+** a 24-hour day).
+** ^SQLite will use the xCurrentTimeInt64() method to get the current
+** date and time if that method is available (if iVersion is 2 or
+** greater and the function pointer is not NULL) and will fall back
+** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
*/
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
- int iVersion; /* Structure version number */
+ int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@@ -815,8 +871,16 @@
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
+ /*
+ ** The methods above are in version 1 of the sqlite_vfs object
+ ** definition. Those that follow are added in version 2 or later
+ */
+ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
+ /*
+ ** The methods above are in versions 1 and 2 of the sqlite_vfs object.
+ ** New fields may be appended in figure versions. The iVersion
+ ** value will increment whenever this happens.
+ */
};
/*
@@ -837,6 +901,44 @@
#define SQLITE_ACCESS_READ 2
/*
+** CAPI3REF: Flags for the xShmLock VFS method
+**
+** These integer constants define the various locking operations
+** allowed by the xShmLock method of [sqlite3_io_methods]. The
+** following are the only legal combinations of flags to the
+** xShmLock method:
+**
+** <ul>
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
+** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
+** </ul>
+**
+** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
+** was given no the corresponding lock.
+**
+** The xShmLock method can transition between unlocked and SHARED or
+** between unlocked and EXCLUSIVE. It cannot transition between SHARED
+** and EXCLUSIVE.
+*/
+#define SQLITE_SHM_UNLOCK 1
+#define SQLITE_SHM_LOCK 2
+#define SQLITE_SHM_SHARED 4
+#define SQLITE_SHM_EXCLUSIVE 8
+
+/*
+** CAPI3REF: Maximum xShmLock index
+**
+** The xShmLock method on [sqlite3_io_methods] may use values
+** between 0 and this upper bound as its "offset" argument.
+** The SQLite core will never attempt to acquire or release a
+** lock outside of this range
+*/
+#define SQLITE_SHM_NLOCK 8
+
+
+/*
** CAPI3REF: Initialize The SQLite Library
**
** ^The sqlite3_initialize() routine initializes the
@@ -945,11 +1047,10 @@
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
-** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -969,11 +1070,10 @@
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
-** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@@ -1055,7 +1155,6 @@
/*
** CAPI3REF: Configuration Options
-** EXPERIMENTAL
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1241,6 +1340,24 @@
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
+** <dt>SQLITE_CONFIG_LOG</dt>
+** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** function with a call signature of void(*)(void*,int,const char*),
+** and a pointer to void. ^If the function pointer is not NULL, it is
+** invoked by [sqlite3_log()] to process each logging event. ^If the
+** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
+** passed through as the first parameter to the application-defined logger
+** function whenever that function is invoked. ^The second parameter to
+** the logger function is a copy of the first parameter to the corresponding
+** [sqlite3_log()] call and is intended to be a [result code] or an
+** [extended result code]. ^The third parameter passed to the logger is
+** log message after formatting via [sqlite3_snprintf()].
+** The SQLite logging interface is not reentrant; the logger function
+** supplied by the application must not invoke any SQLite interface.
+** In a multi-threaded application, the application-defined logger
+** function must be threadsafe. </dd>
+**
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1261,8 +1378,7 @@
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
+** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@@ -2038,7 +2154,6 @@
/*
** CAPI3REF: Tracing And Profiling Functions
-** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2056,7 +2171,7 @@
** the original statement text and an estimate of wall-clock time
** of how long that statement took to run.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
+SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
@@ -2849,6 +2964,14 @@
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
+** For all versions of SQLite up to and including 3.6.23.1, it was required
+** after sqlite3_step() returned anything other than [SQLITE_ROW] that
+** [sqlite3_reset()] be called before any subsequent invocation of
+** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
+** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
+** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
+** automatically in this circumstance rather than returning [SQLITE_MISUSE].
+**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@@ -3661,6 +3784,7 @@
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
+#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@@ -3687,6 +3811,25 @@
);
/*
+** Specify the activation key for a SEE database. Unless
+** activated, none of the SEE routines will work.
+*/
+SQLITE_API void sqlite3_activate_see(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+#ifdef SQLITE_ENABLE_CEROD
+/*
+** Specify the activation key for a CEROD database. Unless
+** activated, none of the CEROD routines will work.
+*/
+SQLITE_API void sqlite3_activate_cerod(
+ const char *zPassPhrase /* Activation phrase */
+);
+#endif
+
+/*
** CAPI3REF: Suspend Execution For A Short Time
**
** ^The sqlite3_sleep() function causes the current thread to suspend execution
@@ -3824,8 +3967,6 @@
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
-** ^The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@@ -4111,8 +4252,6 @@
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -4132,7 +4271,6 @@
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
-** EXPERIMENTAL
**
** This structure, sometimes called a a "virtual table module",
** defines the implementation of a [virtual tables].
@@ -4179,7 +4317,6 @@
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
-** EXPERIMENTAL
**
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the [xBestIndex]
@@ -4261,7 +4398,6 @@
/*
** CAPI3REF: Register A Virtual Table Implementation
-** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -4283,13 +4419,13 @@
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -4300,7 +4436,6 @@
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@@ -4326,7 +4461,6 @@
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
-** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@@ -4348,18 +4482,16 @@
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
-** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
-** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -4374,7 +4506,7 @@
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -4384,8 +4516,6 @@
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@@ -4728,7 +4858,6 @@
/*
** CAPI3REF: Mutex Methods Object
-** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@@ -4941,11 +5070,11 @@
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_LAST 16
+#define SQLITE_TESTCTRL_PGHDRSZ 17
+#define SQLITE_TESTCTRL_LAST 17
/*
** CAPI3REF: SQLite Runtime Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about the preformance of SQLite, and optionally to reset various
@@ -4973,12 +5102,11 @@
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
-** EXPERIMENTAL
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
@@ -5065,14 +5193,15 @@
/*
** CAPI3REF: Database Connection Status
-** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
-** is the parameter to interrogate. ^Currently, the only allowed value
-** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
-** Additional options will likely appear in future releases of SQLite.
+** is an integer constant, taken from the set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
+** determiness the parameter to interrogate. The set of
+** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
+** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
@@ -5081,11 +5210,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
-** EXPERIMENTAL
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@@ -5100,14 +5228,21 @@
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
+**
+** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
+** <dd>^This parameter returns the approximate number of of bytes of heap
+** memory used by all pager caches associated with the database connection.
+** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
+** checked out.</dd>)^
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
+#define SQLITE_DBSTATUS_CACHE_USED 1
+#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
-** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
@@ -5129,11 +5264,10 @@
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
-** EXPERIMENTAL
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
@@ -5151,14 +5285,21 @@
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.</dd>
**
+** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
+** <dd>^This is the number of rows inserted into transient indices that
+** were created automatically in order to help joins run faster.
+** A non-zero value in this counter may indicate an opportunity to
+** improvement performance by adding permanent indices that do not
+** need to be reinitialized each time the statement is run.</dd>
+**
** </dl>
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
+#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
-** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@@ -5173,7 +5314,6 @@
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
-** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
** register an alternative page cache implementation by passing in an
@@ -5315,7 +5455,6 @@
/*
** CAPI3REF: Online Backup Object
-** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@@ -5328,7 +5467,6 @@
/*
** CAPI3REF: Online Backup API.
-** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
@@ -5397,10 +5535,14 @@
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
-** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
-** database was opened read-only or if
-** the destination is an in-memory database with a different page size
-** from the source database.
+** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
+** <ol>
+** <li> the destination database was opened read-only, or
+** <li> the destination database is using write-ahead-log journaling
+** and the destination and source page sizes differ, or
+** <li> The destination database is an in-memory database and the
+** destination and source page sizes differ.
+** </ol>)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
@@ -5516,7 +5658,6 @@
/*
** CAPI3REF: Unlock Notification
-** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -5638,7 +5779,6 @@
/*
** CAPI3REF: String Comparison
-** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
@@ -5649,16 +5789,19 @@
/*
** CAPI3REF: Error Logging Interface
-** EXPERIMENTAL
**
** ^The [sqlite3_log()] interface writes a message into the error log
-** established by the [SQLITE_CONFIG_ERRORLOG] option to [sqlite3_config()].
+** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
+** ^If logging is enabled, the zFormat string and subsequent arguments are
+** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
** nothing to prevent an application from calling sqlite3_log(), doing so
** is considered bad form.
**
+** The zFormat string must not be NULL.
+**
** To avoid deadlocks and other threading problems, the sqlite3_log() routine
** will not use dynamically allocated memory. The log message is stored in
** a fixed-length buffer on the stack. If the log message is longer than
@@ -5667,16 +5810,89 @@
*/
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
-// Begin Android add
/*
-** Android additional API.
+** CAPI3REF: Write-Ahead Log Commit Hook
**
-** This function changes the default behavior of BEGIN to IMMEDIATE if called
-** with immediate=1.
-** Calling with immediate=0 will revert to DEFERRED.
+** ^The [sqlite3_wal_hook()] function is used to register a callback that
+** will be invoked each time a database connection commits data to a
+** [write-ahead log] (i.e. whenever a transaction is committed in
+** [journal_mode | journal_mode=WAL mode]).
+**
+** ^The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released, so the implementation
+** may read, write or [checkpoint] the database as required.
+**
+** ^The first parameter passed to the callback function when it is invoked
+** is a copy of the third parameter passed to sqlite3_wal_hook() when
+** registering the callback. ^The second is a copy of the database handle.
+** ^The third parameter is the name of the database that was written to -
+** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
+** is the number of pages currently in the write-ahead log file,
+** including those that were just committed.
+**
+** The callback function should normally return [SQLITE_OK]. ^If an error
+** code is returned, that error will propagate back up through the
+** SQLite code base to cause the statement that provoked the callback
+** to report an error, though the commit will have still occurred. If the
+** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
+** that does not correspond to any valid SQLite error code, the results
+** are undefined.
+**
+** A single database handle may have at most a single write-ahead log callback
+** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
+** previously registered write-ahead log callback. ^Note that the
+** [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
+** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
-int sqlite3_set_transaction_default_immediate(sqlite3*, int immediate);
-// End Android add
+SQLITE_API void *sqlite3_wal_hook(
+ sqlite3*,
+ int(*)(void *,sqlite3*,const char*,int),
+ void*
+);
+
+/*
+** CAPI3REF: Configure an auto-checkpoint
+**
+** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
+** [sqlite3_wal_hook()] that causes any database on [database connection] D
+** to automatically [checkpoint]
+** after committing a transaction if there are N or
+** more frames in the [write-ahead log] file. ^Passing zero or
+** a negative value as the nFrame parameter disables automatic
+** checkpoints entirely.
+**
+** ^The callback registered by this function replaces any existing callback
+** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
+** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
+** configured by this function.
+**
+** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
+** from SQL.
+**
+** ^Every new [database connection] defaults to having the auto-checkpoint
+** enabled with a threshold of 1000 pages. The use of this interface
+** is only necessary if the default setting is found to be suboptimal
+** for a particular application.
+*/
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+
+/*
+** CAPI3REF: Checkpoint a database
+**
+** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
+** on [database connection] D to be [checkpointed]. ^If X is NULL or an
+** empty string, then a checkpoint is run on all databases of
+** connection D. ^If the database connection D is not in
+** [WAL | write-ahead log mode] then this interface is a harmless no-op.
+**
+** ^The [wal_checkpoint pragma] can be used to invoke this interface
+** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
+** [wal_autocheckpoint pragma] can be used to cause this interface to be
+** run whenever the WAL reaches a certain size threshold.
+*/
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
diff --git a/dist/sqlite3.h.orig b/dist/sqlite3.h.orig
deleted file mode 100644
index 56efddd..0000000
--- a/dist/sqlite3.h.orig
+++ /dev/null
@@ -1,5682 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the SQLite library
-** presents to client programs. If a C-function, structure, datatype,
-** or constant definition does not appear in this file, then it is
-** not a published API of SQLite, is subject to change without
-** notice, and should not be referenced by programs that use SQLite.
-**
-** Some of the definitions that are in this file are marked as
-** "experimental". Experimental interfaces are normally new
-** features recently added to SQLite. We do not anticipate changes
-** to experimental interfaces but reserve the right to make minor changes
-** if experience from use "in the wild" suggest such changes are prudent.
-**
-** The official C-language API documentation for SQLite is derived
-** from comments in this file. This file is the authoritative source
-** on how SQLite interfaces are suppose to operate.
-**
-** The name of this file under configuration management is "sqlite.h.in".
-** The makefile makes some minor changes to this file (such as inserting
-** the version number) and changes its name to "sqlite3.h" as
-** part of the build process.
-*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
-#include <stdarg.h> /* Needed for the definition of va_list */
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
-** Add the ability to override 'extern'
-*/
-#ifndef SQLITE_EXTERN
-# define SQLITE_EXTERN extern
-#endif
-
-#ifndef SQLITE_API
-# define SQLITE_API
-#endif
-
-
-/*
-** These no-op macros are used in front of interfaces to mark those
-** interfaces as either deprecated or experimental. New applications
-** should not use deprecated interfaces - they are support for backwards
-** compatibility only. Application writers should be aware that
-** experimental interfaces are subject to change in point releases.
-**
-** These macros used to resolve to various kinds of compiler magic that
-** would generate warning messages when they were used. But that
-** compiler magic ended up generating such a flurry of bug reports
-** that we have taken it all out and gone back to using simple
-** noop macros.
-*/
-#define SQLITE_DEPRECATED
-#define SQLITE_EXPERIMENTAL
-
-/*
-** Ensure these symbols were not defined by some previous header file.
-*/
-#ifdef SQLITE_VERSION
-# undef SQLITE_VERSION
-#endif
-#ifdef SQLITE_VERSION_NUMBER
-# undef SQLITE_VERSION_NUMBER
-#endif
-
-/*
-** CAPI3REF: Compile-Time Library Version Numbers
-**
-** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header
-** evaluates to a string literal that is the SQLite version in the
-** format "X.Y.Z" where X is the major version number (always 3 for
-** SQLite3) and Y is the minor version number and Z is the release number.)^
-** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer
-** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
-** numbers used in [SQLITE_VERSION].)^
-** The SQLITE_VERSION_NUMBER for any given release of SQLite will also
-** be larger than the release from which it is derived. Either Y will
-** be held constant and Z will be incremented or else Y will be incremented
-** and Z will be reset to zero.
-**
-** Since version 3.6.18, SQLite source code has been stored in the
-** <a href="http://www.fossil-scm.org/">Fossil configuration management
-** system</a>. ^The SQLITE_SOURCE_ID macro evalutes to
-** a string which identifies a particular check-in of SQLite
-** within its configuration management system. ^The SQLITE_SOURCE_ID
-** string contains the date and time of the check-in (UTC) and an SHA1
-** hash of the entire source tree.
-**
-** See also: [sqlite3_libversion()],
-** [sqlite3_libversion_number()], [sqlite3_sourceid()],
-** [sqlite_version()] and [sqlite_source_id()].
-*/
-#define SQLITE_VERSION "3.6.22"
-#define SQLITE_VERSION_NUMBER 3006022
-#define SQLITE_SOURCE_ID "2010-03-22 23:55:10 82dd61fccff3e4c77e060e5734cd4b4e2eeb7c32"
-
-/*
-** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version
-**
-** These interfaces provide the same information as the [SQLITE_VERSION],
-** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
-** but are associated with the library instead of the header file. ^(Cautious
-** programmers might include assert() statements in their application to
-** verify that values returned by these interfaces match the macros in
-** the header, and thus insure that the application is
-** compiled with matching library and header files.
-**
-** <blockquote><pre>
-** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
-** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
-** </pre></blockquote>)^
-**
-** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION]
-** macro. ^The sqlite3_libversion() function returns a pointer to the
-** to the sqlite3_version[] string constant. The sqlite3_libversion()
-** function is provided for use in DLLs since DLL users usually do not have
-** direct access to string constants within the DLL. ^The
-** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function a pointer
-** to a string constant whose value is the same as the [SQLITE_SOURCE_ID]
-** C preprocessor macro.
-**
-** See also: [sqlite_version()] and [sqlite_source_id()].
-*/
-SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
-SQLITE_API const char *sqlite3_libversion(void);
-SQLITE_API const char *sqlite3_sourceid(void);
-SQLITE_API int sqlite3_libversion_number(void);
-
-/*
-** CAPI3REF: Test To See If The Library Is Threadsafe
-**
-** ^The sqlite3_threadsafe() function returns zero if and only if
-** SQLite was compiled mutexing code omitted due to the
-** [SQLITE_THREADSAFE] compile-time option being set to 0.
-**
-** SQLite can be compiled with or without mutexes. When
-** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
-** are enabled and SQLite is threadsafe. When the
-** [SQLITE_THREADSAFE] macro is 0,
-** the mutexes are omitted. Without the mutexes, it is not safe
-** to use SQLite concurrently from more than one thread.
-**
-** Enabling mutexes incurs a measurable performance penalty.
-** So if speed is of utmost importance, it makes sense to disable
-** the mutexes. But for maximum safety, mutexes should be enabled.
-** ^The default behavior is for mutexes to be enabled.
-**
-** This interface can be used by an application to make sure that the
-** version of SQLite that it is linking against was compiled with
-** the desired setting of the [SQLITE_THREADSAFE] macro.
-**
-** This interface only reports on the compile-time mutex setting
-** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with
-** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
-** can be fully or partially disabled using a call to [sqlite3_config()]
-** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
-** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the
-** sqlite3_threadsafe() function shows only the compile-time setting of
-** thread safety, not any run-time changes to that setting made by
-** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
-** is unchanged by calls to sqlite3_config().)^
-**
-** See the [threading mode] documentation for additional information.
-*/
-SQLITE_API int sqlite3_threadsafe(void);
-
-/*
-** CAPI3REF: Database Connection Handle
-** KEYWORDS: {database connection} {database connections}
-**
-** Each open SQLite database is represented by a pointer to an instance of
-** the opaque structure named "sqlite3". It is useful to think of an sqlite3
-** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
-** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()]
-** is its destructor. There are many other interfaces (such as
-** [sqlite3_prepare_v2()], [sqlite3_create_function()], and
-** [sqlite3_busy_timeout()] to name but three) that are methods on an
-** sqlite3 object.
-*/
-typedef struct sqlite3 sqlite3;
-
-/*
-** CAPI3REF: 64-Bit Integer Types
-** KEYWORDS: sqlite_int64 sqlite_uint64
-**
-** Because there is no cross-platform way to specify 64-bit integer types
-** SQLite includes typedefs for 64-bit signed and unsigned integers.
-**
-** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions.
-** The sqlite_int64 and sqlite_uint64 types are supported for backwards
-** compatibility only.
-**
-** ^The sqlite3_int64 and sqlite_int64 types can store integer values
-** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
-** between 0 and +18446744073709551615 inclusive.
-*/
-#ifdef SQLITE_INT64_TYPE
- typedef SQLITE_INT64_TYPE sqlite_int64;
- typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
-#elif defined(_MSC_VER) || defined(__BORLANDC__)
- typedef __int64 sqlite_int64;
- typedef unsigned __int64 sqlite_uint64;
-#else
- typedef long long int sqlite_int64;
- typedef unsigned long long int sqlite_uint64;
-#endif
-typedef sqlite_int64 sqlite3_int64;
-typedef sqlite_uint64 sqlite3_uint64;
-
-/*
-** If compiling for a processor that lacks floating point support,
-** substitute integer for floating-point.
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# define double sqlite3_int64
-#endif
-
-/*
-** CAPI3REF: Closing A Database Connection
-**
-** ^The sqlite3_close() routine is the destructor for the [sqlite3] object.
-** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is
-** successfullly destroyed and all associated resources are deallocated.
-**
-** Applications must [sqlite3_finalize | finalize] all [prepared statements]
-** and [sqlite3_blob_close | close] all [BLOB handles] associated with
-** the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close() is called on a [database connection] that still has
-** outstanding [prepared statements] or [BLOB handles], then it returns
-** SQLITE_BUSY.
-**
-** ^If [sqlite3_close()] is invoked while a transaction is open,
-** the transaction is automatically rolled back.
-**
-** The C parameter to [sqlite3_close(C)] must be either a NULL
-** pointer or an [sqlite3] object pointer obtained
-** from [sqlite3_open()], [sqlite3_open16()], or
-** [sqlite3_open_v2()], and not previously closed.
-** ^Calling sqlite3_close() with a NULL pointer argument is a
-** harmless no-op.
-*/
-SQLITE_API int sqlite3_close(sqlite3 *);
-
-/*
-** The type for a callback function.
-** This is legacy and deprecated. It is included for historical
-** compatibility and is not documented.
-*/
-typedef int (*sqlite3_callback)(void*,int,char**, char**);
-
-/*
-** CAPI3REF: One-Step Query Execution Interface
-**
-** The sqlite3_exec() interface is a convenience wrapper around
-** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
-** that allows an application to run multiple statements of SQL
-** without having to use a lot of C code.
-**
-** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
-** semicolon-separate SQL statements passed into its 2nd argument,
-** in the context of the [database connection] passed in as its 1st
-** argument. ^If the callback function of the 3rd argument to
-** sqlite3_exec() is not NULL, then it is invoked for each result row
-** coming out of the evaluated SQL statements. ^The 4th argument to
-** to sqlite3_exec() is relayed through to the 1st argument of each
-** callback invocation. ^If the callback pointer to sqlite3_exec()
-** is NULL, then no callback is ever invoked and result rows are
-** ignored.
-**
-** ^If an error occurs while evaluating the SQL statements passed into
-** sqlite3_exec(), then execution of the current statement stops and
-** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec()
-** is not NULL then any error message is written into memory obtained
-** from [sqlite3_malloc()] and passed back through the 5th parameter.
-** To avoid memory leaks, the application should invoke [sqlite3_free()]
-** on error message strings returned through the 5th parameter of
-** of sqlite3_exec() after the error message string is no longer needed.
-** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors
-** occur, then sqlite3_exec() sets the pointer in its 5th parameter to
-** NULL before returning.
-**
-** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec()
-** routine returns SQLITE_ABORT without invoking the callback again and
-** without running any subsequent SQL statements.
-**
-** ^The 2nd argument to the sqlite3_exec() callback function is the
-** number of columns in the result. ^The 3rd argument to the sqlite3_exec()
-** callback is an array of pointers to strings obtained as if from
-** [sqlite3_column_text()], one for each column. ^If an element of a
-** result row is NULL then the corresponding string pointer for the
-** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the
-** sqlite3_exec() callback is an array of pointers to strings where each
-** entry represents the name of corresponding result column as obtained
-** from [sqlite3_column_name()].
-**
-** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
-** to an empty string, or a pointer that contains only whitespace and/or
-** SQL comments, then no SQL statements are evaluated and the database
-** is not changed.
-**
-** Restrictions:
-**
-** <ul>
-** <li> The application must insure that the 1st parameter to sqlite3_exec()
-** is a valid and open [database connection].
-** <li> The application must not close [database connection] specified by
-** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
-** <li> The application must not modify the SQL statement text passed into
-** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
-** </ul>
-*/
-SQLITE_API int sqlite3_exec(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be evaluated */
- int (*callback)(void*,int,char**,char**), /* Callback function */
- void *, /* 1st argument to callback */
- char **errmsg /* Error msg written here */
-);
-
-/*
-** CAPI3REF: Result Codes
-** KEYWORDS: SQLITE_OK {error code} {error codes}
-** KEYWORDS: {result code} {result codes}
-**
-** Many SQLite functions return an integer result code from the set shown
-** here in order to indicates success or failure.
-**
-** New error codes may be added in future versions of SQLite.
-**
-** See also: [SQLITE_IOERR_READ | extended result codes]
-*/
-#define SQLITE_OK 0 /* Successful result */
-/* beginning-of-error-codes */
-#define SQLITE_ERROR 1 /* SQL error or missing database */
-#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
-#define SQLITE_PERM 3 /* Access permission denied */
-#define SQLITE_ABORT 4 /* Callback routine requested an abort */
-#define SQLITE_BUSY 5 /* The database file is locked */
-#define SQLITE_LOCKED 6 /* A table in the database is locked */
-#define SQLITE_NOMEM 7 /* A malloc() failed */
-#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
-#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
-#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
-#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
-#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
-#define SQLITE_FULL 13 /* Insertion failed because database is full */
-#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Database is empty */
-#define SQLITE_SCHEMA 17 /* The database schema changed */
-#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
-#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
-#define SQLITE_MISMATCH 20 /* Data type mismatch */
-#define SQLITE_MISUSE 21 /* Library used incorrectly */
-#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
-#define SQLITE_AUTH 23 /* Authorization denied */
-#define SQLITE_FORMAT 24 /* Auxiliary database format error */
-#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
-#define SQLITE_NOTADB 26 /* File opened that is not a database file */
-#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
-#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
-/* end-of-error-codes */
-
-/*
-** CAPI3REF: Extended Result Codes
-** KEYWORDS: {extended error code} {extended error codes}
-** KEYWORDS: {extended result code} {extended result codes}
-**
-** In its default configuration, SQLite API routines return one of 26 integer
-** [SQLITE_OK | result codes]. However, experience has shown that many of
-** these result codes are too coarse-grained. They do not provide as
-** much information about problems as programmers might like. In an effort to
-** address this, newer versions of SQLite (version 3.3.8 and later) include
-** support for additional result codes that provide more detailed information
-** about errors. The extended result codes are enabled or disabled
-** on a per database connection basis using the
-** [sqlite3_extended_result_codes()] API.
-**
-** Some of the available extended result codes are listed here.
-** One may expect the number of extended result codes will be expand
-** over time. Software that uses extended result codes should expect
-** to see new result codes in future releases of SQLite.
-**
-** The SQLITE_OK result code will never be extended. It will always
-** be exactly zero.
-*/
-#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
-#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
-#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
-#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
-#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
-#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
-#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
-#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
-#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
-#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
-#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))
-#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))
-#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8))
-#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))
-#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
-#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
-#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
-#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
-
-/*
-** CAPI3REF: Flags For File Open Operations
-**
-** These bit values are intended for use in the
-** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
-*/
-#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
-#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
-#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
-#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
-#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
-#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
-#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
-#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
-#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
-#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
-
-/*
-** CAPI3REF: Device Characteristics
-**
-** The xDeviceCapabilities method of the [sqlite3_io_methods]
-** object returns an integer which is a vector of the these
-** bit values expressing I/O characteristics of the mass storage
-** device that holds the file that the [sqlite3_io_methods]
-** refers to.
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
-
-/*
-** CAPI3REF: File Locking Levels
-**
-** SQLite uses one of these integer values as the second
-** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlite3_io_methods] object.
-*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
-
-/*
-** CAPI3REF: Synchronization Type Flags
-**
-** When SQLite invokes the xSync() method of an
-** [sqlite3_io_methods] object it uses a combination of
-** these integer values as the second argument.
-**
-** When the SQLITE_SYNC_DATAONLY flag is used, it means that the
-** sync operation only needs to flush data to mass storage. Inode
-** information need not be flushed. If the lower four bits of the flag
-** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics.
-** If the lower four bits equal SQLITE_SYNC_FULL, that means
-** to use Mac OS X style fullsync instead of fsync().
-*/
-#define SQLITE_SYNC_NORMAL 0x00002
-#define SQLITE_SYNC_FULL 0x00003
-#define SQLITE_SYNC_DATAONLY 0x00010
-
-/*
-** CAPI3REF: OS Interface Open File Handle
-**
-** An [sqlite3_file] object represents an open file in the
-** [sqlite3_vfs | OS interface layer]. Individual OS interface
-** implementations will
-** want to subclass this object by appending additional fields
-** for their own use. The pMethods entry is a pointer to an
-** [sqlite3_io_methods] object that defines methods for performing
-** I/O operations on the open file.
-*/
-typedef struct sqlite3_file sqlite3_file;
-struct sqlite3_file {
- const struct sqlite3_io_methods *pMethods; /* Methods for an open file */
-};
-
-/*
-** CAPI3REF: OS Interface File Virtual Methods Object
-**
-** Every file opened by the [sqlite3_vfs] xOpen method populates an
-** [sqlite3_file] object (or, more commonly, a subclass of the
-** [sqlite3_file] object) with a pointer to an instance of this object.
-** This object defines the methods used to perform various operations
-** against the open file represented by the [sqlite3_file] object.
-**
-** If the xOpen method sets the sqlite3_file.pMethods element
-** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
-** may be invoked even if the xOpen reported that it failed. The
-** only way to prevent a call to xClose following a failed xOpen
-** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
-**
-** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
-** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
-** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY]
-** flag may be ORed in to indicate that only the data of the file
-** and not its inode needs to be synced.
-**
-** The integer values to xLock() and xUnlock() are one of
-** <ul>
-** <li> [SQLITE_LOCK_NONE],
-** <li> [SQLITE_LOCK_SHARED],
-** <li> [SQLITE_LOCK_RESERVED],
-** <li> [SQLITE_LOCK_PENDING], or
-** <li> [SQLITE_LOCK_EXCLUSIVE].
-** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
-** The xCheckReservedLock() method checks whether any database connection,
-** either in this process or in some other process, is holding a RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false otherwise.
-**
-** The xFileControl() method is a generic interface that allows custom
-** VFS implementations to directly control an open file using the
-** [sqlite3_file_control()] interface. The second "op" argument is an
-** integer opcode. The third argument is a generic pointer intended to
-** point to a structure that may contain arguments or space in which to
-** write return values. Potential uses for xFileControl() might be
-** functions to enable blocking locks with timeouts, to change the
-** locking strategy (for example to use dot-file locks), to inquire
-** about the status of a lock, or to break stale locks. The SQLite
-** core reserves all opcodes less than 100 for its own use.
-** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
-** Applications that define a custom xFileControl method should use opcodes
-** greater than 100 to avoid conflicts.
-**
-** The xSectorSize() method returns the sector size of the
-** device that underlies the file. The sector size is the
-** minimum write that can be performed without disturbing
-** other bytes in the file. The xDeviceCharacteristics()
-** method returns a bit vector describing behaviors of the
-** underlying device:
-**
-** <ul>
-** <li> [SQLITE_IOCAP_ATOMIC]
-** <li> [SQLITE_IOCAP_ATOMIC512]
-** <li> [SQLITE_IOCAP_ATOMIC1K]
-** <li> [SQLITE_IOCAP_ATOMIC2K]
-** <li> [SQLITE_IOCAP_ATOMIC4K]
-** <li> [SQLITE_IOCAP_ATOMIC8K]
-** <li> [SQLITE_IOCAP_ATOMIC16K]
-** <li> [SQLITE_IOCAP_ATOMIC32K]
-** <li> [SQLITE_IOCAP_ATOMIC64K]
-** <li> [SQLITE_IOCAP_SAFE_APPEND]
-** <li> [SQLITE_IOCAP_SEQUENTIAL]
-** </ul>
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-**
-** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill
-** in the unread portions of the buffer with zeros. A VFS that
-** fails to zero-fill short reads might seem to work. However,
-** failure to zero-fill short reads will eventually lead to
-** database corruption.
-*/
-typedef struct sqlite3_io_methods sqlite3_io_methods;
-struct sqlite3_io_methods {
- int iVersion;
- int (*xClose)(sqlite3_file*);
- int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
- int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
- int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
- int (*xSync)(sqlite3_file*, int flags);
- int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
- int (*xLock)(sqlite3_file*, int);
- int (*xUnlock)(sqlite3_file*, int);
- int (*xCheckReservedLock)(sqlite3_file*, int *pResOut);
- int (*xFileControl)(sqlite3_file*, int op, void *pArg);
- int (*xSectorSize)(sqlite3_file*);
- int (*xDeviceCharacteristics)(sqlite3_file*);
- /* Additional methods may be added in future releases */
-};
-
-/*
-** CAPI3REF: Standard File Control Opcodes
-**
-** These integer constants are opcodes for the xFileControl method
-** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()]
-** interface.
-**
-** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
-** opcode causes the xFileControl method to write the current state of
-** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
-** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-*/
-#define SQLITE_FCNTL_LOCKSTATE 1
-#define SQLITE_GET_LOCKPROXYFILE 2
-#define SQLITE_SET_LOCKPROXYFILE 3
-#define SQLITE_LAST_ERRNO 4
-
-/*
-** CAPI3REF: Mutex Handle
-**
-** The mutex module within SQLite defines [sqlite3_mutex] to be an
-** abstract type for a mutex object. The SQLite core never looks
-** at the internal representation of an [sqlite3_mutex]. It only
-** deals with pointers to the [sqlite3_mutex] object.
-**
-** Mutexes are created using [sqlite3_mutex_alloc()].
-*/
-typedef struct sqlite3_mutex sqlite3_mutex;
-
-/*
-** CAPI3REF: OS Interface Object
-**
-** An instance of the sqlite3_vfs object defines the interface between
-** the SQLite core and the underlying operating system. The "vfs"
-** in the name of the object stands for "virtual file system".
-**
-** The value of the iVersion field is initially 1 but may be larger in
-** future versions of SQLite. Additional fields may be appended to this
-** object when the iVersion value is increased. Note that the structure
-** of the sqlite3_vfs object changes in the transaction between
-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
-** modified.
-**
-** The szOsFile field is the size of the subclassed [sqlite3_file]
-** structure used by this VFS. mxPathname is the maximum length of
-** a pathname in this VFS.
-**
-** Registered sqlite3_vfs objects are kept on a linked list formed by
-** the pNext pointer. The [sqlite3_vfs_register()]
-** and [sqlite3_vfs_unregister()] interfaces manage this list
-** in a thread-safe way. The [sqlite3_vfs_find()] interface
-** searches the list. Neither the application code nor the VFS
-** implementation should use the pNext pointer.
-**
-** The pNext field is the only field in the sqlite3_vfs
-** structure that SQLite will ever modify. SQLite will only access
-** or modify this field while holding a particular static mutex.
-** The application should never modify anything within the sqlite3_vfs
-** object once the object has been registered.
-**
-** The zName field holds the name of the VFS module. The name must
-** be unique across all VFS modules.
-**
-** SQLite will guarantee that the zFilename parameter to xOpen
-** is either a NULL pointer or string obtained
-** from xFullPathname(). SQLite further guarantees that
-** the string will be valid and unchanged until xClose() is
-** called. Because of the previous sentence,
-** the [sqlite3_file] can safely store a pointer to the
-** filename if it needs to remember the filename for some reason.
-** If the zFilename parameter is xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file. Whenever the
-** xFilename parameter is NULL it will also be the case that the
-** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
-**
-** The flags argument to xOpen() includes all bits set in
-** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
-** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
-** If xOpen() opens a file read-only then it sets *pOutFlags to
-** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
-**
-** SQLite will also add one of the following flags to the xOpen()
-** call, depending on the object being opened:
-**
-** <ul>
-** <li> [SQLITE_OPEN_MAIN_DB]
-** <li> [SQLITE_OPEN_MAIN_JOURNAL]
-** <li> [SQLITE_OPEN_TEMP_DB]
-** <li> [SQLITE_OPEN_TEMP_JOURNAL]
-** <li> [SQLITE_OPEN_TRANSIENT_DB]
-** <li> [SQLITE_OPEN_SUBJOURNAL]
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul>
-**
-** The file I/O implementation can use the object type flags to
-** change the way it deals with files. For example, an application
-** that does not care about crash recovery or rollback might make
-** the open of a journal file a no-op. Writes to this journal would
-** also be no-ops, and any attempt to read the journal would return
-** SQLITE_IOERR. Or the implementation might recognize that a database
-** file will be doing page-aligned sector reads and writes in a random
-** order and set up its I/O subsystem accordingly.
-**
-** SQLite might also add one of the following flags to the xOpen method:
-**
-** <ul>
-** <li> [SQLITE_OPEN_DELETEONCLOSE]
-** <li> [SQLITE_OPEN_EXCLUSIVE]
-** </ul>
-**
-** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed. The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP databases, journals and for subjournals.
-**
-** The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
-** with the [SQLITE_OPEN_CREATE] flag, which are both directly
-** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
-** SQLITE_OPEN_CREATE, is used to indicate that file should always
-** be created, and that it is an error if it already exists.
-** It is <i>not</i> used to indicate the file should be opened
-** for exclusive access.
-**
-** At least szOsFile bytes of memory are allocated by SQLite
-** to hold the [sqlite3_file] structure passed as the third
-** argument to xOpen. The xOpen method does not have to
-** allocate the structure; it should just fill it in. Note that
-** the xOpen method must set the sqlite3_file.pMethods to either
-** a valid [sqlite3_io_methods] object or to NULL. xOpen must do
-** this even if the open fails. SQLite expects that the sqlite3_file.pMethods
-** element will be valid after xOpen returns regardless of the success
-** or failure of the xOpen call.
-**
-** The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
-** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
-** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
-** to test whether a file is at least readable. The file can be a
-** directory.
-**
-** SQLite will always allocate at least mxPathname+1 bytes for the
-** output buffer xFullPathname. The exact size of the output buffer
-** is also passed as a parameter to both methods. If the output buffer
-** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is
-** handled as a fatal error by SQLite, vfs implementations should endeavor
-** to prevent this by setting mxPathname to a sufficiently large value.
-**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
-** included in the VFS structure for completeness.
-** The xRandomness() function attempts to return nBytes bytes
-** of good-quality randomness into zOut. The return value is
-** the actual number of bytes of randomness obtained.
-** The xSleep() method causes the calling thread to sleep for at
-** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and time.
-**
-*/
-typedef struct sqlite3_vfs sqlite3_vfs;
-struct sqlite3_vfs {
- int iVersion; /* Structure version number */
- int szOsFile; /* Size of subclassed sqlite3_file */
- int mxPathname; /* Maximum file pathname length */
- sqlite3_vfs *pNext; /* Next registered VFS */
- const char *zName; /* Name of this virtual file system */
- void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
- int flags, int *pOutFlags);
- int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
- int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
- int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
- void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
- void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
- void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);
- void (*xDlClose)(sqlite3_vfs*, void*);
- int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
- int (*xSleep)(sqlite3_vfs*, int microseconds);
- int (*xCurrentTime)(sqlite3_vfs*, double*);
- int (*xGetLastError)(sqlite3_vfs*, int, char *);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
-};
-
-/*
-** CAPI3REF: Flags for the xAccess VFS method
-**
-** These integer constants can be used as the third parameter to
-** the xAccess method of an [sqlite3_vfs] object. They determine
-** what kind of permissions the xAccess method is looking for.
-** With SQLITE_ACCESS_EXISTS, the xAccess method
-** simply checks whether the file exists.
-** With SQLITE_ACCESS_READWRITE, the xAccess method
-** checks whether the file is both readable and writable.
-** With SQLITE_ACCESS_READ, the xAccess method
-** checks whether the file is readable.
-*/
-#define SQLITE_ACCESS_EXISTS 0
-#define SQLITE_ACCESS_READWRITE 1
-#define SQLITE_ACCESS_READ 2
-
-/*
-** CAPI3REF: Initialize The SQLite Library
-**
-** ^The sqlite3_initialize() routine initializes the
-** SQLite library. ^The sqlite3_shutdown() routine
-** deallocates any resources that were allocated by sqlite3_initialize().
-** These routines are designed to aid in process initialization and
-** shutdown on embedded systems. Workstation applications using
-** SQLite normally do not need to invoke either of these routines.
-**
-** A call to sqlite3_initialize() is an "effective" call if it is
-** the first time sqlite3_initialize() is invoked during the lifetime of
-** the process, or if it is the first time sqlite3_initialize() is invoked
-** following a call to sqlite3_shutdown(). ^(Only an effective call
-** of sqlite3_initialize() does any initialization. All other calls
-** are harmless no-ops.)^
-**
-** A call to sqlite3_shutdown() is an "effective" call if it is the first
-** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only
-** an effective call to sqlite3_shutdown() does any deinitialization.
-** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^
-**
-** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown()
-** is not. The sqlite3_shutdown() interface must only be called from a
-** single thread. All open [database connections] must be closed and all
-** other SQLite resources must be deallocated prior to invoking
-** sqlite3_shutdown().
-**
-** Among other things, ^sqlite3_initialize() will invoke
-** sqlite3_os_init(). Similarly, ^sqlite3_shutdown()
-** will invoke sqlite3_os_end().
-**
-** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success.
-** ^If for some reason, sqlite3_initialize() is unable to initialize
-** the library (perhaps it is unable to allocate a needed resource such
-** as a mutex) it returns an [error code] other than [SQLITE_OK].
-**
-** ^The sqlite3_initialize() routine is called internally by many other
-** SQLite interfaces so that an application usually does not need to
-** invoke sqlite3_initialize() directly. For example, [sqlite3_open()]
-** calls sqlite3_initialize() so the SQLite library will be automatically
-** initialized when [sqlite3_open()] is called if it has not be initialized
-** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT]
-** compile-time option, then the automatic calls to sqlite3_initialize()
-** are omitted and the application must call sqlite3_initialize() directly
-** prior to using any other SQLite interface. For maximum portability,
-** it is recommended that applications always invoke sqlite3_initialize()
-** directly prior to using any other SQLite interface. Future releases
-** of SQLite may require this. In other words, the behavior exhibited
-** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the
-** default behavior in some future release of SQLite.
-**
-** The sqlite3_os_init() routine does operating-system specific
-** initialization of the SQLite library. The sqlite3_os_end()
-** routine undoes the effect of sqlite3_os_init(). Typical tasks
-** performed by these routines include allocation or deallocation
-** of static resources, initialization of global variables,
-** setting up a default [sqlite3_vfs] module, or setting up
-** a default configuration using [sqlite3_config()].
-**
-** The application should never invoke either sqlite3_os_init()
-** or sqlite3_os_end() directly. The application should only invoke
-** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init()
-** interface is called automatically by sqlite3_initialize() and
-** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate
-** implementations for sqlite3_os_init() and sqlite3_os_end()
-** are built into SQLite when it is compiled for Unix, Windows, or OS/2.
-** When [custom builds | built for other platforms]
-** (using the [SQLITE_OS_OTHER=1] compile-time
-** option) the application must supply a suitable implementation for
-** sqlite3_os_init() and sqlite3_os_end(). An application-supplied
-** implementation of sqlite3_os_init() or sqlite3_os_end()
-** must return [SQLITE_OK] on success and some other [error code] upon
-** failure.
-*/
-SQLITE_API int sqlite3_initialize(void);
-SQLITE_API int sqlite3_shutdown(void);
-SQLITE_API int sqlite3_os_init(void);
-SQLITE_API int sqlite3_os_end(void);
-
-/*
-** CAPI3REF: Configuring The SQLite Library
-**
-** The sqlite3_config() interface is used to make global configuration
-** changes to SQLite in order to tune SQLite to the specific needs of
-** the application. The default configuration is recommended for most
-** applications and so this routine is usually not necessary. It is
-** provided to support rare applications with unusual needs.
-**
-** The sqlite3_config() interface is not threadsafe. The application
-** must insure that no other SQLite interfaces are invoked by other
-** threads while sqlite3_config() is running. Furthermore, sqlite3_config()
-** may only be invoked prior to library initialization using
-** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
-** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
-** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlite3_os_init()].
-**
-** The first argument to sqlite3_config() is an integer
-** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines
-** what property of SQLite is to be configured. Subsequent arguments
-** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option]
-** in the first argument.
-**
-** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
-** ^If the option is unknown or SQLite is unable to set the option
-** then this routine returns a non-zero [error code].
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
-
-/*
-** CAPI3REF: Configure database connections
-** EXPERIMENTAL
-**
-** The sqlite3_db_config() interface is used to make configuration
-** changes to a [database connection]. The interface is similar to
-** [sqlite3_config()] except that the changes apply to a single
-** [database connection] (specified in the first argument). The
-** sqlite3_db_config() interface should only be used immediately after
-** the database connection is created using [sqlite3_open()],
-** [sqlite3_open16()], or [sqlite3_open_v2()].
-**
-** The second argument to sqlite3_db_config(D,V,...) is the
-** configuration verb - an integer code that indicates what
-** aspect of the [database connection] is being configured.
-** The only choice for this value is [SQLITE_DBCONFIG_LOOKASIDE].
-** New verbs are likely to be added in future releases of SQLite.
-** Additional arguments depend on the verb.
-**
-** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
-** the call is considered successful.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
-
-/*
-** CAPI3REF: Memory Allocation Routines
-** EXPERIMENTAL
-**
-** An instance of this object defines the interface between SQLite
-** and low-level memory allocation routines.
-**
-** This object is used in only one place in the SQLite interface.
-** A pointer to an instance of this object is the argument to
-** [sqlite3_config()] when the configuration option is
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
-** By creating an instance of this object
-** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
-** during configuration, an application can specify an alternative
-** memory allocation subsystem for SQLite to use for all of its
-** dynamic memory needs.
-**
-** Note that SQLite comes with several [built-in memory allocators]
-** that are perfectly adequate for the overwhelming majority of applications
-** and that this object is only useful to a tiny minority of applications
-** with specialized memory allocation requirements. This object is
-** also used during testing of SQLite in order to specify an alternative
-** memory allocator that simulates memory out-of-memory conditions in
-** order to verify that SQLite recovers gracefully from such
-** conditions.
-**
-** The xMalloc and xFree methods must work like the
-** malloc() and free() functions from the standard C library.
-** The xRealloc method must work like realloc() from the standard C library
-** with the exception that if the second argument to xRealloc is zero,
-** xRealloc must be a no-op - it must not perform any allocation or
-** deallocation. ^SQLite guarantees that the second argument to
-** xRealloc is always a value returned by a prior call to xRoundup.
-** And so in cases where xRoundup always returns a positive number,
-** xRealloc can perform exactly as the standard library realloc() and
-** still be in compliance with this specification.
-**
-** xSize should return the allocated size of a memory allocation
-** previously obtained from xMalloc or xRealloc. The allocated size
-** is always at least as big as the requested size but may be larger.
-**
-** The xRoundup method returns what would be the allocated size of
-** a memory allocation given a particular requested size. Most memory
-** allocators round up memory allocations at least to the next multiple
-** of 8. Some allocators round up to a larger multiple or to a power of 2.
-** Every memory allocation request coming in through [sqlite3_malloc()]
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
-** that causes the corresponding memory allocation to fail.
-**
-** The xInit method initializes the memory allocator. (For example,
-** it might allocate any require mutexes or initialize internal data
-** structures. The xShutdown method is invoked (indirectly) by
-** [sqlite3_shutdown()] and should deallocate any resources acquired
-** by xInit. The pAppData pointer is used as the only parameter to
-** xInit and xShutdown.
-**
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
-** the xInit method, so the xInit method need not be threadsafe. The
-** xShutdown method is only called from [sqlite3_shutdown()] so it does
-** not need to be threadsafe either. For all other methods, SQLite
-** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the
-** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which
-** it is by default) and so the methods are automatically serialized.
-** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other
-** methods must be threadsafe or else make their own arrangements for
-** serialization.
-**
-** SQLite will never invoke xInit() more than once without an intervening
-** call to xShutdown().
-*/
-typedef struct sqlite3_mem_methods sqlite3_mem_methods;
-struct sqlite3_mem_methods {
- void *(*xMalloc)(int); /* Memory allocation function */
- void (*xFree)(void*); /* Free a prior allocation */
- void *(*xRealloc)(void*,int); /* Resize an allocation */
- int (*xSize)(void*); /* Return the size of an allocation */
- int (*xRoundup)(int); /* Round up request size to allocation size */
- int (*xInit)(void*); /* Initialize the memory allocator */
- void (*xShutdown)(void*); /* Deinitialize the memory allocator */
- void *pAppData; /* Argument to xInit() and xShutdown() */
-};
-
-/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
-**
-** These constants are the available integer configuration options that
-** can be passed as the first argument to the [sqlite3_config()] interface.
-**
-** New configuration options may be added in future releases of SQLite.
-** Existing configuration options might be discontinued. Applications
-** should check the return code from [sqlite3_config()] to make sure that
-** the call worked. The [sqlite3_config()] interface will return a
-** non-zero [error code] if a discontinued or unsupported configuration option
-** is invoked.
-**
-** <dl>
-** <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
-** <dd>There are no arguments to this option. ^This option sets the
-** [threading mode] to Single-thread. In other words, it disables
-** all mutexing and puts SQLite into a mode where it can only be used
-** by a single thread. ^If SQLite is compiled with
-** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
-** it is not possible to change the [threading mode] from its default
-** value of Single-thread and so [sqlite3_config()] will return
-** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
-** configuration option.</dd>
-**
-** <dt>SQLITE_CONFIG_MULTITHREAD</dt>
-** <dd>There are no arguments to this option. ^This option sets the
-** [threading mode] to Multi-thread. In other words, it disables
-** mutexing on [database connection] and [prepared statement] objects.
-** The application is responsible for serializing access to
-** [database connections] and [prepared statements]. But other mutexes
-** are enabled so that SQLite will be safe to use in a multi-threaded
-** environment as long as no two threads attempt to use the same
-** [database connection] at the same time. ^If SQLite is compiled with
-** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
-** it is not possible to set the Multi-thread [threading mode] and
-** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
-** SQLITE_CONFIG_MULTITHREAD configuration option.</dd>
-**
-** <dt>SQLITE_CONFIG_SERIALIZED</dt>
-** <dd>There are no arguments to this option. ^This option sets the
-** [threading mode] to Serialized. In other words, this option enables
-** all mutexes including the recursive
-** mutexes on [database connection] and [prepared statement] objects.
-** In this mode (which is the default when SQLite is compiled with
-** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access
-** to [database connections] and [prepared statements] so that the
-** application is free to use the same [database connection] or the
-** same [prepared statement] in different threads at the same time.
-** ^If SQLite is compiled with
-** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
-** it is not possible to set the Serialized [threading mode] and
-** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
-** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
-**
-** <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The argument specifies
-** alternative low-level memory allocation routines to be used in place of
-** the memory allocation routines built into SQLite.)^ ^SQLite makes
-** its own private copy of the content of the [sqlite3_mem_methods] structure
-** before the [sqlite3_config()] call returns.</dd>
-**
-** <dt>SQLITE_CONFIG_GETMALLOC</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
-** structure is filled with the currently defined memory allocation routines.)^
-** This option can be used to overload the default memory allocation
-** routines with a wrapper that simulations memory allocation failure or
-** tracks memory usage, for example. </dd>
-**
-** <dt>SQLITE_CONFIG_MEMSTATUS</dt>
-** <dd> ^This option takes single argument of type int, interpreted as a
-** boolean, which enables or disables the collection of memory allocation
-** statistics. ^(When memory allocation statistics are disabled, the
-** following SQLite interfaces become non-operational:
-** <ul>
-** <li> [sqlite3_memory_used()]
-** <li> [sqlite3_memory_highwater()]
-** <li> [sqlite3_soft_heap_limit()]
-** <li> [sqlite3_status()]
-** </ul>)^
-** ^Memory allocation statistics are enabled by default unless SQLite is
-** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory
-** allocation statistics are disabled by default.
-** </dd>
-**
-** <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** scratch memory. There are three arguments: A pointer an 8-byte
-** aligned memory buffer from which the scrach allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N). The sz
-** argument must be a multiple of 16. The sz parameter should be a few bytes
-** larger than the actual scratch space required due to internal overhead.
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will use no more than one scratch buffer per thread. So
-** N should be set to the expected maximum number of threads. ^SQLite will
-** never require a scratch buffer that is more than 6 times the database
-** page size. ^If SQLite needs needs additional scratch memory beyond
-** what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
-**
-** <dt>SQLITE_CONFIG_PAGECACHE</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implemenation.
-** This configuration should not be used if an application-define page
-** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
-** There are three arguments to this option: A pointer to 8-byte aligned
-** memory, the size of each page buffer (sz), and the number of pages (N).
-** The sz argument should be the size of the largest database page
-** (a power of two between 512 and 32768) plus a little extra for each
-** page header. ^The page header size is 20 to 40 bytes depending on
-** the host architecture. ^It is harmless, apart from the wasted memory,
-** to make sz a little too large. The first
-** argument should point to an allocation of at least sz*N bytes of memory.
-** ^SQLite will use the memory provided by the first argument to satisfy its
-** memory needs for the first N pages that it adds to cache. ^If additional
-** page cache memory is needed beyond what is provided by this option, then
-** SQLite goes to [sqlite3_malloc()] for the additional storage space.
-** ^The implementation might use one or more of the N buffers to hold
-** memory accounting information. The pointer in the first argument must
-** be aligned to an 8-byte boundary or subsequent behavior of SQLite
-** will be undefined.</dd>
-**
-** <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^This option specifies a static memory buffer that SQLite will use
-** for all of its dynamic memory allocation needs beyond those provided
-** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
-** There are three arguments: An 8-byte aligned pointer to the memory,
-** the number of bytes in the memory buffer, and the minimum allocation size.
-** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
-** to using its default memory allocator (the system malloc() implementation),
-** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
-** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
-** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
-** allocator is engaged to handle all of SQLites memory allocation needs.
-** The first pointer (the memory pointer) must be aligned to an 8-byte
-** boundary or subsequent behavior of SQLite will be undefined.</dd>
-**
-** <dt>SQLITE_CONFIG_MUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The argument specifies
-** alternative low-level mutex routines to be used in place
-** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
-** content of the [sqlite3_mutex_methods] structure before the call to
-** [sqlite3_config()] returns. ^If SQLite is compiled with
-** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
-** the entire mutexing subsystem is omitted from the build and hence calls to
-** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
-** return [SQLITE_ERROR].</dd>
-**
-** <dt>SQLITE_CONFIG_GETMUTEX</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** instance of the [sqlite3_mutex_methods] structure. The
-** [sqlite3_mutex_methods]
-** structure is filled with the currently defined mutex routines.)^
-** This option can be used to overload the default mutex allocation
-** routines with a wrapper used to track mutex usage for performance
-** profiling or testing, for example. ^If SQLite is compiled with
-** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
-** the entire mutexing subsystem is omitted from the build and hence calls to
-** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
-** return [SQLITE_ERROR].</dd>
-**
-** <dt>SQLITE_CONFIG_LOOKASIDE</dt>
-** <dd> ^(This option takes two arguments that determine the default
-** memory allocation for the lookaside memory allocator on each
-** [database connection]. The first argument is the
-** size of each lookaside buffer slot and the second is the number of
-** slots allocated to each database connection.)^ ^(This option sets the
-** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
-** verb to [sqlite3_db_config()] can be used to change the lookaside
-** configuration on individual connections.)^ </dd>
-**
-** <dt>SQLITE_CONFIG_PCACHE</dt>
-** <dd> ^(This option takes a single argument which is a pointer to
-** an [sqlite3_pcache_methods] object. This object specifies the interface
-** to a custom page cache implementation.)^ ^SQLite makes a copy of the
-** object and uses it for page cache memory allocations.</dd>
-**
-** <dt>SQLITE_CONFIG_GETPCACHE</dt>
-** <dd> ^(This option takes a single argument which is a pointer to an
-** [sqlite3_pcache_methods] object. SQLite copies of the current
-** page cache implementation into that object.)^ </dd>
-**
-** </dl>
-*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
-#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-
-/*
-** CAPI3REF: Configuration Options
-** EXPERIMENTAL
-**
-** These constants are the available integer configuration options that
-** can be passed as the second argument to the [sqlite3_db_config()] interface.
-**
-** New configuration options may be added in future releases of SQLite.
-** Existing configuration options might be discontinued. Applications
-** should check the return code from [sqlite3_db_config()] to make sure that
-** the call worked. ^The [sqlite3_db_config()] interface will return a
-** non-zero [error code] if a discontinued or unsupported configuration option
-** is invoked.
-**
-** <dl>
-** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <dd> ^This option takes three additional arguments that determine the
-** [lookaside memory allocator] configuration for the [database connection].
-** ^The first argument (the third parameter to [sqlite3_db_config()] is a
-** pointer to an memory buffer to use for lookaside memory.
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
-** may be NULL in which case SQLite will allocate the
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
-** size of each lookaside buffer slot. ^The third argument is the number of
-** slots. The size of the buffer in the first argument must be greater than
-** or equal to the product of the second and third arguments. The buffer
-** must be aligned to an 8-byte boundary. ^If the second argument to
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
-** rounded down to the next smaller
-** multiple of 8. See also: [SQLITE_CONFIG_LOOKASIDE]</dd>
-**
-** </dl>
-*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
-
-
-/*
-** CAPI3REF: Enable Or Disable Extended Result Codes
-**
-** ^The sqlite3_extended_result_codes() routine enables or disables the
-** [extended result codes] feature of SQLite. ^The extended result
-** codes are disabled by default for historical compatibility.
-*/
-SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
-
-/*
-** CAPI3REF: Last Insert Rowid
-**
-** ^Each entry in an SQLite table has a unique 64-bit signed
-** integer key called the [ROWID | "rowid"]. ^The rowid is always available
-** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
-** names are not also used by explicitly declared columns. ^If
-** the table has a column of type [INTEGER PRIMARY KEY] then that column
-** is another alias for the rowid.
-**
-** ^This routine returns the [rowid] of the most recent
-** successful [INSERT] into the database from the [database connection]
-** in the first argument. ^If no successful [INSERT]s
-** have ever occurred on that database connection, zero is returned.
-**
-** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted
-** row is returned by this routine as long as the trigger is running.
-** But once the trigger terminates, the value returned by this routine
-** reverts to the last value inserted before the trigger fired.)^
-**
-** ^An [INSERT] that fails due to a constraint violation is not a
-** successful [INSERT] and does not change the value returned by this
-** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK,
-** and INSERT OR ABORT make no changes to the return value of this
-** routine when their insertion fails. ^(When INSERT OR REPLACE
-** encounters a constraint violation, it does not fail. The
-** INSERT continues to completion after deleting rows that caused
-** the constraint problem so INSERT OR REPLACE will always change
-** the return value of this interface.)^
-**
-** ^For the purposes of this routine, an [INSERT] is considered to
-** be successful even if it is subsequently rolled back.
-**
-** This function is accessible to SQL statements via the
-** [last_insert_rowid() SQL function].
-**
-** If a separate thread performs a new [INSERT] on the same
-** database connection while the [sqlite3_last_insert_rowid()]
-** function is running and thus changes the last insert [rowid],
-** then the value returned by [sqlite3_last_insert_rowid()] is
-** unpredictable and might not equal either the old or the new
-** last insert [rowid].
-*/
-SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
-
-/*
-** CAPI3REF: Count The Number Of Rows Modified
-**
-** ^This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the [database connection] specified by the first parameter.
-** ^(Only changes that are directly specified by the [INSERT], [UPDATE],
-** or [DELETE] statement are counted. Auxiliary changes caused by
-** triggers or [foreign key actions] are not counted.)^ Use the
-** [sqlite3_total_changes()] function to find the total number of changes
-** including changes caused by triggers and foreign key actions.
-**
-** ^Changes to a view that are simulated by an [INSTEAD OF trigger]
-** are not counted. Only real table changes are counted.
-**
-** ^(A "row change" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of [REPLACE] constraint resolution,
-** rollback, ABORT processing, [DROP TABLE], or by any other
-** mechanisms do not count as direct row changes.)^
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a [CREATE TRIGGER | trigger].
-** Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** ^This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** ^Thus, when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level. ^(Within the body of a trigger,
-** the sqlite3_changes() interface can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include changes
-** caused by subtriggers since those have their own context.)^
-**
-** See also the [sqlite3_total_changes()] interface, the
-** [count_changes pragma], and the [changes() SQL function].
-**
-** If a separate thread makes changes on the same database connection
-** while [sqlite3_changes()] is running then the value returned
-** is unpredictable and not meaningful.
-*/
-SQLITE_API int sqlite3_changes(sqlite3*);
-
-/*
-** CAPI3REF: Total Number Of Rows Modified
-**
-** ^This function returns the number of row changes caused by [INSERT],
-** [UPDATE] or [DELETE] statements since the [database connection] was opened.
-** ^(The count returned by sqlite3_total_changes() includes all changes
-** from all [CREATE TRIGGER | trigger] contexts and changes made by
-** [foreign key actions]. However,
-** the count does not include changes used to implement [REPLACE] constraints,
-** do rollbacks or ABORT processing, or [DROP TABLE] processing. The
-** count does not include rows of views that fire an [INSTEAD OF trigger],
-** though if the INSTEAD OF trigger makes changes of its own, those changes
-** are counted.)^
-** ^The sqlite3_total_changes() function counts the changes as soon as
-** the statement that makes them is completed (when the statement handle
-** is passed to [sqlite3_reset()] or [sqlite3_finalize()]).
-**
-** See also the [sqlite3_changes()] interface, the
-** [count_changes pragma], and the [total_changes() SQL function].
-**
-** If a separate thread makes changes on the same database connection
-** while [sqlite3_total_changes()] is running then the value
-** returned is unpredictable and not meaningful.
-*/
-SQLITE_API int sqlite3_total_changes(sqlite3*);
-
-/*
-** CAPI3REF: Interrupt A Long-Running Query
-**
-** ^This function causes any pending database operation to abort and
-** return at its earliest opportunity. This routine is typically
-** called in response to a user action such as pressing "Cancel"
-** or Ctrl-C where the user wants a long query operation to halt
-** immediately.
-**
-** ^It is safe to call this routine from a thread different from the
-** thread that is currently running the database operation. But it
-** is not safe to call this routine with a [database connection] that
-** is closed or might close before sqlite3_interrupt() returns.
-**
-** ^If an SQL operation is very nearly finished at the time when
-** sqlite3_interrupt() is called, then it might not have an opportunity
-** to be interrupted and might continue to completion.
-**
-** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT].
-** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE
-** that is inside an explicit transaction, then the entire transaction
-** will be rolled back automatically.
-**
-** ^The sqlite3_interrupt(D) call is in effect until all currently running
-** SQL statements on [database connection] D complete. ^Any new SQL statements
-** that are started after the sqlite3_interrupt() call and before the
-** running statements reaches zero are interrupted as if they had been
-** running prior to the sqlite3_interrupt() call. ^New SQL statements
-** that are started after the running statement count reaches zero are
-** not effected by the sqlite3_interrupt().
-** ^A call to sqlite3_interrupt(D) that occurs when there are no running
-** SQL statements is a no-op and has no effect on SQL statements
-** that are started after the sqlite3_interrupt() call returns.
-**
-** If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
-*/
-SQLITE_API void sqlite3_interrupt(sqlite3*);
-
-/*
-** CAPI3REF: Determine If An SQL Statement Is Complete
-**
-** These routines are useful during command-line input to determine if the
-** currently entered text seems to form a complete SQL statement or
-** if additional input is needed before sending the text into
-** SQLite for parsing. ^These routines return 1 if the input string
-** appears to be a complete SQL statement. ^A statement is judged to be
-** complete if it ends with a semicolon token and is not a prefix of a
-** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within
-** string literals or quoted identifier names or comments are not
-** independent tokens (they are part of the token in which they are
-** embedded) and thus do not count as a statement terminator. ^Whitespace
-** and comments that follow the final semicolon are ignored.
-**
-** ^These routines return 0 if the statement is incomplete. ^If a
-** memory allocation fails, then SQLITE_NOMEM is returned.
-**
-** ^These routines do not parse the SQL statements thus
-** will not detect syntactically incorrect SQL.
-**
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
-** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
-** automatically by sqlite3_complete16(). If that initialization fails,
-** then the return value from sqlite3_complete16() will be non-zero
-** regardless of whether or not the input SQL is complete.)^
-**
-** The input to [sqlite3_complete()] must be a zero-terminated
-** UTF-8 string.
-**
-** The input to [sqlite3_complete16()] must be a zero-terminated
-** UTF-16 string in native byte order.
-*/
-SQLITE_API int sqlite3_complete(const char *sql);
-SQLITE_API int sqlite3_complete16(const void *sql);
-
-/*
-** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
-**
-** ^This routine sets a callback function that might be invoked whenever
-** an attempt is made to open a database table that another thread
-** or process has locked.
-**
-** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]
-** is returned immediately upon encountering the lock. ^If the busy callback
-** is not NULL, then the callback might be invoked with two arguments.
-**
-** ^The first argument to the busy handler is a copy of the void* pointer which
-** is the third argument to sqlite3_busy_handler(). ^The second argument to
-** the busy handler callback is the number of times that the busy handler has
-** been invoked for this locking event. ^If the
-** busy callback returns 0, then no additional attempts are made to
-** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
-** ^If the callback returns non-zero, then another attempt
-** is made to open the database for reading and the cycle repeats.
-**
-** The presence of a busy handler does not guarantee that it will be invoked
-** when there is lock contention. ^If SQLite determines that invoking the busy
-** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
-** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler.
-** Consider a scenario where one process is holding a read lock that
-** it is trying to promote to a reserved lock and
-** a second process is holding a reserved lock that it is trying
-** to promote to an exclusive lock. The first process cannot proceed
-** because it is blocked by the second and the second process cannot
-** proceed because it is blocked by the first. If both processes
-** invoke the busy handlers, neither will make any progress. Therefore,
-** SQLite returns [SQLITE_BUSY] for the first process, hoping that this
-** will induce the first process to release its read lock and allow
-** the second process to proceed.
-**
-** ^The default busy callback is NULL.
-**
-** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
-** when SQLite is in the middle of a large transaction where all the
-** changes will not fit into the in-memory cache. SQLite will
-** already hold a RESERVED lock on the database file, but it needs
-** to promote this lock to EXCLUSIVE so that it can spill cache
-** pages into the database file without harm to concurrent
-** readers. ^If it is unable to promote the lock, then the in-memory
-** cache will be left in an inconsistent state and so the error
-** code is promoted from the relatively benign [SQLITE_BUSY] to
-** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion
-** forces an automatic rollback of the changes. See the
-** <a href="/cvstrac/wiki?p=CorruptionFollowingBusyError">
-** CorruptionFollowingBusyError</a> wiki page for a discussion of why
-** this is important.
-**
-** ^(There can only be a single busy handler defined for each
-** [database connection]. Setting a new busy handler clears any
-** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()]
-** will also set or clear the busy handler.
-**
-** The busy callback should not take any actions which modify the
-** database connection that invoked the busy handler. Any such actions
-** result in undefined behavior.
-**
-** A busy handler must not close the database connection
-** or [prepared statement] that invoked the busy handler.
-*/
-SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
-
-/*
-** CAPI3REF: Set A Busy Timeout
-**
-** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
-** for a specified amount of time when a table is locked. ^The handler
-** will sleep multiple times until at least "ms" milliseconds of sleeping
-** have accumulated. ^After at least "ms" milliseconds of sleeping,
-** the handler returns 0 which causes [sqlite3_step()] to return
-** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
-**
-** ^Calling this routine with an argument less than or equal to zero
-** turns off all busy handlers.
-**
-** ^(There can only be a single busy handler for a particular
-** [database connection] any any given moment. If another busy handler
-** was defined (using [sqlite3_busy_handler()]) prior to calling
-** this routine, that other busy handler is cleared.)^
-*/
-SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
-
-/*
-** CAPI3REF: Convenience Routines For Running Queries
-**
-** Definition: A <b>result table</b> is memory data structure created by the
-** [sqlite3_get_table()] interface. A result table records the
-** complete query results from one or more queries.
-**
-** The table conceptually has a number of rows and columns. But
-** these numbers are not part of the result table itself. These
-** numbers are obtained separately. Let N be the number of rows
-** and M be the number of columns.
-**
-** A result table is an array of pointers to zero-terminated UTF-8 strings.
-** There are (N+1)*M elements in the array. The first M pointers point
-** to zero-terminated strings that contain the names of the columns.
-** The remaining entries all point to query results. NULL values result
-** in NULL pointers. All other values are in their UTF-8 zero-terminated
-** string representation as returned by [sqlite3_column_text()].
-**
-** A result table might consist of one or more memory allocations.
-** It is not safe to pass a result table directly to [sqlite3_free()].
-** A result table should be deallocated using [sqlite3_free_table()].
-**
-** As an example of the result table format, suppose a query result
-** is as follows:
-**
-** <blockquote><pre>
-** Name | Age
-** -----------------------
-** Alice | 43
-** Bob | 28
-** Cindy | 21
-** </pre></blockquote>
-**
-** There are two column (M==2) and three rows (N==3). Thus the
-** result table has 8 entries. Suppose the result table is stored
-** in an array names azResult. Then azResult holds this content:
-**
-** <blockquote><pre>
-** azResult[0] = "Name";
-** azResult[1] = "Age";
-** azResult[2] = "Alice";
-** azResult[3] = "43";
-** azResult[4] = "Bob";
-** azResult[5] = "28";
-** azResult[6] = "Cindy";
-** azResult[7] = "21";
-** </pre></blockquote>
-**
-** ^The sqlite3_get_table() function evaluates one or more
-** semicolon-separated SQL statements in the zero-terminated UTF-8
-** string of its 2nd parameter and returns a result table to the
-** pointer given in its 3rd parameter.
-**
-** After the application has finished with the result from sqlite3_get_table(),
-** it should pass the result table pointer to sqlite3_free_table() in order to
-** release the memory that was malloced. Because of the way the
-** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
-** function must not try to call [sqlite3_free()] directly. Only
-** [sqlite3_free_table()] is able to release the memory properly and safely.
-**
-** ^(The sqlite3_get_table() interface is implemented as a wrapper around
-** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access
-** to any internal data structures of SQLite. It uses only the public
-** interface defined here. As a consequence, errors that occur in the
-** wrapper layer outside of the internal [sqlite3_exec()] call are not
-** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].)^
-*/
-SQLITE_API int sqlite3_get_table(
- sqlite3 *db, /* An open database */
- const char *zSql, /* SQL to be evaluated */
- char ***pazResult, /* Results of the query */
- int *pnRow, /* Number of result rows written here */
- int *pnColumn, /* Number of result columns written here */
- char **pzErrmsg /* Error msg written here */
-);
-SQLITE_API void sqlite3_free_table(char **result);
-
-/*
-** CAPI3REF: Formatted String Printing Functions
-**
-** These routines are work-alikes of the "printf()" family of functions
-** from the standard C library.
-**
-** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
-** The strings returned by these two routines should be
-** released by [sqlite3_free()]. ^Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
-** memory to hold the resulting string.
-**
-** ^(In sqlite3_snprintf() routine is similar to "snprintf()" from
-** the standard C library. The result is written into the
-** buffer supplied as the second parameter whose size is given by
-** the first parameter. Note that the order of the
-** first two parameters is reversed from snprintf().)^ This is an
-** historical accident that cannot be fixed without breaking
-** backwards compatibility. ^(Note also that sqlite3_snprintf()
-** returns a pointer to its buffer instead of the number of
-** characters actually written into the buffer.)^ We admit that
-** the number of characters written would be a more useful return
-** value but we cannot change the implementation of sqlite3_snprintf()
-** now without breaking compatibility.
-**
-** ^As long as the buffer size is greater than zero, sqlite3_snprintf()
-** guarantees that the buffer is always zero-terminated. ^The first
-** parameter "n" is the total size of the buffer, including space for
-** the zero terminator. So the longest string that can be completely
-** written will be n-1 characters.
-**
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
-**
-** ^(The %q option works like %s in that it substitutes a null-terminated
-** string from the argument list. But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal.)^ By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, assume the string variable zText contains text as follows:
-**
-** <blockquote><pre>
-** char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct. Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error. As a general rule you should
-** always use %q instead of %s when inserting text into a string literal.
-**
-** ^(The %Q option works like %q except it also adds single quotes around
-** the outside of the total string. Additionally, if the parameter in the
-** argument list is a NULL pointer, %Q substitutes the text "NULL" (without
-** single quotes).)^ So, for example, one could say:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** ^(The "%z" formatting option works like "%s" but with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string.)^
-*/
-SQLITE_API char *sqlite3_mprintf(const char*,...);
-SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
-
-/*
-** CAPI3REF: Memory Allocation Subsystem
-**
-** The SQLite core uses these three routines for all of its own
-** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation. The
-** Windows VFS uses native malloc() and free() for some operations.
-**
-** ^The sqlite3_malloc() routine returns a pointer to a block
-** of memory at least N bytes in length, where N is the parameter.
-** ^If sqlite3_malloc() is unable to obtain sufficient free
-** memory, it returns a NULL pointer. ^If the parameter N to
-** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
-** a NULL pointer.
-**
-** ^Calling sqlite3_free() with a pointer previously returned
-** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
-** that it might be reused. ^The sqlite3_free() routine is
-** a no-op if is called with a NULL pointer. Passing a NULL pointer
-** to sqlite3_free() is harmless. After being freed, memory
-** should neither be read nor written. Even reading previously freed
-** memory might result in a segmentation fault or other severe error.
-** Memory corruption, a segmentation fault, or other severe error
-** might result if sqlite3_free() is called with a non-NULL pointer that
-** was not obtained from sqlite3_malloc() or sqlite3_realloc().
-**
-** ^(The sqlite3_realloc() interface attempts to resize a
-** prior memory allocation to be at least N bytes, where N is the
-** second parameter. The memory allocation to be resized is the first
-** parameter.)^ ^ If the first parameter to sqlite3_realloc()
-** is a NULL pointer then its behavior is identical to calling
-** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
-** ^If the second parameter to sqlite3_realloc() is zero or
-** negative then the behavior is exactly the same as calling
-** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
-** ^sqlite3_realloc() returns a pointer to a memory allocation
-** of at least N bytes in size or NULL if sufficient memory is unavailable.
-** ^If M is the size of the prior allocation, then min(N,M) bytes
-** of the prior allocation are copied into the beginning of buffer returned
-** by sqlite3_realloc() and the prior allocation is freed.
-** ^If sqlite3_realloc() returns NULL, then the prior allocation
-** is not freed.
-**
-** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary.
-**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted. That capability
-** is no longer provided. Only built-in memory allocators can be used.
-**
-** The Windows OS interface layer calls
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular Windows
-** installation. Memory allocation errors are detected, but
-** they are reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
-** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
-** must be either NULL or else pointers obtained from a prior
-** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
-** not yet been released.
-**
-** The application must not read or write any part of
-** a block of memory after it has been released using
-** [sqlite3_free()] or [sqlite3_realloc()].
-*/
-SQLITE_API void *sqlite3_malloc(int);
-SQLITE_API void *sqlite3_realloc(void*, int);
-SQLITE_API void sqlite3_free(void*);
-
-/*
-** CAPI3REF: Memory Allocator Statistics
-**
-** SQLite provides these two interfaces for reporting on the status
-** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()]
-** routines, which form the built-in memory allocation subsystem.
-**
-** ^The [sqlite3_memory_used()] routine returns the number of bytes
-** of memory currently outstanding (malloced but not freed).
-** ^The [sqlite3_memory_highwater()] routine returns the maximum
-** value of [sqlite3_memory_used()] since the high-water mark
-** was last reset. ^The values returned by [sqlite3_memory_used()] and
-** [sqlite3_memory_highwater()] include any overhead
-** added by SQLite in its implementation of [sqlite3_malloc()],
-** but not overhead added by the any underlying system library
-** routines that [sqlite3_malloc()] may call.
-**
-** ^The memory high-water mark is reset to the current value of
-** [sqlite3_memory_used()] if and only if the parameter to
-** [sqlite3_memory_highwater()] is true. ^The value returned
-** by [sqlite3_memory_highwater(1)] is the high-water mark
-** prior to the reset.
-*/
-SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
-
-/*
-** CAPI3REF: Pseudo-Random Number Generator
-**
-** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
-** select random [ROWID | ROWIDs] when inserting new records into a table that
-** already uses the largest possible [ROWID]. The PRNG is also used for
-** the build-in random() and randomblob() SQL functions. This interface allows
-** applications to access the same PRNG for other purposes.
-**
-** ^A call to this routine stores N bytes of randomness into buffer P.
-**
-** ^The first time this routine is invoked (either internally or by
-** the application) the PRNG is seeded using randomness obtained
-** from the xRandomness method of the default [sqlite3_vfs] object.
-** ^On all subsequent invocations, the pseudo-randomness is generated
-** internally and without recourse to the [sqlite3_vfs] xRandomness
-** method.
-*/
-SQLITE_API void sqlite3_randomness(int N, void *P);
-
-/*
-** CAPI3REF: Compile-Time Authorization Callbacks
-**
-** ^This routine registers a authorizer callback with a particular
-** [database connection], supplied in the first argument.
-** ^The authorizer callback is invoked as SQL statements are being compiled
-** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various
-** points during the compilation process, as logic is being created
-** to perform various actions, the authorizer callback is invoked to
-** see if those actions are allowed. ^The authorizer callback should
-** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the
-** specific action but allow the SQL statement to continue to be
-** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
-** rejected with an error. ^If the authorizer callback returns
-** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
-** then the [sqlite3_prepare_v2()] or equivalent call that triggered
-** the authorizer will fail with an error message.
-**
-** When the callback returns [SQLITE_OK], that means the operation
-** requested is ok. ^When the callback returns [SQLITE_DENY], the
-** [sqlite3_prepare_v2()] or equivalent call that triggered the
-** authorizer will fail with an error message explaining that
-** access is denied.
-**
-** ^The first parameter to the authorizer callback is a copy of the third
-** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
-** to the callback is an integer [SQLITE_COPY | action code] that specifies
-** the particular action to be authorized. ^The third through sixth parameters
-** to the callback are zero-terminated strings that contain additional
-** details about the action to be authorized.
-**
-** ^If the action code is [SQLITE_READ]
-** and the callback returns [SQLITE_IGNORE] then the
-** [prepared statement] statement is constructed to substitute
-** a NULL value in place of the table column that would have
-** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
-** return can be used to deny an untrusted user access to individual
-** columns of a table.
-** ^If the action code is [SQLITE_DELETE] and the callback returns
-** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
-** [truncate optimization] is disabled and all rows are deleted individually.
-**
-** An authorizer is used when [sqlite3_prepare | preparing]
-** SQL statements from an untrusted source, to ensure that the SQL statements
-** do not try to access data they are not allowed to see, or that they do not
-** try to execute malicious statements that damage the database. For
-** example, an application may allow a user to enter arbitrary
-** SQL queries for evaluation by a database. But the application does
-** not want the user to be able to make arbitrary changes to the
-** database. An authorizer could then be put in place while the
-** user-entered SQL is being [sqlite3_prepare | prepared] that
-** disallows everything except [SELECT] statements.
-**
-** Applications that need to process SQL from untrusted sources
-** might also consider lowering resource limits using [sqlite3_limit()]
-** and limiting database size using the [max_page_count] [PRAGMA]
-** in addition to using an authorizer.
-**
-** ^(Only a single authorizer can be in place on a database connection
-** at a time. Each call to sqlite3_set_authorizer overrides the
-** previous call.)^ ^Disable the authorizer by installing a NULL callback.
-** The authorizer is disabled by default.
-**
-** The authorizer callback must not do anything that will modify
-** the database connection that invoked the authorizer callback.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
-**
-** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
-** statement might be re-prepared during [sqlite3_step()] due to a
-** schema change. Hence, the application should ensure that the
-** correct authorizer callback remains in place during the [sqlite3_step()].
-**
-** ^Note that the authorizer callback is invoked only during
-** [sqlite3_prepare()] or its variants. Authorization is not
-** performed during statement evaluation in [sqlite3_step()], unless
-** as stated in the previous paragraph, sqlite3_step() invokes
-** sqlite3_prepare_v2() to reprepare a statement after a schema change.
-*/
-SQLITE_API int sqlite3_set_authorizer(
- sqlite3*,
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
- void *pUserData
-);
-
-/*
-** CAPI3REF: Authorizer Return Codes
-**
-** The [sqlite3_set_authorizer | authorizer callback function] must
-** return either [SQLITE_OK] or one of these two constants in order
-** to signal SQLite whether or not the action is permitted. See the
-** [sqlite3_set_authorizer | authorizer documentation] for additional
-** information.
-*/
-#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
-#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
-
-/*
-** CAPI3REF: Authorizer Action Codes
-**
-** The [sqlite3_set_authorizer()] interface registers a callback function
-** that is invoked to authorize certain SQL statement actions. The
-** second parameter to the callback is an integer code that specifies
-** what action is being authorized. These are the integer action codes that
-** the authorizer callback may be passed.
-**
-** These action code values signify what kind of operation is to be
-** authorized. The 3rd and 4th parameters to the authorization
-** callback function will be parameters or NULL depending on which of these
-** codes is used as the second parameter. ^(The 5th parameter to the
-** authorizer callback is the name of the database ("main", "temp",
-** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback
-** is the name of the inner-most trigger or view that is responsible for
-** the access attempt or NULL if this access attempt is directly from
-** top-level SQL code.
-*/
-/******************************************* 3rd ************ 4th ***********/
-#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
-#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
-#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
-#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
-#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
-#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
-#define SQLITE_DELETE 9 /* Table Name NULL */
-#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
-#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
-#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
-#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
-#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
-#define SQLITE_DROP_VIEW 17 /* View Name NULL */
-#define SQLITE_INSERT 18 /* Table Name NULL */
-#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
-#define SQLITE_READ 20 /* Table Name Column Name */
-#define SQLITE_SELECT 21 /* NULL NULL */
-#define SQLITE_TRANSACTION 22 /* Operation NULL */
-#define SQLITE_UPDATE 23 /* Table Name Column Name */
-#define SQLITE_ATTACH 24 /* Filename NULL */
-#define SQLITE_DETACH 25 /* Database Name NULL */
-#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
-#define SQLITE_REINDEX 27 /* Index Name NULL */
-#define SQLITE_ANALYZE 28 /* Table Name NULL */
-#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
-#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
-#define SQLITE_FUNCTION 31 /* NULL Function Name */
-#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */
-#define SQLITE_COPY 0 /* No longer used */
-
-/*
-** CAPI3REF: Tracing And Profiling Functions
-** EXPERIMENTAL
-**
-** These routines register callback functions that can be used for
-** tracing and profiling the execution of SQL statements.
-**
-** ^The callback function registered by sqlite3_trace() is invoked at
-** various times when an SQL statement is being run by [sqlite3_step()].
-** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the
-** SQL statement text as the statement first begins executing.
-** ^(Additional sqlite3_trace() callbacks might occur
-** as each triggered subprogram is entered. The callbacks for triggers
-** contain a UTF-8 SQL comment that identifies the trigger.)^
-**
-** ^The callback function registered by sqlite3_profile() is invoked
-** as each SQL statement finishes. ^The profile callback contains
-** the original statement text and an estimate of wall-clock time
-** of how long that statement took to run.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
- void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
-
-/*
-** CAPI3REF: Query Progress Callbacks
-**
-** ^This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()]. An example use for this
-** interface is to keep a GUI updated during a large query.
-**
-** ^If the progress callback returns non-zero, the operation is
-** interrupted. This feature can be used to implement a
-** "Cancel" button on a GUI progress dialog box.
-**
-** The progress handler must not do anything that will modify
-** the database connection that invoked the progress handler.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
-**
-*/
-SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
-
-/*
-** CAPI3REF: Opening A New Database Connection
-**
-** ^These routines open an SQLite database file whose name is given by the
-** filename argument. ^The filename argument is interpreted as UTF-8 for
-** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
-** order for sqlite3_open16(). ^(A [database connection] handle is usually
-** returned in *ppDb, even if an error occurs. The only exception is that
-** if SQLite is unable to allocate memory to hold the [sqlite3] object,
-** a NULL will be written into *ppDb instead of a pointer to the [sqlite3]
-** object.)^ ^(If the database is opened (and/or created) successfully, then
-** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The
-** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
-** an English language description of the error following a failure of any
-** of the sqlite3_open() routines.
-**
-** ^The default encoding for the database will be UTF-8 if
-** sqlite3_open() or sqlite3_open_v2() is called and
-** UTF-16 in the native byte order if sqlite3_open16() is used.
-**
-** Whether or not an error occurs when it is opened, resources
-** associated with the [database connection] handle should be released by
-** passing it to [sqlite3_close()] when it is no longer required.
-**
-** The sqlite3_open_v2() interface works like sqlite3_open()
-** except that it accepts two additional parameters for additional control
-** over the new database connection. ^(The flags parameter to
-** sqlite3_open_v2() can take one of
-** the following three values, optionally combined with the
-** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^
-**
-** <dl>
-** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
-** <dd>The database is opened in read-only mode. If the database does not
-** already exist, an error is returned.</dd>)^
-**
-** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
-** <dd>The database is opened for reading and writing if possible, or reading
-** only if the file is write protected by the operating system. In either
-** case the database must already exist, otherwise an error is returned.</dd>)^
-**
-** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
-** <dd>The database is opened for reading and writing, and is creates it if
-** it does not already exist. This is the behavior that is always used for
-** sqlite3_open() and sqlite3_open16().</dd>)^
-** </dl>
-**
-** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above or one of the combinations shown above combined
-** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_SHAREDCACHE] flags,
-** then the behavior is undefined.
-**
-** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
-** opens in the multi-thread [threading mode] as long as the single-thread
-** mode has not been set at compile-time or start-time. ^If the
-** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
-** in the serialized [threading mode] unless single-thread was
-** previously selected at compile-time or start-time.
-** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
-** eligible to use [shared cache mode], regardless of whether or not shared
-** cache is enabled using [sqlite3_enable_shared_cache()]. ^The
-** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
-** participate in [shared cache mode] even if it is enabled.
-**
-** ^If the filename is ":memory:", then a private, temporary in-memory database
-** is created for the connection. ^This in-memory database will vanish when
-** the database connection is closed. Future versions of SQLite might
-** make use of additional special filenames that begin with the ":" character.
-** It is recommended that when a database filename actually does begin with
-** a ":" character you should prefix the filename with a pathname such as
-** "./" to avoid ambiguity.
-**
-** ^If the filename is an empty string, then a private, temporary
-** on-disk database will be created. ^This private database will be
-** automatically deleted as soon as the database connection is closed.
-**
-** ^The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system interface that
-** the new database connection should use. ^If the fourth parameter is
-** a NULL pointer then the default [sqlite3_vfs] object is used.
-**
-** <b>Note to Windows users:</b> The encoding used for the filename argument
-** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
-** codepage is currently defined. Filenames containing international
-** characters must be converted to UTF-8 prior to passing them into
-** sqlite3_open() or sqlite3_open_v2().
-*/
-SQLITE_API int sqlite3_open(
- const char *filename, /* Database filename (UTF-8) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-SQLITE_API int sqlite3_open16(
- const void *filename, /* Database filename (UTF-16) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-SQLITE_API int sqlite3_open_v2(
- const char *filename, /* Database filename (UTF-8) */
- sqlite3 **ppDb, /* OUT: SQLite db handle */
- int flags, /* Flags */
- const char *zVfs /* Name of VFS module to use */
-);
-
-/*
-** CAPI3REF: Error Codes And Messages
-**
-** ^The sqlite3_errcode() interface returns the numeric [result code] or
-** [extended result code] for the most recent failed sqlite3_* API call
-** associated with a [database connection]. If a prior API call failed
-** but the most recent API call succeeded, the return value from
-** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode()
-** interface is the same except that it always returns the
-** [extended result code] even when extended result codes are
-** disabled.
-**
-** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
-** ^(Memory to hold the error message string is managed internally.
-** The application does not need to worry about freeing the result.
-** However, the error string might be overwritten or deallocated by
-** subsequent calls to other SQLite interface functions.)^
-**
-** When the serialized [threading mode] is in use, it might be the
-** case that a second error occurs on a separate thread in between
-** the time of the first error and the call to these interfaces.
-** When that happens, the second error will be reported since these
-** interfaces always report the most recent result. To avoid
-** this, each thread can obtain exclusive use of the [database connection] D
-** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning
-** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after
-** all calls to the interfaces listed here are completed.
-**
-** If an interface fails with SQLITE_MISUSE, that means the interface
-** was invoked incorrectly by the application. In that case, the
-** error code and message may or may not be set.
-*/
-SQLITE_API int sqlite3_errcode(sqlite3 *db);
-SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
-
-/*
-** CAPI3REF: SQL Statement Object
-** KEYWORDS: {prepared statement} {prepared statements}
-**
-** An instance of this object represents a single SQL statement.
-** This object is variously known as a "prepared statement" or a
-** "compiled SQL statement" or simply as a "statement".
-**
-** The life of a statement object goes something like this:
-**
-** <ol>
-** <li> Create the object using [sqlite3_prepare_v2()] or a related
-** function.
-** <li> Bind values to [host parameters] using the sqlite3_bind_*()
-** interfaces.
-** <li> Run the SQL by calling [sqlite3_step()] one or more times.
-** <li> Reset the statement using [sqlite3_reset()] then go back
-** to step 2. Do this zero or more times.
-** <li> Destroy the object using [sqlite3_finalize()].
-** </ol>
-**
-** Refer to documentation on individual methods above for additional
-** information.
-*/
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-/*
-** CAPI3REF: Run-time Limits
-**
-** ^(This interface allows the size of various constructs to be limited
-** on a connection by connection basis. The first parameter is the
-** [database connection] whose limit is to be set or queried. The
-** second parameter is one of the [limit categories] that define a
-** class of constructs to be size limited. The third parameter is the
-** new limit for that construct. The function returns the old limit.)^
-**
-** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For the limit category of SQLITE_LIMIT_XYZ there is a
-** [limits | hard upper bound]
-** set by a compile-time C preprocessor macro named
-** [limits | SQLITE_MAX_XYZ].
-** (The "_LIMIT_" in the name is changed to "_MAX_".))^
-** ^Attempts to increase a limit above its hard upper bound are
-** silently truncated to the hard upper bound.
-**
-** Run-time limits are intended for use in applications that manage
-** both their own internal database and also databases that are controlled
-** by untrusted external sources. An example application might be a
-** web browser that has its own databases for storing history and
-** separate databases controlled by JavaScript applications downloaded
-** off the Internet. The internal databases can be given the
-** large, default limits. Databases managed by external sources can
-** be given much smaller limits designed to prevent a denial of service
-** attack. Developers might also want to use the [sqlite3_set_authorizer()]
-** interface to further control untrusted SQL. The size of the database
-** created by an untrusted script can be contained using the
-** [max_page_count] [PRAGMA].
-**
-** New run-time limit categories may be added in future releases.
-*/
-SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
-
-/*
-** CAPI3REF: Run-Time Limit Categories
-** KEYWORDS: {limit category} {*limit categories}
-**
-** These constants define various performance limits
-** that can be lowered at run-time using [sqlite3_limit()].
-** The synopsis of the meanings of the various limits is shown below.
-** Additional information is available at [limits | Limits in SQLite].
-**
-** <dl>
-** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
-** <dd>The maximum size of any string or BLOB or table row.<dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
-** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_COLUMN</dt>
-** <dd>The maximum number of columns in a table definition or in the
-** result set of a [SELECT] or the maximum number of columns in an index
-** or in an ORDER BY or GROUP BY clause.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
-** <dd>The maximum depth of the parse tree on any expression.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
-** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
-** <dd>The maximum number of instructions in a virtual machine program
-** used to implement an SQL statement.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
-** <dd>The maximum number of arguments on a function.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
-** <dd>The maximum number of [ATTACH | attached databases].)^</dd>
-**
-** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt>
-** <dd>The maximum length of the pattern argument to the [LIKE] or
-** [GLOB] operators.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
-** <dd>The maximum number of variables in an SQL statement that can
-** be bound.</dd>)^
-**
-** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
-** <dd>The maximum depth of recursion for triggers.</dd>)^
-** </dl>
-*/
-#define SQLITE_LIMIT_LENGTH 0
-#define SQLITE_LIMIT_SQL_LENGTH 1
-#define SQLITE_LIMIT_COLUMN 2
-#define SQLITE_LIMIT_EXPR_DEPTH 3
-#define SQLITE_LIMIT_COMPOUND_SELECT 4
-#define SQLITE_LIMIT_VDBE_OP 5
-#define SQLITE_LIMIT_FUNCTION_ARG 6
-#define SQLITE_LIMIT_ATTACHED 7
-#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
-#define SQLITE_LIMIT_VARIABLE_NUMBER 9
-#define SQLITE_LIMIT_TRIGGER_DEPTH 10
-
-/*
-** CAPI3REF: Compiling An SQL Statement
-** KEYWORDS: {SQL statement compiler}
-**
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of these routines.
-**
-** The first argument, "db", is a [database connection] obtained from a
-** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
-** [sqlite3_open16()]. The database connection must not have been closed.
-**
-** The second argument, "zSql", is the statement to be compiled, encoded
-** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
-** use UTF-16.
-**
-** ^If the nByte argument is less than zero, then zSql is read up to the
-** first zero terminator. ^If nByte is non-negative, then it is the maximum
-** number of bytes read from zSql. ^When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** the nByte-th byte, whichever comes first. If the caller knows
-** that the supplied string is nul-terminated, then there is a small
-** performance advantage to be gained by passing an nByte parameter that
-** is equal to the number of bytes in the input string <i>including</i>
-** the nul-terminator bytes.
-**
-** ^If pzTail is not NULL then *pzTail is made to point to the first byte
-** past the end of the first SQL statement in zSql. These routines only
-** compile the first statement in zSql, so *pzTail is left pointing to
-** what remains uncompiled.
-**
-** ^*ppStmt is left pointing to a compiled [prepared statement] that can be
-** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set
-** to NULL. ^If the input text contains no SQL (if the input is an empty
-** string or a comment) then *ppStmt is set to NULL.
-** The calling procedure is responsible for deleting the compiled
-** SQL statement using [sqlite3_finalize()] after it has finished with it.
-** ppStmt may not be NULL.
-**
-** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
-** otherwise an [error code] is returned.
-**
-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
-** recommended for all new programs. The two older interfaces are retained
-** for backwards compatibility, but their use is discouraged.
-** ^In the "v2" interfaces, the prepared statement
-** that is returned (the [sqlite3_stmt] object) contains a copy of the
-** original SQL text. This causes the [sqlite3_step()] interface to
-** behave differently in three ways:
-**
-** <ol>
-** <li>
-** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
-** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again. ^If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA]. But unlike the legacy behavior, [SQLITE_SCHEMA] is
-** now a fatal error. Calling [sqlite3_prepare_v2()] again will not make the
-** error go away. Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return.
-** </li>
-**
-** <li>
-** ^When an error occurs, [sqlite3_step()] will return one of the detailed
-** [error codes] or [extended error codes]. ^The legacy behavior was that
-** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code
-** and the application would have to make a second call to [sqlite3_reset()]
-** in order to find the underlying cause of the problem. With the "v2" prepare
-** interfaces, the underlying reason for the error is returned immediately.
-** </li>
-**
-** <li>
-** ^If the value of a [parameter | host parameter] in the WHERE clause might
-** change the query plan for a statement, then the statement may be
-** automatically recompiled (as if there had been a schema change) on the first
-** [sqlite3_step()] call following any change to the
-** [sqlite3_bind_text | bindings] of the [parameter].
-** </li>
-** </ol>
-*/
-SQLITE_API int sqlite3_prepare(
- sqlite3 *db, /* Database handle */
- const char *zSql, /* SQL statement, UTF-8 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const char **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-SQLITE_API int sqlite3_prepare_v2(
- sqlite3 *db, /* Database handle */
- const char *zSql, /* SQL statement, UTF-8 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const char **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-SQLITE_API int sqlite3_prepare16(
- sqlite3 *db, /* Database handle */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-SQLITE_API int sqlite3_prepare16_v2(
- sqlite3 *db, /* Database handle */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-
-/*
-** CAPI3REF: Retrieving Statement SQL
-**
-** ^This interface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement] if that statement was
-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
-*/
-SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Dynamically Typed Value Object
-** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
-**
-** SQLite uses the sqlite3_value object to represent all values
-** that can be stored in a database table. SQLite uses dynamic typing
-** for the values it stores. ^Values stored in sqlite3_value objects
-** can be integers, floating point values, strings, BLOBs, or NULL.
-**
-** An sqlite3_value object may be either "protected" or "unprotected".
-** Some interfaces require a protected sqlite3_value. Other interfaces
-** will accept either a protected or an unprotected sqlite3_value.
-** Every interface that accepts sqlite3_value arguments specifies
-** whether or not it requires a protected sqlite3_value.
-**
-** The terms "protected" and "unprotected" refer to whether or not
-** a mutex is held. A internal mutex is held for a protected
-** sqlite3_value object but no mutex is held for an unprotected
-** sqlite3_value object. If SQLite is compiled to be single-threaded
-** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
-** or if SQLite is run in one of reduced mutex modes
-** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
-** then there is no distinction between protected and unprotected
-** sqlite3_value objects and they can be used interchangeably. However,
-** for maximum code portability it is recommended that applications
-** still make the distinction between between protected and unprotected
-** sqlite3_value objects even when not strictly required.
-**
-** ^The sqlite3_value objects that are passed as parameters into the
-** implementation of [application-defined SQL functions] are protected.
-** ^The sqlite3_value object returned by
-** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
-** The [sqlite3_value_blob | sqlite3_value_type()] family of
-** interfaces require protected sqlite3_value objects.
-*/
-typedef struct Mem sqlite3_value;
-
-/*
-** CAPI3REF: SQL Function Context Object
-**
-** The context in which an SQL function executes is stored in an
-** sqlite3_context object. ^A pointer to an sqlite3_context object
-** is always first parameter to [application-defined SQL functions].
-** The application-defined SQL function implementation will pass this
-** pointer through into calls to [sqlite3_result_int | sqlite3_result()],
-** [sqlite3_aggregate_context()], [sqlite3_user_data()],
-** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()],
-** and/or [sqlite3_set_auxdata()].
-*/
-typedef struct sqlite3_context sqlite3_context;
-
-/*
-** CAPI3REF: Binding Values To Prepared Statements
-** KEYWORDS: {host parameter} {host parameters} {host parameter name}
-** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
-**
-** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
-** literals may be replaced by a [parameter] that matches one of following
-** templates:
-**
-** <ul>
-** <li> ?
-** <li> ?NNN
-** <li> :VVV
-** <li> @VVV
-** <li> $VVV
-** </ul>
-**
-** In the templates above, NNN represents an integer literal,
-** and VVV represents an alphanumeric identifer.)^ ^The values of these
-** parameters (also called "host parameter names" or "SQL parameters")
-** can be set using the sqlite3_bind_*() routines defined here.
-**
-** ^The first argument to the sqlite3_bind_*() routines is always
-** a pointer to the [sqlite3_stmt] object returned from
-** [sqlite3_prepare_v2()] or its variants.
-**
-** ^The second argument is the index of the SQL parameter to be set.
-** ^The leftmost SQL parameter has an index of 1. ^When the same named
-** SQL parameter is used more than once, second and subsequent
-** occurrences have the same index as the first occurrence.
-** ^The index for named parameters can be looked up using the
-** [sqlite3_bind_parameter_index()] API if desired. ^The index
-** for "?NNN" parameters is the value of NNN.
-** ^The NNN value must be between 1 and the [sqlite3_limit()]
-** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
-**
-** ^The third argument is the value to bind to the parameter.
-**
-** ^(In those routines that have a fourth argument, its value is the
-** number of bytes in the parameter. To be clear: the value is the
-** number of <u>bytes</u> in the value, not the number of characters.)^
-** ^If the fourth parameter is negative, the length of the string is
-** the number of bytes up to the first zero terminator.
-**
-** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. ^If the fifth argument is
-** the special value [SQLITE_STATIC], then SQLite assumes that the
-** information is in static, unmanaged space and does not need to be freed.
-** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
-** SQLite makes its own private copy of the data immediately, before
-** the sqlite3_bind_*() routine returns.
-**
-** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
-** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
-** (just an integer to hold its size) while it is being processed.
-** Zeroblobs are intended to serve as placeholders for BLOBs whose
-** content is later written using
-** [sqlite3_blob_open | incremental BLOB I/O] routines.
-** ^A negative value for the zeroblob results in a zero-length BLOB.
-**
-** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
-** for the [prepared statement] or with a prepared statement for which
-** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
-** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_()
-** routine is passed a [prepared statement] that has been finalized, the
-** result is undefined and probably harmful.
-**
-** ^Bindings are not cleared by the [sqlite3_reset()] routine.
-** ^Unbound parameters are interpreted as NULL.
-**
-** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
-** [error code] if anything goes wrong.
-** ^[SQLITE_RANGE] is returned if the parameter
-** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
-**
-** See also: [sqlite3_bind_parameter_count()],
-** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
-*/
-SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-
-/*
-** CAPI3REF: Number Of SQL Parameters
-**
-** ^This routine can be used to find the number of [SQL parameters]
-** in a [prepared statement]. SQL parameters are tokens of the
-** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as
-** placeholders for values that are [sqlite3_bind_blob | bound]
-** to the parameters at a later time.
-**
-** ^(This routine actually returns the index of the largest (rightmost)
-** parameter. For all forms except ?NNN, this will correspond to the
-** number of unique parameters. If parameters of the ?NNN form are used,
-** there may be gaps in the list.)^
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_name()], and
-** [sqlite3_bind_parameter_index()].
-*/
-SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Name Of A Host Parameter
-**
-** ^The sqlite3_bind_parameter_name(P,N) interface returns
-** the name of the N-th [SQL parameter] in the [prepared statement] P.
-** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA"
-** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA"
-** respectively.
-** In other words, the initial ":" or "$" or "@" or "?"
-** is included as part of the name.)^
-** ^Parameters of the form "?" without a following integer have no name
-** and are referred to as "nameless" or "anonymous parameters".
-**
-** ^The first host parameter has an index of 1, not 0.
-**
-** ^If the value N is out of range or if the N-th parameter is
-** nameless, then NULL is returned. ^The returned string is
-** always in UTF-8 encoding even if the named parameter was
-** originally specified as UTF-16 in [sqlite3_prepare16()] or
-** [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-*/
-SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
-
-/*
-** CAPI3REF: Index Of A Parameter With A Given Name
-**
-** ^Return the index of an SQL parameter given its name. ^The
-** index value returned is suitable for use as the second
-** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero
-** is returned if no matching parameter is found. ^The parameter
-** name must be given in UTF-8 even if the original statement
-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-*/
-SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
-
-/*
-** CAPI3REF: Reset All Bindings On A Prepared Statement
-**
-** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
-** the [sqlite3_bind_blob | bindings] on a [prepared statement].
-** ^Use this routine to reset all host parameters to NULL.
-*/
-SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number Of Columns In A Result Set
-**
-** ^Return the number of columns in the result set returned by the
-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
-** statement that does not return data (for example an [UPDATE]).
-*/
-SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Column Names In A Result Set
-**
-** ^These routines return the name assigned to a particular column
-** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
-** interface returns a pointer to a zero-terminated UTF-8 string
-** and sqlite3_column_name16() returns a pointer to a zero-terminated
-** UTF-16 string. ^The first parameter is the [prepared statement]
-** that implements the [SELECT] statement. ^The second parameter is the
-** column number. ^The leftmost column is number 0.
-**
-** ^The returned string pointer is valid until either the [prepared statement]
-** is destroyed by [sqlite3_finalize()] or until the next call to
-** sqlite3_column_name() or sqlite3_column_name16() on the same column.
-**
-** ^If sqlite3_malloc() fails during the processing of either routine
-** (for example during a conversion from UTF-8 to UTF-16) then a
-** NULL pointer is returned.
-**
-** ^The name of a result column is the value of the "AS" clause for
-** that column, if there is an AS clause. If there is no AS clause
-** then the name of the column is unspecified and may change from
-** one release of SQLite to the next.
-*/
-SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
-
-/*
-** CAPI3REF: Source Of Data In A Query Result
-**
-** ^These routines provide a means to determine the database, table, and
-** table column that is the origin of a particular result column in
-** [SELECT] statement.
-** ^The name of the database or table or column can be returned as
-** either a UTF-8 or UTF-16 string. ^The _database_ routines return
-** the database name, the _table_ routines return the table name, and
-** the origin_ routines return the column name.
-** ^The returned string is valid until the [prepared statement] is destroyed
-** using [sqlite3_finalize()] or until the same information is requested
-** again in a different encoding.
-**
-** ^The names returned are the original un-aliased names of the
-** database, table, and column.
-**
-** ^The first argument to these interfaces is a [prepared statement].
-** ^These functions return information about the Nth result column returned by
-** the statement, where N is the second function argument.
-** ^The left-most column is column 0 for these routines.
-**
-** ^If the Nth column returned by the statement is an expression or
-** subquery and is not a column value, then all of these functions return
-** NULL. ^These routine might also return NULL if a memory allocation error
-** occurs. ^Otherwise, they return the name of the attached database, table,
-** or column that query result column was extracted from.
-**
-** ^As with all other SQLite APIs, those whose names end with "16" return
-** UTF-16 encoded strings and the other functions return UTF-8.
-**
-** ^These APIs are only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
-**
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
-** If two or more threads call one or more
-** [sqlite3_column_database_name | column metadata interfaces]
-** for the same [prepared statement] and result column
-** at the same time then the results are undefined.
-*/
-SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
-
-/*
-** CAPI3REF: Declared Datatype Of A Query Result
-**
-** ^(The first parameter is a [prepared statement].
-** If this statement is a [SELECT] statement and the Nth column of the
-** returned result set of that [SELECT] is a table column (not an
-** expression or subquery) then the declared type of the table
-** column is returned.)^ ^If the Nth column of the result set is an
-** expression or subquery, then a NULL pointer is returned.
-** ^The returned string is always UTF-8 encoded.
-**
-** ^(For example, given the database schema:
-**
-** CREATE TABLE t1(c1 VARIANT);
-**
-** and the following statement to be compiled:
-**
-** SELECT c1 + 1, c1 FROM t1;
-**
-** this routine would return the string "VARIANT" for the second result
-** column (i==1), and a NULL pointer for the first result column (i==0).)^
-**
-** ^SQLite uses dynamic run-time typing. ^So just because a column
-** is declared to contain a particular type does not mean that the
-** data stored in that column is of the declared type. SQLite is
-** strongly typed, but the typing is dynamic not static. ^Type
-** is associated with individual values, not with the containers
-** used to hold those values.
-*/
-SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
-
-/*
-** CAPI3REF: Evaluate An SQL Statement
-**
-** After a [prepared statement] has been prepared using either
-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
-** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
-** must be called one or more times to evaluate the statement.
-**
-** The details of the behavior of the sqlite3_step() interface depend
-** on whether the statement was prepared using the newer "v2" interface
-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
-** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
-** new "v2" interface is recommended for new applications but the legacy
-** interface will continue to be supported.
-**
-** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
-** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
-** ^With the "v2" interface, any of the other [result codes] or
-** [extended result codes] might be returned as well.
-**
-** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
-** database locks it needs to do its job. ^If the statement is a [COMMIT]
-** or occurs outside of an explicit transaction, then you can retry the
-** statement. If the statement is not a [COMMIT] and occurs within a
-** explicit transaction then you should rollback the transaction before
-** continuing.
-**
-** ^[SQLITE_DONE] means that the statement has finished executing
-** successfully. sqlite3_step() should not be called again on this virtual
-** machine without first calling [sqlite3_reset()] to reset the virtual
-** machine back to its initial state.
-**
-** ^If the SQL statement being executed returns any data, then [SQLITE_ROW]
-** is returned each time a new row of data is ready for processing by the
-** caller. The values may be accessed using the [column access functions].
-** sqlite3_step() is called again to retrieve the next row of data.
-**
-** ^[SQLITE_ERROR] means that a run-time error (such as a constraint
-** violation) has occurred. sqlite3_step() should not be called again on
-** the VM. More information may be found by calling [sqlite3_errmsg()].
-** ^With the legacy interface, a more specific error code (for example,
-** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth)
-** can be obtained by calling [sqlite3_reset()] on the
-** [prepared statement]. ^In the "v2" interface,
-** the more specific error code is returned directly by sqlite3_step().
-**
-** [SQLITE_MISUSE] means that the this routine was called inappropriately.
-** Perhaps it was called on a [prepared statement] that has
-** already been [sqlite3_finalize | finalized] or on one that had
-** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could
-** be the case that the same database connection is being used by two or
-** more threads at the same moment in time.
-**
-** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
-** API always returns a generic error code, [SQLITE_ERROR], following any
-** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
-** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the
-** specific [error codes] that better describes the error.
-** We admit that this is a goofy design. The problem has been fixed
-** with the "v2" interface. If you prepare all of your SQL statements
-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
-** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
-** then the more specific [error codes] are returned directly
-** by sqlite3_step(). The use of the "v2" interface is recommended.
-*/
-SQLITE_API int sqlite3_step(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number of columns in a result set
-**
-** ^The sqlite3_data_count(P) the number of columns in the
-** of the result set of [prepared statement] P.
-*/
-SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Fundamental Datatypes
-** KEYWORDS: SQLITE_TEXT
-**
-** ^(Every value in SQLite has one of five fundamental datatypes:
-**
-** <ul>
-** <li> 64-bit signed integer
-** <li> 64-bit IEEE floating point number
-** <li> string
-** <li> BLOB
-** <li> NULL
-** </ul>)^
-**
-** These constants are codes for each of those types.
-**
-** Note that the SQLITE_TEXT constant was also used in SQLite version 2
-** for a completely different meaning. Software that links against both
-** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not
-** SQLITE_TEXT.
-*/
-#define SQLITE_INTEGER 1
-#define SQLITE_FLOAT 2
-#define SQLITE_BLOB 4
-#define SQLITE_NULL 5
-#ifdef SQLITE_TEXT
-# undef SQLITE_TEXT
-#else
-# define SQLITE_TEXT 3
-#endif
-#define SQLITE3_TEXT 3
-
-/*
-** CAPI3REF: Result Values From A Query
-** KEYWORDS: {column access functions}
-**
-** These routines form the "result set" interface.
-**
-** ^These routines return information about a single column of the current
-** result row of a query. ^In every case the first argument is a pointer
-** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
-** that was returned from [sqlite3_prepare_v2()] or one of its variants)
-** and the second argument is the index of the column for which information
-** should be returned. ^The leftmost column of the result set has the index 0.
-** ^The number of columns in the result can be determined using
-** [sqlite3_column_count()].
-**
-** If the SQL statement does not currently point to a valid row, or if the
-** column index is out of range, the result is undefined.
-** These routines may only be called when the most recent call to
-** [sqlite3_step()] has returned [SQLITE_ROW] and neither
-** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently.
-** If any of these routines are called after [sqlite3_reset()] or
-** [sqlite3_finalize()] or after [sqlite3_step()] has returned
-** something other than [SQLITE_ROW], the results are undefined.
-** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
-** are called from a different thread while any of these routines
-** are pending, then the results are undefined.
-**
-** ^The sqlite3_column_type() routine returns the
-** [SQLITE_INTEGER | datatype code] for the initial data type
-** of the result column. ^The returned value is one of [SQLITE_INTEGER],
-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
-** returned by sqlite3_column_type() is only meaningful if no type
-** conversions have occurred as described below. After a type conversion,
-** the value returned by sqlite3_column_type() is undefined. Future
-** versions of SQLite may change the behavior of sqlite3_column_type()
-** following a type conversion.
-**
-** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
-** routine returns the number of bytes in that BLOB or string.
-** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
-** the string to UTF-8 and then returns the number of bytes.
-** ^If the result is a numeric value then sqlite3_column_bytes() uses
-** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
-** the number of bytes in that string.
-** ^The value returned does not include the zero terminator at the end
-** of the string. ^For clarity: the value returned is the number of
-** bytes in the string, not the number of characters.
-**
-** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
-** even empty strings, are always zero terminated. ^The return
-** value from sqlite3_column_blob() for a zero-length BLOB is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** ^The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.
-** ^The zero terminator is not included in this count.
-**
-** ^The object returned by [sqlite3_column_value()] is an
-** [unprotected sqlite3_value] object. An unprotected sqlite3_value object
-** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()].
-** If the [unprotected sqlite3_value] object returned by
-** [sqlite3_column_value()] is used in any other way, including calls
-** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
-** or [sqlite3_value_bytes()], then the behavior is undefined.
-**
-** These routines attempt to convert the value where appropriate. ^For
-** example, if the internal representation is FLOAT and a text result
-** is requested, [sqlite3_snprintf()] is used internally to perform the
-** conversion automatically. ^(The following table details the conversions
-** that are applied:
-**
-** <blockquote>
-** <table border="1">
-** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion
-**
-** <tr><td> NULL <td> INTEGER <td> Result is 0
-** <tr><td> NULL <td> FLOAT <td> Result is 0.0
-** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
-** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
-** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
-** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
-** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT
-** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
-** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
-** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
-** <tr><td> TEXT <td> INTEGER <td> Use atoi()
-** <tr><td> TEXT <td> FLOAT <td> Use atof()
-** <tr><td> TEXT <td> BLOB <td> No change
-** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
-** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
-** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
-** </table>
-** </blockquote>)^
-**
-** The table above makes reference to standard C library functions atoi()
-** and atof(). SQLite does not really use these functions. It has its
-** own equivalent internal routines. The atoi() and atof() names are
-** used in the table for brevity and because they are familiar to most
-** C programmers.
-**
-** ^Note that when type conversions occur, pointers returned by prior
-** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
-** sqlite3_column_text16() may be invalidated.
-** ^(Type conversions and pointer invalidations might occur
-** in the following cases:
-**
-** <ul>
-** <li> The initial content is a BLOB and sqlite3_column_text() or
-** sqlite3_column_text16() is called. A zero-terminator might
-** need to be added to the string.</li>
-** <li> The initial content is UTF-8 text and sqlite3_column_bytes16() or
-** sqlite3_column_text16() is called. The content must be converted
-** to UTF-16.</li>
-** <li> The initial content is UTF-16 text and sqlite3_column_bytes() or
-** sqlite3_column_text() is called. The content must be converted
-** to UTF-8.</li>
-** </ul>)^
-**
-** ^Conversions between UTF-16be and UTF-16le are always done in place and do
-** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified. Other kinds
-** of conversion are done in place when it is possible, but sometimes they
-** are not possible and in those cases prior pointers are invalidated.
-**
-** ^(The safest and easiest to remember policy is to invoke these routines
-** in one of the following ways:
-**
-** <ul>
-** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
-** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
-** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>)^
-**
-** In other words, you should call sqlite3_column_text(),
-** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result
-** into the desired format, then invoke sqlite3_column_bytes() or
-** sqlite3_column_bytes16() to find the size of the result. Do not mix calls
-** to sqlite3_column_text() or sqlite3_column_blob() with calls to
-** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16()
-** with calls to sqlite3_column_bytes().
-**
-** ^The pointers returned are valid until a type conversion occurs as
-** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
-** [sqlite3_finalize()] is called. ^The memory space used to hold strings
-** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
-** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
-** [sqlite3_free()].
-**
-** ^(If a memory allocation error occurs during the evaluation of any
-** of these routines, a default value is returned. The default value
-** is either the integer 0, the floating point number 0.0, or a NULL
-** pointer. Subsequent calls to [sqlite3_errcode()] will return
-** [SQLITE_NOMEM].)^
-*/
-SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
-
-/*
-** CAPI3REF: Destroy A Prepared Statement Object
-**
-** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the statement was executed successfully or not executed at all, then
-** SQLITE_OK is returned. ^If execution of the statement failed then an
-** [error code] or [extended error code] is returned.
-**
-** ^This routine can be called at any point during the execution of the
-** [prepared statement]. ^If the virtual machine has not
-** completed execution when this routine is called, that is like
-** encountering an error or an [sqlite3_interrupt | interrupt].
-** ^Incomplete updates may be rolled back and transactions canceled,
-** depending on the circumstances, and the
-** [error code] returned will be [SQLITE_ABORT].
-*/
-SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Reset A Prepared Statement Object
-**
-** The sqlite3_reset() function is called to reset a [prepared statement]
-** object back to its initial state, ready to be re-executed.
-** ^Any SQL statement variables that had values bound to them using
-** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
-** Use [sqlite3_clear_bindings()] to reset the bindings.
-**
-** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
-** back to the beginning of its program.
-**
-** ^If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlite3_step(S)] has never before been called on S,
-** then [sqlite3_reset(S)] returns [SQLITE_OK].
-**
-** ^If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S indicated an error, then
-** [sqlite3_reset(S)] returns an appropriate [error code].
-**
-** ^The [sqlite3_reset(S)] interface does not change the values
-** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
-*/
-SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Create Or Redefine SQL Functions
-** KEYWORDS: {function creation routines}
-** KEYWORDS: {application-defined SQL function}
-** KEYWORDS: {application-defined SQL functions}
-**
-** ^These two functions (collectively known as "function creation routines")
-** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates. The only difference between the
-** two is that the second parameter, the name of the (scalar) function or
-** aggregate, is encoded in UTF-8 for sqlite3_create_function() and UTF-16
-** for sqlite3_create_function16().
-**
-** ^The first parameter is the [database connection] to which the SQL
-** function is to be added. ^If an application uses more than one database
-** connection then application-defined SQL functions must be added
-** to each database connection separately.
-**
-** The second parameter is the name of the SQL function to be created or
-** redefined. ^The length of the name is limited to 255 bytes, exclusive of
-** the zero-terminator. Note that the name length limit is in bytes, not
-** characters. ^Any attempt to create a function with a longer name
-** will result in [SQLITE_ERROR] being returned.
-**
-** ^The third parameter (nArg)
-** is the number of arguments that the SQL function or
-** aggregate takes. ^If this parameter is -1, then the SQL function or
-** aggregate may take any number of arguments between 0 and the limit
-** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third
-** parameter is less than -1 or greater than 127 then the behavior is
-** undefined.
-**
-** The fourth parameter, eTextRep, specifies what
-** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters. Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
-** more efficient with one encoding than another. ^An application may
-** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
-** times with the same function but with different values of eTextRep.
-** ^When multiple implementations of the same function are available, SQLite
-** will pick the one that involves the least amount of data conversion.
-** If there is only a single implementation which does not care what text
-** encoding is used, then the fourth argument should be [SQLITE_ANY].
-**
-** ^(The fifth parameter is an arbitrary pointer. The implementation of the
-** function can gain access to this pointer using [sqlite3_user_data()].)^
-**
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
-** pointers to C-language functions that implement the SQL function or
-** aggregate. ^A scalar SQL function requires an implementation of the xFunc
-** callback only; NULL pointers should be passed as the xStep and xFinal
-** parameters. ^An aggregate SQL function requires an implementation of xStep
-** and xFinal and NULL should be passed for xFunc. ^To delete an existing
-** SQL function or aggregate, pass NULL for all three function callbacks.
-**
-** ^It is permitted to register multiple implementations of the same
-** functions with the same name but with either differing numbers of
-** arguments or differing preferred text encodings. ^SQLite will use
-** the implementation that most closely matches the way in which the
-** SQL function is used. ^A function implementation with a non-negative
-** nArg parameter is a better match than a function implementation with
-** a negative nArg. ^A function where the preferred text encoding
-** matches the database encoding is a better
-** match than a function where the encoding is different.
-** ^A function where the encoding difference is between UTF16le and UTF16be
-** is a closer match than a function where the encoding difference is
-** between UTF8 and UTF16.
-**
-** ^Built-in functions may be overloaded by new application-defined functions.
-** ^The first application-defined function with a given name overrides all
-** built-in functions in the same [database connection] with the same name.
-** ^Subsequent application-defined functions of the same name only override
-** prior application-defined functions that are an exact match for the
-** number of parameters and preferred encoding.
-**
-** ^An application-defined function is permitted to call other
-** SQLite interfaces. However, such calls must not
-** close the database connection nor finalize or reset the prepared
-** statement in which the function is running.
-*/
-SQLITE_API int sqlite3_create_function(
- sqlite3 *db,
- const char *zFunctionName,
- int nArg,
- int eTextRep,
- void *pApp,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-SQLITE_API int sqlite3_create_function16(
- sqlite3 *db,
- const void *zFunctionName,
- int nArg,
- int eTextRep,
- void *pApp,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-
-/*
-** CAPI3REF: Text Encodings
-**
-** These constant define integer codes that represent the various
-** text encodings supported by SQLite.
-*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
-#define SQLITE_UTF16 4 /* Use native byte order */
-#define SQLITE_ANY 5 /* sqlite3_create_function only */
-#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
-
-/*
-** CAPI3REF: Deprecated Functions
-** DEPRECATED
-**
-** These functions are [deprecated]. In order to maintain
-** backwards compatibility with older code, these functions continue
-** to be supported. However, new applications should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you what they do.
-*/
-#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
-#endif
-
-/*
-** CAPI3REF: Obtaining SQL Function Parameter Values
-**
-** The C-language implementation of SQL functions and aggregates uses
-** this set of interface routines to access the parameter values on
-** the function or aggregate.
-**
-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
-** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
-** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
-** each parameter to the SQL function. These routines are used to
-** extract values from the [sqlite3_value] objects.
-**
-** These routines work only with [protected sqlite3_value] objects.
-** Any attempt to use these routines on an [unprotected sqlite3_value]
-** object results in undefined behavior.
-**
-** ^These routines work just like the corresponding [column access functions]
-** except that these routines take a single [protected sqlite3_value] object
-** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
-**
-** ^The sqlite3_value_text16() interface extracts a UTF-16 string
-** in the native byte-order of the host machine. ^The
-** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
-** extract UTF-16 strings as big-endian and little-endian respectively.
-**
-** ^(The sqlite3_value_numeric_type() interface attempts to apply
-** numeric affinity to the value. This means that an attempt is
-** made to convert the value to an integer or floating point. If
-** such a conversion is possible without loss of information (in other
-** words, if the value is a string that looks like a number)
-** then the conversion is performed. Otherwise no conversion occurs.
-** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
-**
-** Please pay particular attention to the fact that the pointer returned
-** from [sqlite3_value_blob()], [sqlite3_value_text()], or
-** [sqlite3_value_text16()] can be invalidated by a subsequent call to
-** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
-** or [sqlite3_value_text16()].
-**
-** These routines must be called from the same thread as
-** the SQL function that supplied the [sqlite3_value*] parameters.
-*/
-SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double sqlite3_value_double(sqlite3_value*);
-SQLITE_API int sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int sqlite3_value_type(sqlite3_value*);
-SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
-
-/*
-** CAPI3REF: Obtain Aggregate Function Context
-**
-** Implementions of aggregate SQL functions use this
-** routine to allocate memory for storing their state.
-**
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
-** for a particular aggregate function, SQLite
-** allocates N of memory, zeroes out that memory, and returns a pointer
-** to the new memory. ^On second and subsequent calls to
-** sqlite3_aggregate_context() for the same aggregate function instance,
-** the same buffer is returned. Sqlite3_aggregate_context() is normally
-** called once for each invocation of the xStep callback and then one
-** last time when the xFinal callback is invoked. ^(When no rows match
-** an aggregate query, the xStep() callback of the aggregate function
-** implementation is never called and xFinal() is called exactly once.
-** In those cases, sqlite3_aggregate_context() might be called for the
-** first time from within xFinal().)^
-**
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is
-** less than or equal to zero or if a memory allocate error occurs.
-**
-** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
-** determined by the N parameter on first successful call. Changing the
-** value of N in subsequent call to sqlite3_aggregate_context() within
-** the same aggregate function instance will not resize the memory
-** allocation.)^
-**
-** ^SQLite automatically frees the memory allocated by
-** sqlite3_aggregate_context() when the aggregate query concludes.
-**
-** The first parameter must be a copy of the
-** [sqlite3_context | SQL function context] that is the first parameter
-** to the xStep or xFinal callback routine that implements the aggregate
-** function.
-**
-** This routine must be called from the same thread in which
-** the aggregate SQL function is running.
-*/
-SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
-
-/*
-** CAPI3REF: User Data For Functions
-**
-** ^The sqlite3_user_data() interface returns a copy of
-** the pointer that was the pUserData parameter (the 5th parameter)
-** of the [sqlite3_create_function()]
-** and [sqlite3_create_function16()] routines that originally
-** registered the application defined function.
-**
-** This routine must be called from the same thread in which
-** the application-defined function is running.
-*/
-SQLITE_API void *sqlite3_user_data(sqlite3_context*);
-
-/*
-** CAPI3REF: Database Connection For Functions
-**
-** ^The sqlite3_context_db_handle() interface returns a copy of
-** the pointer to the [database connection] (the 1st parameter)
-** of the [sqlite3_create_function()]
-** and [sqlite3_create_function16()] routines that originally
-** registered the application defined function.
-*/
-SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
-
-/*
-** CAPI3REF: Function Auxiliary Data
-**
-** The following two functions may be used by scalar SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. This may
-** be used, for example, to add a regular-expression matching scalar
-** function. The compiled version of the regular expression is stored as
-** metadata associated with the SQL value passed as the regular expression
-** pattern. The compiled regular expression can be reused on multiple
-** invocations of the same function so that the original pattern string
-** does not need to be recompiled on each invocation.
-**
-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function. ^If no metadata has been ever
-** been set for the Nth argument of the function, or if the corresponding
-** function parameter has changed since the meta-data was set,
-** then sqlite3_get_auxdata() returns a NULL pointer.
-**
-** ^The sqlite3_set_auxdata() interface saves the metadata
-** pointed to by its 3rd parameter as the metadata for the N-th
-** argument of the application-defined function. Subsequent
-** calls to sqlite3_get_auxdata() might return this data, if it has
-** not been destroyed.
-** ^If it is not NULL, SQLite will invoke the destructor
-** function given by the 4th parameter to sqlite3_set_auxdata() on
-** the metadata when the corresponding function parameter changes
-** or when the SQL statement completes, whichever comes first.
-**
-** SQLite is free to call the destructor and drop metadata on any
-** parameter of any function at any time. ^The only guarantee is that
-** the destructor will be called before the metadata is dropped.
-**
-** ^(In practice, metadata is preserved between function calls for
-** expressions that are constant at compile time. This includes literal
-** values and [parameters].)^
-**
-** These routines must be called from the same thread in which
-** the SQL function is running.
-*/
-SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
-
-
-/*
-** CAPI3REF: Constants Defining Special Destructor Behavior
-**
-** These are special values for the destructor that is passed in as the
-** final argument to routines like [sqlite3_result_blob()]. ^If the destructor
-** argument is SQLITE_STATIC, it means that the content pointer is constant
-** and will never change. It does not need to be destroyed. ^The
-** SQLITE_TRANSIENT value means that the content will likely change in
-** the near future and that SQLite should make its own private copy of
-** the content before returning.
-**
-** The typedef is necessary to work around problems in certain
-** C++ compilers. See ticket #2191.
-*/
-typedef void (*sqlite3_destructor_type)(void*);
-#define SQLITE_STATIC ((sqlite3_destructor_type)0)
-#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
-
-/*
-** CAPI3REF: Setting The Result Of An SQL Function
-**
-** These routines are used by the xFunc or xFinal callbacks that
-** implement SQL functions and aggregates. See
-** [sqlite3_create_function()] and [sqlite3_create_function16()]
-** for additional information.
-**
-** These functions work very much like the [parameter binding] family of
-** functions used to bind values to host parameters in prepared statements.
-** Refer to the [SQL parameter] documentation for additional information.
-**
-** ^The sqlite3_result_blob() interface sets the result from
-** an application-defined function to be the BLOB whose content is pointed
-** to by the second parameter and which is N bytes long where N is the
-** third parameter.
-**
-** ^The sqlite3_result_zeroblob() interfaces set the result of
-** the application-defined function to be a BLOB containing all zero
-** bytes and N bytes in size, where N is the value of the 2nd parameter.
-**
-** ^The sqlite3_result_double() interface sets the result from
-** an application-defined function to be a floating point value specified
-** by its 2nd argument.
-**
-** ^The sqlite3_result_error() and sqlite3_result_error16() functions
-** cause the implemented SQL function to throw an exception.
-** ^SQLite uses the string pointed to by the
-** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
-** as the text of an error message. ^SQLite interprets the error
-** message string from sqlite3_result_error() as UTF-8. ^SQLite
-** interprets the string from sqlite3_result_error16() as UTF-16 in native
-** byte order. ^If the third parameter to sqlite3_result_error()
-** or sqlite3_result_error16() is negative then SQLite takes as the error
-** message all text up through the first zero character.
-** ^If the third parameter to sqlite3_result_error() or
-** sqlite3_result_error16() is non-negative then SQLite takes that many
-** bytes (not characters) from the 2nd parameter as the error message.
-** ^The sqlite3_result_error() and sqlite3_result_error16()
-** routines make a private copy of the error message text before
-** they return. Hence, the calling function can deallocate or
-** modify the text after they return without harm.
-** ^The sqlite3_result_error_code() function changes the error code
-** returned by SQLite as a result of an error in a function. ^By default,
-** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error()
-** or sqlite3_result_error16() resets the error code to SQLITE_ERROR.
-**
-** ^The sqlite3_result_toobig() interface causes SQLite to throw an error
-** indicating that a string or BLOB is too long to represent.
-**
-** ^The sqlite3_result_nomem() interface causes SQLite to throw an error
-** indicating that a memory allocation failed.
-**
-** ^The sqlite3_result_int() interface sets the return value
-** of the application-defined function to be the 32-bit signed integer
-** value given in the 2nd argument.
-** ^The sqlite3_result_int64() interface sets the return value
-** of the application-defined function to be the 64-bit signed integer
-** value given in the 2nd argument.
-**
-** ^The sqlite3_result_null() interface sets the return value
-** of the application-defined function to be NULL.
-**
-** ^The sqlite3_result_text(), sqlite3_result_text16(),
-** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
-** set the return value of the application-defined function to be
-** a text string which is represented as UTF-8, UTF-16 native byte order,
-** UTF-16 little endian, or UTF-16 big endian, respectively.
-** ^SQLite takes the text result from the application from
-** the 2nd parameter of the sqlite3_result_text* interfaces.
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
-** is non-negative, then as many bytes (not characters) of the text
-** pointed to by the 2nd parameter are taken as the application-defined
-** function result.
-** ^If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
-** function as the destructor on the text or BLOB result when it has
-** finished using that result.
-** ^If the 4th parameter to the sqlite3_result_text* interfaces or to
-** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite
-** assumes that the text or BLOB result is in constant space and does not
-** copy the content of the parameter nor call a destructor on the content
-** when it has finished using that result.
-** ^If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
-** then SQLite makes a copy of the result into space obtained from
-** from [sqlite3_malloc()] before it returns.
-**
-** ^The sqlite3_result_value() interface sets the result of
-** the application-defined function to be a copy the
-** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
-** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
-** so that the [sqlite3_value] specified in the parameter may change or
-** be deallocated after sqlite3_result_value() returns without harm.
-** ^A [protected sqlite3_value] object may always be used where an
-** [unprotected sqlite3_value] object is required, so either
-** kind of [sqlite3_value] object can be used with this interface.
-**
-** If these routines are called from within the different thread
-** than the one containing the application-defined function that received
-** the [sqlite3_context] pointer, the results are undefined.
-*/
-SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void sqlite3_result_null(sqlite3_context*);
-SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
-
-/*
-** CAPI3REF: Define New Collating Sequences
-**
-** These functions are used to add new collation sequences to the
-** [database connection] specified as the first argument.
-**
-** ^The name of the new collation sequence is specified as a UTF-8 string
-** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). ^In all cases
-** the name is passed as the second function argument.
-**
-** ^The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE], or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian, or UTF-16 big-endian, respectively. ^The
-** third argument might also be [SQLITE_UTF16] to indicate that the routine
-** expects pointers to be UTF-16 strings in the native byte order, or the
-** argument can be [SQLITE_UTF16_ALIGNED] if the
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF-16 in the native byte order.
-**
-** A pointer to the user supplied routine must be passed as the fifth
-** argument. ^If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore).
-** ^Each time the application supplied function is invoked, it is passed
-** as its first parameter a copy of the void* passed as the fourth argument
-** to sqlite3_create_collation() or sqlite3_create_collation16().
-**
-** ^The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered. The application defined collation routine should
-** return negative, zero or positive if the first string is less than,
-** equal to, or greater than the second string. i.e. (STRING1 - STRING2).
-**
-** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** except that it takes an extra argument which is a destructor for
-** the collation. ^The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** ^Collations are destroyed when they are overridden by later calls to the
-** collation creation functions or when the [database connection] is closed
-** using [sqlite3_close()].
-**
-** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
-*/
-SQLITE_API int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-SQLITE_API int sqlite3_create_collation_v2(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*),
- void(*xDestroy)(void*)
-);
-SQLITE_API int sqlite3_create_collation16(
- sqlite3*,
- const void *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-
-/*
-** CAPI3REF: Collation Needed Callbacks
-**
-** ^To avoid having to register all collation sequences before a database
-** can be used, a single callback function may be registered with the
-** [database connection] to be invoked whenever an undefined collation
-** sequence is required.
-**
-** ^If the function is registered using the sqlite3_collation_needed() API,
-** then it is passed the names of undefined collation sequences as strings
-** encoded in UTF-8. ^If sqlite3_collation_needed16() is used,
-** the names are passed as UTF-16 in machine native byte order.
-** ^A call to either function replaces the existing collation-needed callback.
-**
-** ^(When the callback is invoked, the first argument passed is a copy
-** of the second argument to sqlite3_collation_needed() or
-** sqlite3_collation_needed16(). The second argument is the database
-** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE],
-** or [SQLITE_UTF16LE], indicating the most desirable form of the collation
-** sequence function required. The fourth parameter is the name of the
-** required collation sequence.)^
-**
-** The callback function should register the desired collation using
-** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
-** [sqlite3_create_collation_v2()].
-*/
-SQLITE_API int sqlite3_collation_needed(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const char*)
-);
-SQLITE_API int sqlite3_collation_needed16(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const void*)
-);
-
-/*
-** Specify the key for an encrypted database. This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_key(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The key */
-);
-
-/*
-** Change the key on an open database. If the current database is not
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_rekey(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The new key */
-);
-
-/*
-** CAPI3REF: Suspend Execution For A Short Time
-**
-** ^The sqlite3_sleep() function causes the current thread to suspend execution
-** for at least a number of milliseconds specified in its parameter.
-**
-** ^If the operating system does not support sleep requests with
-** millisecond time resolution, then the time will be rounded up to
-** the nearest second. ^The number of milliseconds of sleep actually
-** requested from the operating system is returned.
-**
-** ^SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object.
-*/
-SQLITE_API int sqlite3_sleep(int);
-
-/*
-** CAPI3REF: Name Of The Folder Holding Temporary Files
-**
-** ^(If this global variable is made to point to a string which is
-** the name of a folder (a.k.a. directory), then all temporary files
-** created by SQLite when using a built-in [sqlite3_vfs | VFS]
-** will be placed in that directory.)^ ^If this variable
-** is a NULL pointer, then SQLite performs a search for an appropriate
-** temporary file directory.
-**
-** It is not safe to read or modify this variable in more than one
-** thread at a time. It is not safe to read or modify this variable
-** if a [database connection] is being used at the same time in a separate
-** thread.
-** It is intended that this variable be set once
-** as part of process initialization and before any SQLite interface
-** routines have been called and that this variable remain unchanged
-** thereafter.
-**
-** ^The [temp_store_directory pragma] may modify this variable and cause
-** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
-** the [temp_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
-** [sqlite3_malloc] and the pragma may attempt to free that memory
-** using [sqlite3_free].
-** Hence, if this variable is modified directly, either it should be
-** made NULL or made to point to memory obtained from [sqlite3_malloc]
-** or else the use of the [temp_store_directory pragma] should be avoided.
-*/
-SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory;
-
-/*
-** CAPI3REF: Test For Auto-Commit Mode
-** KEYWORDS: {autocommit mode}
-**
-** ^The sqlite3_get_autocommit() interface returns non-zero or
-** zero if the given database connection is or is not in autocommit mode,
-** respectively. ^Autocommit mode is on by default.
-** ^Autocommit mode is disabled by a [BEGIN] statement.
-** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK].
-**
-** If certain kinds of errors occur on a statement within a multi-statement
-** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR],
-** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the
-** transaction might be rolled back automatically. The only way to
-** find out whether SQLite automatically rolled back the transaction after
-** an error is to use this function.
-**
-** If another thread changes the autocommit status of the database
-** connection while this routine is running, then the return value
-** is undefined.
-*/
-SQLITE_API int sqlite3_get_autocommit(sqlite3*);
-
-/*
-** CAPI3REF: Find The Database Handle Of A Prepared Statement
-**
-** ^The sqlite3_db_handle interface returns the [database connection] handle
-** to which a [prepared statement] belongs. ^The [database connection]
-** returned by sqlite3_db_handle is the same [database connection]
-** that was the first argument
-** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
-** create the statement in the first place.
-*/
-SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Find the next prepared statement
-**
-** ^This interface returns a pointer to the next [prepared statement] after
-** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
-** then this interface returns a pointer to the first prepared statement
-** associated with the database connection pDb. ^If no prepared statement
-** satisfies the conditions of this routine, it returns NULL.
-**
-** The [database connection] pointer D in a call to
-** [sqlite3_next_stmt(D,S)] must refer to an open database
-** connection and in particular must not be a NULL pointer.
-*/
-SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Commit And Rollback Notification Callbacks
-**
-** ^The sqlite3_commit_hook() interface registers a callback
-** function to be invoked whenever a transaction is [COMMIT | committed].
-** ^Any callback set by a previous call to sqlite3_commit_hook()
-** for the same database connection is overridden.
-** ^The sqlite3_rollback_hook() interface registers a callback
-** function to be invoked whenever a transaction is [ROLLBACK | rolled back].
-** ^Any callback set by a previous call to sqlite3_rollback_hook()
-** for the same database connection is overridden.
-** ^The pArg argument is passed through to the callback.
-** ^If the callback on a commit hook function returns non-zero,
-** then the commit is converted into a rollback.
-**
-** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions
-** return the P argument from the previous call of the same function
-** on the same [database connection] D, or NULL for
-** the first call for each function on D.
-**
-** The callback implementation must not do anything that will modify
-** the database connection that invoked the callback. Any actions
-** to modify the database connection must be deferred until after the
-** completion of the [sqlite3_step()] call that triggered the commit
-** or rollback hook in the first place.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
-**
-** ^Registering a NULL function disables the callback.
-**
-** ^When the commit hook callback routine returns zero, the [COMMIT]
-** operation is allowed to continue normally. ^If the commit hook
-** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK].
-** ^The rollback hook is invoked on a rollback that results from a commit
-** hook returning non-zero, just as it would be with any other rollback.
-**
-** ^For the purposes of this API, a transaction is said to have been
-** rolled back if an explicit "ROLLBACK" statement is executed, or
-** an error or constraint causes an implicit rollback to occur.
-** ^The rollback callback is not invoked if a transaction is
-** automatically rolled back because the database connection is closed.
-** ^The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
-**
-** See also the [sqlite3_update_hook()] interface.
-*/
-SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
-
-/*
-** CAPI3REF: Data Change Notification Callbacks
-**
-** ^The sqlite3_update_hook() interface registers a callback function
-** with the [database connection] identified by the first argument
-** to be invoked whenever a row is updated, inserted or deleted.
-** ^Any callback set by a previous call to this function
-** for the same database connection is overridden.
-**
-** ^The second argument is a pointer to the function to invoke when a
-** row is updated, inserted or deleted.
-** ^The first argument to the callback is a copy of the third argument
-** to sqlite3_update_hook().
-** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
-** or [SQLITE_UPDATE], depending on the operation that caused the callback
-** to be invoked.
-** ^The third and fourth arguments to the callback contain pointers to the
-** database and table name containing the affected row.
-** ^The final callback parameter is the [rowid] of the row.
-** ^In the case of an update, this is the [rowid] after the update takes place.
-**
-** ^(The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).)^
-**
-** ^In the current implementation, the update hook
-** is not invoked when duplication rows are deleted because of an
-** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook
-** invoked when rows are deleted using the [truncate optimization].
-** The exceptions defined in this paragraph might change in a future
-** release of SQLite.
-**
-** The update hook implementation must not do anything that will modify
-** the database connection that invoked the update hook. Any actions
-** to modify the database connection must be deferred until after the
-** completion of the [sqlite3_step()] call that triggered the update hook.
-** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
-** database connections for the meaning of "modify" in this paragraph.
-**
-** ^The sqlite3_update_hook(D,C,P) function
-** returns the P argument from the previous call
-** on the same [database connection] D, or NULL for
-** the first call on D.
-**
-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
-** interfaces.
-*/
-SQLITE_API void *sqlite3_update_hook(
- sqlite3*,
- void(*)(void *,int ,char const *,char const *,sqlite3_int64),
- void*
-);
-
-/*
-** CAPI3REF: Enable Or Disable Shared Pager Cache
-** KEYWORDS: {shared cache}
-**
-** ^(This routine enables or disables the sharing of the database cache
-** and schema data structures between [database connection | connections]
-** to the same database. Sharing is enabled if the argument is true
-** and disabled if the argument is false.)^
-**
-** ^Cache sharing is enabled and disabled for an entire process.
-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
-** sharing was enabled or disabled for each thread separately.
-**
-** ^(The cache sharing mode set by this interface effects all subsequent
-** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** Existing database connections continue use the sharing mode
-** that was in effect at the time they were opened.)^
-**
-** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
-** successfully. An [error code] is returned otherwise.)^
-**
-** ^Shared cache is disabled by default. But this might change in
-** future releases of SQLite. Applications that care about shared
-** cache setting should set it explicitly.
-**
-** See Also: [SQLite Shared-Cache Mode]
-*/
-SQLITE_API int sqlite3_enable_shared_cache(int);
-
-/*
-** CAPI3REF: Attempt To Free Heap Memory
-**
-** ^The sqlite3_release_memory() interface attempts to free N bytes
-** of heap memory by deallocating non-essential memory allocations
-** held by the database library. Memory used to cache database
-** pages to improve performance is an example of non-essential memory.
-** ^sqlite3_release_memory() returns the number of bytes actually freed,
-** which might be more or less than the amount requested.
-*/
-SQLITE_API int sqlite3_release_memory(int);
-
-/*
-** CAPI3REF: Impose A Limit On Heap Size
-**
-** ^The sqlite3_soft_heap_limit() interface places a "soft" limit
-** on the amount of heap memory that may be allocated by SQLite.
-** ^If an internal allocation is requested that would exceed the
-** soft heap limit, [sqlite3_release_memory()] is invoked one or
-** more times to free up some space before the allocation is performed.
-**
-** ^The limit is called "soft" because if [sqlite3_release_memory()]
-** cannot free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
-**
-** ^A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** ^The default value for the soft heap limit is zero.
-**
-** ^(SQLite makes a best effort to honor the soft heap limit.
-** But if the soft heap limit cannot be honored, execution will
-** continue without error or notification.)^ This is why the limit is
-** called a "soft" limit. It is advisory only.
-**
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs. Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
-*/
-SQLITE_API void sqlite3_soft_heap_limit(int);
-
-/*
-** CAPI3REF: Extract Metadata About A Column Of A Table
-**
-** ^This routine returns metadata about a specific column of a specific
-** database table accessible using the [database connection] handle
-** passed as the first function argument.
-**
-** ^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
-** for the table using the same algorithm used by the database engine to
-** resolve unqualified table references.
-**
-** ^The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
-**
-** ^Metadata is returned by writing to the memory locations passed as the 5th
-** and subsequent parameters to this function. ^Any of these arguments may be
-** NULL, in which case the corresponding element of metadata is omitted.
-**
-** ^(<blockquote>
-** <table border="1">
-** <tr><th> Parameter <th> Output<br>Type <th> Description
-**
-** <tr><td> 5th <td> const char* <td> Data type
-** <tr><td> 6th <td> const char* <td> Name of default collation sequence
-** <tr><td> 7th <td> int <td> True if column has a NOT NULL constraint
-** <tr><td> 8th <td> int <td> True if column is part of the PRIMARY KEY
-** <tr><td> 9th <td> int <td> True if column is [AUTOINCREMENT]
-** </table>
-** </blockquote>)^
-**
-** ^The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
-** call to any SQLite API function.
-**
-** ^If the specified table is actually a view, an [error code] is returned.
-**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and an
-** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
-** parameters are set for the explicitly declared column. ^(If there is no
-** explicitly declared [INTEGER PRIMARY KEY] column, then the output
-** parameters are set as follows:
-**
-** <pre>
-** data type: "INTEGER"
-** collation sequence: "BINARY"
-** not null: 0
-** primary key: 1
-** auto increment: 0
-** </pre>)^
-**
-** ^(This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an [error code] is returned and an error message left
-** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^
-**
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined.
-*/
-SQLITE_API int sqlite3_table_column_metadata(
- sqlite3 *db, /* Connection handle */
- const char *zDbName, /* Database name or NULL */
- const char *zTableName, /* Table name */
- const char *zColumnName, /* Column name */
- char const **pzDataType, /* OUTPUT: Declared data type */
- char const **pzCollSeq, /* OUTPUT: Collation sequence name */
- int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
- int *pPrimaryKey, /* OUTPUT: True if column part of PK */
- int *pAutoinc /* OUTPUT: True if column is auto-increment */
-);
-
-/*
-** CAPI3REF: Load An Extension
-**
-** ^This interface loads an SQLite extension library from the named file.
-**
-** ^The sqlite3_load_extension() interface attempts to load an
-** SQLite extension library contained in the file zFile.
-**
-** ^The entry point is zProc.
-** ^zProc may be 0, in which case the name of the entry point
-** defaults to "sqlite3_extension_init".
-** ^The sqlite3_load_extension() interface returns
-** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
-** ^If an error occurs and pzErrMsg is not 0, then the
-** [sqlite3_load_extension()] interface shall attempt to
-** fill *pzErrMsg with error message text stored in memory
-** obtained from [sqlite3_malloc()]. The calling function
-** should free this memory by calling [sqlite3_free()].
-**
-** ^Extension loading must be enabled using
-** [sqlite3_enable_load_extension()] prior to calling this API,
-** otherwise an error will be returned.
-**
-** See also the [load_extension() SQL function].
-*/
-SQLITE_API int sqlite3_load_extension(
- sqlite3 *db, /* Load the extension into this database connection */
- const char *zFile, /* Name of the shared library containing extension */
- const char *zProc, /* Entry point. Derived from zFile if 0 */
- char **pzErrMsg /* Put error message here if not 0 */
-);
-
-/*
-** CAPI3REF: Enable Or Disable Extension Loading
-**
-** ^So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following API
-** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
-**
-** ^Extension loading is off by default. See ticket #1863.
-** ^Call the sqlite3_enable_load_extension() routine with onoff==1
-** to turn extension loading on and call it with onoff==0 to turn
-** it back off again.
-*/
-SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
-
-/*
-** CAPI3REF: Automatically Load An Extensions
-**
-** ^This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new [database connections].
-**
-** ^(This routine stores a pointer to the extension entry point
-** in an array that is obtained from [sqlite3_malloc()]. That memory
-** is deallocated by [sqlite3_reset_auto_extension()].)^
-**
-** ^This function registers an extension entry point that is
-** automatically invoked whenever a new [database connection]
-** is opened using [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()].
-** ^Duplicate extensions are detected so calling this routine
-** multiple times with the same extension is harmless.
-** ^Automatic extensions apply across all threads.
-*/
-SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
-
-/*
-** CAPI3REF: Reset Automatic Extension Loading
-**
-** ^(This function disables all previously registered automatic
-** extensions. It undoes the effect of all prior
-** [sqlite3_auto_extension()] calls.)^
-**
-** ^This function disables automatic extensions in all threads.
-*/
-SQLITE_API void sqlite3_reset_auto_extension(void);
-
-/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
-** Structures used by the virtual table interface
-*/
-typedef struct sqlite3_vtab sqlite3_vtab;
-typedef struct sqlite3_index_info sqlite3_index_info;
-typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
-typedef struct sqlite3_module sqlite3_module;
-
-/*
-** CAPI3REF: Virtual Table Object
-** KEYWORDS: sqlite3_module {virtual table module}
-** EXPERIMENTAL
-**
-** This structure, sometimes called a a "virtual table module",
-** defines the implementation of a [virtual tables].
-** This structure consists mostly of methods for the module.
-**
-** ^A virtual table module is created by filling in a persistent
-** instance of this structure and passing a pointer to that instance
-** to [sqlite3_create_module()] or [sqlite3_create_module_v2()].
-** ^The registration remains valid until it is replaced by a different
-** module or until the [database connection] closes. The content
-** of this structure must not change while it is registered with
-** any database connection.
-*/
-struct sqlite3_module {
- int iVersion;
- int (*xCreate)(sqlite3*, void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVTab, char**);
- int (*xConnect)(sqlite3*, void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVTab, char**);
- int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
- int (*xDisconnect)(sqlite3_vtab *pVTab);
- int (*xDestroy)(sqlite3_vtab *pVTab);
- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
- int (*xClose)(sqlite3_vtab_cursor*);
- int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv);
- int (*xNext)(sqlite3_vtab_cursor*);
- int (*xEof)(sqlite3_vtab_cursor*);
- int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
- int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
- int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
- int (*xBegin)(sqlite3_vtab *pVTab);
- int (*xSync)(sqlite3_vtab *pVTab);
- int (*xCommit)(sqlite3_vtab *pVTab);
- int (*xRollback)(sqlite3_vtab *pVTab);
- int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
- void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
- void **ppArg);
- int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
-};
-
-/*
-** CAPI3REF: Virtual Table Indexing Information
-** KEYWORDS: sqlite3_index_info
-** EXPERIMENTAL
-**
-** The sqlite3_index_info structure and its substructures is used to
-** pass information into and receive the reply from the [xBestIndex]
-** method of a [virtual table module]. The fields under **Inputs** are the
-** inputs to xBestIndex and are read-only. xBestIndex inserts its
-** results into the **Outputs** fields.
-**
-** ^(The aConstraint[] array records WHERE clause constraints of the form:
-**
-** <pre>column OP expr</pre>
-**
-** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is
-** stored in aConstraint[].op.)^ ^(The index of the column is stored in
-** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the
-** expr on the right-hand side can be evaluated (and thus the constraint
-** is usable) and false if it cannot.)^
-**
-** ^The optimizer automatically inverts terms of the form "expr OP column"
-** and makes other simplifications to the WHERE clause in an attempt to
-** get as many WHERE clause terms into the form shown above as possible.
-** ^The aConstraint[] array only reports WHERE clause terms that are
-** relevant to the particular virtual table being queried.
-**
-** ^Information about the ORDER BY clause is stored in aOrderBy[].
-** ^Each term of aOrderBy records a column of the ORDER BY clause.
-**
-** The [xBestIndex] method must fill aConstraintUsage[] with information
-** about what parameters to pass to xFilter. ^If argvIndex>0 then
-** the right-hand side of the corresponding aConstraint[] is evaluated
-** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit
-** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.)^
-**
-** ^The idxNum and idxPtr values are recorded and passed into the
-** [xFilter] method.
-** ^[sqlite3_free()] is used to free idxPtr if and only if
-** needToFreeIdxPtr is true.
-**
-** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
-** the correct order to satisfy the ORDER BY clause so that no separate
-** sorting step is required.
-**
-** ^The estimatedCost value is an estimate of the cost of doing the
-** particular lookup. A full scan of a table with N entries should have
-** a cost of N. A binary search of a table of N entries should have a
-** cost of approximately log(N).
-*/
-struct sqlite3_index_info {
- /* Inputs */
- int nConstraint; /* Number of entries in aConstraint */
- struct sqlite3_index_constraint {
- int iColumn; /* Column on left-hand side of constraint */
- unsigned char op; /* Constraint operator */
- unsigned char usable; /* True if this constraint is usable */
- int iTermOffset; /* Used internally - xBestIndex should ignore */
- } *aConstraint; /* Table of WHERE clause constraints */
- int nOrderBy; /* Number of terms in the ORDER BY clause */
- struct sqlite3_index_orderby {
- int iColumn; /* Column number */
- unsigned char desc; /* True for DESC. False for ASC. */
- } *aOrderBy; /* The ORDER BY clause */
- /* Outputs */
- struct sqlite3_index_constraint_usage {
- int argvIndex; /* if >0, constraint is part of argv to xFilter */
- unsigned char omit; /* Do not code a test for this constraint */
- } *aConstraintUsage;
- int idxNum; /* Number used to identify the index */
- char *idxStr; /* String, possibly obtained from sqlite3_malloc */
- int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
- int orderByConsumed; /* True if output is already ordered */
- double estimatedCost; /* Estimated cost of using this index */
-};
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-
-/*
-** CAPI3REF: Register A Virtual Table Implementation
-** EXPERIMENTAL
-**
-** ^These routines are used to register a new [virtual table module] name.
-** ^Module names must be registered before
-** creating a new [virtual table] using the module and before using a
-** preexisting [virtual table] for the module.
-**
-** ^The module name is registered on the [database connection] specified
-** by the first parameter. ^The name of the module is given by the
-** second parameter. ^The third parameter is a pointer to
-** the implementation of the [virtual table module]. ^The fourth
-** parameter is an arbitrary client data pointer that is passed through
-** into the [xCreate] and [xConnect] methods of the virtual table module
-** when a new virtual table is be being created or reinitialized.
-**
-** ^The sqlite3_create_module_v2() interface has a fifth parameter which
-** is a pointer to a destructor for the pClientData. ^SQLite will
-** invoke the destructor function (if it is not NULL) when SQLite
-** no longer needs the pClientData pointer. ^The sqlite3_create_module()
-** interface is equivalent to sqlite3_create_module_v2() with a NULL
-** destructor.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
- sqlite3 *db, /* SQLite connection to register module with */
- const char *zName, /* Name of the module */
- const sqlite3_module *p, /* Methods for the module */
- void *pClientData /* Client data for xCreate/xConnect */
-);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
- sqlite3 *db, /* SQLite connection to register module with */
- const char *zName, /* Name of the module */
- const sqlite3_module *p, /* Methods for the module */
- void *pClientData, /* Client data for xCreate/xConnect */
- void(*xDestroy)(void*) /* Module destructor function */
-);
-
-/*
-** CAPI3REF: Virtual Table Instance Object
-** KEYWORDS: sqlite3_vtab
-** EXPERIMENTAL
-**
-** Every [virtual table module] implementation uses a subclass
-** of this object to describe a particular instance
-** of the [virtual table]. Each subclass will
-** be tailored to the specific needs of the module implementation.
-** The purpose of this superclass is to define certain fields that are
-** common to all module implementations.
-**
-** ^Virtual tables methods can set an error message by assigning a
-** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should
-** take care that any prior string is freed by a call to [sqlite3_free()]
-** prior to assigning a new string to zErrMsg. ^After the error message
-** is delivered up to the client application, the string will be automatically
-** freed by sqlite3_free() and the zErrMsg field will be zeroed.
-*/
-struct sqlite3_vtab {
- const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* NO LONGER USED */
- char *zErrMsg; /* Error message from sqlite3_mprintf() */
- /* Virtual table implementations will typically add additional fields */
-};
-
-/*
-** CAPI3REF: Virtual Table Cursor Object
-** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
-** EXPERIMENTAL
-**
-** Every [virtual table module] implementation uses a subclass of the
-** following structure to describe cursors that point into the
-** [virtual table] and are used
-** to loop through the virtual table. Cursors are created using the
-** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed
-** by the [sqlite3_module.xClose | xClose] method. Cursors are used
-** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods
-** of the module. Each module implementation will define
-** the content of a cursor structure to suit its own needs.
-**
-** This superclass exists in order to define fields of the cursor that
-** are common to all implementations.
-*/
-struct sqlite3_vtab_cursor {
- sqlite3_vtab *pVtab; /* Virtual table of this cursor */
- /* Virtual table implementations will typically add additional fields */
-};
-
-/*
-** CAPI3REF: Declare The Schema Of A Virtual Table
-** EXPERIMENTAL
-**
-** ^The [xCreate] and [xConnect] methods of a
-** [virtual table module] call this interface
-** to declare the format (the names and datatypes of the columns) of
-** the virtual tables they implement.
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
-
-/*
-** CAPI3REF: Overload A Function For A Virtual Table
-** EXPERIMENTAL
-**
-** ^(Virtual tables can provide alternative implementations of functions
-** using the [xFindFunction] method of the [virtual table module].
-** But global versions of those functions
-** must exist in order to be overloaded.)^
-**
-** ^(This API makes sure a global version of a function with a particular
-** name and number of parameters exists. If no such function exists
-** before this API is called, a new function is created.)^ ^The implementation
-** of the new function always causes an exception to be thrown. So
-** the new function is not good for anything by itself. Its only
-** purpose is to be a placeholder function that can be overloaded
-** by a [virtual table].
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
-
-/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
-*/
-
-/*
-** CAPI3REF: A Handle To An Open BLOB
-** KEYWORDS: {BLOB handle} {BLOB handles}
-**
-** An instance of this object represents an open BLOB on which
-** [sqlite3_blob_open | incremental BLOB I/O] can be performed.
-** ^Objects of this type are created by [sqlite3_blob_open()]
-** and destroyed by [sqlite3_blob_close()].
-** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
-** can be used to read or write small subsections of the BLOB.
-** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes.
-*/
-typedef struct sqlite3_blob sqlite3_blob;
-
-/*
-** CAPI3REF: Open A BLOB For Incremental I/O
-**
-** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
-** in row iRow, column zColumn, table zTable in database zDb;
-** in other words, the same BLOB that would be selected by:
-**
-** <pre>
-** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
-** </pre>)^
-**
-** ^If the flags parameter is non-zero, then the BLOB is opened for read
-** and write access. ^If it is zero, the BLOB is opened for read access.
-** ^It is not possible to open a column that is part of an index or primary
-** key for writing. ^If [foreign key constraints] are enabled, it is
-** not possible to open a column that is part of a [child key] for writing.
-**
-** ^Note that the database name is not the filename that contains
-** the database but rather the symbolic name of the database that
-** appears after the AS keyword when the database is connected using [ATTACH].
-** ^For the main database file, the database name is "main".
-** ^For TEMP tables, the database name is "temp".
-**
-** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
-** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
-** to be a null pointer.)^
-** ^This function sets the [database connection] error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
-** functions. ^Note that the *ppBlob variable is always initialized in a
-** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
-** regardless of the success or failure of this routine.
-**
-** ^(If the row that a BLOB handle points to is modified by an
-** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
-** then the BLOB handle is marked as "expired".
-** This is true if any column of the row is changed, even a column
-** other than the one the BLOB handle is open on.)^
-** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for
-** a expired BLOB handle fail with an return code of [SQLITE_ABORT].
-** ^(Changes written into a BLOB prior to the BLOB expiring are not
-** rolled back by the expiration of the BLOB. Such changes will eventually
-** commit if the transaction continues to completion.)^
-**
-** ^Use the [sqlite3_blob_bytes()] interface to determine the size of
-** the opened blob. ^The size of a blob may not be changed by this
-** interface. Use the [UPDATE] SQL command to change the size of a
-** blob.
-**
-** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function can be used, if desired,
-** to create an empty, zero-filled blob in which to read or write using
-** this interface.
-**
-** To avoid a resource leak, every open [BLOB handle] should eventually
-** be released by a call to [sqlite3_blob_close()].
-*/
-SQLITE_API int sqlite3_blob_open(
- sqlite3*,
- const char *zDb,
- const char *zTable,
- const char *zColumn,
- sqlite3_int64 iRow,
- int flags,
- sqlite3_blob **ppBlob
-);
-
-/*
-** CAPI3REF: Close A BLOB Handle
-**
-** ^Closes an open [BLOB handle].
-**
-** ^Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in [autocommit mode].
-** ^If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit.
-**
-** ^(Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. Any errors that occur during
-** closing are reported as a non-zero return value.)^
-**
-** ^(The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.)^
-**
-** ^Calling this routine with a null pointer (such as would be returned
-** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
-*/
-SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
-
-/*
-** CAPI3REF: Return The Size Of An Open BLOB
-**
-** ^Returns the size in bytes of the BLOB accessible via the
-** successfully opened [BLOB handle] in its only argument. ^The
-** incremental blob I/O routines can only read or overwriting existing
-** blob content; they cannot change the size of a blob.
-**
-** This routine only works on a [BLOB handle] which has been created
-** by a prior successful call to [sqlite3_blob_open()] and which has not
-** been closed by [sqlite3_blob_close()]. Passing any other pointer in
-** to this routine results in undefined and probably undesirable behavior.
-*/
-SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
-
-/*
-** CAPI3REF: Read Data From A BLOB Incrementally
-**
-** ^(This function is used to read data from an open [BLOB handle] into a
-** caller-supplied buffer. N bytes of data are copied into buffer Z
-** from the open BLOB, starting at offset iOffset.)^
-**
-** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is
-** less than zero, [SQLITE_ERROR] is returned and no data is read.
-** ^The size of the blob (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
-**
-** ^An attempt to read from an expired [BLOB handle] fails with an
-** error code of [SQLITE_ABORT].
-**
-** ^(On success, sqlite3_blob_read() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
-** This routine only works on a [BLOB handle] which has been created
-** by a prior successful call to [sqlite3_blob_open()] and which has not
-** been closed by [sqlite3_blob_close()]. Passing any other pointer in
-** to this routine results in undefined and probably undesirable behavior.
-**
-** See also: [sqlite3_blob_write()].
-*/
-SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
-
-/*
-** CAPI3REF: Write Data Into A BLOB Incrementally
-**
-** ^This function is used to write data into an open [BLOB handle] from a
-** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
-** into the open BLOB, starting at offset iOffset.
-**
-** ^If the [BLOB handle] passed as the first argument was not opened for
-** writing (the flags parameter to [sqlite3_blob_open()] was zero),
-** this function returns [SQLITE_READONLY].
-**
-** ^This function may only modify the contents of the BLOB; it is
-** not possible to increase the size of a BLOB using this API.
-** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. ^If N is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-** The size of the BLOB (and hence the maximum value of N+iOffset)
-** can be determined using the [sqlite3_blob_bytes()] interface.
-**
-** ^An attempt to write to an expired [BLOB handle] fails with an
-** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
-** before the [BLOB handle] expired are not rolled back by the
-** expiration of the handle, though of course those changes might
-** have been overwritten by the statement that expired the BLOB handle
-** or by other independent statements.
-**
-** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
-** Otherwise, an [error code] or an [extended error code] is returned.)^
-**
-** This routine only works on a [BLOB handle] which has been created
-** by a prior successful call to [sqlite3_blob_open()] and which has not
-** been closed by [sqlite3_blob_close()]. Passing any other pointer in
-** to this routine results in undefined and probably undesirable behavior.
-**
-** See also: [sqlite3_blob_read()].
-*/
-SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
-
-/*
-** CAPI3REF: Virtual File System Objects
-**
-** A virtual filesystem (VFS) is an [sqlite3_vfs] object
-** that SQLite uses to interact
-** with the underlying operating system. Most SQLite builds come with a
-** single default VFS that is appropriate for the host computer.
-** New VFSes can be registered and existing VFSes can be unregistered.
-** The following interfaces are provided.
-**
-** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name.
-** ^Names are case sensitive.
-** ^Names are zero-terminated UTF-8 strings.
-** ^If there is no match, a NULL pointer is returned.
-** ^If zVfsName is NULL then the default VFS is returned.
-**
-** ^New VFSes are registered with sqlite3_vfs_register().
-** ^Each new VFS becomes the default VFS if the makeDflt flag is set.
-** ^The same VFS can be registered multiple times without injury.
-** ^To make an existing VFS into the default VFS, register it again
-** with the makeDflt flag set. If two different VFSes with the
-** same name are registered, the behavior is undefined. If a
-** VFS is registered with a name that is NULL or an empty string,
-** then the behavior is undefined.
-**
-** ^Unregister a VFS with the sqlite3_vfs_unregister() interface.
-** ^(If the default VFS is unregistered, another VFS is chosen as
-** the default. The choice for the new VFS is arbitrary.)^
-*/
-SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
-
-/*
-** CAPI3REF: Mutexes
-**
-** The SQLite core uses these routines for thread
-** synchronization. Though they are intended for internal
-** use by SQLite, code that links against SQLite is
-** permitted to use any of these routines.
-**
-** The SQLite source code contains multiple implementations
-** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. ^(The following
-** implementations are available in the SQLite core:
-**
-** <ul>
-** <li> SQLITE_MUTEX_OS2
-** <li> SQLITE_MUTEX_PTHREAD
-** <li> SQLITE_MUTEX_W32
-** <li> SQLITE_MUTEX_NOOP
-** </ul>)^
-**
-** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
-** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
-** are appropriate for use on OS/2, Unix, and Windows.
-**
-** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
-** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
-** implementation is included with the library. In this case the
-** application must supply a custom mutex implementation using the
-** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
-** before calling sqlite3_initialize() or any other public sqlite3_
-** function that calls sqlite3_initialize().)^
-**
-** ^The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. ^If it returns NULL
-** that means that a mutex could not be allocated. ^SQLite
-** will unwind its stack and return an error. ^(The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
-**
-** <ul>
-** <li> SQLITE_MUTEX_FAST
-** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
-** <li> SQLITE_MUTEX_STATIC_MEM
-** <li> SQLITE_MUTEX_STATIC_MEM2
-** <li> SQLITE_MUTEX_STATIC_PRNG
-** <li> SQLITE_MUTEX_STATIC_LRU
-** <li> SQLITE_MUTEX_STATIC_LRU2
-** </ul>)^
-**
-** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
-** cause sqlite3_mutex_alloc() to create
-** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
-** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
-** The mutex implementation does not need to make a distinction
-** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. ^SQLite will only request a recursive mutex in
-** cases where it really needs one. ^If a faster non-recursive mutex
-** implementation is available on the host platform, the mutex subsystem
-** might return such a mutex in response to SQLITE_MUTEX_FAST.
-**
-** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
-** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
-** a pointer to a static preexisting mutex. ^Six static mutexes are
-** used by the current version of SQLite. Future versions of SQLite
-** may add additional static mutexes. Static mutexes are for internal
-** use by SQLite only. Applications that use SQLite mutexes should
-** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
-** SQLITE_MUTEX_RECURSIVE.
-**
-** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
-** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. ^But for the static
-** mutex types, the same mutex is returned on every call that has
-** the same type number.
-**
-** ^The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. ^SQLite is careful to deallocate every
-** dynamic mutex that it allocates. The dynamic mutexes must not be in
-** use when they are deallocated. Attempting to deallocate a static
-** mutex results in undefined behavior. ^SQLite never deallocates
-** a static mutex.
-**
-** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
-** to enter a mutex. ^If another thread is already within the mutex,
-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
-** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
-** upon successful entry. ^(Mutexes created using
-** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** In such cases the,
-** mutex must be exited an equal number of times before another thread
-** can enter.)^ ^(If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** SQLite will never exhibit
-** such behavior in its own use of mutexes.)^
-**
-** ^(Some systems (for example, Windows 95) do not support the operation
-** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
-**
-** ^The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. ^(The behavior
-** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. SQLite will
-** never do either.)^
-**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
-**
-** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
-*/
-SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
-SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
-
-/*
-** CAPI3REF: Mutex Methods Object
-** EXPERIMENTAL
-**
-** An instance of this structure defines the low-level routines
-** used to allocate and use mutexes.
-**
-** Usually, the default mutex implementations provided by SQLite are
-** sufficient, however the user has the option of substituting a custom
-** implementation for specialized deployments or systems for which SQLite
-** does not provide a suitable implementation. In this case, the user
-** creates and populates an instance of this structure to pass
-** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
-** Additionally, an instance of this structure can be used as an
-** output variable when querying the system for the current mutex
-** implementation, using the [SQLITE_CONFIG_GETMUTEX] option.
-**
-** ^The xMutexInit method defined by this structure is invoked as
-** part of system initialization by the sqlite3_initialize() function.
-** ^The xMutexInit routine is calle by SQLite exactly once for each
-** effective call to [sqlite3_initialize()].
-**
-** ^The xMutexEnd method defined by this structure is invoked as
-** part of system shutdown by the sqlite3_shutdown() function. The
-** implementation of this method is expected to release all outstanding
-** resources obtained by the mutex methods implementation, especially
-** those obtained by the xMutexInit method. ^The xMutexEnd()
-** interface is invoked exactly once for each call to [sqlite3_shutdown()].
-**
-** ^(The remaining seven methods defined by this structure (xMutexAlloc,
-** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and
-** xMutexNotheld) implement the following interfaces (respectively):
-**
-** <ul>
-** <li> [sqlite3_mutex_alloc()] </li>
-** <li> [sqlite3_mutex_free()] </li>
-** <li> [sqlite3_mutex_enter()] </li>
-** <li> [sqlite3_mutex_try()] </li>
-** <li> [sqlite3_mutex_leave()] </li>
-** <li> [sqlite3_mutex_held()] </li>
-** <li> [sqlite3_mutex_notheld()] </li>
-** </ul>)^
-**
-** The only difference is that the public sqlite3_XXX functions enumerated
-** above silently ignore any invocations that pass a NULL pointer instead
-** of a valid mutex handle. The implementations of the methods defined
-** by this structure are not required to handle this case, the results
-** of passing a NULL pointer instead of a valid mutex handle are undefined
-** (i.e. it is acceptable to provide an implementation that segfaults if
-** it is passed a NULL pointer).
-**
-** The xMutexInit() method must be threadsafe. ^It must be harmless to
-** invoke xMutexInit() mutiple times within the same process and without
-** intervening calls to xMutexEnd(). Second and subsequent calls to
-** xMutexInit() must be no-ops.
-**
-** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
-** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
-** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
-** memory allocation for a fast or recursive mutex.
-**
-** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is
-** called, but only if the prior call to xMutexInit returned SQLITE_OK.
-** If xMutexInit fails in any way, it is expected to clean up after itself
-** prior to returning.
-*/
-typedef struct sqlite3_mutex_methods sqlite3_mutex_methods;
-struct sqlite3_mutex_methods {
- int (*xMutexInit)(void);
- int (*xMutexEnd)(void);
- sqlite3_mutex *(*xMutexAlloc)(int);
- void (*xMutexFree)(sqlite3_mutex *);
- void (*xMutexEnter)(sqlite3_mutex *);
- int (*xMutexTry)(sqlite3_mutex *);
- void (*xMutexLeave)(sqlite3_mutex *);
- int (*xMutexHeld)(sqlite3_mutex *);
- int (*xMutexNotheld)(sqlite3_mutex *);
-};
-
-/*
-** CAPI3REF: Mutex Verification Routines
-**
-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. ^The SQLite core
-** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. ^The SQLite core only
-** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. ^External mutex implementations
-** are only required to provide these routines if SQLITE_DEBUG is
-** defined and if NDEBUG is not defined.
-**
-** ^These routines should return true if the mutex in their argument
-** is held or not held, respectively, by the calling thread.
-**
-** ^The implementation is not required to provided versions of these
-** routines that actually work. If the implementation does not provide working
-** versions of these routines, it should at least provide stubs that always
-** return true so that one does not get spurious assertion failures.
-**
-** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
-** the routine should return 1. This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist. But the
-** the reason the mutex does not exist is because the build is not
-** using mutexes. And we do not want the assert() containing the
-** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. ^The sqlite3_mutex_notheld()
-** interface should also return 1 when given a NULL pointer.
-*/
-#ifndef NDEBUG
-SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
-#endif
-
-/*
-** CAPI3REF: Mutex Types
-**
-** The [sqlite3_mutex_alloc()] interface takes a single argument
-** which is one of these integer constants.
-**
-** The set of static mutexes may change from one SQLite release to the
-** next. Applications that override the built-in mutex logic must be
-** prepared to accommodate additional static mutexes.
-*/
-#define SQLITE_MUTEX_FAST 0
-#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
-#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
-#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
-#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
-#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
-#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
-#define SQLITE_MUTEX_STATIC_LRU2 7 /* lru page list */
-
-/*
-** CAPI3REF: Retrieve the mutex for a database connection
-**
-** ^This interface returns a pointer the [sqlite3_mutex] object that
-** serializes access to the [database connection] given in the argument
-** when the [threading mode] is Serialized.
-** ^If the [threading mode] is Single-thread or Multi-thread then this
-** routine returns a NULL pointer.
-*/
-SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
-
-/*
-** CAPI3REF: Low-Level Control Of Database Files
-**
-** ^The [sqlite3_file_control()] interface makes a direct call to the
-** xFileControl method for the [sqlite3_io_methods] object associated
-** with a particular database identified by the second argument. ^The
-** name of the database "main" for the main database or "temp" for the
-** TEMP database, or the name that appears after the AS keyword for
-** databases that are added using the [ATTACH] SQL command.
-** ^A NULL pointer can be used in place of "main" to refer to the
-** main database file.
-** ^The third and fourth parameters to this routine
-** are passed directly through to the second and third parameters of
-** the xFileControl method. ^The return value of the xFileControl
-** method becomes the return value of this routine.
-**
-** ^If the second parameter (zDbName) does not match the name of any
-** open database file, then SQLITE_ERROR is returned. ^This error
-** code is not remembered and will not be recalled by [sqlite3_errcode()]
-** or [sqlite3_errmsg()]. The underlying xFileControl method might
-** also return SQLITE_ERROR. There is no way to distinguish between
-** an incorrect zDbName and an SQLITE_ERROR return from the underlying
-** xFileControl method.
-**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
-*/
-SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
-
-/*
-** CAPI3REF: Testing Interface
-**
-** ^The sqlite3_test_control() interface is used to read out internal
-** state of SQLite and to inject faults into SQLite for testing
-** purposes. ^The first parameter is an operation code that determines
-** the number, meaning, and operation of all subsequent parameters.
-**
-** This interface is not for use by applications. It exists solely
-** for verifying the correct operation of the SQLite library. Depending
-** on how the SQLite library is compiled, this interface might not exist.
-**
-** The details of the operation codes, their meanings, the parameters
-** they take, and what they do are all subject to change without notice.
-** Unlike most of the SQLite API, this function is not guaranteed to
-** operate consistently from one release to the next.
-*/
-SQLITE_API int sqlite3_test_control(int op, ...);
-
-/*
-** CAPI3REF: Testing Interface Operation Codes
-**
-** These constants are the valid operation code parameters used
-** as the first argument to [sqlite3_test_control()].
-**
-** These parameters and their meanings are subject to change
-** without notice. These values are for testing purposes only.
-** Applications should not use any of these parameters or the
-** [sqlite3_test_control()] interface.
-*/
-#define SQLITE_TESTCTRL_FIRST 5
-#define SQLITE_TESTCTRL_PRNG_SAVE 5
-#define SQLITE_TESTCTRL_PRNG_RESTORE 6
-#define SQLITE_TESTCTRL_PRNG_RESET 7
-#define SQLITE_TESTCTRL_BITVEC_TEST 8
-#define SQLITE_TESTCTRL_FAULT_INSTALL 9
-#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
-#define SQLITE_TESTCTRL_PENDING_BYTE 11
-#define SQLITE_TESTCTRL_ASSERT 12
-#define SQLITE_TESTCTRL_ALWAYS 13
-#define SQLITE_TESTCTRL_RESERVE 14
-#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
-#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_LAST 16
-
-/*
-** CAPI3REF: SQLite Runtime Status
-** EXPERIMENTAL
-**
-** ^This interface is used to retrieve runtime status information
-** about the preformance of SQLite, and optionally to reset various
-** highwater marks. ^The first argument is an integer code for
-** the specific parameter to measure. ^(Recognized integer codes
-** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
-** ^The current value of the parameter is returned into *pCurrent.
-** ^The highest recorded value is returned in *pHighwater. ^If the
-** resetFlag is true, then the highest record value is reset after
-** *pHighwater is written. ^(Some parameters do not record the highest
-** value. For those parameters
-** nothing is written into *pHighwater and the resetFlag is ignored.)^
-** ^(Other parameters record only the highwater mark and not the current
-** value. For these latter parameters nothing is written into *pCurrent.)^
-**
-** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
-** non-zero [error code] on failure.
-**
-** This routine is threadsafe but is not atomic. This routine can be
-** called while other threads are running the same or different SQLite
-** interfaces. However the values returned in *pCurrent and
-** *pHighwater reflect the status of SQLite at different points in time
-** and it is possible that another thread might change the parameter
-** in between the times when *pCurrent and *pHighwater are written.
-**
-** See also: [sqlite3_db_status()]
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
-
-
-/*
-** CAPI3REF: Status Parameters
-** EXPERIMENTAL
-**
-** These integer constants designate various run-time status parameters
-** that can be returned by [sqlite3_status()].
-**
-** <dl>
-** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
-** <dd>This parameter is the current amount of memory checked out
-** using [sqlite3_malloc()], either directly or indirectly. The
-** figure includes calls made to [sqlite3_malloc()] by the application
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
-** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
-** this parameter. The amount returned is the sum of the allocation
-** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
-** internal equivalents). Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
-** <dd>This parameter returns the number of pages used out of the
-** [pagecache memory allocator] that was configured using
-** [SQLITE_CONFIG_PAGECACHE]. The
-** value returned is in pages, not in bytes.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
-** <dd>This parameter returns the number of bytes of page cache
-** allocation which could not be statisfied by the [SQLITE_CONFIG_PAGECACHE]
-** buffer and where forced to overflow to [sqlite3_malloc()]. The
-** returned value includes allocations that overflowed because they
-** where too large (they were larger than the "sz" parameter to
-** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
-** no space was left in the page cache.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [pagecache memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
-** <dd>This parameter returns the number of allocations used out of the
-** [scratch memory allocator] configured using
-** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
-** <dd>This parameter returns the number of bytes of scratch memory
-** allocation which could not be statisfied by the [SQLITE_CONFIG_SCRATCH]
-** buffer and where forced to overflow to [sqlite3_malloc()]. The values
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
-**
-** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
-** <dd>This parameter records the largest memory allocation request
-** handed to [scratch memory allocator]. Only the value returned in the
-** *pHighwater parameter to [sqlite3_status()] is of interest.
-** The value written into the *pCurrent parameter is undefined.</dd>)^
-**
-** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
-** <dd>This parameter records the deepest parser stack. It is only
-** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
-** </dl>
-**
-** New status parameters may be added from time to time.
-*/
-#define SQLITE_STATUS_MEMORY_USED 0
-#define SQLITE_STATUS_PAGECACHE_USED 1
-#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
-#define SQLITE_STATUS_MALLOC_SIZE 5
-#define SQLITE_STATUS_PARSER_STACK 6
-#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
-
-/*
-** CAPI3REF: Database Connection Status
-** EXPERIMENTAL
-**
-** ^This interface is used to retrieve runtime status information
-** about a single [database connection]. ^The first argument is the
-** database connection object to be interrogated. ^The second argument
-** is the parameter to interrogate. ^Currently, the only allowed value
-** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
-** Additional options will likely appear in future releases of SQLite.
-**
-** ^The current value of the requested parameter is written into *pCur
-** and the highest instantaneous value is written into *pHiwtr. ^If
-** the resetFlg is true, then the highest instantaneous value is
-** reset back down to the current value.
-**
-** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
-
-/*
-** CAPI3REF: Status Parameters for database connections
-** EXPERIMENTAL
-**
-** These constants are the available integer "verbs" that can be passed as
-** the second argument to the [sqlite3_db_status()] interface.
-**
-** New verbs may be added in future releases of SQLite. Existing verbs
-** might be discontinued. Applications should check the return code from
-** [sqlite3_db_status()] to make sure that the call worked.
-** The [sqlite3_db_status()] interface will return a non-zero error code
-** if a discontinued or unsupported verb is invoked.
-**
-** <dl>
-** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
-** <dd>This parameter returns the number of lookaside memory slots currently
-** checked out.</dd>)^
-** </dl>
-*/
-#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
-
-
-/*
-** CAPI3REF: Prepared Statement Status
-** EXPERIMENTAL
-**
-** ^(Each prepared statement maintains various
-** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
-** of times it has performed specific operations.)^ These counters can
-** be used to monitor the performance characteristics of the prepared
-** statements. For example, if the number of table steps greatly exceeds
-** the number of table searches or result rows, that would tend to indicate
-** that the prepared statement is using a full table scan rather than
-** an index.
-**
-** ^(This interface is used to retrieve and reset counter values from
-** a [prepared statement]. The first argument is the prepared statement
-** object to be interrogated. The second argument
-** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter]
-** to be interrogated.)^
-** ^The current value of the requested counter is returned.
-** ^If the resetFlg is true, then the counter is reset to zero after this
-** interface call returns.
-**
-** See also: [sqlite3_status()] and [sqlite3_db_status()].
-*/
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
-
-/*
-** CAPI3REF: Status Parameters for prepared statements
-** EXPERIMENTAL
-**
-** These preprocessor macros define integer codes that name counter
-** values associated with the [sqlite3_stmt_status()] interface.
-** The meanings of the various counters are as follows:
-**
-** <dl>
-** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
-** <dd>^This is the number of times that SQLite has stepped forward in
-** a table as part of a full table scan. Large numbers for this counter
-** may indicate opportunities for performance improvement through
-** careful use of indices.</dd>
-**
-** <dt>SQLITE_STMTSTATUS_SORT</dt>
-** <dd>^This is the number of sort operations that have occurred.
-** A non-zero value in this counter may indicate an opportunity to
-** improvement performance through careful use of indices.</dd>
-**
-** </dl>
-*/
-#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
-#define SQLITE_STMTSTATUS_SORT 2
-
-/*
-** CAPI3REF: Custom Page Cache Object
-** EXPERIMENTAL
-**
-** The sqlite3_pcache type is opaque. It is implemented by
-** the pluggable module. The SQLite core has no knowledge of
-** its size or internal structure and never deals with the
-** sqlite3_pcache object except by holding and passing pointers
-** to the object.
-**
-** See [sqlite3_pcache_methods] for additional information.
-*/
-typedef struct sqlite3_pcache sqlite3_pcache;
-
-/*
-** CAPI3REF: Application Defined Page Cache.
-** KEYWORDS: {page cache}
-** EXPERIMENTAL
-**
-** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
-** register an alternative page cache implementation by passing in an
-** instance of the sqlite3_pcache_methods structure.)^ The majority of the
-** heap memory used by SQLite is used by the page cache to cache data read
-** from, or ready to be written to, the database file. By implementing a
-** custom page cache using this API, an application can control more
-** precisely the amount of memory consumed by SQLite, the way in which
-** that memory is allocated and released, and the policies used to
-** determine exactly which parts of a database file are cached and for
-** how long.
-**
-** ^(The contents of the sqlite3_pcache_methods structure are copied to an
-** internal buffer by SQLite within the call to [sqlite3_config]. Hence
-** the application may discard the parameter after the call to
-** [sqlite3_config()] returns.)^
-**
-** ^The xInit() method is called once for each call to [sqlite3_initialize()]
-** (usually only once during the lifetime of the process). ^(The xInit()
-** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
-** ^The xInit() method can set up up global structures and/or any mutexes
-** required by the custom page cache implementation.
-**
-** ^The xShutdown() method is called from within [sqlite3_shutdown()],
-** if the application invokes this API. It can be used to clean up
-** any outstanding resources before process shutdown, if required.
-**
-** ^SQLite holds a [SQLITE_MUTEX_RECURSIVE] mutex when it invokes
-** the xInit method, so the xInit method need not be threadsafe. ^The
-** xShutdown method is only called from [sqlite3_shutdown()] so it does
-** not need to be threadsafe either. All other methods must be threadsafe
-** in multithreaded applications.
-**
-** ^SQLite will never invoke xInit() more than once without an intervening
-** call to xShutdown().
-**
-** ^The xCreate() method is used to construct a new cache instance. SQLite
-** will typically create one cache instance for each open database file,
-** though this is not guaranteed. ^The
-** first parameter, szPage, is the size in bytes of the pages that must
-** be allocated by the cache. ^szPage will not be a power of two. ^szPage
-** will the page size of the database file that is to be cached plus an
-** increment (here called "R") of about 100 or 200. ^SQLite will use the
-** extra R bytes on each page to store metadata about the underlying
-** database page on disk. The value of R depends
-** on the SQLite version, the target platform, and how SQLite was compiled.
-** ^R is constant for a particular build of SQLite. ^The second argument to
-** xCreate(), bPurgeable, is true if the cache being created will
-** be used to cache database pages of a file stored on disk, or
-** false if it is used for an in-memory database. ^The cache implementation
-** does not have to do anything special based with the value of bPurgeable;
-** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
-** never invoke xUnpin() except to deliberately delete a page.
-** ^In other words, a cache created with bPurgeable set to false will
-** never contain any unpinned pages.
-**
-** ^(The xCachesize() method may be called at any time by SQLite to set the
-** suggested maximum cache-size (number of pages stored by) the cache
-** instance passed as the first argument. This is the value configured using
-** the SQLite "[PRAGMA cache_size]" command.)^ ^As with the bPurgeable
-** parameter, the implementation is not required to do anything with this
-** value; it is advisory only.
-**
-** ^The xPagecount() method should return the number of pages currently
-** stored in the cache.
-**
-** ^The xFetch() method is used to fetch a page and return a pointer to it.
-** ^A 'page', in this context, is a buffer of szPage bytes aligned at an
-** 8-byte boundary. ^The page to be fetched is determined by the key. ^The
-** mimimum key value is 1. After it has been retrieved using xFetch, the page
-** is considered to be "pinned".
-**
-** ^If the requested page is already in the page cache, then the page cache
-** implementation must return a pointer to the page buffer with its content
-** intact. ^(If the requested page is not already in the cache, then the
-** behavior of the cache implementation is determined by the value of the
-** createFlag parameter passed to xFetch, according to the following table:
-**
-** <table border=1 width=85% align=center>
-** <tr><th> createFlag <th> Behaviour when page is not already in cache
-** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
-** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
-** Otherwise return NULL.
-** <tr><td> 2 <td> Make every effort to allocate a new page. Only return
-** NULL if allocating a new page is effectively impossible.
-** </table>)^
-**
-** SQLite will normally invoke xFetch() with a createFlag of 0 or 1. If
-** a call to xFetch() with createFlag==1 returns NULL, then SQLite will
-** attempt to unpin one or more cache pages by spilling the content of
-** pinned pages to disk and synching the operating system disk cache. After
-** attempting to unpin pages, the xFetch() method will be invoked again with
-** a createFlag of 2.
-**
-** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
-** as its second argument. ^(If the third parameter, discard, is non-zero,
-** then the page should be evicted from the cache. In this case SQLite
-** assumes that the next time the page is retrieved from the cache using
-** the xFetch() method, it will be zeroed.)^ ^If the discard parameter is
-** zero, then the page is considered to be unpinned. ^The cache implementation
-** may choose to evict unpinned pages at any time.
-**
-** ^(The cache is not required to perform any reference counting. A single
-** call to xUnpin() unpins the page regardless of the number of prior calls
-** to xFetch().)^
-**
-** ^The xRekey() method is used to change the key value associated with the
-** page passed as the second argument from oldKey to newKey. ^If the cache
-** previously contains an entry associated with newKey, it should be
-** discarded. ^Any prior cache entry associated with newKey is guaranteed not
-** to be pinned.
-**
-** ^When SQLite calls the xTruncate() method, the cache must discard all
-** existing cache entries with page numbers (keys) greater than or equal
-** to the value of the iLimit parameter passed to xTruncate(). ^If any
-** of these pages are pinned, they are implicitly unpinned, meaning that
-** they can be safely discarded.
-**
-** ^The xDestroy() method is used to delete a cache allocated by xCreate().
-** All resources associated with the specified cache should be freed. ^After
-** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
-** handle invalid, and will not use it with any other sqlite3_pcache_methods
-** functions.
-*/
-typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
-struct sqlite3_pcache_methods {
- void *pArg;
- int (*xInit)(void*);
- void (*xShutdown)(void*);
- sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
- void (*xCachesize)(sqlite3_pcache*, int nCachesize);
- int (*xPagecount)(sqlite3_pcache*);
- void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
- void (*xUnpin)(sqlite3_pcache*, void*, int discard);
- void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
- void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
- void (*xDestroy)(sqlite3_pcache*);
-};
-
-/*
-** CAPI3REF: Online Backup Object
-** EXPERIMENTAL
-**
-** The sqlite3_backup object records state information about an ongoing
-** online backup operation. ^The sqlite3_backup object is created by
-** a call to [sqlite3_backup_init()] and is destroyed by a call to
-** [sqlite3_backup_finish()].
-**
-** See Also: [Using the SQLite Online Backup API]
-*/
-typedef struct sqlite3_backup sqlite3_backup;
-
-/*
-** CAPI3REF: Online Backup API.
-** EXPERIMENTAL
-**
-** The backup API copies the content of one database into another.
-** It is useful either for creating backups of databases or
-** for copying in-memory databases to or from persistent files.
-**
-** See Also: [Using the SQLite Online Backup API]
-**
-** ^Exclusive access is required to the destination database for the
-** duration of the operation. ^However the source database is only
-** read-locked while it is actually being read; it is not locked
-** continuously for the entire backup operation. ^Thus, the backup may be
-** performed on a live source database without preventing other users from
-** reading or writing to the source database while the backup is underway.
-**
-** ^(To perform a backup operation:
-** <ol>
-** <li><b>sqlite3_backup_init()</b> is called once to initialize the
-** backup,
-** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
-** the data between the two databases, and finally
-** <li><b>sqlite3_backup_finish()</b> is called to release all resources
-** associated with the backup operation.
-** </ol>)^
-** There should be exactly one call to sqlite3_backup_finish() for each
-** successful call to sqlite3_backup_init().
-**
-** <b>sqlite3_backup_init()</b>
-**
-** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
-** [database connection] associated with the destination database
-** and the database name, respectively.
-** ^The database name is "main" for the main database, "temp" for the
-** temporary database, or the name specified after the AS keyword in
-** an [ATTACH] statement for an attached database.
-** ^The S and M arguments passed to
-** sqlite3_backup_init(D,N,S,M) identify the [database connection]
-** and database name of the source database, respectively.
-** ^The source and destination [database connections] (parameters S and D)
-** must be different or else sqlite3_backup_init(D,N,S,M) will file with
-** an error.
-**
-** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
-** returned and an error code and error message are store3d in the
-** destination [database connection] D.
-** ^The error code and message for the failed call to sqlite3_backup_init()
-** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or
-** [sqlite3_errmsg16()] functions.
-** ^A successful call to sqlite3_backup_init() returns a pointer to an
-** [sqlite3_backup] object.
-** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
-** sqlite3_backup_finish() functions to perform the specified backup
-** operation.
-**
-** <b>sqlite3_backup_step()</b>
-**
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
-** the source and destination databases specified by [sqlite3_backup] object B.
-** ^If N is negative, all remaining source pages are copied.
-** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
-** are still more pages to be copied, then the function resturns [SQLITE_OK].
-** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
-** from source to destination, then it returns [SQLITE_DONE].
-** ^If an error occurs while running sqlite3_backup_step(B,N),
-** then an [error code] is returned. ^As well as [SQLITE_OK] and
-** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY],
-** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
-** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
-**
-** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
-** database was opened read-only or if
-** the destination is an in-memory database with a different page size
-** from the source database.
-**
-** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
-** the [sqlite3_busy_handler | busy-handler function]
-** is invoked (if one is specified). ^If the
-** busy-handler returns non-zero before the lock is available, then
-** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
-** sqlite3_backup_step() can be retried later. ^If the source
-** [database connection]
-** is being used to write to the source database when sqlite3_backup_step()
-** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
-** case the call to sqlite3_backup_step() can be retried later on. ^(If
-** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
-** [SQLITE_READONLY] is returned, then
-** there is no point in retrying the call to sqlite3_backup_step(). These
-** errors are considered fatal.)^ The application must accept
-** that the backup operation has failed and pass the backup operation handle
-** to the sqlite3_backup_finish() to release associated resources.
-**
-** ^The first call to sqlite3_backup_step() obtains an exclusive lock
-** on the destination file. ^The exclusive lock is not released until either
-** sqlite3_backup_finish() is called or the backup operation is complete
-** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
-** sqlite3_backup_step() obtains a [shared lock] on the source database that
-** lasts for the duration of the sqlite3_backup_step() call.
-** ^Because the source database is not locked between calls to
-** sqlite3_backup_step(), the source database may be modified mid-way
-** through the backup process. ^If the source database is modified by an
-** external process or via a database connection other than the one being
-** used by the backup operation, then the backup will be automatically
-** restarted by the next call to sqlite3_backup_step(). ^If the source
-** database is modified by the using the same database connection as is used
-** by the backup operation, then the backup database is automatically
-** updated at the same time.
-**
-** <b>sqlite3_backup_finish()</b>
-**
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
-** application wishes to abandon the backup operation, the application
-** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
-** ^The sqlite3_backup_finish() interfaces releases all
-** resources associated with the [sqlite3_backup] object.
-** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
-** active write-transaction on the destination database is rolled back.
-** The [sqlite3_backup] object is invalid
-** and may not be used following a call to sqlite3_backup_finish().
-**
-** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no
-** sqlite3_backup_step() errors occurred, regardless or whether or not
-** sqlite3_backup_step() completed.
-** ^If an out-of-memory condition or IO error occurred during any prior
-** sqlite3_backup_step() call on the same [sqlite3_backup] object, then
-** sqlite3_backup_finish() returns the corresponding [error code].
-**
-** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step()
-** is not a permanent error and does not affect the return value of
-** sqlite3_backup_finish().
-**
-** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b>
-**
-** ^Each call to sqlite3_backup_step() sets two values inside
-** the [sqlite3_backup] object: the number of pages still to be backed
-** up and the total number of pages in the source databae file.
-** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
-** retrieve these two values, respectively.
-**
-** ^The values returned by these functions are only updated by
-** sqlite3_backup_step(). ^If the source database is modified during a backup
-** operation, then the values are not updated to account for any extra
-** pages that need to be updated or the size of the source database file
-** changing.
-**
-** <b>Concurrent Usage of Database Handles</b>
-**
-** ^The source [database connection] may be used by the application for other
-** purposes while a backup operation is underway or being initialized.
-** ^If SQLite is compiled and configured to support threadsafe database
-** connections, then the source database connection may be used concurrently
-** from within other threads.
-**
-** However, the application must guarantee that the destination
-** [database connection] is not passed to any other API (by any thread) after
-** sqlite3_backup_init() is called and before the corresponding call to
-** sqlite3_backup_finish(). SQLite does not currently check to see
-** if the application incorrectly accesses the destination [database connection]
-** and so no error code is reported, but the operations may malfunction
-** nevertheless. Use of the destination database connection while a
-** backup is in progress might also also cause a mutex deadlock.
-**
-** If running in [shared cache mode], the application must
-** guarantee that the shared cache used by the destination database
-** is not accessed while the backup is running. In practice this means
-** that the application must guarantee that the disk file being
-** backed up to is not accessed by any connection within the process,
-** not just the specific connection that was passed to sqlite3_backup_init().
-**
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
-** threads may safely make multiple concurrent calls to sqlite3_backup_step().
-** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
-** APIs are not strictly speaking threadsafe. If they are invoked at the
-** same time as another thread is invoking sqlite3_backup_step() it is
-** possible that they return invalid values.
-*/
-SQLITE_API sqlite3_backup *sqlite3_backup_init(
- sqlite3 *pDest, /* Destination database handle */
- const char *zDestName, /* Destination database name */
- sqlite3 *pSource, /* Source database handle */
- const char *zSourceName /* Source database name */
-);
-SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
-
-/*
-** CAPI3REF: Unlock Notification
-** EXPERIMENTAL
-**
-** ^When running in shared-cache mode, a database operation may fail with
-** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
-** individual tables within the shared-cache cannot be obtained. See
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
-** ^This API may be used to register a callback that SQLite will invoke
-** when the connection currently holding the required lock relinquishes it.
-** ^This API is only available if the library was compiled with the
-** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
-**
-** See Also: [Using the SQLite Unlock Notification Feature].
-**
-** ^Shared-cache locks are released when a database connection concludes
-** its current transaction, either by committing it or rolling it back.
-**
-** ^When a connection (known as the blocked connection) fails to obtain a
-** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
-** identity of the database connection (the blocking connection) that
-** has locked the required resource is stored internally. ^After an
-** application receives an SQLITE_LOCKED error, it may call the
-** sqlite3_unlock_notify() method with the blocked connection handle as
-** the first argument to register for a callback that will be invoked
-** when the blocking connections current transaction is concluded. ^The
-** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
-** call that concludes the blocking connections transaction.
-**
-** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
-** there is a chance that the blocking connection will have already
-** concluded its transaction by the time sqlite3_unlock_notify() is invoked.
-** If this happens, then the specified callback is invoked immediately,
-** from within the call to sqlite3_unlock_notify().)^
-**
-** ^If the blocked connection is attempting to obtain a write-lock on a
-** shared-cache table, and more than one other connection currently holds
-** a read-lock on the same table, then SQLite arbitrarily selects one of
-** the other connections to use as the blocking connection.
-**
-** ^(There may be at most one unlock-notify callback registered by a
-** blocked connection. If sqlite3_unlock_notify() is called when the
-** blocked connection already has a registered unlock-notify callback,
-** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
-** called with a NULL pointer as its second argument, then any existing
-** unlock-notify callback is cancelled. ^The blocked connections
-** unlock-notify callback may also be canceled by closing the blocked
-** connection using [sqlite3_close()].
-**
-** The unlock-notify callback is not reentrant. If an application invokes
-** any sqlite3_xxx API functions from within an unlock-notify callback, a
-** crash or deadlock may be the result.
-**
-** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always
-** returns SQLITE_OK.
-**
-** <b>Callback Invocation Details</b>
-**
-** When an unlock-notify callback is registered, the application provides a
-** single void* pointer that is passed to the callback when it is invoked.
-** However, the signature of the callback function allows SQLite to pass
-** it an array of void* context pointers. The first argument passed to
-** an unlock-notify callback is a pointer to an array of void* pointers,
-** and the second is the number of entries in the array.
-**
-** When a blocking connections transaction is concluded, there may be
-** more than one blocked connection that has registered for an unlock-notify
-** callback. ^If two or more such blocked connections have specified the
-** same callback function, then instead of invoking the callback function
-** multiple times, it is invoked once with the set of void* context pointers
-** specified by the blocked connections bundled together into an array.
-** This gives the application an opportunity to prioritize any actions
-** related to the set of unblocked database connections.
-**
-** <b>Deadlock Detection</b>
-**
-** Assuming that after registering for an unlock-notify callback a
-** database waits for the callback to be issued before taking any further
-** action (a reasonable assumption), then using this API may cause the
-** application to deadlock. For example, if connection X is waiting for
-** connection Y's transaction to be concluded, and similarly connection
-** Y is waiting on connection X's transaction, then neither connection
-** will proceed and the system may remain deadlocked indefinitely.
-**
-** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock
-** detection. ^If a given call to sqlite3_unlock_notify() would put the
-** system in a deadlocked state, then SQLITE_LOCKED is returned and no
-** unlock-notify callback is registered. The system is said to be in
-** a deadlocked state if connection A has registered for an unlock-notify
-** callback on the conclusion of connection B's transaction, and connection
-** B has itself registered for an unlock-notify callback when connection
-** A's transaction is concluded. ^Indirect deadlock is also detected, so
-** the system is also considered to be deadlocked if connection B has
-** registered for an unlock-notify callback on the conclusion of connection
-** C's transaction, where connection C is waiting on connection A. ^Any
-** number of levels of indirection are allowed.
-**
-** <b>The "DROP TABLE" Exception</b>
-**
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
-** always appropriate to call sqlite3_unlock_notify(). There is however,
-** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
-** SQLite checks if there are any currently executing SELECT statements
-** that belong to the same connection. If there are, SQLITE_LOCKED is
-** returned. In this case there is no "blocking connection", so invoking
-** sqlite3_unlock_notify() results in the unlock-notify callback being
-** invoked immediately. If the application then re-attempts the "DROP TABLE"
-** or "DROP INDEX" query, an infinite loop might be the result.
-**
-** One way around this problem is to check the extended error code returned
-** by an sqlite3_step() call. ^(If there is a blocking connection, then the
-** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
-** the special "DROP TABLE/INDEX" case, the extended error code is just
-** SQLITE_LOCKED.)^
-*/
-SQLITE_API int sqlite3_unlock_notify(
- sqlite3 *pBlocked, /* Waiting connection */
- void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
- void *pNotifyArg /* Argument to pass to xNotify */
-);
-
-
-/*
-** CAPI3REF: String Comparison
-** EXPERIMENTAL
-**
-** ^The [sqlite3_strnicmp()] API allows applications and extensions to
-** compare the contents of two buffers containing UTF-8 strings in a
-** case-indendent fashion, using the same definition of case independence
-** that SQLite uses internally when comparing identifiers.
-*/
-SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
-
-/*
-** CAPI3REF: Error Logging Interface
-** EXPERIMENTAL
-**
-** ^The [sqlite3_log()] interface writes a message into the error log
-** established by the [SQLITE_CONFIG_ERRORLOG] option to [sqlite3_config()].
-**
-** The sqlite3_log() interface is intended for use by extensions such as
-** virtual tables, collating functions, and SQL functions. While there is
-** nothing to prevent an application from calling sqlite3_log(), doing so
-** is considered bad form.
-**
-** To avoid deadlocks and other threading problems, the sqlite3_log() routine
-** will not use dynamically allocated memory. The log message is stored in
-** a fixed-length buffer on the stack. If the log message is longer than
-** a few hundred characters, it will be truncated to the length of the
-** buffer.
-*/
-SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
-
-/*
-** Undo the hack that converts floating point types to integer for
-** builds on processors without floating point support.
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# undef double
-#endif
-
-#ifdef __cplusplus
-} /* End of the 'extern "C"' block */
-#endif
-#endif
-