aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2022-11-28 00:03:49 +0000
committerCy Schubert <cy@FreeBSD.org>2022-11-28 00:03:49 +0000
commitac50343d44f8dff1efe667b4713de4b1351a19e1 (patch)
tree8628e0a6ca73811ad817b9a8033975fe370e6169
parentc51041e1ade322127d8dd584b6e9e5c355f11daa (diff)
downloadsrc-ac50343d44f8dff1efe667b4713de4b1351a19e1.tar.gz
src-ac50343d44f8dff1efe667b4713de4b1351a19e1.zip
sqlite3: Vendor import of sqlite3 3.40.0vendor/sqlite3/sqlite-3400000
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--shell.c5093
-rw-r--r--sqlite3.c4901
-rw-r--r--sqlite3.h117
-rw-r--r--sqlite3ext.h8
-rw-r--r--sqlite3rc.h2
-rw-r--r--tea/Makefile.in189
-rwxr-xr-xtea/configure1991
-rw-r--r--tea/configure.ac94
-rw-r--r--tea/pkgIndex.tcl.in15
-rw-r--r--tea/tclconfig/tcl.m41153
-rw-r--r--tea/win/makefile.vc13
13 files changed, 8812 insertions, 4786 deletions
diff --git a/configure b/configure
index 16251265e4f4..1f9c2c17e787 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for sqlite 3.39.3.
+# Generated by GNU Autoconf 2.71 for sqlite 3.40.0.
#
# Report bugs to <http://www.sqlite.org>.
#
@@ -621,8 +621,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.39.3'
-PACKAGE_STRING='sqlite 3.39.3'
+PACKAGE_VERSION='3.40.0'
+PACKAGE_STRING='sqlite 3.40.0'
PACKAGE_BUGREPORT='http://www.sqlite.org'
PACKAGE_URL=''
@@ -1367,7 +1367,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.39.3 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.40.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1438,7 +1438,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.39.3:";;
+ short | recursive ) echo "Configuration of sqlite 3.40.0:";;
esac
cat <<\_ACEOF
@@ -1563,7 +1563,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.39.3
+sqlite configure 3.40.0
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1833,7 +1833,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.39.3, which was
+It was created by sqlite $as_me 3.40.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3106,7 +3106,7 @@ fi
# Define the identity of the package.
PACKAGE='sqlite'
- VERSION='3.39.3'
+ VERSION='3.40.0'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -15314,7 +15314,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.39.3, which was
+This file was extended by sqlite $as_me 3.40.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15373,7 +15373,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-sqlite config.status 3.39.3
+sqlite config.status 3.40.0
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index e3883098896c..aadce30bf20c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,7 +10,7 @@
#
AC_PREREQ(2.61)
-AC_INIT(sqlite, 3.39.3, http://www.sqlite.org)
+AC_INIT(sqlite, 3.40.0, http://www.sqlite.org)
AC_CONFIG_SRCDIR([sqlite3.c])
AC_CONFIG_AUX_DIR([.])
diff --git a/shell.c b/shell.c
index e66ae0874f52..6280ebf6108f 100644
--- a/shell.c
+++ b/shell.c
@@ -34,6 +34,8 @@
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif
+typedef unsigned int u32;
+typedef unsigned short int u16;
/*
** Optionally #include a user-defined header, whereby compilation options
@@ -56,6 +58,15 @@
#endif
/*
+** If SQLITE_SHELL_FIDDLE is defined then the shell is modified
+** somewhat for use as a WASM module in a web browser. This flag
+** should only be used when building the "fiddle" web application, as
+** the browser-mode build has much different user input requirements
+** and this build mode rewires the user input subsystem to account for
+** that.
+*/
+
+/*
** Warning pragmas copied from msvc.h in the core.
*/
#if defined(_MSC_VER)
@@ -94,6 +105,14 @@
# define _LARGEFILE_SOURCE 1
#endif
+#if defined(SQLITE_SHELL_FIDDLE) && !defined(_POSIX_SOURCE)
+/*
+** emcc requires _POSIX_SOURCE (or one of several similar defines)
+** to expose strdup().
+*/
+# define _POSIX_SOURCE
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -247,20 +266,21 @@ static void setTextMode(FILE *file, int isOutput){
# define setTextMode(X,Y)
#endif
-/*
-** When compiling with emcc (a.k.a. emscripten), we're building a
-** WebAssembly (WASM) bundle and need to disable and rewire a few
-** things.
-*/
-#ifdef __EMSCRIPTEN__
-#define SQLITE_SHELL_WASM_MODE
-#else
-#undef SQLITE_SHELL_WASM_MODE
-#endif
-
/* True if the timer is enabled */
static int enableTimer = 0;
+/* A version of strcmp() that works with NULL values */
+static int cli_strcmp(const char *a, const char *b){
+ if( a==0 ) a = "";
+ if( b==0 ) b = "";
+ return strcmp(a,b);
+}
+static int cli_strncmp(const char *a, const char *b, size_t n){
+ if( a==0 ) a = "";
+ if( b==0 ) b = "";
+ return strncmp(a,b,n);
+}
+
/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
static sqlite3_vfs *clockVfs = 0;
@@ -549,6 +569,7 @@ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
int i;
int n;
int aw = w<0 ? -w : w;
+ if( zUtf==0 ) zUtf = "";
for(i=n=0; zUtf[i]; i++){
if( (zUtf[i]&0xc0)!=0x80 ){
n++;
@@ -692,7 +713,7 @@ static char *local_getline(char *zLine, FILE *in){
if( stdin_is_interactive && in==stdin ){
char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
if( zTrans ){
- int nTrans = strlen30(zTrans)+1;
+ i64 nTrans = strlen(zTrans)+1;
if( nTrans>nLine ){
zLine = realloc(zLine, nTrans);
shell_check_oom(zLine);
@@ -719,7 +740,7 @@ static char *local_getline(char *zLine, FILE *in){
** be freed by the caller or else passed back into this routine via the
** zPrior argument for reuse.
*/
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
@@ -739,7 +760,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
}
return zResult;
}
-#endif /* !SQLITE_SHELL_WASM_MODE */
+#endif /* !SQLITE_SHELL_FIDDLE */
/*
** Return the value of a hexadecimal digit. Return -1 if the input
@@ -828,9 +849,9 @@ static void freeText(ShellText *p){
** quote character for zAppend.
*/
static void appendText(ShellText *p, const char *zAppend, char quote){
- int len;
- int i;
- int nAppend = strlen30(zAppend);
+ i64 len;
+ i64 i;
+ i64 nAppend = strlen30(zAppend);
len = nAppend+p->n+1;
if( quote ){
@@ -989,10 +1010,10 @@ static void shellAddSchemaName(
const char *zName = (const char*)sqlite3_value_text(apVal[2]);
sqlite3 *db = sqlite3_context_db_handle(pCtx);
UNUSED_PARAMETER(nVal);
- if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
+ if( zIn!=0 && cli_strncmp(zIn, "CREATE ", 7)==0 ){
for(i=0; i<ArraySize(aPrefix); i++){
int n = strlen30(aPrefix[i]);
- if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
+ if( cli_strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
char *z = 0;
char *zFake = 0;
if( zSchema ){
@@ -3796,6 +3817,7 @@ SQLITE_EXTENSION_INIT1
/* The end-of-input character */
#define RE_EOF 0 /* End of input */
+#define RE_START 0xfffffff /* Start of input - larger than an UTF-8 */
/* The NFA is implemented as sequence of opcodes taken from the following
** set. Each opcode has a single integer argument.
@@ -3817,6 +3839,33 @@ SQLITE_EXTENSION_INIT1
#define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */
#define RE_OP_NOTSPACE 16 /* Not a digit */
#define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */
+#define RE_OP_ATSTART 18 /* Currently at the start of the string */
+
+#if defined(SQLITE_DEBUG)
+/* Opcode names used for symbolic debugging */
+static const char *ReOpName[] = {
+ "EOF",
+ "MATCH",
+ "ANY",
+ "ANYSTAR",
+ "FORK",
+ "GOTO",
+ "ACCEPT",
+ "CC_INC",
+ "CC_EXC",
+ "CC_VALUE",
+ "CC_RANGE",
+ "WORD",
+ "NOTWORD",
+ "DIGIT",
+ "NOTDIGIT",
+ "SPACE",
+ "NOTSPACE",
+ "BOUNDARY",
+ "ATSTART",
+};
+#endif /* SQLITE_DEBUG */
+
/* Each opcode is a "state" in the NFA */
typedef unsigned short ReStateNumber;
@@ -3851,7 +3900,7 @@ struct ReCompiled {
int *aArg; /* Arguments to each operator */
unsigned (*xNextChar)(ReInput*); /* Next character function */
unsigned char zInit[12]; /* Initial text to match */
- int nInit; /* Number of characters in zInit */
+ int nInit; /* Number of bytes in zInit */
unsigned nState; /* Number of entries in aOp[] and aArg[] */
unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */
};
@@ -3924,7 +3973,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
ReStateNumber *pToFree;
unsigned int i = 0;
unsigned int iSwap = 0;
- int c = RE_EOF+1;
+ int c = RE_START;
int cPrev = 0;
int rc = 0;
ReInput in;
@@ -3943,6 +3992,7 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
in.i++;
}
if( in.i+pRe->nInit>in.mx ) return 0;
+ c = RE_START-1;
}
if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){
@@ -3971,6 +4021,10 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
if( pRe->aArg[x]==c ) re_add_state(pNext, x+1);
break;
}
+ case RE_OP_ATSTART: {
+ if( cPrev==RE_START ) re_add_state(pThis, x+1);
+ break;
+ }
case RE_OP_ANY: {
if( c!=0 ) re_add_state(pNext, x+1);
break;
@@ -4052,7 +4106,9 @@ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){
}
}
for(i=0; i<pNext->nState; i++){
- if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
+ int x = pNext->aState[i];
+ while( pRe->aOp[x]==RE_OP_GOTO ) x += pRe->aArg[x];
+ if( pRe->aOp[x]==RE_OP_ACCEPT ){ rc = 1; break; }
}
re_match_end:
sqlite3_free(pToFree);
@@ -4207,7 +4263,6 @@ static const char *re_subcompile_string(ReCompiled *p){
iStart = p->nState;
switch( c ){
case '|':
- case '$':
case ')': {
p->sIn.i--;
return 0;
@@ -4244,6 +4299,14 @@ static const char *re_subcompile_string(ReCompiled *p){
re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1);
break;
}
+ case '$': {
+ re_append(p, RE_OP_MATCH, RE_EOF);
+ break;
+ }
+ case '^': {
+ re_append(p, RE_OP_ATSTART, 0);
+ break;
+ }
case '{': {
int m = 0, n = 0;
int sz, j;
@@ -4262,6 +4325,7 @@ static const char *re_subcompile_string(ReCompiled *p){
if( m==0 ){
if( n==0 ) return "both m and n are zero in '{m,n}'";
re_insert(p, iPrev, RE_OP_FORK, sz+1);
+ iPrev++;
n--;
}else{
for(j=1; j<m; j++) re_copy(p, iPrev, sz);
@@ -4380,11 +4444,7 @@ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){
re_free(pRe);
return zErr;
}
- if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){
- re_append(pRe, RE_OP_MATCH, RE_EOF);
- re_append(pRe, RE_OP_ACCEPT, 0);
- *ppRe = pRe;
- }else if( pRe->sIn.i>=pRe->sIn.mx ){
+ if( pRe->sIn.i>=pRe->sIn.mx ){
re_append(pRe, RE_OP_ACCEPT, 0);
*ppRe = pRe;
}else{
@@ -4468,6 +4528,67 @@ static void re_sql_func(
}
}
+#if defined(SQLITE_DEBUG)
+/*
+** This function is used for testing and debugging only. It is only available
+** if the SQLITE_DEBUG compile-time option is used.
+**
+** Compile a regular expression and then convert the compiled expression into
+** text and return that text.
+*/
+static void re_bytecode_func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zPattern;
+ const char *zErr;
+ ReCompiled *pRe;
+ sqlite3_str *pStr;
+ int i;
+ int n;
+ char *z;
+
+ zPattern = (const char*)sqlite3_value_text(argv[0]);
+ if( zPattern==0 ) return;
+ zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0);
+ if( zErr ){
+ re_free(pRe);
+ sqlite3_result_error(context, zErr, -1);
+ return;
+ }
+ if( pRe==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ pStr = sqlite3_str_new(0);
+ if( pStr==0 ) goto re_bytecode_func_err;
+ if( pRe->nInit>0 ){
+ sqlite3_str_appendf(pStr, "INIT ");
+ for(i=0; i<pRe->nInit; i++){
+ sqlite3_str_appendf(pStr, "%02x", pRe->zInit[i]);
+ }
+ sqlite3_str_appendf(pStr, "\n");
+ }
+ for(i=0; (unsigned)i<pRe->nState; i++){
+ sqlite3_str_appendf(pStr, "%-8s %4d\n",
+ ReOpName[(unsigned char)pRe->aOp[i]], pRe->aArg[i]);
+ }
+ n = sqlite3_str_length(pStr);
+ z = sqlite3_str_finish(pStr);
+ if( n==0 ){
+ sqlite3_free(z);
+ }else{
+ sqlite3_result_text(context, z, n-1, sqlite3_free);
+ }
+
+re_bytecode_func_err:
+ re_free(pRe);
+}
+
+#endif /* SQLITE_DEBUG */
+
+
/*
** Invoke this routine to register the regexp() function with the
** SQLite database connection.
@@ -4492,12 +4613,19 @@ int sqlite3_regexp_init(
rc = sqlite3_create_function(db, "regexpi", 2,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
(void*)db, re_sql_func, 0, 0);
+#if defined(SQLITE_DEBUG)
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "regexp_bytecode", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, re_bytecode_func, 0, 0);
+ }
+#endif /* SQLITE_DEBUG */
}
return rc;
}
/************************* End ../ext/misc/regexp.c ********************/
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
/************************* Begin ../ext/misc/fileio.c ******************/
/*
** 2014-06-13
@@ -6767,8 +6895,8 @@ SQLITE_EXTENSION_INIT1
#endif
/* typedef sqlite3_int64 i64; */
/* typedef unsigned char u8; */
-typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
-typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
+/* typedef UINT32_TYPE u32; // 4-byte unsigned integer // */
+/* typedef UINT16_TYPE u16; // 2-byte unsigned integer // */
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
@@ -10049,6 +10177,10 @@ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
*/
static int idxIdentifierRequiresQuotes(const char *zId){
int i;
+ int nId = STRLEN(zId);
+
+ if( sqlite3_keyword_check(zId, nId) ) return 1;
+
for(i=0; zId[i]; i++){
if( !(zId[i]=='_')
&& !(zId[i]>='0' && zId[i]<='9')
@@ -11275,7 +11407,12 @@ void sqlite3_expert_destroy(sqlite3expert *p){
/************************* End ../ext/expert/sqlite3expert.c ********************/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
-/************************* Begin ../ext/misc/dbdata.c ******************/
+#define SQLITE_SHELL_HAVE_RECOVER 1
+#else
+#define SQLITE_SHELL_HAVE_RECOVER 0
+#endif
+#if SQLITE_SHELL_HAVE_RECOVER
+/************************* Begin ../ext/recover/dbdata.c ******************/
/*
** 2019-04-17
**
@@ -11349,16 +11486,20 @@ void sqlite3_expert_destroy(sqlite3expert *p){
** It contains one entry for each b-tree pointer between a parent and
** child page in the database.
*/
+
#if !defined(SQLITEINT_H)
/* #include "sqlite3ext.h" */
/* typedef unsigned char u8; */
+/* typedef unsigned int u32; */
#endif
SQLITE_EXTENSION_INIT1
#include <string.h>
#include <assert.h>
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
#define DBDATA_PADDING_BYTES 100
typedef struct DbdataTable DbdataTable;
@@ -11380,11 +11521,12 @@ struct DbdataCursor {
/* Only for the sqlite_dbdata table */
u8 *pRec; /* Buffer containing current record */
- int nRec; /* Size of pRec[] in bytes */
- int nHdr; /* Size of header in bytes */
+ sqlite3_int64 nRec; /* Size of pRec[] in bytes */
+ sqlite3_int64 nHdr; /* Size of header in bytes */
int iField; /* Current field number */
u8 *pHdrPtr;
u8 *pPtr;
+ u32 enc; /* Text encoding */
sqlite3_int64 iIntkey; /* Integer key value */
};
@@ -11577,14 +11719,14 @@ static int dbdataClose(sqlite3_vtab_cursor *pCursor){
/*
** Utility methods to decode 16 and 32-bit big-endian unsigned integers.
*/
-static unsigned int get_uint16(unsigned char *a){
+static u32 get_uint16(unsigned char *a){
return (a[0]<<8)|a[1];
}
-static unsigned int get_uint32(unsigned char *a){
- return ((unsigned int)a[0]<<24)
- | ((unsigned int)a[1]<<16)
- | ((unsigned int)a[2]<<8)
- | ((unsigned int)a[3]);
+static u32 get_uint32(unsigned char *a){
+ return ((u32)a[0]<<24)
+ | ((u32)a[1]<<16)
+ | ((u32)a[2]<<8)
+ | ((u32)a[3]);
}
/*
@@ -11599,7 +11741,7 @@ static unsigned int get_uint32(unsigned char *a){
*/
static int dbdataLoadPage(
DbdataCursor *pCsr, /* Cursor object */
- unsigned int pgno, /* Page number of page to load */
+ u32 pgno, /* Page number of page to load */
u8 **ppPage, /* OUT: pointer to page buffer */
int *pnPage /* OUT: Size of (*ppPage) in bytes */
){
@@ -11609,25 +11751,27 @@ static int dbdataLoadPage(
*ppPage = 0;
*pnPage = 0;
- sqlite3_bind_int64(pStmt, 2, pgno);
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nCopy = sqlite3_column_bytes(pStmt, 0);
- if( nCopy>0 ){
- u8 *pPage;
- pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES);
- if( pPage==0 ){
- rc = SQLITE_NOMEM;
- }else{
- const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
- memcpy(pPage, pCopy, nCopy);
- memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES);
+ if( pgno>0 ){
+ sqlite3_bind_int64(pStmt, 2, pgno);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int nCopy = sqlite3_column_bytes(pStmt, 0);
+ if( nCopy>0 ){
+ u8 *pPage;
+ pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES);
+ if( pPage==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
+ memcpy(pPage, pCopy, nCopy);
+ memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES);
+ }
+ *ppPage = pPage;
+ *pnPage = nCopy;
}
- *ppPage = pPage;
- *pnPage = nCopy;
}
+ rc2 = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
}
- rc2 = sqlite3_reset(pStmt);
- if( rc==SQLITE_OK ) rc = rc2;
return rc;
}
@@ -11636,18 +11780,31 @@ static int dbdataLoadPage(
** Read a varint. Put the value in *pVal and return the number of bytes.
*/
static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
- sqlite3_int64 v = 0;
+ sqlite3_uint64 u = 0;
int i;
for(i=0; i<8; i++){
- v = (v<<7) + (z[i]&0x7f);
- if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
+ u = (u<<7) + (z[i]&0x7f);
+ if( (z[i]&0x80)==0 ){ *pVal = (sqlite3_int64)u; return i+1; }
}
- v = (v<<8) + (z[i]&0xff);
- *pVal = v;
+ u = (u<<8) + (z[i]&0xff);
+ *pVal = (sqlite3_int64)u;
return 9;
}
/*
+** Like dbdataGetVarint(), but set the output to 0 if it is less than 0
+** or greater than 0xFFFFFFFF. This can be used for all varints in an
+** SQLite database except for key values in intkey tables.
+*/
+static int dbdataGetVarintU32(const u8 *z, sqlite3_int64 *pVal){
+ sqlite3_int64 val;
+ int nRet = dbdataGetVarint(z, &val);
+ if( val<0 || val>0xFFFFFFFF ) val = 0;
+ *pVal = val;
+ return nRet;
+}
+
+/*
** Return the number of bytes of space used by an SQLite value of type
** eType.
*/
@@ -11683,9 +11840,10 @@ static int dbdataValueBytes(int eType){
*/
static void dbdataValue(
sqlite3_context *pCtx,
+ u32 enc,
int eType,
u8 *pData,
- int nData
+ sqlite3_int64 nData
){
if( eType>=0 && dbdataValueBytes(eType)<=nData ){
switch( eType ){
@@ -11727,7 +11885,19 @@ static void dbdataValue(
default: {
int n = ((eType-12) / 2);
if( eType % 2 ){
- sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT);
+ switch( enc ){
+#ifndef SQLITE_OMIT_UTF16
+ case SQLITE_UTF16BE:
+ sqlite3_result_text16be(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
+ break;
+ case SQLITE_UTF16LE:
+ sqlite3_result_text16le(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
+ break;
+#endif
+ default:
+ sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
+ break;
+ }
}else{
sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
}
@@ -11755,6 +11925,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
if( rc!=SQLITE_OK ) return rc;
if( pCsr->aPage ) break;
+ if( pCsr->bOnePage ) return SQLITE_OK;
pCsr->iPgno++;
}
pCsr->iCell = pTab->bPtr ? -2 : 0;
@@ -11818,7 +11989,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
if( bNextPage || iOff>pCsr->nPage ){
bNextPage = 1;
}else{
- iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
+ iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
}
/* If this is a leaf intkey cell, load the rowid */
@@ -11865,7 +12036,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
/* Load content from overflow pages */
if( nPayload>nLocal ){
sqlite3_int64 nRem = nPayload - nLocal;
- unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
+ u32 pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
while( nRem>0 ){
u8 *aOvfl = 0;
int nOvfl = 0;
@@ -11885,7 +12056,8 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
}
}
- iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
+ iHdr = dbdataGetVarintU32(pCsr->pRec, &nHdr);
+ if( nHdr>nPayload ) nHdr = 0;
pCsr->nHdr = nHdr;
pCsr->pHdrPtr = &pCsr->pRec[iHdr];
pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
@@ -11899,7 +12071,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){
bNextPage = 1;
}else{
- pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ pCsr->pHdrPtr += dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
pCsr->pPtr += dbdataValueBytes(iType);
}
}
@@ -11938,6 +12110,18 @@ static int dbdataEof(sqlite3_vtab_cursor *pCursor){
return pCsr->aPage==0;
}
+/*
+** Return true if nul-terminated string zSchema ends in "()". Or false
+** otherwise.
+*/
+static int dbdataIsFunction(const char *zSchema){
+ size_t n = strlen(zSchema);
+ if( n>2 && zSchema[n-2]=='(' && zSchema[n-1]==')' ){
+ return (int)n-2;
+ }
+ return 0;
+}
+
/*
** Determine the size in pages of database zSchema (where zSchema is
** "main", "temp" or the name of an attached database) and set
@@ -11948,10 +12132,16 @@ static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab;
char *zSql = 0;
int rc, rc2;
+ int nFunc = 0;
sqlite3_stmt *pStmt = 0;
- zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
+ if( (nFunc = dbdataIsFunction(zSchema))>0 ){
+ zSql = sqlite3_mprintf("SELECT %.*s(0)", nFunc, zSchema);
+ }else{
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
+ }
if( zSql==0 ) return SQLITE_NOMEM;
+
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -11962,6 +12152,25 @@ static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
return rc;
}
+/*
+** Attempt to figure out the encoding of the database by retrieving page 1
+** and inspecting the header field. If successful, set the pCsr->enc variable
+** and return SQLITE_OK. Otherwise, return an SQLite error code.
+*/
+static int dbdataGetEncoding(DbdataCursor *pCsr){
+ int rc = SQLITE_OK;
+ int nPg1 = 0;
+ u8 *aPg1 = 0;
+ rc = dbdataLoadPage(pCsr, 1, &aPg1, &nPg1);
+ assert( rc!=SQLITE_OK || nPg1==0 || nPg1>=512 );
+ if( rc==SQLITE_OK && nPg1>0 ){
+ pCsr->enc = get_uint32(&aPg1[56]);
+ }
+ sqlite3_free(aPg1);
+ return rc;
+}
+
+
/*
** xFilter method for sqlite_dbdata and sqlite_dbptr.
*/
@@ -11979,19 +12188,28 @@ static int dbdataFilter(
assert( pCsr->iPgno==1 );
if( idxNum & 0x01 ){
zSchema = (const char*)sqlite3_value_text(argv[0]);
+ if( zSchema==0 ) zSchema = "";
}
if( idxNum & 0x02 ){
pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
pCsr->bOnePage = 1;
}else{
- pCsr->nPage = dbdataDbsize(pCsr, zSchema);
rc = dbdataDbsize(pCsr, zSchema);
}
if( rc==SQLITE_OK ){
+ int nFunc = 0;
if( pTab->pStmt ){
pCsr->pStmt = pTab->pStmt;
pTab->pStmt = 0;
+ }else if( (nFunc = dbdataIsFunction(zSchema))>0 ){
+ char *zSql = sqlite3_mprintf("SELECT %.*s(?2)", nFunc, zSchema);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+ sqlite3_free(zSql);
+ }
}else{
rc = sqlite3_prepare_v2(pTab->db,
"SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1,
@@ -12004,13 +12222,20 @@ static int dbdataFilter(
}else{
pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
}
+
+ /* Try to determine the encoding of the db by inspecting the header
+ ** field on page 1. */
+ if( rc==SQLITE_OK ){
+ rc = dbdataGetEncoding(pCsr);
+ }
+
if( rc==SQLITE_OK ){
rc = dbdataNext(pCursor);
}
return rc;
}
-/*
+/*
** Return a column for the sqlite_dbdata or sqlite_dbptr table.
*/
static int dbdataColumn(
@@ -12054,11 +12279,12 @@ static int dbdataColumn(
case DBDATA_COLUMN_VALUE: {
if( pCsr->iField<0 ){
sqlite3_result_int64(ctx, pCsr->iIntkey);
- }else{
+ }else if( &pCsr->pRec[pCsr->nRec] >= pCsr->pPtr ){
sqlite3_int64 iType;
- dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
dbdataValue(
- ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
+ ctx, pCsr->enc, iType, pCsr->pPtr,
+ &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
);
}
break;
@@ -12128,7 +12354,3121 @@ int sqlite3_dbdata_init(
return sqlite3DbdataRegister(db);
}
-/************************* End ../ext/misc/dbdata.c ********************/
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
+/************************* End ../ext/recover/dbdata.c ********************/
+/************************* Begin ../ext/recover/sqlite3recover.h ******************/
+/*
+** 2022-08-27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains the public interface to the "recover" extension -
+** an SQLite extension designed to recover data from corrupted database
+** files.
+*/
+
+/*
+** OVERVIEW:
+**
+** To use the API to recover data from a corrupted database, an
+** application:
+**
+** 1) Creates an sqlite3_recover handle by calling either
+** sqlite3_recover_init() or sqlite3_recover_init_sql().
+**
+** 2) Configures the new handle using one or more calls to
+** sqlite3_recover_config().
+**
+** 3) Executes the recovery by repeatedly calling sqlite3_recover_step() on
+** the handle until it returns something other than SQLITE_OK. If it
+** returns SQLITE_DONE, then the recovery operation completed without
+** error. If it returns some other non-SQLITE_OK value, then an error
+** has occurred.
+**
+** 4) Retrieves any error code and English language error message using the
+** sqlite3_recover_errcode() and sqlite3_recover_errmsg() APIs,
+** respectively.
+**
+** 5) Destroys the sqlite3_recover handle and frees all resources
+** using sqlite3_recover_finish().
+**
+** The application may abandon the recovery operation at any point
+** before it is finished by passing the sqlite3_recover handle to
+** sqlite3_recover_finish(). This is not an error, but the final state
+** of the output database, or the results of running the partial script
+** delivered to the SQL callback, are undefined.
+*/
+
+#ifndef _SQLITE_RECOVER_H
+#define _SQLITE_RECOVER_H
+
+/* #include "sqlite3.h" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** An instance of the sqlite3_recover object represents a recovery
+** operation in progress.
+**
+** Constructors:
+**
+** sqlite3_recover_init()
+** sqlite3_recover_init_sql()
+**
+** Destructor:
+**
+** sqlite3_recover_finish()
+**
+** Methods:
+**
+** sqlite3_recover_config()
+** sqlite3_recover_errcode()
+** sqlite3_recover_errmsg()
+** sqlite3_recover_run()
+** sqlite3_recover_step()
+*/
+typedef struct sqlite3_recover sqlite3_recover;
+
+/*
+** These two APIs attempt to create and return a new sqlite3_recover object.
+** In both cases the first two arguments identify the (possibly
+** corrupt) database to recover data from. The first argument is an open
+** database handle and the second the name of a database attached to that
+** handle (i.e. "main", "temp" or the name of an attached database).
+**
+** If sqlite3_recover_init() is used to create the new sqlite3_recover
+** handle, then data is recovered into a new database, identified by
+** string parameter zUri. zUri may be an absolute or relative file path,
+** or may be an SQLite URI. If the identified database file already exists,
+** it is overwritten.
+**
+** If sqlite3_recover_init_sql() is invoked, then any recovered data will
+** be returned to the user as a series of SQL statements. Executing these
+** SQL statements results in the same database as would have been created
+** had sqlite3_recover_init() been used. For each SQL statement in the
+** output, the callback function passed as the third argument (xSql) is
+** invoked once. The first parameter is a passed a copy of the fourth argument
+** to this function (pCtx) as its first parameter, and a pointer to a
+** nul-terminated buffer containing the SQL statement formated as UTF-8 as
+** the second. If the xSql callback returns any value other than SQLITE_OK,
+** then processing is immediately abandoned and the value returned used as
+** the recover handle error code (see below).
+**
+** If an out-of-memory error occurs, NULL may be returned instead of
+** a valid handle. In all other cases, it is the responsibility of the
+** application to avoid resource leaks by ensuring that
+** sqlite3_recover_finish() is called on all allocated handles.
+*/
+sqlite3_recover *sqlite3_recover_init(
+ sqlite3* db,
+ const char *zDb,
+ const char *zUri
+);
+sqlite3_recover *sqlite3_recover_init_sql(
+ sqlite3* db,
+ const char *zDb,
+ int (*xSql)(void*, const char*),
+ void *pCtx
+);
+
+/*
+** Configure an sqlite3_recover object that has just been created using
+** sqlite3_recover_init() or sqlite3_recover_init_sql(). This function
+** may only be called before the first call to sqlite3_recover_step()
+** or sqlite3_recover_run() on the object.
+**
+** The second argument passed to this function must be one of the
+** SQLITE_RECOVER_* symbols defined below. Valid values for the third argument
+** depend on the specific SQLITE_RECOVER_* symbol in use.
+**
+** SQLITE_OK is returned if the configuration operation was successful,
+** or an SQLite error code otherwise.
+*/
+int sqlite3_recover_config(sqlite3_recover*, int op, void *pArg);
+
+/*
+** SQLITE_RECOVER_LOST_AND_FOUND:
+** The pArg argument points to a string buffer containing the name
+** of a "lost-and-found" table in the output database, or NULL. If
+** the argument is non-NULL and the database contains seemingly
+** valid pages that cannot be associated with any table in the
+** recovered part of the schema, data is extracted from these
+** pages to add to the lost-and-found table.
+**
+** SQLITE_RECOVER_FREELIST_CORRUPT:
+** The pArg value must actually be a pointer to a value of type
+** int containing value 0 or 1 cast as a (void*). If this option is set
+** (argument is 1) and a lost-and-found table has been configured using
+** SQLITE_RECOVER_LOST_AND_FOUND, then is assumed that the freelist is
+** corrupt and an attempt is made to recover records from pages that
+** appear to be linked into the freelist. Otherwise, pages on the freelist
+** are ignored. Setting this option can recover more data from the
+** database, but often ends up "recovering" deleted records. The default
+** value is 0 (clear).
+**
+** SQLITE_RECOVER_ROWIDS:
+** The pArg value must actually be a pointer to a value of type
+** int containing value 0 or 1 cast as a (void*). If this option is set
+** (argument is 1), then an attempt is made to recover rowid values
+** that are not also INTEGER PRIMARY KEY values. If this option is
+** clear, then new rowids are assigned to all recovered rows. The
+** default value is 1 (set).
+**
+** SQLITE_RECOVER_SLOWINDEXES:
+** The pArg value must actually be a pointer to a value of type
+** int containing value 0 or 1 cast as a (void*). If this option is clear
+** (argument is 0), then when creating an output database, the recover
+** module creates and populates non-UNIQUE indexes right at the end of the
+** recovery operation - after all recoverable data has been inserted
+** into the new database. This is faster overall, but means that the
+** final call to sqlite3_recover_step() for a recovery operation may
+** be need to create a large number of indexes, which may be very slow.
+**
+** Or, if this option is set (argument is 1), then non-UNIQUE indexes
+** are created in the output database before it is populated with
+** recovered data. This is slower overall, but avoids the slow call
+** to sqlite3_recover_step() at the end of the recovery operation.
+**
+** The default option value is 0.
+*/
+#define SQLITE_RECOVER_LOST_AND_FOUND 1
+#define SQLITE_RECOVER_FREELIST_CORRUPT 2
+#define SQLITE_RECOVER_ROWIDS 3
+#define SQLITE_RECOVER_SLOWINDEXES 4
+
+/*
+** Perform a unit of work towards the recovery operation. This function
+** must normally be called multiple times to complete database recovery.
+**
+** If no error occurs but the recovery operation is not completed, this
+** function returns SQLITE_OK. If recovery has been completed successfully
+** then SQLITE_DONE is returned. If an error has occurred, then an SQLite
+** error code (e.g. SQLITE_IOERR or SQLITE_NOMEM) is returned. It is not
+** considered an error if some or all of the data cannot be recovered
+** due to database corruption.
+**
+** Once sqlite3_recover_step() has returned a value other than SQLITE_OK,
+** all further such calls on the same recover handle are no-ops that return
+** the same non-SQLITE_OK value.
+*/
+int sqlite3_recover_step(sqlite3_recover*);
+
+/*
+** Run the recovery operation to completion. Return SQLITE_OK if successful,
+** or an SQLite error code otherwise. Calling this function is the same
+** as executing:
+**
+** while( SQLITE_OK==sqlite3_recover_step(p) );
+** return sqlite3_recover_errcode(p);
+*/
+int sqlite3_recover_run(sqlite3_recover*);
+
+/*
+** If an error has been encountered during a prior call to
+** sqlite3_recover_step(), then this function attempts to return a
+** pointer to a buffer containing an English language explanation of
+** the error. If no error message is available, or if an out-of memory
+** error occurs while attempting to allocate a buffer in which to format
+** the error message, NULL is returned.
+**
+** The returned buffer remains valid until the sqlite3_recover handle is
+** destroyed using sqlite3_recover_finish().
+*/
+const char *sqlite3_recover_errmsg(sqlite3_recover*);
+
+/*
+** If this function is called on an sqlite3_recover handle after
+** an error occurs, an SQLite error code is returned. Otherwise, SQLITE_OK.
+*/
+int sqlite3_recover_errcode(sqlite3_recover*);
+
+/*
+** Clean up a recovery object created by a call to sqlite3_recover_init().
+** The results of using a recovery object with any API after it has been
+** passed to this function are undefined.
+**
+** This function returns the same value as sqlite3_recover_errcode().
+*/
+int sqlite3_recover_finish(sqlite3_recover*);
+
+
+#ifdef __cplusplus
+} /* end of the 'extern "C"' block */
+#endif
+
+#endif /* ifndef _SQLITE_RECOVER_H */
+
+/************************* End ../ext/recover/sqlite3recover.h ********************/
+/************************* Begin ../ext/recover/sqlite3recover.c ******************/
+/*
+** 2022-08-27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+*/
+
+
+/* #include "sqlite3recover.h" */
+#include <assert.h>
+#include <string.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Declaration for public API function in file dbdata.c. This may be called
+** with NULL as the final two arguments to register the sqlite_dbptr and
+** sqlite_dbdata virtual tables with a database handle.
+*/
+#ifdef _WIN32
+
+#endif
+int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*);
+
+/* typedef unsigned int u32; */
+/* typedef unsigned char u8; */
+/* typedef sqlite3_int64 i64; */
+
+typedef struct RecoverTable RecoverTable;
+typedef struct RecoverColumn RecoverColumn;
+
+/*
+** When recovering rows of data that can be associated with table
+** definitions recovered from the sqlite_schema table, each table is
+** represented by an instance of the following object.
+**
+** iRoot:
+** The root page in the original database. Not necessarily (and usually
+** not) the same in the recovered database.
+**
+** zTab:
+** Name of the table.
+**
+** nCol/aCol[]:
+** aCol[] is an array of nCol columns. In the order in which they appear
+** in the table.
+**
+** bIntkey:
+** Set to true for intkey tables, false for WITHOUT ROWID.
+**
+** iRowidBind:
+** Each column in the aCol[] array has associated with it the index of
+** the bind parameter its values will be bound to in the INSERT statement
+** used to construct the output database. If the table does has a rowid
+** but not an INTEGER PRIMARY KEY column, then iRowidBind contains the
+** index of the bind paramater to which the rowid value should be bound.
+** Otherwise, it contains -1. If the table does contain an INTEGER PRIMARY
+** KEY column, then the rowid value should be bound to the index associated
+** with the column.
+**
+** pNext:
+** All RecoverTable objects used by the recovery operation are allocated
+** and populated as part of creating the recovered database schema in
+** the output database, before any non-schema data are recovered. They
+** are then stored in a singly-linked list linked by this variable beginning
+** at sqlite3_recover.pTblList.
+*/
+struct RecoverTable {
+ u32 iRoot; /* Root page in original database */
+ char *zTab; /* Name of table */
+ int nCol; /* Number of columns in table */
+ RecoverColumn *aCol; /* Array of columns */
+ int bIntkey; /* True for intkey, false for without rowid */
+ int iRowidBind; /* If >0, bind rowid to INSERT here */
+ RecoverTable *pNext;
+};
+
+/*
+** Each database column is represented by an instance of the following object
+** stored in the RecoverTable.aCol[] array of the associated table.
+**
+** iField:
+** The index of the associated field within database records. Or -1 if
+** there is no associated field (e.g. for virtual generated columns).
+**
+** iBind:
+** The bind index of the INSERT statement to bind this columns values
+** to. Or 0 if there is no such index (iff (iField<0)).
+**
+** bIPK:
+** True if this is the INTEGER PRIMARY KEY column.
+**
+** zCol:
+** Name of column.
+**
+** eHidden:
+** A RECOVER_EHIDDEN_* constant value (see below for interpretation of each).
+*/
+struct RecoverColumn {
+ int iField; /* Field in record on disk */
+ int iBind; /* Binding to use in INSERT */
+ int bIPK; /* True for IPK column */
+ char *zCol;
+ int eHidden;
+};
+
+#define RECOVER_EHIDDEN_NONE 0 /* Normal database column */
+#define RECOVER_EHIDDEN_HIDDEN 1 /* Column is __HIDDEN__ */
+#define RECOVER_EHIDDEN_VIRTUAL 2 /* Virtual generated column */
+#define RECOVER_EHIDDEN_STORED 3 /* Stored generated column */
+
+/*
+** Bitmap object used to track pages in the input database. Allocated
+** and manipulated only by the following functions:
+**
+** recoverBitmapAlloc()
+** recoverBitmapFree()
+** recoverBitmapSet()
+** recoverBitmapQuery()
+**
+** nPg:
+** Largest page number that may be stored in the bitmap. The range
+** of valid keys is 1 to nPg, inclusive.
+**
+** aElem[]:
+** Array large enough to contain a bit for each key. For key value
+** iKey, the associated bit is the bit (iKey%32) of aElem[iKey/32].
+** In other words, the following is true if bit iKey is set, or
+** false if it is clear:
+**
+** (aElem[iKey/32] & (1 << (iKey%32))) ? 1 : 0
+*/
+typedef struct RecoverBitmap RecoverBitmap;
+struct RecoverBitmap {
+ i64 nPg; /* Size of bitmap */
+ u32 aElem[1]; /* Array of 32-bit bitmasks */
+};
+
+/*
+** State variables (part of the sqlite3_recover structure) used while
+** recovering data for tables identified in the recovered schema (state
+** RECOVER_STATE_WRITING).
+*/
+typedef struct RecoverStateW1 RecoverStateW1;
+struct RecoverStateW1 {
+ sqlite3_stmt *pTbls;
+ sqlite3_stmt *pSel;
+ sqlite3_stmt *pInsert;
+ int nInsert;
+
+ RecoverTable *pTab; /* Table currently being written */
+ int nMax; /* Max column count in any schema table */
+ sqlite3_value **apVal; /* Array of nMax values */
+ int nVal; /* Number of valid entries in apVal[] */
+ int bHaveRowid;
+ i64 iRowid;
+ i64 iPrevPage;
+ int iPrevCell;
+};
+
+/*
+** State variables (part of the sqlite3_recover structure) used while
+** recovering data destined for the lost and found table (states
+** RECOVER_STATE_LOSTANDFOUND[123]).
+*/
+typedef struct RecoverStateLAF RecoverStateLAF;
+struct RecoverStateLAF {
+ RecoverBitmap *pUsed;
+ i64 nPg; /* Size of db in pages */
+ sqlite3_stmt *pAllAndParent;
+ sqlite3_stmt *pMapInsert;
+ sqlite3_stmt *pMaxField;
+ sqlite3_stmt *pUsedPages;
+ sqlite3_stmt *pFindRoot;
+ sqlite3_stmt *pInsert; /* INSERT INTO lost_and_found ... */
+ sqlite3_stmt *pAllPage;
+ sqlite3_stmt *pPageData;
+ sqlite3_value **apVal;
+ int nMaxField;
+};
+
+/*
+** Main recover handle structure.
+*/
+struct sqlite3_recover {
+ /* Copies of sqlite3_recover_init[_sql]() parameters */
+ sqlite3 *dbIn; /* Input database */
+ char *zDb; /* Name of input db ("main" etc.) */
+ char *zUri; /* URI for output database */
+ void *pSqlCtx; /* SQL callback context */
+ int (*xSql)(void*,const char*); /* Pointer to SQL callback function */
+
+ /* Values configured by sqlite3_recover_config() */
+ char *zStateDb; /* State database to use (or NULL) */
+ char *zLostAndFound; /* Name of lost-and-found table (or NULL) */
+ int bFreelistCorrupt; /* SQLITE_RECOVER_FREELIST_CORRUPT setting */
+ int bRecoverRowid; /* SQLITE_RECOVER_ROWIDS setting */
+ int bSlowIndexes; /* SQLITE_RECOVER_SLOWINDEXES setting */
+
+ int pgsz;
+ int detected_pgsz;
+ int nReserve;
+ u8 *pPage1Disk;
+ u8 *pPage1Cache;
+
+ /* Error code and error message */
+ int errCode; /* For sqlite3_recover_errcode() */
+ char *zErrMsg; /* For sqlite3_recover_errmsg() */
+
+ int eState;
+ int bCloseTransaction;
+
+ /* Variables used with eState==RECOVER_STATE_WRITING */
+ RecoverStateW1 w1;
+
+ /* Variables used with states RECOVER_STATE_LOSTANDFOUND[123] */
+ RecoverStateLAF laf;
+
+ /* Fields used within sqlite3_recover_run() */
+ sqlite3 *dbOut; /* Output database */
+ sqlite3_stmt *pGetPage; /* SELECT against input db sqlite_dbdata */
+ RecoverTable *pTblList; /* List of tables recovered from schema */
+};
+
+/*
+** The various states in which an sqlite3_recover object may exist:
+**
+** RECOVER_STATE_INIT:
+** The object is initially created in this state. sqlite3_recover_step()
+** has yet to be called. This is the only state in which it is permitted
+** to call sqlite3_recover_config().
+**
+** RECOVER_STATE_WRITING:
+**
+** RECOVER_STATE_LOSTANDFOUND1:
+** State to populate the bitmap of pages used by other tables or the
+** database freelist.
+**
+** RECOVER_STATE_LOSTANDFOUND2:
+** Populate the recovery.map table - used to figure out a "root" page
+** for each lost page from in the database from which records are
+** extracted.
+**
+** RECOVER_STATE_LOSTANDFOUND3:
+** Populate the lost-and-found table itself.
+*/
+#define RECOVER_STATE_INIT 0
+#define RECOVER_STATE_WRITING 1
+#define RECOVER_STATE_LOSTANDFOUND1 2
+#define RECOVER_STATE_LOSTANDFOUND2 3
+#define RECOVER_STATE_LOSTANDFOUND3 4
+#define RECOVER_STATE_SCHEMA2 5
+#define RECOVER_STATE_DONE 6
+
+
+/*
+** Global variables used by this extension.
+*/
+typedef struct RecoverGlobal RecoverGlobal;
+struct RecoverGlobal {
+ const sqlite3_io_methods *pMethods;
+ sqlite3_recover *p;
+};
+static RecoverGlobal recover_g;
+
+/*
+** Use this static SQLite mutex to protect the globals during the
+** first call to sqlite3_recover_step().
+*/
+#define RECOVER_MUTEX_ID SQLITE_MUTEX_STATIC_APP2
+
+
+/*
+** Default value for SQLITE_RECOVER_ROWIDS (sqlite3_recover.bRecoverRowid).
+*/
+#define RECOVER_ROWID_DEFAULT 1
+
+/*
+** Mutex handling:
+**
+** recoverEnterMutex() - Enter the recovery mutex
+** recoverLeaveMutex() - Leave the recovery mutex
+** recoverAssertMutexHeld() - Assert that the recovery mutex is held
+*/
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
+# define recoverEnterMutex()
+# define recoverLeaveMutex()
+#else
+static void recoverEnterMutex(void){
+ sqlite3_mutex_enter(sqlite3_mutex_alloc(RECOVER_MUTEX_ID));
+}
+static void recoverLeaveMutex(void){
+ sqlite3_mutex_leave(sqlite3_mutex_alloc(RECOVER_MUTEX_ID));
+}
+#endif
+#if SQLITE_THREADSAFE+0>=1 && defined(SQLITE_DEBUG)
+static void recoverAssertMutexHeld(void){
+ assert( sqlite3_mutex_held(sqlite3_mutex_alloc(RECOVER_MUTEX_ID)) );
+}
+#else
+# define recoverAssertMutexHeld()
+#endif
+
+
+/*
+** Like strlen(). But handles NULL pointer arguments.
+*/
+static int recoverStrlen(const char *zStr){
+ if( zStr==0 ) return 0;
+ return (int)(strlen(zStr)&0x7fffffff);
+}
+
+/*
+** This function is a no-op if the recover handle passed as the first
+** argument already contains an error (if p->errCode!=SQLITE_OK).
+**
+** Otherwise, an attempt is made to allocate, zero and return a buffer nByte
+** bytes in size. If successful, a pointer to the new buffer is returned. Or,
+** if an OOM error occurs, NULL is returned and the handle error code
+** (p->errCode) set to SQLITE_NOMEM.
+*/
+static void *recoverMalloc(sqlite3_recover *p, i64 nByte){
+ void *pRet = 0;
+ assert( nByte>0 );
+ if( p->errCode==SQLITE_OK ){
+ pRet = sqlite3_malloc64(nByte);
+ if( pRet ){
+ memset(pRet, 0, nByte);
+ }else{
+ p->errCode = SQLITE_NOMEM;
+ }
+ }
+ return pRet;
+}
+
+/*
+** Set the error code and error message for the recover handle passed as
+** the first argument. The error code is set to the value of parameter
+** errCode.
+**
+** Parameter zFmt must be a printf() style formatting string. The handle
+** error message is set to the result of using any trailing arguments for
+** parameter substitutions in the formatting string.
+**
+** For example:
+**
+** recoverError(p, SQLITE_ERROR, "no such table: %s", zTablename);
+*/
+static int recoverError(
+ sqlite3_recover *p,
+ int errCode,
+ const char *zFmt, ...
+){
+ char *z = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ if( zFmt ){
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ }
+ sqlite3_free(p->zErrMsg);
+ p->zErrMsg = z;
+ p->errCode = errCode;
+ return errCode;
+}
+
+
+/*
+** This function is a no-op if p->errCode is initially other than SQLITE_OK.
+** In this case it returns NULL.
+**
+** Otherwise, an attempt is made to allocate and return a bitmap object
+** large enough to store a bit for all page numbers between 1 and nPg,
+** inclusive. The bitmap is initially zeroed.
+*/
+static RecoverBitmap *recoverBitmapAlloc(sqlite3_recover *p, i64 nPg){
+ int nElem = (nPg+1+31) / 32;
+ int nByte = sizeof(RecoverBitmap) + nElem*sizeof(u32);
+ RecoverBitmap *pRet = (RecoverBitmap*)recoverMalloc(p, nByte);
+
+ if( pRet ){
+ pRet->nPg = nPg;
+ }
+ return pRet;
+}
+
+/*
+** Free a bitmap object allocated by recoverBitmapAlloc().
+*/
+static void recoverBitmapFree(RecoverBitmap *pMap){
+ sqlite3_free(pMap);
+}
+
+/*
+** Set the bit associated with page iPg in bitvec pMap.
+*/
+static void recoverBitmapSet(RecoverBitmap *pMap, i64 iPg){
+ if( iPg<=pMap->nPg ){
+ int iElem = (iPg / 32);
+ int iBit = (iPg % 32);
+ pMap->aElem[iElem] |= (((u32)1) << iBit);
+ }
+}
+
+/*
+** Query bitmap object pMap for the state of the bit associated with page
+** iPg. Return 1 if it is set, or 0 otherwise.
+*/
+static int recoverBitmapQuery(RecoverBitmap *pMap, i64 iPg){
+ int ret = 1;
+ if( iPg<=pMap->nPg && iPg>0 ){
+ int iElem = (iPg / 32);
+ int iBit = (iPg % 32);
+ ret = (pMap->aElem[iElem] & (((u32)1) << iBit)) ? 1 : 0;
+ }
+ return ret;
+}
+
+/*
+** Set the recover handle error to the error code and message returned by
+** calling sqlite3_errcode() and sqlite3_errmsg(), respectively, on database
+** handle db.
+*/
+static int recoverDbError(sqlite3_recover *p, sqlite3 *db){
+ return recoverError(p, sqlite3_errcode(db), "%s", sqlite3_errmsg(db));
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK).
+**
+** Otherwise, it attempts to prepare the SQL statement in zSql against
+** database handle db. If successful, the statement handle is returned.
+** Or, if an error occurs, NULL is returned and an error left in the
+** recover handle.
+*/
+static sqlite3_stmt *recoverPrepare(
+ sqlite3_recover *p,
+ sqlite3 *db,
+ const char *zSql
+){
+ sqlite3_stmt *pStmt = 0;
+ if( p->errCode==SQLITE_OK ){
+ if( sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) ){
+ recoverDbError(p, db);
+ }
+ }
+ return pStmt;
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK).
+**
+** Otherwise, argument zFmt is used as a printf() style format string,
+** along with any trailing arguments, to create an SQL statement. This
+** SQL statement is prepared against database handle db and, if successful,
+** the statment handle returned. Or, if an error occurs - either during
+** the printf() formatting or when preparing the resulting SQL - an
+** error code and message are left in the recover handle.
+*/
+static sqlite3_stmt *recoverPreparePrintf(
+ sqlite3_recover *p,
+ sqlite3 *db,
+ const char *zFmt, ...
+){
+ sqlite3_stmt *pStmt = 0;
+ if( p->errCode==SQLITE_OK ){
+ va_list ap;
+ char *z;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ if( z==0 ){
+ p->errCode = SQLITE_NOMEM;
+ }else{
+ pStmt = recoverPrepare(p, db, z);
+ sqlite3_free(z);
+ }
+ }
+ return pStmt;
+}
+
+/*
+** Reset SQLite statement handle pStmt. If the call to sqlite3_reset()
+** indicates that an error occurred, and there is not already an error
+** in the recover handle passed as the first argument, set the error
+** code and error message appropriately.
+**
+** This function returns a copy of the statement handle pointer passed
+** as the second argument.
+*/
+static sqlite3_stmt *recoverReset(sqlite3_recover *p, sqlite3_stmt *pStmt){
+ int rc = sqlite3_reset(pStmt);
+ if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT && p->errCode==SQLITE_OK ){
+ recoverDbError(p, sqlite3_db_handle(pStmt));
+ }
+ return pStmt;
+}
+
+/*
+** Finalize SQLite statement handle pStmt. If the call to sqlite3_reset()
+** indicates that an error occurred, and there is not already an error
+** in the recover handle passed as the first argument, set the error
+** code and error message appropriately.
+*/
+static void recoverFinalize(sqlite3_recover *p, sqlite3_stmt *pStmt){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
+ int rc = sqlite3_finalize(pStmt);
+ if( rc!=SQLITE_OK && p->errCode==SQLITE_OK ){
+ recoverDbError(p, db);
+ }
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). A copy of p->errCode is returned in this
+** case.
+**
+** Otherwise, execute SQL script zSql. If successful, return SQLITE_OK.
+** Or, if an error occurs, leave an error code and message in the recover
+** handle and return a copy of the error code.
+*/
+static int recoverExec(sqlite3_recover *p, sqlite3 *db, const char *zSql){
+ if( p->errCode==SQLITE_OK ){
+ int rc = sqlite3_exec(db, zSql, 0, 0, 0);
+ if( rc ){
+ recoverDbError(p, db);
+ }
+ }
+ return p->errCode;
+}
+
+/*
+** Bind the value pVal to parameter iBind of statement pStmt. Leave an
+** error in the recover handle passed as the first argument if an error
+** (e.g. an OOM) occurs.
+*/
+static void recoverBindValue(
+ sqlite3_recover *p,
+ sqlite3_stmt *pStmt,
+ int iBind,
+ sqlite3_value *pVal
+){
+ if( p->errCode==SQLITE_OK ){
+ int rc = sqlite3_bind_value(pStmt, iBind, pVal);
+ if( rc ) recoverError(p, rc, 0);
+ }
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). NULL is returned in this case.
+**
+** Otherwise, an attempt is made to interpret zFmt as a printf() style
+** formatting string and the result of using the trailing arguments for
+** parameter substitution with it written into a buffer obtained from
+** sqlite3_malloc(). If successful, a pointer to the buffer is returned.
+** It is the responsibility of the caller to eventually free the buffer
+** using sqlite3_free().
+**
+** Or, if an error occurs, an error code and message is left in the recover
+** handle and NULL returned.
+*/
+static char *recoverMPrintf(sqlite3_recover *p, const char *zFmt, ...){
+ va_list ap;
+ char *z;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ if( p->errCode==SQLITE_OK ){
+ if( z==0 ) p->errCode = SQLITE_NOMEM;
+ }else{
+ sqlite3_free(z);
+ z = 0;
+ }
+ return z;
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). Zero is returned in this case.
+**
+** Otherwise, execute "PRAGMA page_count" against the input database. If
+** successful, return the integer result. Or, if an error occurs, leave an
+** error code and error message in the sqlite3_recover handle and return
+** zero.
+*/
+static i64 recoverPageCount(sqlite3_recover *p){
+ i64 nPg = 0;
+ if( p->errCode==SQLITE_OK ){
+ sqlite3_stmt *pStmt = 0;
+ pStmt = recoverPreparePrintf(p, p->dbIn, "PRAGMA %Q.page_count", p->zDb);
+ if( pStmt ){
+ sqlite3_step(pStmt);
+ nPg = sqlite3_column_int64(pStmt, 0);
+ }
+ recoverFinalize(p, pStmt);
+ }
+ return nPg;
+}
+
+/*
+** Implementation of SQL scalar function "read_i32". The first argument to
+** this function must be a blob. The second a non-negative integer. This
+** function reads and returns a 32-bit big-endian integer from byte
+** offset (4*<arg2>) of the blob.
+**
+** SELECT read_i32(<blob>, <idx>)
+*/
+static void recoverReadI32(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *pBlob;
+ int nBlob;
+ int iInt;
+
+ assert( argc==2 );
+ nBlob = sqlite3_value_bytes(argv[0]);
+ pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
+ iInt = sqlite3_value_int(argv[1]) & 0xFFFF;
+
+ if( (iInt+1)*4<=nBlob ){
+ const unsigned char *a = &pBlob[iInt*4];
+ i64 iVal = ((i64)a[0]<<24)
+ + ((i64)a[1]<<16)
+ + ((i64)a[2]<< 8)
+ + ((i64)a[3]<< 0);
+ sqlite3_result_int64(context, iVal);
+ }
+}
+
+/*
+** Implementation of SQL scalar function "page_is_used". This function
+** is used as part of the procedure for locating orphan rows for the
+** lost-and-found table, and it depends on those routines having populated
+** the sqlite3_recover.laf.pUsed variable.
+**
+** The only argument to this function is a page-number. It returns true
+** if the page has already been used somehow during data recovery, or false
+** otherwise.
+**
+** SELECT page_is_used(<pgno>);
+*/
+static void recoverPageIsUsed(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ sqlite3_recover *p = (sqlite3_recover*)sqlite3_user_data(pCtx);
+ i64 pgno = sqlite3_value_int64(apArg[0]);
+ assert( nArg==1 );
+ sqlite3_result_int(pCtx, recoverBitmapQuery(p->laf.pUsed, pgno));
+}
+
+/*
+** The implementation of a user-defined SQL function invoked by the
+** sqlite_dbdata and sqlite_dbptr virtual table modules to access pages
+** of the database being recovered.
+**
+** This function always takes a single integer argument. If the argument
+** is zero, then the value returned is the number of pages in the db being
+** recovered. If the argument is greater than zero, it is a page number.
+** The value returned in this case is an SQL blob containing the data for
+** the identified page of the db being recovered. e.g.
+**
+** SELECT getpage(0); -- return number of pages in db
+** SELECT getpage(4); -- return page 4 of db as a blob of data
+*/
+static void recoverGetPage(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ sqlite3_recover *p = (sqlite3_recover*)sqlite3_user_data(pCtx);
+ i64 pgno = sqlite3_value_int64(apArg[0]);
+ sqlite3_stmt *pStmt = 0;
+
+ assert( nArg==1 );
+ if( pgno==0 ){
+ i64 nPg = recoverPageCount(p);
+ sqlite3_result_int64(pCtx, nPg);
+ return;
+ }else{
+ if( p->pGetPage==0 ){
+ pStmt = p->pGetPage = recoverPreparePrintf(
+ p, p->dbIn, "SELECT data FROM sqlite_dbpage(%Q) WHERE pgno=?", p->zDb
+ );
+ }else if( p->errCode==SQLITE_OK ){
+ pStmt = p->pGetPage;
+ }
+
+ if( pStmt ){
+ sqlite3_bind_int64(pStmt, 1, pgno);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const u8 *aPg;
+ int nPg;
+ assert( p->errCode==SQLITE_OK );
+ aPg = sqlite3_column_blob(pStmt, 0);
+ nPg = sqlite3_column_bytes(pStmt, 0);
+ if( pgno==1 && nPg==p->pgsz && 0==memcmp(p->pPage1Cache, aPg, nPg) ){
+ aPg = p->pPage1Disk;
+ }
+ sqlite3_result_blob(pCtx, aPg, nPg-p->nReserve, SQLITE_TRANSIENT);
+ }
+ recoverReset(p, pStmt);
+ }
+ }
+
+ if( p->errCode ){
+ if( p->zErrMsg ) sqlite3_result_error(pCtx, p->zErrMsg, -1);
+ sqlite3_result_error_code(pCtx, p->errCode);
+ }
+}
+
+/*
+** Find a string that is not found anywhere in z[]. Return a pointer
+** to that string.
+**
+** Try to use zA and zB first. If both of those are already found in z[]
+** then make up some string and store it in the buffer zBuf.
+*/
+static const char *recoverUnusedString(
+ const char *z, /* Result must not appear anywhere in z */
+ const char *zA, const char *zB, /* Try these first */
+ char *zBuf /* Space to store a generated string */
+){
+ unsigned i = 0;
+ if( strstr(z, zA)==0 ) return zA;
+ if( strstr(z, zB)==0 ) return zB;
+ do{
+ sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
+ }while( strstr(z,zBuf)!=0 );
+ return zBuf;
+}
+
+/*
+** Implementation of scalar SQL function "escape_crnl". The argument passed to
+** this function is the output of built-in function quote(). If the first
+** character of the input is "'", indicating that the value passed to quote()
+** was a text value, then this function searches the input for "\n" and "\r"
+** characters and adds a wrapper similar to the following:
+**
+** replace(replace(<input>, '\n', char(10), '\r', char(13));
+**
+** Or, if the first character of the input is not "'", then a copy of the input
+** is returned.
+*/
+static void recoverEscapeCrnl(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zText = (const char*)sqlite3_value_text(argv[0]);
+ if( zText && zText[0]=='\'' ){
+ int nText = sqlite3_value_bytes(argv[0]);
+ int i;
+ char zBuf1[20];
+ char zBuf2[20];
+ const char *zNL = 0;
+ const char *zCR = 0;
+ int nCR = 0;
+ int nNL = 0;
+
+ for(i=0; zText[i]; i++){
+ if( zNL==0 && zText[i]=='\n' ){
+ zNL = recoverUnusedString(zText, "\\n", "\\012", zBuf1);
+ nNL = (int)strlen(zNL);
+ }
+ if( zCR==0 && zText[i]=='\r' ){
+ zCR = recoverUnusedString(zText, "\\r", "\\015", zBuf2);
+ nCR = (int)strlen(zCR);
+ }
+ }
+
+ if( zNL || zCR ){
+ int iOut = 0;
+ i64 nMax = (nNL > nCR) ? nNL : nCR;
+ i64 nAlloc = nMax * nText + (nMax+64)*2;
+ char *zOut = (char*)sqlite3_malloc64(nAlloc);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+
+ if( zNL && zCR ){
+ memcpy(&zOut[iOut], "replace(replace(", 16);
+ iOut += 16;
+ }else{
+ memcpy(&zOut[iOut], "replace(", 8);
+ iOut += 8;
+ }
+ for(i=0; zText[i]; i++){
+ if( zText[i]=='\n' ){
+ memcpy(&zOut[iOut], zNL, nNL);
+ iOut += nNL;
+ }else if( zText[i]=='\r' ){
+ memcpy(&zOut[iOut], zCR, nCR);
+ iOut += nCR;
+ }else{
+ zOut[iOut] = zText[i];
+ iOut++;
+ }
+ }
+
+ if( zNL ){
+ memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+ memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
+ memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
+ }
+ if( zCR ){
+ memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+ memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
+ memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
+ }
+
+ sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
+ sqlite3_free(zOut);
+ return;
+ }
+ }
+
+ sqlite3_result_value(context, argv[0]);
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). A copy of the error code is returned in
+** this case.
+**
+** Otherwise, attempt to populate temporary table "recovery.schema" with the
+** parts of the database schema that can be extracted from the input database.
+**
+** If no error occurs, SQLITE_OK is returned. Otherwise, an error code
+** and error message are left in the recover handle and a copy of the
+** error code returned. It is not considered an error if part of all of
+** the database schema cannot be recovered due to corruption.
+*/
+static int recoverCacheSchema(sqlite3_recover *p){
+ return recoverExec(p, p->dbOut,
+ "WITH RECURSIVE pages(p) AS ("
+ " SELECT 1"
+ " UNION"
+ " SELECT child FROM sqlite_dbptr('getpage()'), pages WHERE pgno=p"
+ ")"
+ "INSERT INTO recovery.schema SELECT"
+ " max(CASE WHEN field=0 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=1 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=2 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=3 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=4 THEN value ELSE NULL END)"
+ "FROM sqlite_dbdata('getpage()') WHERE pgno IN ("
+ " SELECT p FROM pages"
+ ") GROUP BY pgno, cell"
+ );
+}
+
+/*
+** If this recover handle is not in SQL callback mode (i.e. was not created
+** using sqlite3_recover_init_sql()) of if an error has already occurred,
+** this function is a no-op. Otherwise, issue a callback with SQL statement
+** zSql as the parameter.
+**
+** If the callback returns non-zero, set the recover handle error code to
+** the value returned (so that the caller will abandon processing).
+*/
+static void recoverSqlCallback(sqlite3_recover *p, const char *zSql){
+ if( p->errCode==SQLITE_OK && p->xSql ){
+ int res = p->xSql(p->pSqlCtx, zSql);
+ if( res ){
+ recoverError(p, SQLITE_ERROR, "callback returned an error - %d", res);
+ }
+ }
+}
+
+/*
+** Transfer the following settings from the input database to the output
+** database:
+**
+** + page-size,
+** + auto-vacuum settings,
+** + database encoding,
+** + user-version (PRAGMA user_version), and
+** + application-id (PRAGMA application_id), and
+*/
+static void recoverTransferSettings(sqlite3_recover *p){
+ const char *aPragma[] = {
+ "encoding",
+ "page_size",
+ "auto_vacuum",
+ "user_version",
+ "application_id"
+ };
+ int ii;
+
+ /* Truncate the output database to 0 pages in size. This is done by
+ ** opening a new, empty, temp db, then using the backup API to clobber
+ ** any existing output db with a copy of it. */
+ if( p->errCode==SQLITE_OK ){
+ sqlite3 *db2 = 0;
+ int rc = sqlite3_open("", &db2);
+ if( rc!=SQLITE_OK ){
+ recoverDbError(p, db2);
+ return;
+ }
+
+ for(ii=0; ii<sizeof(aPragma)/sizeof(aPragma[0]); ii++){
+ const char *zPrag = aPragma[ii];
+ sqlite3_stmt *p1 = 0;
+ p1 = recoverPreparePrintf(p, p->dbIn, "PRAGMA %Q.%s", p->zDb, zPrag);
+ if( p->errCode==SQLITE_OK && sqlite3_step(p1)==SQLITE_ROW ){
+ const char *zArg = (const char*)sqlite3_column_text(p1, 0);
+ char *z2 = recoverMPrintf(p, "PRAGMA %s = %Q", zPrag, zArg);
+ recoverSqlCallback(p, z2);
+ recoverExec(p, db2, z2);
+ sqlite3_free(z2);
+ if( zArg==0 ){
+ recoverError(p, SQLITE_NOMEM, 0);
+ }
+ }
+ recoverFinalize(p, p1);
+ }
+ recoverExec(p, db2, "CREATE TABLE t1(a); DROP TABLE t1;");
+
+ if( p->errCode==SQLITE_OK ){
+ sqlite3 *db = p->dbOut;
+ sqlite3_backup *pBackup = sqlite3_backup_init(db, "main", db2, "main");
+ if( pBackup ){
+ sqlite3_backup_step(pBackup, -1);
+ p->errCode = sqlite3_backup_finish(pBackup);
+ }else{
+ recoverDbError(p, db);
+ }
+ }
+
+ sqlite3_close(db2);
+ }
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). A copy of the error code is returned in
+** this case.
+**
+** Otherwise, an attempt is made to open the output database, attach
+** and create the schema of the temporary database used to store
+** intermediate data, and to register all required user functions and
+** virtual table modules with the output handle.
+**
+** If no error occurs, SQLITE_OK is returned. Otherwise, an error code
+** and error message are left in the recover handle and a copy of the
+** error code returned.
+*/
+static int recoverOpenOutput(sqlite3_recover *p){
+ struct Func {
+ const char *zName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
+ } aFunc[] = {
+ { "getpage", 1, recoverGetPage },
+ { "page_is_used", 1, recoverPageIsUsed },
+ { "read_i32", 2, recoverReadI32 },
+ { "escape_crnl", 1, recoverEscapeCrnl },
+ };
+
+ const int flags = SQLITE_OPEN_URI|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
+ sqlite3 *db = 0; /* New database handle */
+ int ii; /* For iterating through aFunc[] */
+
+ assert( p->dbOut==0 );
+
+ if( sqlite3_open_v2(p->zUri, &db, flags, 0) ){
+ recoverDbError(p, db);
+ }
+
+ /* Register the sqlite_dbdata and sqlite_dbptr virtual table modules.
+ ** These two are registered with the output database handle - this
+ ** module depends on the input handle supporting the sqlite_dbpage
+ ** virtual table only. */
+ if( p->errCode==SQLITE_OK ){
+ p->errCode = sqlite3_dbdata_init(db, 0, 0);
+ }
+
+ /* Register the custom user-functions with the output handle. */
+ for(ii=0; p->errCode==SQLITE_OK && ii<sizeof(aFunc)/sizeof(aFunc[0]); ii++){
+ p->errCode = sqlite3_create_function(db, aFunc[ii].zName,
+ aFunc[ii].nArg, SQLITE_UTF8, (void*)p, aFunc[ii].xFunc, 0, 0
+ );
+ }
+
+ p->dbOut = db;
+ return p->errCode;
+}
+
+/*
+** Attach the auxiliary database 'recovery' to the output database handle.
+** This temporary database is used during the recovery process and then
+** discarded.
+*/
+static void recoverOpenRecovery(sqlite3_recover *p){
+ char *zSql = recoverMPrintf(p, "ATTACH %Q AS recovery;", p->zStateDb);
+ recoverExec(p, p->dbOut, zSql);
+ recoverExec(p, p->dbOut,
+ "PRAGMA writable_schema = 1;"
+ "CREATE TABLE recovery.map(pgno INTEGER PRIMARY KEY, parent INT);"
+ "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
+ );
+ sqlite3_free(zSql);
+}
+
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK).
+**
+** Otherwise, argument zName must be the name of a table that has just been
+** created in the output database. This function queries the output db
+** for the schema of said table, and creates a RecoverTable object to
+** store the schema in memory. The new RecoverTable object is linked into
+** the list at sqlite3_recover.pTblList.
+**
+** Parameter iRoot must be the root page of table zName in the INPUT
+** database.
+*/
+static void recoverAddTable(
+ sqlite3_recover *p,
+ const char *zName, /* Name of table created in output db */
+ i64 iRoot /* Root page of same table in INPUT db */
+){
+ sqlite3_stmt *pStmt = recoverPreparePrintf(p, p->dbOut,
+ "PRAGMA table_xinfo(%Q)", zName
+ );
+
+ if( pStmt ){
+ int iPk = -1;
+ int iBind = 1;
+ RecoverTable *pNew = 0;
+ int nCol = 0;
+ int nName = recoverStrlen(zName);
+ int nByte = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ nCol++;
+ nByte += (sqlite3_column_bytes(pStmt, 1)+1);
+ }
+ nByte += sizeof(RecoverTable) + nCol*sizeof(RecoverColumn) + nName+1;
+ recoverReset(p, pStmt);
+
+ pNew = recoverMalloc(p, nByte);
+ if( pNew ){
+ int i = 0;
+ int iField = 0;
+ char *csr = 0;
+ pNew->aCol = (RecoverColumn*)&pNew[1];
+ pNew->zTab = csr = (char*)&pNew->aCol[nCol];
+ pNew->nCol = nCol;
+ pNew->iRoot = iRoot;
+ memcpy(csr, zName, nName);
+ csr += nName+1;
+
+ for(i=0; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ int iPKF = sqlite3_column_int(pStmt, 5);
+ int n = sqlite3_column_bytes(pStmt, 1);
+ const char *z = (const char*)sqlite3_column_text(pStmt, 1);
+ const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
+ int eHidden = sqlite3_column_int(pStmt, 6);
+
+ if( iPk==-1 && iPKF==1 && !sqlite3_stricmp("integer", zType) ) iPk = i;
+ if( iPKF>1 ) iPk = -2;
+ pNew->aCol[i].zCol = csr;
+ pNew->aCol[i].eHidden = eHidden;
+ if( eHidden==RECOVER_EHIDDEN_VIRTUAL ){
+ pNew->aCol[i].iField = -1;
+ }else{
+ pNew->aCol[i].iField = iField++;
+ }
+ if( eHidden!=RECOVER_EHIDDEN_VIRTUAL
+ && eHidden!=RECOVER_EHIDDEN_STORED
+ ){
+ pNew->aCol[i].iBind = iBind++;
+ }
+ memcpy(csr, z, n);
+ csr += (n+1);
+ }
+
+ pNew->pNext = p->pTblList;
+ p->pTblList = pNew;
+ pNew->bIntkey = 1;
+ }
+
+ recoverFinalize(p, pStmt);
+
+ pStmt = recoverPreparePrintf(p, p->dbOut, "PRAGMA index_xinfo(%Q)", zName);
+ while( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
+ int iField = sqlite3_column_int(pStmt, 0);
+ int iCol = sqlite3_column_int(pStmt, 1);
+
+ assert( iField<pNew->nCol && iCol<pNew->nCol );
+ pNew->aCol[iCol].iField = iField;
+
+ pNew->bIntkey = 0;
+ iPk = -2;
+ }
+ recoverFinalize(p, pStmt);
+
+ if( p->errCode==SQLITE_OK ){
+ if( iPk>=0 ){
+ pNew->aCol[iPk].bIPK = 1;
+ }else if( pNew->bIntkey ){
+ pNew->iRowidBind = iBind++;
+ }
+ }
+ }
+}
+
+/*
+** This function is called after recoverCacheSchema() has cached those parts
+** of the input database schema that could be recovered in temporary table
+** "recovery.schema". This function creates in the output database copies
+** of all parts of that schema that must be created before the tables can
+** be populated. Specifically, this means:
+**
+** * all tables that are not VIRTUAL, and
+** * UNIQUE indexes.
+**
+** If the recovery handle uses SQL callbacks, then callbacks containing
+** the associated "CREATE TABLE" and "CREATE INDEX" statements are made.
+**
+** Additionally, records are added to the sqlite_schema table of the
+** output database for any VIRTUAL tables. The CREATE VIRTUAL TABLE
+** records are written directly to sqlite_schema, not actually executed.
+** If the handle is in SQL callback mode, then callbacks are invoked
+** with equivalent SQL statements.
+*/
+static int recoverWriteSchema1(sqlite3_recover *p){
+ sqlite3_stmt *pSelect = 0;
+ sqlite3_stmt *pTblname = 0;
+
+ pSelect = recoverPrepare(p, p->dbOut,
+ "WITH dbschema(rootpage, name, sql, tbl, isVirtual, isIndex) AS ("
+ " SELECT rootpage, name, sql, "
+ " type='table', "
+ " sql LIKE 'create virtual%',"
+ " (type='index' AND (sql LIKE '%unique%' OR ?1))"
+ " FROM recovery.schema"
+ ")"
+ "SELECT rootpage, tbl, isVirtual, name, sql"
+ " FROM dbschema "
+ " WHERE tbl OR isIndex"
+ " ORDER BY tbl DESC, name=='sqlite_sequence' DESC"
+ );
+
+ pTblname = recoverPrepare(p, p->dbOut,
+ "SELECT name FROM sqlite_schema "
+ "WHERE type='table' ORDER BY rowid DESC LIMIT 1"
+ );
+
+ if( pSelect ){
+ sqlite3_bind_int(pSelect, 1, p->bSlowIndexes);
+ while( sqlite3_step(pSelect)==SQLITE_ROW ){
+ i64 iRoot = sqlite3_column_int64(pSelect, 0);
+ int bTable = sqlite3_column_int(pSelect, 1);
+ int bVirtual = sqlite3_column_int(pSelect, 2);
+ const char *zName = (const char*)sqlite3_column_text(pSelect, 3);
+ const char *zSql = (const char*)sqlite3_column_text(pSelect, 4);
+ char *zFree = 0;
+ int rc = SQLITE_OK;
+
+ if( bVirtual ){
+ zSql = (const char*)(zFree = recoverMPrintf(p,
+ "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)",
+ zName, zName, zSql
+ ));
+ }
+ rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ recoverSqlCallback(p, zSql);
+ if( bTable && !bVirtual ){
+ if( SQLITE_ROW==sqlite3_step(pTblname) ){
+ const char *zTbl = (const char*)sqlite3_column_text(pTblname, 0);
+ recoverAddTable(p, zTbl, iRoot);
+ }
+ recoverReset(p, pTblname);
+ }
+ }else if( rc!=SQLITE_ERROR ){
+ recoverDbError(p, p->dbOut);
+ }
+ sqlite3_free(zFree);
+ }
+ }
+ recoverFinalize(p, pSelect);
+ recoverFinalize(p, pTblname);
+
+ return p->errCode;
+}
+
+/*
+** This function is called after the output database has been populated. It
+** adds all recovered schema elements that were not created in the output
+** database by recoverWriteSchema1() - everything except for tables and
+** UNIQUE indexes. Specifically:
+**
+** * views,
+** * triggers,
+** * non-UNIQUE indexes.
+**
+** If the recover handle is in SQL callback mode, then equivalent callbacks
+** are issued to create the schema elements.
+*/
+static int recoverWriteSchema2(sqlite3_recover *p){
+ sqlite3_stmt *pSelect = 0;
+
+ pSelect = recoverPrepare(p, p->dbOut,
+ p->bSlowIndexes ?
+ "SELECT rootpage, sql FROM recovery.schema "
+ " WHERE type!='table' AND type!='index'"
+ :
+ "SELECT rootpage, sql FROM recovery.schema "
+ " WHERE type!='table' AND (type!='index' OR sql NOT LIKE '%unique%')"
+ );
+
+ if( pSelect ){
+ while( sqlite3_step(pSelect)==SQLITE_ROW ){
+ const char *zSql = (const char*)sqlite3_column_text(pSelect, 1);
+ int rc = sqlite3_exec(p->dbOut, zSql, 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ recoverSqlCallback(p, zSql);
+ }else if( rc!=SQLITE_ERROR ){
+ recoverDbError(p, p->dbOut);
+ }
+ }
+ }
+ recoverFinalize(p, pSelect);
+
+ return p->errCode;
+}
+
+/*
+** This function is a no-op if recover handle p already contains an error
+** (if p->errCode!=SQLITE_OK). In this case it returns NULL.
+**
+** Otherwise, if the recover handle is configured to create an output
+** database (was created by sqlite3_recover_init()), then this function
+** prepares and returns an SQL statement to INSERT a new record into table
+** pTab, assuming the first nField fields of a record extracted from disk
+** are valid.
+**
+** For example, if table pTab is:
+**
+** CREATE TABLE name(a, b GENERATED ALWAYS AS (a+1) STORED, c, d, e);
+**
+** And nField is 4, then the SQL statement prepared and returned is:
+**
+** INSERT INTO (a, c, d) VALUES (?1, ?2, ?3);
+**
+** In this case even though 4 values were extracted from the input db,
+** only 3 are written to the output, as the generated STORED column
+** cannot be written.
+**
+** If the recover handle is in SQL callback mode, then the SQL statement
+** prepared is such that evaluating it returns a single row containing
+** a single text value - itself an SQL statement similar to the above,
+** except with SQL literals in place of the variables. For example:
+**
+** SELECT 'INSERT INTO (a, c, d) VALUES ('
+** || quote(?1) || ', '
+** || quote(?2) || ', '
+** || quote(?3) || ')';
+**
+** In either case, it is the responsibility of the caller to eventually
+** free the statement handle using sqlite3_finalize().
+*/
+static sqlite3_stmt *recoverInsertStmt(
+ sqlite3_recover *p,
+ RecoverTable *pTab,
+ int nField
+){
+ sqlite3_stmt *pRet = 0;
+ const char *zSep = "";
+ const char *zSqlSep = "";
+ char *zSql = 0;
+ char *zFinal = 0;
+ char *zBind = 0;
+ int ii;
+ int bSql = p->xSql ? 1 : 0;
+
+ if( nField<=0 ) return 0;
+
+ assert( nField<=pTab->nCol );
+
+ zSql = recoverMPrintf(p, "INSERT OR IGNORE INTO %Q(", pTab->zTab);
+
+ if( pTab->iRowidBind ){
+ assert( pTab->bIntkey );
+ zSql = recoverMPrintf(p, "%z_rowid_", zSql);
+ if( bSql ){
+ zBind = recoverMPrintf(p, "%zquote(?%d)", zBind, pTab->iRowidBind);
+ }else{
+ zBind = recoverMPrintf(p, "%z?%d", zBind, pTab->iRowidBind);
+ }
+ zSqlSep = "||', '||";
+ zSep = ", ";
+ }
+
+ for(ii=0; ii<nField; ii++){
+ int eHidden = pTab->aCol[ii].eHidden;
+ if( eHidden!=RECOVER_EHIDDEN_VIRTUAL
+ && eHidden!=RECOVER_EHIDDEN_STORED
+ ){
+ assert( pTab->aCol[ii].iField>=0 && pTab->aCol[ii].iBind>=1 );
+ zSql = recoverMPrintf(p, "%z%s%Q", zSql, zSep, pTab->aCol[ii].zCol);
+
+ if( bSql ){
+ zBind = recoverMPrintf(p,
+ "%z%sescape_crnl(quote(?%d))", zBind, zSqlSep, pTab->aCol[ii].iBind
+ );
+ zSqlSep = "||', '||";
+ }else{
+ zBind = recoverMPrintf(p, "%z%s?%d", zBind, zSep, pTab->aCol[ii].iBind);
+ }
+ zSep = ", ";
+ }
+ }
+
+ if( bSql ){
+ zFinal = recoverMPrintf(p, "SELECT %Q || ') VALUES (' || %s || ')'",
+ zSql, zBind
+ );
+ }else{
+ zFinal = recoverMPrintf(p, "%s) VALUES (%s)", zSql, zBind);
+ }
+
+ pRet = recoverPrepare(p, p->dbOut, zFinal);
+ sqlite3_free(zSql);
+ sqlite3_free(zBind);
+ sqlite3_free(zFinal);
+
+ return pRet;
+}
+
+
+/*
+** Search the list of RecoverTable objects at p->pTblList for one that
+** has root page iRoot in the input database. If such an object is found,
+** return a pointer to it. Otherwise, return NULL.
+*/
+static RecoverTable *recoverFindTable(sqlite3_recover *p, u32 iRoot){
+ RecoverTable *pRet = 0;
+ for(pRet=p->pTblList; pRet && pRet->iRoot!=iRoot; pRet=pRet->pNext);
+ return pRet;
+}
+
+/*
+** This function attempts to create a lost and found table within the
+** output db. If successful, it returns a pointer to a buffer containing
+** the name of the new table. It is the responsibility of the caller to
+** eventually free this buffer using sqlite3_free().
+**
+** If an error occurs, NULL is returned and an error code and error
+** message left in the recover handle.
+*/
+static char *recoverLostAndFoundCreate(
+ sqlite3_recover *p, /* Recover object */
+ int nField /* Number of column fields in new table */
+){
+ char *zTbl = 0;
+ sqlite3_stmt *pProbe = 0;
+ int ii = 0;
+
+ pProbe = recoverPrepare(p, p->dbOut,
+ "SELECT 1 FROM sqlite_schema WHERE name=?"
+ );
+ for(ii=-1; zTbl==0 && p->errCode==SQLITE_OK && ii<1000; ii++){
+ int bFail = 0;
+ if( ii<0 ){
+ zTbl = recoverMPrintf(p, "%s", p->zLostAndFound);
+ }else{
+ zTbl = recoverMPrintf(p, "%s_%d", p->zLostAndFound, ii);
+ }
+
+ if( p->errCode==SQLITE_OK ){
+ sqlite3_bind_text(pProbe, 1, zTbl, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pProbe) ){
+ bFail = 1;
+ }
+ recoverReset(p, pProbe);
+ }
+
+ if( bFail ){
+ sqlite3_clear_bindings(pProbe);
+ sqlite3_free(zTbl);
+ zTbl = 0;
+ }
+ }
+ recoverFinalize(p, pProbe);
+
+ if( zTbl ){
+ const char *zSep = 0;
+ char *zField = 0;
+ char *zSql = 0;
+
+ zSep = "rootpgno INTEGER, pgno INTEGER, nfield INTEGER, id INTEGER, ";
+ for(ii=0; p->errCode==SQLITE_OK && ii<nField; ii++){
+ zField = recoverMPrintf(p, "%z%sc%d", zField, zSep, ii);
+ zSep = ", ";
+ }
+
+ zSql = recoverMPrintf(p, "CREATE TABLE %s(%s)", zTbl, zField);
+ sqlite3_free(zField);
+
+ recoverExec(p, p->dbOut, zSql);
+ recoverSqlCallback(p, zSql);
+ sqlite3_free(zSql);
+ }else if( p->errCode==SQLITE_OK ){
+ recoverError(
+ p, SQLITE_ERROR, "failed to create %s output table", p->zLostAndFound
+ );
+ }
+
+ return zTbl;
+}
+
+/*
+** Synthesize and prepare an INSERT statement to write to the lost_and_found
+** table in the output database. The name of the table is zTab, and it has
+** nField c* fields.
+*/
+static sqlite3_stmt *recoverLostAndFoundInsert(
+ sqlite3_recover *p,
+ const char *zTab,
+ int nField
+){
+ int nTotal = nField + 4;
+ int ii;
+ char *zBind = 0;
+ sqlite3_stmt *pRet = 0;
+
+ if( p->xSql==0 ){
+ for(ii=0; ii<nTotal; ii++){
+ zBind = recoverMPrintf(p, "%z%s?", zBind, zBind?", ":"", ii);
+ }
+ pRet = recoverPreparePrintf(
+ p, p->dbOut, "INSERT INTO %s VALUES(%s)", zTab, zBind
+ );
+ }else{
+ const char *zSep = "";
+ for(ii=0; ii<nTotal; ii++){
+ zBind = recoverMPrintf(p, "%z%squote(?)", zBind, zSep);
+ zSep = "|| ', ' ||";
+ }
+ pRet = recoverPreparePrintf(
+ p, p->dbOut, "SELECT 'INSERT INTO %s VALUES(' || %s || ')'", zTab, zBind
+ );
+ }
+
+ sqlite3_free(zBind);
+ return pRet;
+}
+
+/*
+** Input database page iPg contains data that will be written to the
+** lost-and-found table of the output database. This function attempts
+** to identify the root page of the tree that page iPg belonged to.
+** If successful, it sets output variable (*piRoot) to the page number
+** of the root page and returns SQLITE_OK. Otherwise, if an error occurs,
+** an SQLite error code is returned and the final value of *piRoot
+** undefined.
+*/
+static int recoverLostAndFoundFindRoot(
+ sqlite3_recover *p,
+ i64 iPg,
+ i64 *piRoot
+){
+ RecoverStateLAF *pLaf = &p->laf;
+
+ if( pLaf->pFindRoot==0 ){
+ pLaf->pFindRoot = recoverPrepare(p, p->dbOut,
+ "WITH RECURSIVE p(pgno) AS ("
+ " SELECT ?"
+ " UNION"
+ " SELECT parent FROM recovery.map AS m, p WHERE m.pgno=p.pgno"
+ ") "
+ "SELECT p.pgno FROM p, recovery.map m WHERE m.pgno=p.pgno "
+ " AND m.parent IS NULL"
+ );
+ }
+ if( p->errCode==SQLITE_OK ){
+ sqlite3_bind_int64(pLaf->pFindRoot, 1, iPg);
+ if( sqlite3_step(pLaf->pFindRoot)==SQLITE_ROW ){
+ *piRoot = sqlite3_column_int64(pLaf->pFindRoot, 0);
+ }else{
+ *piRoot = iPg;
+ }
+ recoverReset(p, pLaf->pFindRoot);
+ }
+ return p->errCode;
+}
+
+/*
+** Recover data from page iPage of the input database and write it to
+** the lost-and-found table in the output database.
+*/
+static void recoverLostAndFoundOnePage(sqlite3_recover *p, i64 iPage){
+ RecoverStateLAF *pLaf = &p->laf;
+ sqlite3_value **apVal = pLaf->apVal;
+ sqlite3_stmt *pPageData = pLaf->pPageData;
+ sqlite3_stmt *pInsert = pLaf->pInsert;
+
+ int nVal = -1;
+ int iPrevCell = 0;
+ i64 iRoot = 0;
+ int bHaveRowid = 0;
+ i64 iRowid = 0;
+ int ii = 0;
+
+ if( recoverLostAndFoundFindRoot(p, iPage, &iRoot) ) return;
+ sqlite3_bind_int64(pPageData, 1, iPage);
+ while( p->errCode==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPageData) ){
+ int iCell = sqlite3_column_int64(pPageData, 0);
+ int iField = sqlite3_column_int64(pPageData, 1);
+
+ if( iPrevCell!=iCell && nVal>=0 ){
+ /* Insert the new row */
+ sqlite3_bind_int64(pInsert, 1, iRoot); /* rootpgno */
+ sqlite3_bind_int64(pInsert, 2, iPage); /* pgno */
+ sqlite3_bind_int(pInsert, 3, nVal); /* nfield */
+ if( bHaveRowid ){
+ sqlite3_bind_int64(pInsert, 4, iRowid); /* id */
+ }
+ for(ii=0; ii<nVal; ii++){
+ recoverBindValue(p, pInsert, 5+ii, apVal[ii]);
+ }
+ if( sqlite3_step(pInsert)==SQLITE_ROW ){
+ recoverSqlCallback(p, (const char*)sqlite3_column_text(pInsert, 0));
+ }
+ recoverReset(p, pInsert);
+
+ /* Discard the accumulated row data */
+ for(ii=0; ii<nVal; ii++){
+ sqlite3_value_free(apVal[ii]);
+ apVal[ii] = 0;
+ }
+ sqlite3_clear_bindings(pInsert);
+ bHaveRowid = 0;
+ nVal = -1;
+ }
+
+ if( iCell<0 ) break;
+
+ if( iField<0 ){
+ assert( nVal==-1 );
+ iRowid = sqlite3_column_int64(pPageData, 2);
+ bHaveRowid = 1;
+ nVal = 0;
+ }else if( iField<pLaf->nMaxField ){
+ sqlite3_value *pVal = sqlite3_column_value(pPageData, 2);
+ apVal[iField] = sqlite3_value_dup(pVal);
+ assert( iField==nVal || (nVal==-1 && iField==0) );
+ nVal = iField+1;
+ if( apVal[iField]==0 ){
+ recoverError(p, SQLITE_NOMEM, 0);
+ }
+ }
+
+ iPrevCell = iCell;
+ }
+ recoverReset(p, pPageData);
+
+ for(ii=0; ii<nVal; ii++){
+ sqlite3_value_free(apVal[ii]);
+ apVal[ii] = 0;
+ }
+}
+
+/*
+** Perform one step (sqlite3_recover_step()) of work for the connection
+** passed as the only argument, which is guaranteed to be in
+** RECOVER_STATE_LOSTANDFOUND3 state - during which the lost-and-found
+** table of the output database is populated with recovered data that can
+** not be assigned to any recovered schema object.
+*/
+static int recoverLostAndFound3Step(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+ if( p->errCode==SQLITE_OK ){
+ if( pLaf->pInsert==0 ){
+ return SQLITE_DONE;
+ }else{
+ if( p->errCode==SQLITE_OK ){
+ int res = sqlite3_step(pLaf->pAllPage);
+ if( res==SQLITE_ROW ){
+ i64 iPage = sqlite3_column_int64(pLaf->pAllPage, 0);
+ if( recoverBitmapQuery(pLaf->pUsed, iPage)==0 ){
+ recoverLostAndFoundOnePage(p, iPage);
+ }
+ }else{
+ recoverReset(p, pLaf->pAllPage);
+ return SQLITE_DONE;
+ }
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Initialize resources required in RECOVER_STATE_LOSTANDFOUND3
+** state - during which the lost-and-found table of the output database
+** is populated with recovered data that can not be assigned to any
+** recovered schema object.
+*/
+static void recoverLostAndFound3Init(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+
+ if( pLaf->nMaxField>0 ){
+ char *zTab = 0; /* Name of lost_and_found table */
+
+ zTab = recoverLostAndFoundCreate(p, pLaf->nMaxField);
+ pLaf->pInsert = recoverLostAndFoundInsert(p, zTab, pLaf->nMaxField);
+ sqlite3_free(zTab);
+
+ pLaf->pAllPage = recoverPreparePrintf(p, p->dbOut,
+ "WITH RECURSIVE seq(ii) AS ("
+ " SELECT 1 UNION ALL SELECT ii+1 FROM seq WHERE ii<%lld"
+ ")"
+ "SELECT ii FROM seq" , p->laf.nPg
+ );
+ pLaf->pPageData = recoverPrepare(p, p->dbOut,
+ "SELECT cell, field, value "
+ "FROM sqlite_dbdata('getpage()') d WHERE d.pgno=? "
+ "UNION ALL "
+ "SELECT -1, -1, -1"
+ );
+
+ pLaf->apVal = (sqlite3_value**)recoverMalloc(p,
+ pLaf->nMaxField*sizeof(sqlite3_value*)
+ );
+ }
+}
+
+/*
+** Initialize resources required in RECOVER_STATE_WRITING state - during which
+** tables recovered from the schema of the input database are populated with
+** recovered data.
+*/
+static int recoverWriteDataInit(sqlite3_recover *p){
+ RecoverStateW1 *p1 = &p->w1;
+ RecoverTable *pTbl = 0;
+ int nByte = 0;
+
+ /* Figure out the maximum number of columns for any table in the schema */
+ assert( p1->nMax==0 );
+ for(pTbl=p->pTblList; pTbl; pTbl=pTbl->pNext){
+ if( pTbl->nCol>p1->nMax ) p1->nMax = pTbl->nCol;
+ }
+
+ /* Allocate an array of (sqlite3_value*) in which to accumulate the values
+ ** that will be written to the output database in a single row. */
+ nByte = sizeof(sqlite3_value*) * (p1->nMax+1);
+ p1->apVal = (sqlite3_value**)recoverMalloc(p, nByte);
+ if( p1->apVal==0 ) return p->errCode;
+
+ /* Prepare the SELECT to loop through schema tables (pTbls) and the SELECT
+ ** to loop through cells that appear to belong to a single table (pSel). */
+ p1->pTbls = recoverPrepare(p, p->dbOut,
+ "SELECT rootpage FROM recovery.schema "
+ " WHERE type='table' AND (sql NOT LIKE 'create virtual%')"
+ " ORDER BY (tbl_name='sqlite_sequence') ASC"
+ );
+ p1->pSel = recoverPrepare(p, p->dbOut,
+ "WITH RECURSIVE pages(page) AS ("
+ " SELECT ?1"
+ " UNION"
+ " SELECT child FROM sqlite_dbptr('getpage()'), pages "
+ " WHERE pgno=page"
+ ") "
+ "SELECT page, cell, field, value "
+ "FROM sqlite_dbdata('getpage()') d, pages p WHERE p.page=d.pgno "
+ "UNION ALL "
+ "SELECT 0, 0, 0, 0"
+ );
+
+ return p->errCode;
+}
+
+/*
+** Clean up resources allocated by recoverWriteDataInit() (stuff in
+** sqlite3_recover.w1).
+*/
+static void recoverWriteDataCleanup(sqlite3_recover *p){
+ RecoverStateW1 *p1 = &p->w1;
+ int ii;
+ for(ii=0; ii<p1->nVal; ii++){
+ sqlite3_value_free(p1->apVal[ii]);
+ }
+ sqlite3_free(p1->apVal);
+ recoverFinalize(p, p1->pInsert);
+ recoverFinalize(p, p1->pTbls);
+ recoverFinalize(p, p1->pSel);
+ memset(p1, 0, sizeof(*p1));
+}
+
+/*
+** Perform one step (sqlite3_recover_step()) of work for the connection
+** passed as the only argument, which is guaranteed to be in
+** RECOVER_STATE_WRITING state - during which tables recovered from the
+** schema of the input database are populated with recovered data.
+*/
+static int recoverWriteDataStep(sqlite3_recover *p){
+ RecoverStateW1 *p1 = &p->w1;
+ sqlite3_stmt *pSel = p1->pSel;
+ sqlite3_value **apVal = p1->apVal;
+
+ if( p->errCode==SQLITE_OK && p1->pTab==0 ){
+ if( sqlite3_step(p1->pTbls)==SQLITE_ROW ){
+ i64 iRoot = sqlite3_column_int64(p1->pTbls, 0);
+ p1->pTab = recoverFindTable(p, iRoot);
+
+ recoverFinalize(p, p1->pInsert);
+ p1->pInsert = 0;
+
+ /* If this table is unknown, return early. The caller will invoke this
+ ** function again and it will move on to the next table. */
+ if( p1->pTab==0 ) return p->errCode;
+
+ /* If this is the sqlite_sequence table, delete any rows added by
+ ** earlier INSERT statements on tables with AUTOINCREMENT primary
+ ** keys before recovering its contents. The p1->pTbls SELECT statement
+ ** is rigged to deliver "sqlite_sequence" last of all, so we don't
+ ** worry about it being modified after it is recovered. */
+ if( sqlite3_stricmp("sqlite_sequence", p1->pTab->zTab)==0 ){
+ recoverExec(p, p->dbOut, "DELETE FROM sqlite_sequence");
+ recoverSqlCallback(p, "DELETE FROM sqlite_sequence");
+ }
+
+ /* Bind the root page of this table within the original database to
+ ** SELECT statement p1->pSel. The SELECT statement will then iterate
+ ** through cells that look like they belong to table pTab. */
+ sqlite3_bind_int64(pSel, 1, iRoot);
+
+ p1->nVal = 0;
+ p1->bHaveRowid = 0;
+ p1->iPrevPage = -1;
+ p1->iPrevCell = -1;
+ }else{
+ return SQLITE_DONE;
+ }
+ }
+ assert( p->errCode!=SQLITE_OK || p1->pTab );
+
+ if( p->errCode==SQLITE_OK && sqlite3_step(pSel)==SQLITE_ROW ){
+ RecoverTable *pTab = p1->pTab;
+
+ i64 iPage = sqlite3_column_int64(pSel, 0);
+ int iCell = sqlite3_column_int(pSel, 1);
+ int iField = sqlite3_column_int(pSel, 2);
+ sqlite3_value *pVal = sqlite3_column_value(pSel, 3);
+ int bNewCell = (p1->iPrevPage!=iPage || p1->iPrevCell!=iCell);
+
+ assert( bNewCell==0 || (iField==-1 || iField==0) );
+ assert( bNewCell || iField==p1->nVal || p1->nVal==pTab->nCol );
+
+ if( bNewCell ){
+ int ii = 0;
+ if( p1->nVal>=0 ){
+ if( p1->pInsert==0 || p1->nVal!=p1->nInsert ){
+ recoverFinalize(p, p1->pInsert);
+ p1->pInsert = recoverInsertStmt(p, pTab, p1->nVal);
+ p1->nInsert = p1->nVal;
+ }
+ if( p1->nVal>0 ){
+ sqlite3_stmt *pInsert = p1->pInsert;
+ for(ii=0; ii<pTab->nCol; ii++){
+ RecoverColumn *pCol = &pTab->aCol[ii];
+ int iBind = pCol->iBind;
+ if( iBind>0 ){
+ if( pCol->bIPK ){
+ sqlite3_bind_int64(pInsert, iBind, p1->iRowid);
+ }else if( pCol->iField<p1->nVal ){
+ recoverBindValue(p, pInsert, iBind, apVal[pCol->iField]);
+ }
+ }
+ }
+ if( p->bRecoverRowid && pTab->iRowidBind>0 && p1->bHaveRowid ){
+ sqlite3_bind_int64(pInsert, pTab->iRowidBind, p1->iRowid);
+ }
+ if( SQLITE_ROW==sqlite3_step(pInsert) ){
+ const char *z = (const char*)sqlite3_column_text(pInsert, 0);
+ recoverSqlCallback(p, z);
+ }
+ recoverReset(p, pInsert);
+ assert( p->errCode || pInsert );
+ if( pInsert ) sqlite3_clear_bindings(pInsert);
+ }
+ }
+
+ for(ii=0; ii<p1->nVal; ii++){
+ sqlite3_value_free(apVal[ii]);
+ apVal[ii] = 0;
+ }
+ p1->nVal = -1;
+ p1->bHaveRowid = 0;
+ }
+
+ if( iPage!=0 ){
+ if( iField<0 ){
+ p1->iRowid = sqlite3_column_int64(pSel, 3);
+ assert( p1->nVal==-1 );
+ p1->nVal = 0;
+ p1->bHaveRowid = 1;
+ }else if( iField<pTab->nCol ){
+ assert( apVal[iField]==0 );
+ apVal[iField] = sqlite3_value_dup( pVal );
+ if( apVal[iField]==0 ){
+ recoverError(p, SQLITE_NOMEM, 0);
+ }
+ p1->nVal = iField+1;
+ }
+ p1->iPrevCell = iCell;
+ p1->iPrevPage = iPage;
+ }
+ }else{
+ recoverReset(p, pSel);
+ p1->pTab = 0;
+ }
+
+ return p->errCode;
+}
+
+/*
+** Initialize resources required by sqlite3_recover_step() in
+** RECOVER_STATE_LOSTANDFOUND1 state - during which the set of pages not
+** already allocated to a recovered schema element is determined.
+*/
+static void recoverLostAndFound1Init(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+ sqlite3_stmt *pStmt = 0;
+
+ assert( p->laf.pUsed==0 );
+ pLaf->nPg = recoverPageCount(p);
+ pLaf->pUsed = recoverBitmapAlloc(p, pLaf->nPg);
+
+ /* Prepare a statement to iterate through all pages that are part of any tree
+ ** in the recoverable part of the input database schema to the bitmap. And,
+ ** if !p->bFreelistCorrupt, add all pages that appear to be part of the
+ ** freelist. */
+ pStmt = recoverPrepare(
+ p, p->dbOut,
+ "WITH trunk(pgno) AS ("
+ " SELECT read_i32(getpage(1), 8) AS x WHERE x>0"
+ " UNION"
+ " SELECT read_i32(getpage(trunk.pgno), 0) AS x FROM trunk WHERE x>0"
+ "),"
+ "trunkdata(pgno, data) AS ("
+ " SELECT pgno, getpage(pgno) FROM trunk"
+ "),"
+ "freelist(data, n, freepgno) AS ("
+ " SELECT data, min(16384, read_i32(data, 1)-1), pgno FROM trunkdata"
+ " UNION ALL"
+ " SELECT data, n-1, read_i32(data, 2+n) FROM freelist WHERE n>=0"
+ "),"
+ ""
+ "roots(r) AS ("
+ " SELECT 1 UNION ALL"
+ " SELECT rootpage FROM recovery.schema WHERE rootpage>0"
+ "),"
+ "used(page) AS ("
+ " SELECT r FROM roots"
+ " UNION"
+ " SELECT child FROM sqlite_dbptr('getpage()'), used "
+ " WHERE pgno=page"
+ ") "
+ "SELECT page FROM used"
+ " UNION ALL "
+ "SELECT freepgno FROM freelist WHERE NOT ?"
+ );
+ if( pStmt ) sqlite3_bind_int(pStmt, 1, p->bFreelistCorrupt);
+ pLaf->pUsedPages = pStmt;
+}
+
+/*
+** Perform one step (sqlite3_recover_step()) of work for the connection
+** passed as the only argument, which is guaranteed to be in
+** RECOVER_STATE_LOSTANDFOUND1 state - during which the set of pages not
+** already allocated to a recovered schema element is determined.
+*/
+static int recoverLostAndFound1Step(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+ int rc = p->errCode;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_step(pLaf->pUsedPages);
+ if( rc==SQLITE_ROW ){
+ i64 iPg = sqlite3_column_int64(pLaf->pUsedPages, 0);
+ recoverBitmapSet(pLaf->pUsed, iPg);
+ rc = SQLITE_OK;
+ }else{
+ recoverFinalize(p, pLaf->pUsedPages);
+ pLaf->pUsedPages = 0;
+ }
+ }
+ return rc;
+}
+
+/*
+** Initialize resources required by RECOVER_STATE_LOSTANDFOUND2
+** state - during which the pages identified in RECOVER_STATE_LOSTANDFOUND1
+** are sorted into sets that likely belonged to the same database tree.
+*/
+static void recoverLostAndFound2Init(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+
+ assert( p->laf.pAllAndParent==0 );
+ assert( p->laf.pMapInsert==0 );
+ assert( p->laf.pMaxField==0 );
+ assert( p->laf.nMaxField==0 );
+
+ pLaf->pMapInsert = recoverPrepare(p, p->dbOut,
+ "INSERT OR IGNORE INTO recovery.map(pgno, parent) VALUES(?, ?)"
+ );
+ pLaf->pAllAndParent = recoverPreparePrintf(p, p->dbOut,
+ "WITH RECURSIVE seq(ii) AS ("
+ " SELECT 1 UNION ALL SELECT ii+1 FROM seq WHERE ii<%lld"
+ ")"
+ "SELECT pgno, child FROM sqlite_dbptr('getpage()') "
+ " UNION ALL "
+ "SELECT NULL, ii FROM seq", p->laf.nPg
+ );
+ pLaf->pMaxField = recoverPreparePrintf(p, p->dbOut,
+ "SELECT max(field)+1 FROM sqlite_dbdata('getpage') WHERE pgno = ?"
+ );
+}
+
+/*
+** Perform one step (sqlite3_recover_step()) of work for the connection
+** passed as the only argument, which is guaranteed to be in
+** RECOVER_STATE_LOSTANDFOUND2 state - during which the pages identified
+** in RECOVER_STATE_LOSTANDFOUND1 are sorted into sets that likely belonged
+** to the same database tree.
+*/
+static int recoverLostAndFound2Step(sqlite3_recover *p){
+ RecoverStateLAF *pLaf = &p->laf;
+ if( p->errCode==SQLITE_OK ){
+ int res = sqlite3_step(pLaf->pAllAndParent);
+ if( res==SQLITE_ROW ){
+ i64 iChild = sqlite3_column_int(pLaf->pAllAndParent, 1);
+ if( recoverBitmapQuery(pLaf->pUsed, iChild)==0 ){
+ sqlite3_bind_int64(pLaf->pMapInsert, 1, iChild);
+ sqlite3_bind_value(pLaf->pMapInsert, 2,
+ sqlite3_column_value(pLaf->pAllAndParent, 0)
+ );
+ sqlite3_step(pLaf->pMapInsert);
+ recoverReset(p, pLaf->pMapInsert);
+ sqlite3_bind_int64(pLaf->pMaxField, 1, iChild);
+ if( SQLITE_ROW==sqlite3_step(pLaf->pMaxField) ){
+ int nMax = sqlite3_column_int(pLaf->pMaxField, 0);
+ if( nMax>pLaf->nMaxField ) pLaf->nMaxField = nMax;
+ }
+ recoverReset(p, pLaf->pMaxField);
+ }
+ }else{
+ recoverFinalize(p, pLaf->pAllAndParent);
+ pLaf->pAllAndParent =0;
+ return SQLITE_DONE;
+ }
+ }
+ return p->errCode;
+}
+
+/*
+** Free all resources allocated as part of sqlite3_recover_step() calls
+** in one of the RECOVER_STATE_LOSTANDFOUND[123] states.
+*/
+static void recoverLostAndFoundCleanup(sqlite3_recover *p){
+ recoverBitmapFree(p->laf.pUsed);
+ p->laf.pUsed = 0;
+ sqlite3_finalize(p->laf.pUsedPages);
+ sqlite3_finalize(p->laf.pAllAndParent);
+ sqlite3_finalize(p->laf.pMapInsert);
+ sqlite3_finalize(p->laf.pMaxField);
+ sqlite3_finalize(p->laf.pFindRoot);
+ sqlite3_finalize(p->laf.pInsert);
+ sqlite3_finalize(p->laf.pAllPage);
+ sqlite3_finalize(p->laf.pPageData);
+ p->laf.pUsedPages = 0;
+ p->laf.pAllAndParent = 0;
+ p->laf.pMapInsert = 0;
+ p->laf.pMaxField = 0;
+ p->laf.pFindRoot = 0;
+ p->laf.pInsert = 0;
+ p->laf.pAllPage = 0;
+ p->laf.pPageData = 0;
+ sqlite3_free(p->laf.apVal);
+ p->laf.apVal = 0;
+}
+
+/*
+** Free all resources allocated as part of sqlite3_recover_step() calls.
+*/
+static void recoverFinalCleanup(sqlite3_recover *p){
+ RecoverTable *pTab = 0;
+ RecoverTable *pNext = 0;
+
+ recoverWriteDataCleanup(p);
+ recoverLostAndFoundCleanup(p);
+
+ for(pTab=p->pTblList; pTab; pTab=pNext){
+ pNext = pTab->pNext;
+ sqlite3_free(pTab);
+ }
+ p->pTblList = 0;
+ sqlite3_finalize(p->pGetPage);
+ p->pGetPage = 0;
+
+ {
+#ifndef NDEBUG
+ int res =
+#endif
+ sqlite3_close(p->dbOut);
+ assert( res==SQLITE_OK );
+ }
+ p->dbOut = 0;
+}
+
+/*
+** Decode and return an unsigned 16-bit big-endian integer value from
+** buffer a[].
+*/
+static u32 recoverGetU16(const u8 *a){
+ return (((u32)a[0])<<8) + ((u32)a[1]);
+}
+
+/*
+** Decode and return an unsigned 32-bit big-endian integer value from
+** buffer a[].
+*/
+static u32 recoverGetU32(const u8 *a){
+ return (((u32)a[0])<<24) + (((u32)a[1])<<16) + (((u32)a[2])<<8) + ((u32)a[3]);
+}
+
+/*
+** Decode an SQLite varint from buffer a[]. Write the decoded value to (*pVal)
+** and return the number of bytes consumed.
+*/
+static int recoverGetVarint(const u8 *a, i64 *pVal){
+ sqlite3_uint64 u = 0;
+ int i;
+ for(i=0; i<8; i++){
+ u = (u<<7) + (a[i]&0x7f);
+ if( (a[i]&0x80)==0 ){ *pVal = (sqlite3_int64)u; return i+1; }
+ }
+ u = (u<<8) + (a[i]&0xff);
+ *pVal = (sqlite3_int64)u;
+ return 9;
+}
+
+/*
+** The second argument points to a buffer n bytes in size. If this buffer
+** or a prefix thereof appears to contain a well-formed SQLite b-tree page,
+** return the page-size in bytes. Otherwise, if the buffer does not
+** appear to contain a well-formed b-tree page, return 0.
+*/
+static int recoverIsValidPage(u8 *aTmp, const u8 *a, int n){
+ u8 *aUsed = aTmp;
+ int nFrag = 0;
+ int nActual = 0;
+ int iFree = 0;
+ int nCell = 0; /* Number of cells on page */
+ int iCellOff = 0; /* Offset of cell array in page */
+ int iContent = 0;
+ int eType = 0;
+ int ii = 0;
+
+ eType = (int)a[0];
+ if( eType!=0x02 && eType!=0x05 && eType!=0x0A && eType!=0x0D ) return 0;
+
+ iFree = (int)recoverGetU16(&a[1]);
+ nCell = (int)recoverGetU16(&a[3]);
+ iContent = (int)recoverGetU16(&a[5]);
+ if( iContent==0 ) iContent = 65536;
+ nFrag = (int)a[7];
+
+ if( iContent>n ) return 0;
+
+ memset(aUsed, 0, n);
+ memset(aUsed, 0xFF, iContent);
+
+ /* Follow the free-list. This is the same format for all b-tree pages. */
+ if( iFree && iFree<=iContent ) return 0;
+ while( iFree ){
+ int iNext = 0;
+ int nByte = 0;
+ if( iFree>(n-4) ) return 0;
+ iNext = recoverGetU16(&a[iFree]);
+ nByte = recoverGetU16(&a[iFree+2]);
+ if( iFree+nByte>n ) return 0;
+ if( iNext && iNext<iFree+nByte ) return 0;
+ memset(&aUsed[iFree], 0xFF, nByte);
+ iFree = iNext;
+ }
+
+ /* Run through the cells */
+ if( eType==0x02 || eType==0x05 ){
+ iCellOff = 12;
+ }else{
+ iCellOff = 8;
+ }
+ if( (iCellOff + 2*nCell)>iContent ) return 0;
+ for(ii=0; ii<nCell; ii++){
+ int iByte;
+ i64 nPayload = 0;
+ int nByte = 0;
+ int iOff = recoverGetU16(&a[iCellOff + 2*ii]);
+ if( iOff<iContent || iOff>n ){
+ return 0;
+ }
+ if( eType==0x05 || eType==0x02 ) nByte += 4;
+ nByte += recoverGetVarint(&a[iOff+nByte], &nPayload);
+ if( eType==0x0D ){
+ i64 dummy = 0;
+ nByte += recoverGetVarint(&a[iOff+nByte], &dummy);
+ }
+ if( eType!=0x05 ){
+ int X = (eType==0x0D) ? n-35 : (((n-12)*64/255)-23);
+ int M = ((n-12)*32/255)-23;
+ int K = M+((nPayload-M)%(n-4));
+
+ if( nPayload<X ){
+ nByte += nPayload;
+ }else if( K<=X ){
+ nByte += K+4;
+ }else{
+ nByte += M+4;
+ }
+ }
+
+ if( iOff+nByte>n ){
+ return 0;
+ }
+ for(iByte=iOff; iByte<(iOff+nByte); iByte++){
+ if( aUsed[iByte]!=0 ){
+ return 0;
+ }
+ aUsed[iByte] = 0xFF;
+ }
+ }
+
+ nActual = 0;
+ for(ii=0; ii<n; ii++){
+ if( aUsed[ii]==0 ) nActual++;
+ }
+ return (nActual==nFrag);
+}
+
+
+static int recoverVfsClose(sqlite3_file*);
+static int recoverVfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int recoverVfsWrite(sqlite3_file*, const void*, int, sqlite3_int64);
+static int recoverVfsTruncate(sqlite3_file*, sqlite3_int64 size);
+static int recoverVfsSync(sqlite3_file*, int flags);
+static int recoverVfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int recoverVfsLock(sqlite3_file*, int);
+static int recoverVfsUnlock(sqlite3_file*, int);
+static int recoverVfsCheckReservedLock(sqlite3_file*, int *pResOut);
+static int recoverVfsFileControl(sqlite3_file*, int op, void *pArg);
+static int recoverVfsSectorSize(sqlite3_file*);
+static int recoverVfsDeviceCharacteristics(sqlite3_file*);
+static int recoverVfsShmMap(sqlite3_file*, int, int, int, void volatile**);
+static int recoverVfsShmLock(sqlite3_file*, int offset, int n, int flags);
+static void recoverVfsShmBarrier(sqlite3_file*);
+static int recoverVfsShmUnmap(sqlite3_file*, int deleteFlag);
+static int recoverVfsFetch(sqlite3_file*, sqlite3_int64, int, void**);
+static int recoverVfsUnfetch(sqlite3_file *pFd, sqlite3_int64 iOff, void *p);
+
+static sqlite3_io_methods recover_methods = {
+ 2, /* iVersion */
+ recoverVfsClose,
+ recoverVfsRead,
+ recoverVfsWrite,
+ recoverVfsTruncate,
+ recoverVfsSync,
+ recoverVfsFileSize,
+ recoverVfsLock,
+ recoverVfsUnlock,
+ recoverVfsCheckReservedLock,
+ recoverVfsFileControl,
+ recoverVfsSectorSize,
+ recoverVfsDeviceCharacteristics,
+ recoverVfsShmMap,
+ recoverVfsShmLock,
+ recoverVfsShmBarrier,
+ recoverVfsShmUnmap,
+ recoverVfsFetch,
+ recoverVfsUnfetch
+};
+
+static int recoverVfsClose(sqlite3_file *pFd){
+ assert( pFd->pMethods!=&recover_methods );
+ return pFd->pMethods->xClose(pFd);
+}
+
+/*
+** Write value v to buffer a[] as a 16-bit big-endian unsigned integer.
+*/
+static void recoverPutU16(u8 *a, u32 v){
+ a[0] = (v>>8) & 0x00FF;
+ a[1] = (v>>0) & 0x00FF;
+}
+
+/*
+** Write value v to buffer a[] as a 32-bit big-endian unsigned integer.
+*/
+static void recoverPutU32(u8 *a, u32 v){
+ a[0] = (v>>24) & 0x00FF;
+ a[1] = (v>>16) & 0x00FF;
+ a[2] = (v>>8) & 0x00FF;
+ a[3] = (v>>0) & 0x00FF;
+}
+
+/*
+** Detect the page-size of the database opened by file-handle pFd by
+** searching the first part of the file for a well-formed SQLite b-tree
+** page. If parameter nReserve is non-zero, then as well as searching for
+** a b-tree page with zero reserved bytes, this function searches for one
+** with nReserve reserved bytes at the end of it.
+**
+** If successful, set variable p->detected_pgsz to the detected page-size
+** in bytes and return SQLITE_OK. Or, if no error occurs but no valid page
+** can be found, return SQLITE_OK but leave p->detected_pgsz set to 0. Or,
+** if an error occurs (e.g. an IO or OOM error), then an SQLite error code
+** is returned. The final value of p->detected_pgsz is undefined in this
+** case.
+*/
+static int recoverVfsDetectPagesize(
+ sqlite3_recover *p, /* Recover handle */
+ sqlite3_file *pFd, /* File-handle open on input database */
+ u32 nReserve, /* Possible nReserve value */
+ i64 nSz /* Size of database file in bytes */
+){
+ int rc = SQLITE_OK;
+ const int nMin = 512;
+ const int nMax = 65536;
+ const int nMaxBlk = 4;
+ u32 pgsz = 0;
+ int iBlk = 0;
+ u8 *aPg = 0;
+ u8 *aTmp = 0;
+ int nBlk = 0;
+
+ aPg = (u8*)sqlite3_malloc(2*nMax);
+ if( aPg==0 ) return SQLITE_NOMEM;
+ aTmp = &aPg[nMax];
+
+ nBlk = (nSz+nMax-1)/nMax;
+ if( nBlk>nMaxBlk ) nBlk = nMaxBlk;
+
+ do {
+ for(iBlk=0; rc==SQLITE_OK && iBlk<nBlk; iBlk++){
+ int nByte = (nSz>=((iBlk+1)*nMax)) ? nMax : (nSz % nMax);
+ memset(aPg, 0, nMax);
+ rc = pFd->pMethods->xRead(pFd, aPg, nByte, iBlk*nMax);
+ if( rc==SQLITE_OK ){
+ int pgsz2;
+ for(pgsz2=(pgsz ? pgsz*2 : nMin); pgsz2<=nMax; pgsz2=pgsz2*2){
+ int iOff;
+ for(iOff=0; iOff<nMax; iOff+=pgsz2){
+ if( recoverIsValidPage(aTmp, &aPg[iOff], pgsz2-nReserve) ){
+ pgsz = pgsz2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if( pgsz>(u32)p->detected_pgsz ){
+ p->detected_pgsz = pgsz;
+ p->nReserve = nReserve;
+ }
+ if( nReserve==0 ) break;
+ nReserve = 0;
+ }while( 1 );
+
+ p->detected_pgsz = pgsz;
+ sqlite3_free(aPg);
+ return rc;
+}
+
+/*
+** The xRead() method of the wrapper VFS. This is used to intercept calls
+** to read page 1 of the input database.
+*/
+static int recoverVfsRead(sqlite3_file *pFd, void *aBuf, int nByte, i64 iOff){
+ int rc = SQLITE_OK;
+ if( pFd->pMethods==&recover_methods ){
+ pFd->pMethods = recover_g.pMethods;
+ rc = pFd->pMethods->xRead(pFd, aBuf, nByte, iOff);
+ if( nByte==16 ){
+ sqlite3_randomness(16, aBuf);
+ }else
+ if( rc==SQLITE_OK && iOff==0 && nByte>=108 ){
+ /* Ensure that the database has a valid header file. The only fields
+ ** that really matter to recovery are:
+ **
+ ** + Database page size (16-bits at offset 16)
+ ** + Size of db in pages (32-bits at offset 28)
+ ** + Database encoding (32-bits at offset 56)
+ **
+ ** Also preserved are:
+ **
+ ** + first freelist page (32-bits at offset 32)
+ ** + size of freelist (32-bits at offset 36)
+ **
+ ** We also try to preserve the auto-vacuum, incr-value, user-version
+ ** and application-id fields - all 32 bit quantities at offsets
+ ** 52, 60, 64 and 68. All other fields are set to known good values.
+ **
+ ** Byte offset 105 should also contain the page-size as a 16-bit
+ ** integer.
+ */
+ const int aPreserve[] = {32, 36, 52, 60, 64, 68};
+ u8 aHdr[108] = {
+ 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00,
+ 0xFF, 0xFF, 0x01, 0x01, 0x00, 0x40, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x2e, 0x5b, 0x30,
+
+ 0x0D, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00
+ };
+ u8 *a = (u8*)aBuf;
+
+ u32 pgsz = recoverGetU16(&a[16]);
+ u32 nReserve = a[20];
+ u32 enc = recoverGetU32(&a[56]);
+ u32 dbsz = 0;
+ i64 dbFileSize = 0;
+ int ii;
+ sqlite3_recover *p = recover_g.p;
+
+ if( pgsz==0x01 ) pgsz = 65536;
+ rc = pFd->pMethods->xFileSize(pFd, &dbFileSize);
+
+ if( rc==SQLITE_OK && p->detected_pgsz==0 ){
+ rc = recoverVfsDetectPagesize(p, pFd, nReserve, dbFileSize);
+ }
+ if( p->detected_pgsz ){
+ pgsz = p->detected_pgsz;
+ nReserve = p->nReserve;
+ }
+
+ if( pgsz ){
+ dbsz = dbFileSize / pgsz;
+ }
+ if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16BE && enc!=SQLITE_UTF16LE ){
+ enc = SQLITE_UTF8;
+ }
+
+ sqlite3_free(p->pPage1Cache);
+ p->pPage1Cache = 0;
+ p->pPage1Disk = 0;
+
+ p->pgsz = nByte;
+ p->pPage1Cache = (u8*)recoverMalloc(p, nByte*2);
+ if( p->pPage1Cache ){
+ p->pPage1Disk = &p->pPage1Cache[nByte];
+ memcpy(p->pPage1Disk, aBuf, nByte);
+
+ recoverPutU32(&aHdr[28], dbsz);
+ recoverPutU32(&aHdr[56], enc);
+ recoverPutU16(&aHdr[105], pgsz-nReserve);
+ if( pgsz==65536 ) pgsz = 1;
+ recoverPutU16(&aHdr[16], pgsz);
+ aHdr[20] = nReserve;
+ for(ii=0; ii<sizeof(aPreserve)/sizeof(aPreserve[0]); ii++){
+ memcpy(&aHdr[aPreserve[ii]], &a[aPreserve[ii]], 4);
+ }
+ memcpy(aBuf, aHdr, sizeof(aHdr));
+ memset(&((u8*)aBuf)[sizeof(aHdr)], 0, nByte-sizeof(aHdr));
+
+ memcpy(p->pPage1Cache, aBuf, nByte);
+ }else{
+ rc = p->errCode;
+ }
+
+ }
+ pFd->pMethods = &recover_methods;
+ }else{
+ rc = pFd->pMethods->xRead(pFd, aBuf, nByte, iOff);
+ }
+ return rc;
+}
+
+/*
+** Used to make sqlite3_io_methods wrapper methods less verbose.
+*/
+#define RECOVER_VFS_WRAPPER(code) \
+ int rc = SQLITE_OK; \
+ if( pFd->pMethods==&recover_methods ){ \
+ pFd->pMethods = recover_g.pMethods; \
+ rc = code; \
+ pFd->pMethods = &recover_methods; \
+ }else{ \
+ rc = code; \
+ } \
+ return rc;
+
+/*
+** Methods of the wrapper VFS. All methods except for xRead() and xClose()
+** simply uninstall the sqlite3_io_methods wrapper, invoke the equivalent
+** method on the lower level VFS, then reinstall the wrapper before returning.
+** Those that return an integer value use the RECOVER_VFS_WRAPPER macro.
+*/
+static int recoverVfsWrite(
+ sqlite3_file *pFd, const void *aBuf, int nByte, i64 iOff
+){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xWrite(pFd, aBuf, nByte, iOff)
+ );
+}
+static int recoverVfsTruncate(sqlite3_file *pFd, sqlite3_int64 size){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xTruncate(pFd, size)
+ );
+}
+static int recoverVfsSync(sqlite3_file *pFd, int flags){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xSync(pFd, flags)
+ );
+}
+static int recoverVfsFileSize(sqlite3_file *pFd, sqlite3_int64 *pSize){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xFileSize(pFd, pSize)
+ );
+}
+static int recoverVfsLock(sqlite3_file *pFd, int eLock){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xLock(pFd, eLock)
+ );
+}
+static int recoverVfsUnlock(sqlite3_file *pFd, int eLock){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xUnlock(pFd, eLock)
+ );
+}
+static int recoverVfsCheckReservedLock(sqlite3_file *pFd, int *pResOut){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xCheckReservedLock(pFd, pResOut)
+ );
+}
+static int recoverVfsFileControl(sqlite3_file *pFd, int op, void *pArg){
+ RECOVER_VFS_WRAPPER (
+ (pFd->pMethods ? pFd->pMethods->xFileControl(pFd, op, pArg) : SQLITE_NOTFOUND)
+ );
+}
+static int recoverVfsSectorSize(sqlite3_file *pFd){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xSectorSize(pFd)
+ );
+}
+static int recoverVfsDeviceCharacteristics(sqlite3_file *pFd){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xDeviceCharacteristics(pFd)
+ );
+}
+static int recoverVfsShmMap(
+ sqlite3_file *pFd, int iPg, int pgsz, int bExtend, void volatile **pp
+){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xShmMap(pFd, iPg, pgsz, bExtend, pp)
+ );
+}
+static int recoverVfsShmLock(sqlite3_file *pFd, int offset, int n, int flags){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xShmLock(pFd, offset, n, flags)
+ );
+}
+static void recoverVfsShmBarrier(sqlite3_file *pFd){
+ if( pFd->pMethods==&recover_methods ){
+ pFd->pMethods = recover_g.pMethods;
+ pFd->pMethods->xShmBarrier(pFd);
+ pFd->pMethods = &recover_methods;
+ }else{
+ pFd->pMethods->xShmBarrier(pFd);
+ }
+}
+static int recoverVfsShmUnmap(sqlite3_file *pFd, int deleteFlag){
+ RECOVER_VFS_WRAPPER (
+ pFd->pMethods->xShmUnmap(pFd, deleteFlag)
+ );
+}
+
+static int recoverVfsFetch(
+ sqlite3_file *pFd,
+ sqlite3_int64 iOff,
+ int iAmt,
+ void **pp
+){
+ *pp = 0;
+ return SQLITE_OK;
+}
+static int recoverVfsUnfetch(sqlite3_file *pFd, sqlite3_int64 iOff, void *p){
+ return SQLITE_OK;
+}
+
+/*
+** Install the VFS wrapper around the file-descriptor open on the input
+** database for recover handle p. Mutex RECOVER_MUTEX_ID must be held
+** when this function is called.
+*/
+static void recoverInstallWrapper(sqlite3_recover *p){
+ sqlite3_file *pFd = 0;
+ assert( recover_g.pMethods==0 );
+ recoverAssertMutexHeld();
+ sqlite3_file_control(p->dbIn, p->zDb, SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
+ assert( pFd==0 || pFd->pMethods!=&recover_methods );
+ if( pFd && pFd->pMethods ){
+ int iVersion = 1 + (pFd->pMethods->iVersion>1 && pFd->pMethods->xShmMap!=0);
+ recover_g.pMethods = pFd->pMethods;
+ recover_g.p = p;
+ recover_methods.iVersion = iVersion;
+ pFd->pMethods = &recover_methods;
+ }
+}
+
+/*
+** Uninstall the VFS wrapper that was installed around the file-descriptor open
+** on the input database for recover handle p. Mutex RECOVER_MUTEX_ID must be
+** held when this function is called.
+*/
+static void recoverUninstallWrapper(sqlite3_recover *p){
+ sqlite3_file *pFd = 0;
+ recoverAssertMutexHeld();
+ sqlite3_file_control(p->dbIn, p->zDb,SQLITE_FCNTL_FILE_POINTER,(void*)&pFd);
+ if( pFd && pFd->pMethods ){
+ pFd->pMethods = recover_g.pMethods;
+ recover_g.pMethods = 0;
+ recover_g.p = 0;
+ }
+}
+
+/*
+** This function does the work of a single sqlite3_recover_step() call. It
+** is guaranteed that the handle is not in an error state when this
+** function is called.
+*/
+static void recoverStep(sqlite3_recover *p){
+ assert( p && p->errCode==SQLITE_OK );
+ switch( p->eState ){
+ case RECOVER_STATE_INIT:
+ /* This is the very first call to sqlite3_recover_step() on this object.
+ */
+ recoverSqlCallback(p, "BEGIN");
+ recoverSqlCallback(p, "PRAGMA writable_schema = on");
+
+ recoverEnterMutex();
+ recoverInstallWrapper(p);
+
+ /* Open the output database. And register required virtual tables and
+ ** user functions with the new handle. */
+ recoverOpenOutput(p);
+
+ /* Open transactions on both the input and output databases. */
+ recoverExec(p, p->dbIn, "PRAGMA writable_schema = on");
+ recoverExec(p, p->dbIn, "BEGIN");
+ if( p->errCode==SQLITE_OK ) p->bCloseTransaction = 1;
+ recoverExec(p, p->dbIn, "SELECT 1 FROM sqlite_schema");
+ recoverTransferSettings(p);
+ recoverOpenRecovery(p);
+ recoverCacheSchema(p);
+
+ recoverUninstallWrapper(p);
+ recoverLeaveMutex();
+
+ recoverExec(p, p->dbOut, "BEGIN");
+
+ recoverWriteSchema1(p);
+ p->eState = RECOVER_STATE_WRITING;
+ break;
+
+ case RECOVER_STATE_WRITING: {
+ if( p->w1.pTbls==0 ){
+ recoverWriteDataInit(p);
+ }
+ if( SQLITE_DONE==recoverWriteDataStep(p) ){
+ recoverWriteDataCleanup(p);
+ if( p->zLostAndFound ){
+ p->eState = RECOVER_STATE_LOSTANDFOUND1;
+ }else{
+ p->eState = RECOVER_STATE_SCHEMA2;
+ }
+ }
+ break;
+ }
+
+ case RECOVER_STATE_LOSTANDFOUND1: {
+ if( p->laf.pUsed==0 ){
+ recoverLostAndFound1Init(p);
+ }
+ if( SQLITE_DONE==recoverLostAndFound1Step(p) ){
+ p->eState = RECOVER_STATE_LOSTANDFOUND2;
+ }
+ break;
+ }
+ case RECOVER_STATE_LOSTANDFOUND2: {
+ if( p->laf.pAllAndParent==0 ){
+ recoverLostAndFound2Init(p);
+ }
+ if( SQLITE_DONE==recoverLostAndFound2Step(p) ){
+ p->eState = RECOVER_STATE_LOSTANDFOUND3;
+ }
+ break;
+ }
+
+ case RECOVER_STATE_LOSTANDFOUND3: {
+ if( p->laf.pInsert==0 ){
+ recoverLostAndFound3Init(p);
+ }
+ if( SQLITE_DONE==recoverLostAndFound3Step(p) ){
+ p->eState = RECOVER_STATE_SCHEMA2;
+ }
+ break;
+ }
+
+ case RECOVER_STATE_SCHEMA2: {
+ int rc = SQLITE_OK;
+
+ recoverWriteSchema2(p);
+ p->eState = RECOVER_STATE_DONE;
+
+ /* If no error has occurred, commit the write transaction on the output
+ ** database. Regardless of whether or not an error has occurred, make
+ ** an attempt to end the read transaction on the input database. */
+ recoverExec(p, p->dbOut, "COMMIT");
+ rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
+ if( p->errCode==SQLITE_OK ) p->errCode = rc;
+
+ recoverSqlCallback(p, "PRAGMA writable_schema = off");
+ recoverSqlCallback(p, "COMMIT");
+ p->eState = RECOVER_STATE_DONE;
+ recoverFinalCleanup(p);
+ break;
+ };
+
+ case RECOVER_STATE_DONE: {
+ /* no-op */
+ break;
+ };
+ }
+}
+
+
+/*
+** This is a worker function that does the heavy lifting for both init
+** functions:
+**
+** sqlite3_recover_init()
+** sqlite3_recover_init_sql()
+**
+** All this function does is allocate space for the recover handle and
+** take copies of the input parameters. All the real work is done within
+** sqlite3_recover_run().
+*/
+sqlite3_recover *recoverInit(
+ sqlite3* db,
+ const char *zDb,
+ const char *zUri, /* Output URI for _recover_init() */
+ int (*xSql)(void*, const char*),/* SQL callback for _recover_init_sql() */
+ void *pSqlCtx /* Context arg for _recover_init_sql() */
+){
+ sqlite3_recover *pRet = 0;
+ int nDb = 0;
+ int nUri = 0;
+ int nByte = 0;
+
+ if( zDb==0 ){ zDb = "main"; }
+
+ nDb = recoverStrlen(zDb);
+ nUri = recoverStrlen(zUri);
+
+ nByte = sizeof(sqlite3_recover) + nDb+1 + nUri+1;
+ pRet = (sqlite3_recover*)sqlite3_malloc(nByte);
+ if( pRet ){
+ memset(pRet, 0, nByte);
+ pRet->dbIn = db;
+ pRet->zDb = (char*)&pRet[1];
+ pRet->zUri = &pRet->zDb[nDb+1];
+ memcpy(pRet->zDb, zDb, nDb);
+ if( nUri>0 && zUri ) memcpy(pRet->zUri, zUri, nUri);
+ pRet->xSql = xSql;
+ pRet->pSqlCtx = pSqlCtx;
+ pRet->bRecoverRowid = RECOVER_ROWID_DEFAULT;
+ }
+
+ return pRet;
+}
+
+/*
+** Initialize a recovery handle that creates a new database containing
+** the recovered data.
+*/
+sqlite3_recover *sqlite3_recover_init(
+ sqlite3* db,
+ const char *zDb,
+ const char *zUri
+){
+ return recoverInit(db, zDb, zUri, 0, 0);
+}
+
+/*
+** Initialize a recovery handle that returns recovered data in the
+** form of SQL statements via a callback.
+*/
+sqlite3_recover *sqlite3_recover_init_sql(
+ sqlite3* db,
+ const char *zDb,
+ int (*xSql)(void*, const char*),
+ void *pSqlCtx
+){
+ return recoverInit(db, zDb, 0, xSql, pSqlCtx);
+}
+
+/*
+** Return the handle error message, if any.
+*/
+const char *sqlite3_recover_errmsg(sqlite3_recover *p){
+ return (p && p->errCode!=SQLITE_NOMEM) ? p->zErrMsg : "out of memory";
+}
+
+/*
+** Return the handle error code.
+*/
+int sqlite3_recover_errcode(sqlite3_recover *p){
+ return p ? p->errCode : SQLITE_NOMEM;
+}
+
+/*
+** Configure the handle.
+*/
+int sqlite3_recover_config(sqlite3_recover *p, int op, void *pArg){
+ int rc = SQLITE_OK;
+ if( p==0 ){
+ rc = SQLITE_NOMEM;
+ }else if( p->eState!=RECOVER_STATE_INIT ){
+ rc = SQLITE_MISUSE;
+ }else{
+ switch( op ){
+ case 789:
+ /* This undocumented magic configuration option is used to set the
+ ** name of the auxiliary database that is ATTACH-ed to the database
+ ** connection and used to hold state information during the
+ ** recovery process. This option is for debugging use only and
+ ** is subject to change or removal at any time. */
+ sqlite3_free(p->zStateDb);
+ p->zStateDb = recoverMPrintf(p, "%s", (char*)pArg);
+ break;
+
+ case SQLITE_RECOVER_LOST_AND_FOUND: {
+ const char *zArg = (const char*)pArg;
+ sqlite3_free(p->zLostAndFound);
+ if( zArg ){
+ p->zLostAndFound = recoverMPrintf(p, "%s", zArg);
+ }else{
+ p->zLostAndFound = 0;
+ }
+ break;
+ }
+
+ case SQLITE_RECOVER_FREELIST_CORRUPT:
+ p->bFreelistCorrupt = *(int*)pArg;
+ break;
+
+ case SQLITE_RECOVER_ROWIDS:
+ p->bRecoverRowid = *(int*)pArg;
+ break;
+
+ case SQLITE_RECOVER_SLOWINDEXES:
+ p->bSlowIndexes = *(int*)pArg;
+ break;
+
+ default:
+ rc = SQLITE_NOTFOUND;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Do a unit of work towards the recovery job. Return SQLITE_OK if
+** no error has occurred but database recovery is not finished, SQLITE_DONE
+** if database recovery has been successfully completed, or an SQLite
+** error code if an error has occurred.
+*/
+int sqlite3_recover_step(sqlite3_recover *p){
+ if( p==0 ) return SQLITE_NOMEM;
+ if( p->errCode==SQLITE_OK ) recoverStep(p);
+ if( p->eState==RECOVER_STATE_DONE && p->errCode==SQLITE_OK ){
+ return SQLITE_DONE;
+ }
+ return p->errCode;
+}
+
+/*
+** Do the configured recovery operation. Return SQLITE_OK if successful, or
+** else an SQLite error code.
+*/
+int sqlite3_recover_run(sqlite3_recover *p){
+ while( SQLITE_OK==sqlite3_recover_step(p) );
+ return sqlite3_recover_errcode(p);
+}
+
+
+/*
+** Free all resources associated with the recover handle passed as the only
+** argument. The results of using a handle with any sqlite3_recover_**
+** API function after it has been passed to this function are undefined.
+**
+** A copy of the value returned by the first call made to sqlite3_recover_run()
+** on this handle is returned, or SQLITE_OK if sqlite3_recover_run() has
+** not been called on this handle.
+*/
+int sqlite3_recover_finish(sqlite3_recover *p){
+ int rc;
+ if( p==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ recoverFinalCleanup(p);
+ if( p->bCloseTransaction && sqlite3_get_autocommit(p->dbIn)==0 ){
+ rc = sqlite3_exec(p->dbIn, "END", 0, 0, 0);
+ if( p->errCode==SQLITE_OK ) p->errCode = rc;
+ }
+ rc = p->errCode;
+ sqlite3_free(p->zErrMsg);
+ sqlite3_free(p->zStateDb);
+ sqlite3_free(p->zLostAndFound);
+ sqlite3_free(p->pPage1Cache);
+ sqlite3_free(p);
+ }
+ return rc;
+}
+
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
+/************************* End ../ext/recover/sqlite3recover.c ********************/
#endif
#if defined(SQLITE_ENABLE_SESSION)
@@ -12250,15 +15590,16 @@ struct ShellState {
char *zNonce; /* Nonce for temporary safe-mode excapes */
EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
struct {
const char * zInput; /* Input string from wasm/JS proxy */
const char * zPos; /* Cursor pos into zInput */
+ const char * zDefaultDbName; /* Default name for db file */
} wasm;
#endif
};
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
static ShellState shellState;
#endif
@@ -12590,10 +15931,23 @@ static void outputModePop(ShellState *p){
*/
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
int i;
- char *zBlob = (char *)pBlob;
- raw_printf(out,"X'");
- for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); }
- raw_printf(out,"'");
+ unsigned char *aBlob = (unsigned char*)pBlob;
+
+ char *zStr = sqlite3_malloc(nBlob*2 + 1);
+ shell_check_oom(zStr);
+
+ for(i=0; i<nBlob; i++){
+ static const char aHex[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ zStr[i*2] = aHex[ (aBlob[i] >> 4) ];
+ zStr[i*2+1] = aHex[ (aBlob[i] & 0x0F) ];
+ }
+ zStr[i*2] = '\0';
+
+ raw_printf(out,"X'%s'", zStr);
+ sqlite3_free(zStr);
}
/*
@@ -12753,9 +16107,9 @@ static void output_c_string(FILE *out, const char *z){
/*
** Output the given string as a quoted according to JSON quoting rules.
*/
-static void output_json_string(FILE *out, const char *z, int n){
+static void output_json_string(FILE *out, const char *z, i64 n){
unsigned int c;
- if( n<0 ) n = (int)strlen(z);
+ if( n<0 ) n = strlen(z);
fputc('"', out);
while( n-- ){
c = *(z++);
@@ -12926,7 +16280,7 @@ static int safeModeAuth(
UNUSED_PARAMETER(zA4);
switch( op ){
case SQLITE_ATTACH: {
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
/* In WASM builds the filesystem is a virtual sandbox, so
** there's no harm in using ATTACH. */
failIfSafeMode(p, "cannot run ATTACH in safe mode");
@@ -12999,15 +16353,37 @@ static int shellAuth(
**
** This routine converts some CREATE TABLE statements for shadow tables
** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
+**
+** If the schema statement in z[] contains a start-of-comment and if
+** sqlite3_complete() returns false, try to terminate the comment before
+** printing the result. https://sqlite.org/forum/forumpost/d7be961c5c
*/
static void printSchemaLine(FILE *out, const char *z, const char *zTail){
+ char *zToFree = 0;
if( z==0 ) return;
if( zTail==0 ) return;
+ if( zTail[0]==';' && (strstr(z, "/*")!=0 || strstr(z,"--")!=0) ){
+ const char *zOrig = z;
+ static const char *azTerm[] = { "", "*/", "\n" };
+ int i;
+ for(i=0; i<ArraySize(azTerm); i++){
+ char *zNew = sqlite3_mprintf("%s%s;", zOrig, azTerm[i]);
+ if( sqlite3_complete(zNew) ){
+ size_t n = strlen(zNew);
+ zNew[n-1] = 0;
+ zToFree = zNew;
+ z = zNew;
+ break;
+ }
+ sqlite3_free(zNew);
+ }
+ }
if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
}else{
utf8_printf(out, "%s%s", z, zTail);
}
+ sqlite3_free(zToFree);
}
static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
char c = z[n];
@@ -13036,7 +16412,9 @@ static int wsToEol(const char *z){
*/
static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
EQPGraphRow *pNew;
- int nText = strlen30(zText);
+ i64 nText;
+ if( zText==0 ) return;
+ nText = strlen(zText);
if( p->autoEQPtest ){
utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
}
@@ -13081,14 +16459,14 @@ static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){
*/
static void eqp_render_level(ShellState *p, int iEqpId){
EQPGraphRow *pRow, *pNext;
- int n = strlen30(p->sGraph.zPrefix);
+ i64 n = strlen(p->sGraph.zPrefix);
char *z;
for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
pNext = eqp_next_row(p, iEqpId, pRow);
z = pRow->zText;
utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
pNext ? "|--" : "`--", z);
- if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){
+ if( n<(i64)sizeof(p->sGraph.zPrefix)-7 ){
memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
eqp_render_level(p, pRow->iEqpId);
p->sGraph.zPrefix[n] = 0;
@@ -13688,6 +17066,7 @@ static char *shell_error_context(const char *zSql, sqlite3 *db){
while( (zSql[len]&0xc0)==0x80 ) len--;
}
zCode = sqlite3_mprintf("%.*s", len, zSql);
+ shell_check_oom(zCode);
for(i=0; zCode[i]; i++){ if( IsSpace(zSql[i]) ) zCode[i] = ' '; }
if( iOffset<25 ){
zMsg = sqlite3_mprintf("\n %z\n %*s^--- error here", zCode, iOffset, "");
@@ -13804,7 +17183,7 @@ static void displayLinuxIoStats(FILE *out){
int i;
for(i=0; i<ArraySize(aTrans); i++){
int n = strlen30(aTrans[i].zPattern);
- if( strncmp(aTrans[i].zPattern, z, n)==0 ){
+ if( cli_strncmp(aTrans[i].zPattern, z, n)==0 ){
utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
break;
}
@@ -14043,7 +17422,7 @@ static void display_scanstats(
static int str_in_array(const char *zStr, const char **azArray){
int i;
for(i=0; azArray[i]; i++){
- if( 0==strcmp(zStr, azArray[i]) ) return 1;
+ if( 0==cli_strcmp(zStr, azArray[i]) ) return 1;
}
return 0;
}
@@ -14118,7 +17497,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" };
int jj;
for(jj=0; jj<ArraySize(explainCols); jj++){
- if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
+ if( cli_strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){
p->cMode = p->mode;
sqlite3_reset(pSql);
return;
@@ -14842,10 +18221,10 @@ static int expertDotCommand(
int n;
if( z[0]=='-' && z[1]=='-' ) z++;
n = strlen30(z);
- if( n>=2 && 0==strncmp(z, "-verbose", n) ){
+ if( n>=2 && 0==cli_strncmp(z, "-verbose", n) ){
pState->expert.bVerbose = 1;
}
- else if( n>=2 && 0==strncmp(z, "-sample", n) ){
+ else if( n>=2 && 0==cli_strncmp(z, "-sample", n) ){
if( i==(nArg-1) ){
raw_printf(stderr, "option requires an argument: %s\n", z);
rc = SQLITE_ERROR;
@@ -15193,18 +18572,20 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
+ if( zTable==0 ) return 0;
+ if( zType==0 ) return 0;
dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0;
noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0;
- if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
+ if( cli_strcmp(zTable, "sqlite_sequence")==0 && !noSys ){
if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){
if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n");
- }else if( strncmp(zTable, "sqlite_", 7)==0 ){
+ }else if( cli_strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( dataOnly ){
/* no-op */
- }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ }else if( cli_strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
raw_printf(p->out, "PRAGMA writable_schema=ON;\n");
@@ -15222,7 +18603,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
printSchemaLine(p->out, zSql, ";\n");
}
- if( strcmp(zType, "table")==0 ){
+ if( cli_strcmp(zType, "table")==0 ){
ShellText sSelect;
ShellText sTable;
char **azCol;
@@ -15340,7 +18721,7 @@ static int run_schema_dump_query(
*/
static const char *(azHelp[]) = {
#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) \
- && !defined(SQLITE_SHELL_WASM_MODE)
+ && !defined(SQLITE_SHELL_FIDDLE)
".archive ... Manage SQL archives",
" Each command must have exactly one of the following options:",
" -c, --create Create a new archive",
@@ -15366,7 +18747,7 @@ static const char *(azHelp[]) = {
#ifndef SQLITE_OMIT_AUTHORIZATION
".auth ON|OFF Show authorizer callbacks",
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".backup ?DB? FILE Backup DB (default \"main\") to FILE",
" Options:",
" --append Use the appendvfs",
@@ -15374,18 +18755,18 @@ static const char *(azHelp[]) = {
#endif
".bail on|off Stop after hitting an error. Default OFF",
".binary on|off Turn binary output on or off. Default OFF",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".cd DIRECTORY Change the working directory to DIRECTORY",
#endif
".changes on|off Show number of rows changed by SQL",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".check GLOB Fail if output since .testcase does not match",
".clone NEWDB Clone data into NEWDB from the existing database",
#endif
".connection [close] [#] Open or close an auxiliary database connection",
".databases List names and files of attached databases",
".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+#if SQLITE_SHELL_HAVE_RECOVER
".dbinfo ?DB? Show status information about the database",
#endif
".dump ?OBJECTS? Render database content as SQL",
@@ -15404,11 +18785,11 @@ static const char *(azHelp[]) = {
" trace Like \"full\" but enable \"PRAGMA vdbe_trace\"",
#endif
" trigger Like \"full\" but also show trigger bytecode",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".excel Display the output of next command in spreadsheet",
" --bom Put a UTF8 byte-order mark on intermediate file",
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".exit ?CODE? Exit this program with return-code CODE",
#endif
".expert EXPERIMENTAL. Suggest indexes for queries",
@@ -15419,7 +18800,7 @@ static const char *(azHelp[]) = {
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
".headers on|off Turn display of headers on or off",
".help ?-all? ?PATTERN? Show help text for PATTERN",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".import FILE TABLE Import data from FILE into TABLE",
" Options:",
" --ascii Use \\037 and \\036 as column and row separators",
@@ -15448,10 +18829,10 @@ static const char *(azHelp[]) = {
".lint OPTIONS Report potential schema issues.",
" Options:",
" fkey-indexes Find missing foreign key indexes",
-#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE)
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
".load FILE ?ENTRY? Load an extension library",
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
#endif
".mode MODE ?OPTIONS? Set output mode",
@@ -15466,7 +18847,7 @@ static const char *(azHelp[]) = {
" line One value per line",
" list Values delimited by \"|\"",
" markdown Markdown table format",
- " qbox Shorthand for \"box --width 60 --quote\"",
+ " qbox Shorthand for \"box --wrap 60 --quote\"",
" quote Escape answers as for SQL",
" table ASCII-art table",
" tabs Tab-separated values",
@@ -15478,11 +18859,11 @@ static const char *(azHelp[]) = {
" --quote Quote output text as SQL literals",
" --noquote Do not quote output text",
" TABLE The name of SQL table used for \"insert\" mode",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".nonce STRING Suspend safe mode for one command if nonce matches",
#endif
".nullvalue STRING Use STRING in place of NULL values",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
" If FILE begins with '|' then open as a pipe",
" --bom Put a UTF8 byte-order mark at the beginning",
@@ -15504,7 +18885,7 @@ static const char *(azHelp[]) = {
" --nofollow Do not follow symbolic links",
" --readonly Open FILE readonly",
" --zip FILE is a ZIP archive",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
" If FILE begins with '|' then open it as a pipe.",
" Options:",
@@ -15528,20 +18909,19 @@ static const char *(azHelp[]) = {
" --reset Reset the count for each input and interrupt",
#endif
".prompt MAIN CONTINUE Replace the standard prompts",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".quit Exit this program",
".read FILE Read input from FILE or command output",
" If FILE begins with \"|\", it is a command that generates the input.",
#endif
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+#if SQLITE_SHELL_HAVE_RECOVER
".recover Recover as much data as possible from corrupt db.",
- " --freelist-corrupt Assume the freelist is corrupt",
- " --recovery-db NAME Store recovery metadata in database file NAME",
+ " --ignore-freelist Ignore pages that appear to be on db freelist",
" --lost-and-found TABLE Alternative name for the lost-and-found table",
" --no-rowids Do not attempt to recover rowid values",
" that are not also INTEGER PRIMARY KEYs",
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
".save ?OPTIONS? FILE Write database to FILE (an alias for .backup ...)",
#endif
@@ -15578,7 +18958,7 @@ static const char *(azHelp[]) = {
" --sha3-384 Use the sha3-384 algorithm",
" --sha3-512 Use the sha3-512 algorithm",
" Any other argument is a LIKE pattern for tables to hash",
-#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
+#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
".shell CMD ARGS... Run CMD ARGS... in a system shell",
#endif
".show Show the current values for various settings",
@@ -15587,11 +18967,11 @@ static const char *(azHelp[]) = {
" on Turn on automatic stat display",
" stmt Show statement stats",
" vmstep Show the virtual machine step count only",
-#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
+#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
".system CMD ARGS... Run CMD ARGS... in a system shell",
#endif
".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
".testcase NAME Begin redirecting output to 'testcase-out.txt'",
#endif
".testctrl CMD ... Run various sqlite3_test_control() operations",
@@ -15641,9 +19021,9 @@ static int showHelp(FILE *out, const char *zPattern){
char *zPat;
if( zPattern==0
|| zPattern[0]=='0'
- || strcmp(zPattern,"-a")==0
- || strcmp(zPattern,"-all")==0
- || strcmp(zPattern,"--all")==0
+ || cli_strcmp(zPattern,"-a")==0
+ || cli_strcmp(zPattern,"-all")==0
+ || cli_strcmp(zPattern,"--all")==0
){
/* Show all commands, but only one line per command */
if( zPattern==0 ) zPattern = "";
@@ -15880,7 +19260,7 @@ static unsigned char *readHexDb(ShellState *p, int *pnData){
iOffset = k;
continue;
}
- if( strncmp(zLine, "| end ", 6)==0 ){
+ if( cli_strncmp(zLine, "| end ", 6)==0 ){
break;
}
rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
@@ -15908,7 +19288,7 @@ readHexDb_error:
}else{
while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
nLine++;
- if(strncmp(zLine, "| end ", 6)==0 ) break;
+ if(cli_strncmp(zLine, "| end ", 6)==0 ) break;
}
p->lineno = nLine;
}
@@ -16000,28 +19380,28 @@ static void shellEscapeCrnl(
const char *zText = (const char*)sqlite3_value_text(argv[0]);
UNUSED_PARAMETER(argc);
if( zText && zText[0]=='\'' ){
- int nText = sqlite3_value_bytes(argv[0]);
- int i;
+ i64 nText = sqlite3_value_bytes(argv[0]);
+ i64 i;
char zBuf1[20];
char zBuf2[20];
const char *zNL = 0;
const char *zCR = 0;
- int nCR = 0;
- int nNL = 0;
+ i64 nCR = 0;
+ i64 nNL = 0;
for(i=0; zText[i]; i++){
if( zNL==0 && zText[i]=='\n' ){
zNL = unused_string(zText, "\\n", "\\012", zBuf1);
- nNL = (int)strlen(zNL);
+ nNL = strlen(zNL);
}
if( zCR==0 && zText[i]=='\r' ){
zCR = unused_string(zText, "\\r", "\\015", zBuf2);
- nCR = (int)strlen(zCR);
+ nCR = strlen(zCR);
}
}
if( zNL || zCR ){
- int iOut = 0;
+ i64 iOut = 0;
i64 nMax = (nNL > nCR) ? nNL : nCR;
i64 nAlloc = nMax * nText + (nMax+64)*2;
char *zOut = (char*)sqlite3_malloc64(nAlloc);
@@ -16144,11 +19524,11 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_regexp_init(p->db, 0, 0);
sqlite3_ieee_init(p->db, 0, 0);
sqlite3_series_init(p->db, 0, 0);
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
sqlite3_fileio_init(p->db, 0, 0);
sqlite3_completion_init(p->db, 0, 0);
#endif
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+#if SQLITE_SHELL_HAVE_RECOVER
sqlite3_dbdata_init(p->db, 0, 0);
#endif
#ifdef SQLITE_HAVE_ZLIB
@@ -16262,8 +19642,8 @@ static char **readline_completion(const char *zText, int iStart, int iEnd){
** Linenoise completion callback
*/
static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
- int nLine = strlen30(zLine);
- int i, iStart;
+ i64 nLine = strlen(zLine);
+ i64 i, iStart;
sqlite3_stmt *pStmt = 0;
char *zSql;
char zBuf[1000];
@@ -16401,11 +19781,11 @@ static void output_file_close(FILE *f){
*/
static FILE *output_file_open(const char *zFile, int bTextMode){
FILE *f;
- if( strcmp(zFile,"stdout")==0 ){
+ if( cli_strcmp(zFile,"stdout")==0 ){
f = stdout;
- }else if( strcmp(zFile, "stderr")==0 ){
+ }else if( cli_strcmp(zFile, "stderr")==0 ){
f = stderr;
- }else if( strcmp(zFile, "off")==0 ){
+ }else if( cli_strcmp(zFile, "off")==0 ){
f = 0;
}else{
f = fopen(zFile, bTextMode ? "w" : "wb");
@@ -16429,7 +19809,7 @@ static int sql_trace_callback(
ShellState *p = (ShellState*)pArg;
sqlite3_stmt *pStmt;
const char *zSql;
- int nSql;
+ i64 nSql;
if( p->traceOut==0 ) return 0;
if( mType==SQLITE_TRACE_CLOSE ){
utf8_printf(p->traceOut, "-- closing database connection\n");
@@ -16457,17 +19837,18 @@ static int sql_trace_callback(
}
}
if( zSql==0 ) return 0;
- nSql = strlen30(zSql);
+ nSql = strlen(zSql);
+ if( nSql>1000000000 ) nSql = 1000000000;
while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
switch( mType ){
case SQLITE_TRACE_ROW:
case SQLITE_TRACE_STMT: {
- utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql);
+ utf8_printf(p->traceOut, "%.*s;\n", (int)nSql, zSql);
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
- utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec);
+ utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
}
@@ -17016,7 +20397,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
}
if( zDb==0 ){
zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
- }else if( strcmp(zDb,"temp")==0 ){
+ }else if( cli_strcmp(zDb,"temp")==0 ){
zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
}else{
zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
@@ -17032,8 +20413,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
-#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE)
- && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
** Print the current sqlite3_errmsg() value to stderr and return 1.
@@ -17150,7 +20530,7 @@ static int optionMatch(const char *zStr, const char *zOpt){
if( zStr[0]!='-' ) return 0;
zStr++;
if( zStr[0]=='-' ) zStr++;
- return strcmp(zStr, zOpt)==0;
+ return cli_strcmp(zStr, zOpt)==0;
}
/*
@@ -18306,364 +21686,16 @@ end_ar_command:
*******************************************************************************/
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
-/*
-** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op.
-** Otherwise, the SQL statement or statements in zSql are executed using
-** database connection db and the error code written to *pRc before
-** this function returns.
-*/
-static void shellExec(sqlite3 *db, int *pRc, const char *zSql){
- int rc = *pRc;
- if( rc==SQLITE_OK ){
- char *zErr = 0;
- rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
- if( rc!=SQLITE_OK ){
- raw_printf(stderr, "SQL error: %s\n", zErr);
- }
- sqlite3_free(zErr);
- *pRc = rc;
- }
-}
-
-/*
-** Like shellExec(), except that zFmt is a printf() style format string.
-*/
-static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){
- char *z = 0;
- if( *pRc==SQLITE_OK ){
- va_list ap;
- va_start(ap, zFmt);
- z = sqlite3_vmprintf(zFmt, ap);
- va_end(ap);
- if( z==0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- shellExec(db, pRc, z);
- }
- sqlite3_free(z);
- }
-}
-
-/*
-** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
-** Otherwise, an attempt is made to allocate, zero and return a pointer
-** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set
-** to SQLITE_NOMEM and NULL returned.
-*/
-static void *shellMalloc(int *pRc, sqlite3_int64 nByte){
- void *pRet = 0;
- if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc64(nByte);
- if( pRet==0 ){
- *pRc = SQLITE_NOMEM;
- }else{
- memset(pRet, 0, nByte);
- }
- }
- return pRet;
-}
-
-/*
-** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
-** Otherwise, zFmt is treated as a printf() style string. The result of
-** formatting it along with any trailing arguments is written into a
-** buffer obtained from sqlite3_malloc(), and pointer to which is returned.
-** It is the responsibility of the caller to eventually free this buffer
-** using a call to sqlite3_free().
-**
-** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL
-** pointer returned.
-*/
-static char *shellMPrintf(int *pRc, const char *zFmt, ...){
- char *z = 0;
- if( *pRc==SQLITE_OK ){
- va_list ap;
- va_start(ap, zFmt);
- z = sqlite3_vmprintf(zFmt, ap);
- va_end(ap);
- if( z==0 ){
- *pRc = SQLITE_NOMEM;
- }
- }
- return z;
-}
-
-
-/*
-** When running the ".recover" command, each output table, and the special
-** orphaned row table if it is required, is represented by an instance
-** of the following struct.
-*/
-typedef struct RecoverTable RecoverTable;
-struct RecoverTable {
- char *zQuoted; /* Quoted version of table name */
- int nCol; /* Number of columns in table */
- char **azlCol; /* Array of column lists */
- int iPk; /* Index of IPK column */
-};
-
-/*
-** Free a RecoverTable object allocated by recoverFindTable() or
-** recoverOrphanTable().
-*/
-static void recoverFreeTable(RecoverTable *pTab){
- if( pTab ){
- sqlite3_free(pTab->zQuoted);
- if( pTab->azlCol ){
- int i;
- for(i=0; i<=pTab->nCol; i++){
- sqlite3_free(pTab->azlCol[i]);
- }
- sqlite3_free(pTab->azlCol);
- }
- sqlite3_free(pTab);
- }
-}
-
-/*
-** This function is a no-op if (*pRc) is not SQLITE_OK when it is called.
-** Otherwise, it allocates and returns a RecoverTable object based on the
-** final four arguments passed to this function. It is the responsibility
-** of the caller to eventually free the returned object using
-** recoverFreeTable().
-*/
-static RecoverTable *recoverNewTable(
- int *pRc, /* IN/OUT: Error code */
- const char *zName, /* Name of table */
- const char *zSql, /* CREATE TABLE statement */
- int bIntkey,
- int nCol
-){
- sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */
- int rc = *pRc;
- RecoverTable *pTab = 0;
-
- pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable));
- if( rc==SQLITE_OK ){
- int nSqlCol = 0;
- int bSqlIntkey = 0;
- sqlite3_stmt *pStmt = 0;
-
- rc = sqlite3_open("", &dbtmp);
- if( rc==SQLITE_OK ){
- sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0,
- shellIdQuote, 0, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0);
- }
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0);
- if( rc==SQLITE_ERROR ){
- rc = SQLITE_OK;
- goto finished;
- }
- }
- shellPreparePrintf(dbtmp, &rc, &pStmt,
- "SELECT count(*) FROM pragma_table_info(%Q)", zName
- );
- if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- nSqlCol = sqlite3_column_int(pStmt, 0);
- }
- shellFinalize(&rc, pStmt);
-
- if( rc!=SQLITE_OK || nSqlCol<nCol ){
- goto finished;
- }
-
- shellPreparePrintf(dbtmp, &rc, &pStmt,
- "SELECT ("
- " SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage"
- ") FROM sqlite_schema WHERE name = %Q", zName
- );
- if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- bSqlIntkey = sqlite3_column_int(pStmt, 0);
- }
- shellFinalize(&rc, pStmt);
-
- if( bIntkey==bSqlIntkey ){
- int i;
- const char *zPk = "_rowid_";
- sqlite3_stmt *pPkFinder = 0;
-
- /* If this is an intkey table and there is an INTEGER PRIMARY KEY,
- ** set zPk to the name of the PK column, and pTab->iPk to the index
- ** of the column, where columns are 0-numbered from left to right.
- ** Or, if this is a WITHOUT ROWID table or if there is no IPK column,
- ** leave zPk as "_rowid_" and pTab->iPk at -2. */
- pTab->iPk = -2;
- if( bIntkey ){
- shellPreparePrintf(dbtmp, &rc, &pPkFinder,
- "SELECT cid, name FROM pragma_table_info(%Q) "
- " WHERE pk=1 AND type='integer' COLLATE nocase"
- " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)"
- , zName, zName
- );
- if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){
- pTab->iPk = sqlite3_column_int(pPkFinder, 0);
- zPk = (const char*)sqlite3_column_text(pPkFinder, 1);
- if( zPk==0 ){ zPk = "_"; /* Defensive. Should never happen */ }
- }
- }
-
- pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName);
- pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1));
- pTab->nCol = nSqlCol;
-
- if( bIntkey ){
- pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk);
- }else{
- pTab->azlCol[0] = shellMPrintf(&rc, "");
- }
- i = 1;
- shellPreparePrintf(dbtmp, &rc, &pStmt,
- "SELECT %Q || group_concat(shell_idquote(name), ', ') "
- " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) "
- "FROM pragma_table_info(%Q)",
- bIntkey ? ", " : "", pTab->iPk,
- bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ",
- zName
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zText = (const char*)sqlite3_column_text(pStmt, 0);
- pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText);
- i++;
- }
- shellFinalize(&rc, pStmt);
-
- shellFinalize(&rc, pPkFinder);
- }
- }
-
- finished:
- sqlite3_close(dbtmp);
- *pRc = rc;
- if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){
- recoverFreeTable(pTab);
- pTab = 0;
- }
- return pTab;
-}
-
-/*
-** This function is called to search the schema recovered from the
-** sqlite_schema table of the (possibly) corrupt database as part
-** of a ".recover" command. Specifically, for a table with root page
-** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the
-** table must be a WITHOUT ROWID table, or if non-zero, not one of
-** those.
-**
-** If a table is found, a (RecoverTable*) object is returned. Or, if
-** no such table is found, but bIntkey is false and iRoot is the
-** root page of an index in the recovered schema, then (*pbNoop) is
-** set to true and NULL returned. Or, if there is no such table or
-** index, NULL is returned and (*pbNoop) set to 0, indicating that
-** the caller should write data to the orphans table.
-*/
-static RecoverTable *recoverFindTable(
- ShellState *pState, /* Shell state object */
- int *pRc, /* IN/OUT: Error code */
- int iRoot, /* Root page of table */
- int bIntkey, /* True for an intkey table */
- int nCol, /* Number of columns in table */
- int *pbNoop /* OUT: True if iRoot is root of index */
-){
- sqlite3_stmt *pStmt = 0;
- RecoverTable *pRet = 0;
- int bNoop = 0;
- const char *zSql = 0;
- const char *zName = 0;
-
- /* Search the recovered schema for an object with root page iRoot. */
- shellPreparePrintf(pState->db, pRc, &pStmt,
- "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot
- );
- while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zType = (const char*)sqlite3_column_text(pStmt, 0);
- if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){
- bNoop = 1;
- break;
- }
- if( sqlite3_stricmp(zType, "table")==0 ){
- zName = (const char*)sqlite3_column_text(pStmt, 1);
- zSql = (const char*)sqlite3_column_text(pStmt, 2);
- if( zName!=0 && zSql!=0 ){
- pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
- break;
- }
- }
- }
-
- shellFinalize(pRc, pStmt);
- *pbNoop = bNoop;
- return pRet;
-}
+#if SQLITE_SHELL_HAVE_RECOVER
/*
-** Return a RecoverTable object representing the orphans table.
+** This function is used as a callback by the recover extension. Simply
+** print the supplied SQL statement to stdout.
*/
-static RecoverTable *recoverOrphanTable(
- ShellState *pState, /* Shell state object */
- int *pRc, /* IN/OUT: Error code */
- const char *zLostAndFound, /* Base name for orphans table */
- int nCol /* Number of user data columns */
-){
- RecoverTable *pTab = 0;
- if( nCol>=0 && *pRc==SQLITE_OK ){
- int i;
-
- /* This block determines the name of the orphan table. The prefered
- ** name is zLostAndFound. But if that clashes with another name
- ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1
- ** and so on until a non-clashing name is found. */
- int iTab = 0;
- char *zTab = shellMPrintf(pRc, "%s", zLostAndFound);
- sqlite3_stmt *pTest = 0;
- shellPrepare(pState->db, pRc,
- "SELECT 1 FROM recovery.schema WHERE name=?", &pTest
- );
- if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
- while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){
- shellReset(pRc, pTest);
- sqlite3_free(zTab);
- zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++);
- sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
- }
- shellFinalize(pRc, pTest);
-
- pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable));
- if( pTab ){
- pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab);
- pTab->nCol = nCol;
- pTab->iPk = -2;
- if( nCol>0 ){
- pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1));
- if( pTab->azlCol ){
- pTab->azlCol[nCol] = shellMPrintf(pRc, "");
- for(i=nCol-1; i>=0; i--){
- pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]);
- }
- }
- }
-
- if( *pRc!=SQLITE_OK ){
- recoverFreeTable(pTab);
- pTab = 0;
- }else{
- raw_printf(pState->out,
- "CREATE TABLE %s(rootpgno INTEGER, "
- "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted
- );
- for(i=0; i<nCol; i++){
- raw_printf(pState->out, ", c%d", i);
- }
- raw_printf(pState->out, ");\n");
- }
- }
- sqlite3_free(zTab);
- }
- return pTab;
+static int recoverSqlCb(void *pCtx, const char *zSql){
+ ShellState *pState = (ShellState*)pCtx;
+ utf8_printf(pState->out, "%s;\n", zSql);
+ return SQLITE_OK;
}
/*
@@ -18673,32 +21705,33 @@ static RecoverTable *recoverOrphanTable(
*/
static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
int rc = SQLITE_OK;
- sqlite3_stmt *pLoop = 0; /* Loop through all root pages */
- sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */
- sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */
- const char *zRecoveryDb = ""; /* Name of "recovery" database */
- const char *zLostAndFound = "lost_and_found";
- int i;
- int nOrphan = -1;
- RecoverTable *pOrphan = 0;
-
- int bFreelist = 1; /* 0 if --freelist-corrupt is specified */
+ const char *zRecoveryDb = ""; /* Name of "recovery" database. Debug only */
+ const char *zLAF = "lost_and_found";
+ int bFreelist = 1; /* 0 if --ignore-freelist is specified */
int bRowids = 1; /* 0 if --no-rowids */
+ sqlite3_recover *p = 0;
+ int i = 0;
+
for(i=1; i<nArg; i++){
char *z = azArg[i];
int n;
if( z[0]=='-' && z[1]=='-' ) z++;
n = strlen30(z);
- if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){
+ if( n<=17 && memcmp("-ignore-freelist", z, n)==0 ){
bFreelist = 0;
}else
if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
+ /* This option determines the name of the ATTACH-ed database used
+ ** internally by the recovery extension. The default is "" which
+ ** means to use a temporary database that is automatically deleted
+ ** when closed. This option is undocumented and might disappear at
+ ** any moment. */
i++;
zRecoveryDb = azArg[i];
}else
if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
i++;
- zLostAndFound = azArg[i];
+ zLAF = azArg[i];
}else
if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
bRowids = 0;
@@ -18710,281 +21743,25 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
}
}
- shellExecPrintf(pState->db, &rc,
- /* Attach an in-memory database named 'recovery'. Create an indexed
- ** cache of the sqlite_dbptr virtual table. */
- "PRAGMA writable_schema = on;"
- "ATTACH %Q AS recovery;"
- "DROP TABLE IF EXISTS recovery.dbptr;"
- "DROP TABLE IF EXISTS recovery.freelist;"
- "DROP TABLE IF EXISTS recovery.map;"
- "DROP TABLE IF EXISTS recovery.schema;"
- "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb
- );
-
- if( bFreelist ){
- shellExec(pState->db, &rc,
- "WITH trunk(pgno) AS ("
- " SELECT shell_int32("
- " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x "
- " WHERE x>0"
- " UNION"
- " SELECT shell_int32("
- " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x "
- " FROM trunk WHERE x>0"
- "),"
- "freelist(data, n, freepgno) AS ("
- " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno "
- " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno"
- " UNION ALL"
- " SELECT data, n-1, shell_int32(data, 2+n) "
- " FROM freelist WHERE n>=0"
- ")"
- "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;"
- );
- }
-
- /* If this is an auto-vacuum database, add all pointer-map pages to
- ** the freelist table. Do this regardless of whether or not
- ** --freelist-corrupt was specified. */
- shellExec(pState->db, &rc,
- "WITH ptrmap(pgno) AS ("
- " SELECT 2 WHERE shell_int32("
- " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13"
- " )"
- " UNION ALL "
- " SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp "
- " FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)"
- ")"
- "REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap"
- );
-
- shellExec(pState->db, &rc,
- "CREATE TABLE recovery.dbptr("
- " pgno, child, PRIMARY KEY(child, pgno)"
- ") WITHOUT ROWID;"
- "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) "
- " SELECT * FROM sqlite_dbptr"
- " WHERE pgno NOT IN freelist AND child NOT IN freelist;"
-
- /* Delete any pointer to page 1. This ensures that page 1 is considered
- ** a root page, regardless of how corrupt the db is. */
- "DELETE FROM recovery.dbptr WHERE child = 1;"
-
- /* Delete all pointers to any pages that have more than one pointer
- ** to them. Such pages will be treated as root pages when recovering
- ** data. */
- "DELETE FROM recovery.dbptr WHERE child IN ("
- " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1"
- ");"
-
- /* Create the "map" table that will (eventually) contain instructions
- ** for dealing with each page in the db that contains one or more
- ** records. */
- "CREATE TABLE recovery.map("
- "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT"
- ");"
-
- /* Populate table [map]. If there are circular loops of pages in the
- ** database, the following adds all pages in such a loop to the map
- ** as individual root pages. This could be handled better. */
- "WITH pages(i, maxlen) AS ("
- " SELECT page_count, ("
- " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count"
- " ) FROM pragma_page_count WHERE page_count>0"
- " UNION ALL"
- " SELECT i-1, ("
- " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1"
- " ) FROM pages WHERE i>=2"
- ")"
- "INSERT INTO recovery.map(pgno, maxlen, intkey, root) "
- " SELECT i, maxlen, NULL, ("
- " WITH p(orig, pgno, parent) AS ("
- " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)"
- " UNION "
- " SELECT i, p.parent, "
- " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p"
- " )"
- " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)"
- ") "
- "FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;"
- "UPDATE recovery.map AS o SET intkey = ("
- " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno"
- ");"
-
- /* Extract data from page 1 and any linked pages into table
- ** recovery.schema. With the same schema as an sqlite_schema table. */
- "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
- "INSERT INTO recovery.schema SELECT "
- " max(CASE WHEN field=0 THEN value ELSE NULL END),"
- " max(CASE WHEN field=1 THEN value ELSE NULL END),"
- " max(CASE WHEN field=2 THEN value ELSE NULL END),"
- " max(CASE WHEN field=3 THEN value ELSE NULL END),"
- " max(CASE WHEN field=4 THEN value ELSE NULL END)"
- "FROM sqlite_dbdata WHERE pgno IN ("
- " SELECT pgno FROM recovery.map WHERE root=1"
- ")"
- "GROUP BY pgno, cell;"
- "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);"
- );
-
- /* Open a transaction, then print out all non-virtual, non-"sqlite_%"
- ** CREATE TABLE statements that extracted from the existing schema. */
- if( rc==SQLITE_OK ){
- sqlite3_stmt *pStmt = 0;
- /* ".recover" might output content in an order which causes immediate
- ** foreign key constraints to be violated. So disable foreign-key
- ** constraint enforcement to prevent problems when running the output
- ** script. */
- raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n");
- raw_printf(pState->out, "BEGIN;\n");
- raw_printf(pState->out, "PRAGMA writable_schema = on;\n");
- shellPrepare(pState->db, &rc,
- "SELECT sql FROM recovery.schema "
- "WHERE type='table' AND sql LIKE 'create table%'", &pStmt
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0);
- raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n",
- &zCreateTable[12]
- );
- }
- shellFinalize(&rc, pStmt);
- }
-
- /* Figure out if an orphan table will be required. And if so, how many
- ** user columns it should contain */
- shellPrepare(pState->db, &rc,
- "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1"
- , &pLoop
- );
- if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
- nOrphan = sqlite3_column_int(pLoop, 0);
- }
- shellFinalize(&rc, pLoop);
- pLoop = 0;
-
- shellPrepare(pState->db, &rc,
- "SELECT pgno FROM recovery.map WHERE root=?", &pPages
+ p = sqlite3_recover_init_sql(
+ pState->db, "main", recoverSqlCb, (void*)pState
);
- shellPrepare(pState->db, &rc,
- "SELECT max(field), group_concat(shell_escape_crnl(quote"
- "(case when (? AND field<0) then NULL else value end)"
- "), ', ')"
- ", min(field) "
- "FROM sqlite_dbdata WHERE pgno = ? AND field != ?"
- "GROUP BY cell", &pCells
- );
-
- /* Loop through each root page. */
- shellPrepare(pState->db, &rc,
- "SELECT root, intkey, max(maxlen) FROM recovery.map"
- " WHERE root>1 GROUP BY root, intkey ORDER BY root=("
- " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'"
- ")", &pLoop
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
- int iRoot = sqlite3_column_int(pLoop, 0);
- int bIntkey = sqlite3_column_int(pLoop, 1);
- int nCol = sqlite3_column_int(pLoop, 2);
- int bNoop = 0;
- RecoverTable *pTab;
-
- assert( bIntkey==0 || bIntkey==1 );
- pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop);
- if( bNoop || rc ) continue;
- if( pTab==0 ){
- if( pOrphan==0 ){
- pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
- }
- pTab = pOrphan;
- if( pTab==0 ) break;
- }
-
- if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){
- raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
- }
- sqlite3_bind_int(pPages, 1, iRoot);
- if( bRowids==0 && pTab->iPk<0 ){
- sqlite3_bind_int(pCells, 1, 1);
- }else{
- sqlite3_bind_int(pCells, 1, 0);
- }
- sqlite3_bind_int(pCells, 3, pTab->iPk);
-
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){
- int iPgno = sqlite3_column_int(pPages, 0);
- sqlite3_bind_int(pCells, 2, iPgno);
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){
- int nField = sqlite3_column_int(pCells, 0);
- int iMin = sqlite3_column_int(pCells, 2);
- const char *zVal = (const char*)sqlite3_column_text(pCells, 1);
-
- RecoverTable *pTab2 = pTab;
- if( pTab!=pOrphan && (iMin<0)!=bIntkey ){
- if( pOrphan==0 ){
- pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
- }
- pTab2 = pOrphan;
- if( pTab2==0 ) break;
- }
-
- nField = nField+1;
- if( pTab2==pOrphan ){
- raw_printf(pState->out,
- "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
- pTab2->zQuoted, iRoot, iPgno, nField,
- iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField]
- );
- }else{
- raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n",
- pTab2->zQuoted, pTab2->azlCol[nField], zVal
- );
- }
- }
- shellReset(&rc, pCells);
- }
- shellReset(&rc, pPages);
- if( pTab!=pOrphan ) recoverFreeTable(pTab);
- }
- shellFinalize(&rc, pLoop);
- shellFinalize(&rc, pPages);
- shellFinalize(&rc, pCells);
- recoverFreeTable(pOrphan);
-
- /* The rest of the schema */
- if( rc==SQLITE_OK ){
- sqlite3_stmt *pStmt = 0;
- shellPrepare(pState->db, &rc,
- "SELECT sql, name FROM recovery.schema "
- "WHERE sql NOT LIKE 'create table%'", &pStmt
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
- if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){
- const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
- char *zPrint = shellMPrintf(&rc,
- "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)",
- zName, zName, zSql
- );
- raw_printf(pState->out, "%s;\n", zPrint);
- sqlite3_free(zPrint);
- }else{
- raw_printf(pState->out, "%s;\n", zSql);
- }
- }
- shellFinalize(&rc, pStmt);
- }
+ sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
+ sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
+ sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
+ sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
- if( rc==SQLITE_OK ){
- raw_printf(pState->out, "PRAGMA writable_schema = off;\n");
- raw_printf(pState->out, "COMMIT;\n");
+ sqlite3_recover_run(p);
+ if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
+ const char *zErr = sqlite3_recover_errmsg(p);
+ int errCode = sqlite3_recover_errcode(p);
+ raw_printf(stderr, "sql error: %s (%d)\n", zErr, errCode);
}
- sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0);
+ rc = sqlite3_recover_finish(p);
return rc;
}
-#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+#endif /* SQLITE_SHELL_HAVE_RECOVER */
/*
@@ -19256,7 +22033,7 @@ static int do_meta_command(char *zLine, ShellState *p){
clearTempFile(p);
#ifndef SQLITE_OMIT_AUTHORIZATION
- if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
+ if( c=='a' && cli_strncmp(azArg[0], "auth", n)==0 ){
if( nArg!=2 ){
raw_printf(stderr, "Usage: .auth ON|OFF\n");
rc = 1;
@@ -19274,17 +22051,17 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) \
- && !defined(SQLITE_SHELL_WASM_MODE)
- if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
+ && !defined(SQLITE_SHELL_FIDDLE)
+ if( c=='a' && cli_strncmp(azArg[0], "archive", n)==0 ){
open_db(p, 0);
failIfSafeMode(p, "cannot run .archive in safe mode");
rc = arDotCommand(p, 0, azArg, nArg);
}else
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
- if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
- || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
+#ifndef SQLITE_SHELL_FIDDLE
+ if( (c=='b' && n>=3 && cli_strncmp(azArg[0], "backup", n)==0)
+ || (c=='s' && n>=3 && cli_strncmp(azArg[0], "save", n)==0)
){
const char *zDestFile = 0;
const char *zDb = 0;
@@ -19298,10 +22075,10 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *z = azArg[j];
if( z[0]=='-' ){
if( z[1]=='-' ) z++;
- if( strcmp(z, "-append")==0 ){
+ if( cli_strcmp(z, "-append")==0 ){
zVfs = "apndvfs";
}else
- if( strcmp(z, "-async")==0 ){
+ if( cli_strcmp(z, "-async")==0 ){
bAsync = 1;
}else
{
@@ -19351,9 +22128,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
close_db(pDest);
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
+ if( c=='b' && n>=3 && cli_strncmp(azArg[0], "bail", n)==0 ){
if( nArg==2 ){
bail_on_error = booleanValue(azArg[1]);
}else{
@@ -19362,7 +22139,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){
+ if( c=='b' && n>=3 && cli_strncmp(azArg[0], "binary", n)==0 ){
if( nArg==2 ){
if( booleanValue(azArg[1]) ){
setBinaryMode(p->out, 1);
@@ -19378,12 +22155,12 @@ static int do_meta_command(char *zLine, ShellState *p){
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
- if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
+ if( c=='b' && n>=3 && cli_strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='c' && cli_strcmp(azArg[0],"cd")==0 ){
failIfSafeMode(p, "cannot run .cd in safe mode");
if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
@@ -19402,9 +22179,9 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
}
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
+ if( c=='c' && n>=3 && cli_strncmp(azArg[0], "changes", n)==0 ){
if( nArg==2 ){
setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
}else{
@@ -19413,12 +22190,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
/* Cancel output redirection, if it is currently set (by .testcase)
** Then read the content of the testcase-out.txt file and compare against
** azArg[1]. If there are differences, report an error and exit.
*/
- if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
+ if( c=='c' && n>=3 && cli_strncmp(azArg[0], "check", n)==0 ){
char *zRes = 0;
output_reset(p);
if( nArg!=2 ){
@@ -19438,10 +22215,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_free(zRes);
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='c' && cli_strncmp(azArg[0], "clone", n)==0 ){
failIfSafeMode(p, "cannot run .clone in safe mode");
if( nArg==2 ){
tryToClone(p, azArg[1]);
@@ -19450,9 +22227,9 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
}
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){
+ if( c=='c' && cli_strncmp(azArg[0], "connection", n)==0 ){
if( nArg==1 ){
/* List available connections */
int i;
@@ -19479,7 +22256,7 @@ static int do_meta_command(char *zLine, ShellState *p){
globalDb = p->db = p->pAuxDb->db;
p->pAuxDb->db = 0;
}
- }else if( nArg==3 && strcmp(azArg[1], "close")==0
+ }else if( nArg==3 && cli_strcmp(azArg[1], "close")==0
&& IsDigit(azArg[2][0]) && azArg[2][1]==0 ){
int i = azArg[2][0] - '0';
if( i<0 || i>=ArraySize(p->aAuxDb) ){
@@ -19498,7 +22275,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
+ if( c=='d' && n>1 && cli_strncmp(azArg[0], "databases", n)==0 ){
char **azName = 0;
int nName = 0;
sqlite3_stmt *pStmt;
@@ -19537,7 +22314,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(azName);
}else
- if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
static const struct DbConfigChoices {
const char *zName;
int op;
@@ -19562,7 +22339,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int ii, v;
open_db(p, 0);
for(ii=0; ii<ArraySize(aDbConfig); ii++){
- if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
+ if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
if( nArg>=3 ){
sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
}
@@ -19576,18 +22353,18 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
- if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
+#if SQLITE_SHELL_HAVE_RECOVER
+ if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbinfo", n)==0 ){
rc = shell_dbinfo_command(p, nArg, azArg);
}else
- if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
+ if( c=='r' && cli_strncmp(azArg[0], "recover", n)==0 ){
open_db(p, 0);
rc = recoverDatabaseCmd(p, nArg, azArg);
}else
-#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+#endif /* SQLITE_SHELL_HAVE_RECOVER */
- if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
+ if( c=='d' && cli_strncmp(azArg[0], "dump", n)==0 ){
char *zLike = 0;
char *zSql;
int i;
@@ -19600,7 +22377,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( azArg[i][0]=='-' ){
const char *z = azArg[i]+1;
if( z[0]=='-' ) z++;
- if( strcmp(z,"preserve-rowids")==0 ){
+ if( cli_strcmp(z,"preserve-rowids")==0 ){
#ifdef SQLITE_OMIT_VIRTUALTABLE
raw_printf(stderr, "The --preserve-rowids option is not compatible"
" with SQLITE_OMIT_VIRTUALTABLE\n");
@@ -19611,13 +22388,13 @@ static int do_meta_command(char *zLine, ShellState *p){
ShellSetFlag(p, SHFLG_PreserveRowid);
#endif
}else
- if( strcmp(z,"newlines")==0 ){
+ if( cli_strcmp(z,"newlines")==0 ){
ShellSetFlag(p, SHFLG_Newlines);
}else
- if( strcmp(z,"data-only")==0 ){
+ if( cli_strcmp(z,"data-only")==0 ){
ShellSetFlag(p, SHFLG_DumpDataOnly);
}else
- if( strcmp(z,"nosys")==0 ){
+ if( cli_strcmp(z,"nosys")==0 ){
ShellSetFlag(p, SHFLG_DumpNoSys);
}else
{
@@ -19699,7 +22476,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->shellFlgs = savedShellFlags;
}else
- if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
+ if( c=='e' && cli_strncmp(azArg[0], "echo", n)==0 ){
if( nArg==2 ){
setOrClearFlag(p, SHFLG_Echo, azArg[1]);
}else{
@@ -19708,22 +22485,22 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
+ if( c=='e' && cli_strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
p->autoEQPtest = 0;
if( p->autoEQPtrace ){
if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
p->autoEQPtrace = 0;
}
- if( strcmp(azArg[1],"full")==0 ){
+ if( cli_strcmp(azArg[1],"full")==0 ){
p->autoEQP = AUTOEQP_full;
- }else if( strcmp(azArg[1],"trigger")==0 ){
+ }else if( cli_strcmp(azArg[1],"trigger")==0 ){
p->autoEQP = AUTOEQP_trigger;
#ifdef SQLITE_DEBUG
- }else if( strcmp(azArg[1],"test")==0 ){
+ }else if( cli_strcmp(azArg[1],"test")==0 ){
p->autoEQP = AUTOEQP_on;
p->autoEQPtest = 1;
- }else if( strcmp(azArg[1],"trace")==0 ){
+ }else if( cli_strcmp(azArg[1],"trace")==0 ){
p->autoEQP = AUTOEQP_full;
p->autoEQPtrace = 1;
open_db(p, 0);
@@ -19739,8 +22516,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='e' && cli_strncmp(azArg[0], "exit", n)==0 ){
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
rc = 2;
}else
@@ -19748,10 +22525,10 @@ static int do_meta_command(char *zLine, ShellState *p){
/* The ".explain" command is automatic now. It is largely pointless. It
** retained purely for backwards compatibility */
- if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
+ if( c=='e' && cli_strncmp(azArg[0], "explain", n)==0 ){
int val = 1;
if( nArg>=2 ){
- if( strcmp(azArg[1],"auto")==0 ){
+ if( cli_strcmp(azArg[1],"auto")==0 ){
val = 99;
}else{
val = booleanValue(azArg[1]);
@@ -19771,7 +22548,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
+ if( c=='e' && cli_strncmp(azArg[0], "expert", n)==0 ){
if( p->bSafeMode ){
raw_printf(stderr,
"Cannot run experimental commands such as \"%s\" in safe mode\n",
@@ -19784,7 +22561,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
- if( c=='f' && strncmp(azArg[0], "filectrl", n)==0 ){
+ if( c=='f' && cli_strncmp(azArg[0], "filectrl", n)==0 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
@@ -19814,7 +22591,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zCmd = nArg>=2 ? azArg[1] : "help";
if( zCmd[0]=='-'
- && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0)
+ && (cli_strcmp(zCmd,"--schema")==0 || cli_strcmp(zCmd,"-schema")==0)
&& nArg>=4
){
zSchema = azArg[2];
@@ -19830,7 +22607,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
/* --help lists all file-controls */
- if( strcmp(zCmd,"help")==0 ){
+ if( cli_strcmp(zCmd,"help")==0 ){
utf8_printf(p->out, "Available file-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
utf8_printf(p->out, " .filectrl %s %s\n",
@@ -19844,7 +22621,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** of the option name, or a numerical value. */
n2 = strlen30(zCmd);
for(i=0; i<ArraySize(aCtrl); i++){
- if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
+ if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
if( filectrl<0 ){
filectrl = aCtrl[i].ctrlCode;
iCtrl = i;
@@ -19931,7 +22708,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
+ if( c=='f' && cli_strncmp(azArg[0], "fullschema", n)==0 ){
ShellState data;
int doStats = 0;
memcpy(&data, p, sizeof(data));
@@ -19978,7 +22755,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
+ if( c=='h' && cli_strncmp(azArg[0], "headers", n)==0 ){
if( nArg==2 ){
p->showHeader = booleanValue(azArg[1]);
p->shellFlgs |= SHFLG_HeaderSet;
@@ -19988,7 +22765,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
+ if( c=='h' && cli_strncmp(azArg[0], "help", n)==0 ){
if( nArg>=2 ){
n = showHelp(p->out, azArg[1]);
if( n==0 ){
@@ -19999,8 +22776,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='i' && cli_strncmp(azArg[0], "import", n)==0 ){
char *zTable = 0; /* Insert data into this table */
char *zSchema = 0; /* within this schema (may default to "main") */
char *zFile = 0; /* Name of file to extra content from */
@@ -20040,18 +22817,18 @@ static int do_meta_command(char *zLine, ShellState *p){
showHelp(p->out, "import");
goto meta_command_exit;
}
- }else if( strcmp(z,"-v")==0 ){
+ }else if( cli_strcmp(z,"-v")==0 ){
eVerbose++;
- }else if( strcmp(z,"-schema")==0 && i<nArg-1 ){
+ }else if( cli_strcmp(z,"-schema")==0 && i<nArg-1 ){
zSchema = azArg[++i];
- }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){
+ }else if( cli_strcmp(z,"-skip")==0 && i<nArg-1 ){
nSkip = integerValue(azArg[++i]);
- }else if( strcmp(z,"-ascii")==0 ){
+ }else if( cli_strcmp(z,"-ascii")==0 ){
sCtx.cColSep = SEP_Unit[0];
sCtx.cRowSep = SEP_Record[0];
xRead = ascii_read_one_field;
useOutputMode = 0;
- }else if( strcmp(z,"-csv")==0 ){
+ }else if( cli_strcmp(z,"-csv")==0 ){
sCtx.cColSep = ',';
sCtx.cRowSep = '\n';
xRead = csv_read_one_field;
@@ -20091,7 +22868,9 @@ static int do_meta_command(char *zLine, ShellState *p){
"Error: non-null row separator required for import\n");
goto meta_command_exit;
}
- if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
+ if( nSep==2 && p->mode==MODE_Csv
+ && cli_strcmp(p->rowSeparator,SEP_CrLf)==0
+ ){
/* When importing CSV (only), if the row separator is set to the
** default output row separator, change it to the default input
** row separator. This avoids having to maintain different input
@@ -20290,10 +23069,10 @@ static int do_meta_command(char *zLine, ShellState *p){
sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
}
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
#ifndef SQLITE_UNTESTABLE
- if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
+ if( c=='i' && cli_strncmp(azArg[0], "imposter", n)==0 ){
char *zSql;
char *zCollist = 0;
sqlite3_stmt *pStmt;
@@ -20394,13 +23173,13 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
#ifdef SQLITE_ENABLE_IOTRACE
- if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+ if( c=='i' && cli_strncmp(azArg[0], "iotrace", n)==0 ){
SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...);
if( iotrace && iotrace!=stdout ) fclose(iotrace);
iotrace = 0;
if( nArg<2 ){
sqlite3IoTrace = 0;
- }else if( strcmp(azArg[1], "-")==0 ){
+ }else if( cli_strcmp(azArg[1], "-")==0 ){
sqlite3IoTrace = iotracePrintf;
iotrace = stdout;
}else{
@@ -20416,7 +23195,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
- if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
+ if( c=='l' && n>=5 && cli_strncmp(azArg[0], "limits", n)==0 ){
static const struct {
const char *zLimitName; /* Name of a limit */
int limitCode; /* Integer code for that limit */
@@ -20475,13 +23254,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
+ if( c=='l' && n>2 && cli_strncmp(azArg[0], "lint", n)==0 ){
open_db(p, 0);
lintDotCommand(p, azArg, nArg);
}else
-#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE)
- if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_FIDDLE)
+ if( c=='l' && cli_strncmp(azArg[0], "load", n)==0 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
failIfSafeMode(p, "cannot run .load in safe mode");
@@ -20502,8 +23281,8 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='l' && cli_strncmp(azArg[0], "log", n)==0 ){
failIfSafeMode(p, "cannot run .log in safe mode");
if( nArg!=2 ){
raw_printf(stderr, "Usage: .log FILENAME\n");
@@ -20516,7 +23295,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
- if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
+ if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
@@ -20535,10 +23314,10 @@ static int do_meta_command(char *zLine, ShellState *p){
cmOpts.bQuote = 0;
}else if( zMode==0 ){
zMode = z;
- /* Apply defaults for qbox pseudo-mods. If that
+ /* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
- if( strcmp(z, "qbox")==0 ){
+ if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
cmOpts = cmo;
@@ -20577,58 +23356,58 @@ static int do_meta_command(char *zLine, ShellState *p){
zMode = modeDescr[p->mode];
}
n2 = strlen30(zMode);
- if( strncmp(zMode,"lines",n2)==0 ){
+ if( cli_strncmp(zMode,"lines",n2)==0 ){
p->mode = MODE_Line;
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( strncmp(zMode,"columns",n2)==0 ){
+ }else if( cli_strncmp(zMode,"columns",n2)==0 ){
p->mode = MODE_Column;
if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
p->showHeader = 1;
}
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
p->cmOpts = cmOpts;
- }else if( strncmp(zMode,"list",n2)==0 ){
+ }else if( cli_strncmp(zMode,"list",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( strncmp(zMode,"html",n2)==0 ){
+ }else if( cli_strncmp(zMode,"html",n2)==0 ){
p->mode = MODE_Html;
- }else if( strncmp(zMode,"tcl",n2)==0 ){
+ }else if( cli_strncmp(zMode,"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( strncmp(zMode,"csv",n2)==0 ){
+ }else if( cli_strncmp(zMode,"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
- }else if( strncmp(zMode,"tabs",n2)==0 ){
+ }else if( cli_strncmp(zMode,"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
- }else if( strncmp(zMode,"insert",n2)==0 ){
+ }else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
- }else if( strncmp(zMode,"quote",n2)==0 ){
+ }else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
- }else if( strncmp(zMode,"ascii",n2)==0 ){
+ }else if( cli_strncmp(zMode,"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
- }else if( strncmp(zMode,"markdown",n2)==0 ){
+ }else if( cli_strncmp(zMode,"markdown",n2)==0 ){
p->mode = MODE_Markdown;
p->cmOpts = cmOpts;
- }else if( strncmp(zMode,"table",n2)==0 ){
+ }else if( cli_strncmp(zMode,"table",n2)==0 ){
p->mode = MODE_Table;
p->cmOpts = cmOpts;
- }else if( strncmp(zMode,"box",n2)==0 ){
+ }else if( cli_strncmp(zMode,"box",n2)==0 ){
p->mode = MODE_Box;
p->cmOpts = cmOpts;
- }else if( strncmp(zMode,"count",n2)==0 ){
+ }else if( cli_strncmp(zMode,"count",n2)==0 ){
p->mode = MODE_Count;
- }else if( strncmp(zMode,"off",n2)==0 ){
+ }else if( cli_strncmp(zMode,"off",n2)==0 ){
p->mode = MODE_Off;
- }else if( strncmp(zMode,"json",n2)==0 ){
+ }else if( cli_strncmp(zMode,"json",n2)==0 ){
p->mode = MODE_Json;
}else{
raw_printf(stderr, "Error: mode should be one of: "
@@ -20639,12 +23418,12 @@ static int do_meta_command(char *zLine, ShellState *p){
p->cMode = p->mode;
}else
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='n' && strcmp(azArg[0], "nonce")==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='n' && cli_strcmp(azArg[0], "nonce")==0 ){
if( nArg!=2 ){
raw_printf(stderr, "Usage: .nonce NONCE\n");
rc = 1;
- }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
+ }else if( p->zNonce==0 || cli_strcmp(azArg[1],p->zNonce)!=0 ){
raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n",
p->lineno, azArg[1]);
exit(1);
@@ -20654,9 +23433,9 @@ static int do_meta_command(char *zLine, ShellState *p){
** at the end of this procedure */
}
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
+ if( c=='n' && cli_strncmp(azArg[0], "nullvalue", n)==0 ){
if( nArg==2 ){
sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
"%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
@@ -20666,7 +23445,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
+ if( c=='o' && cli_strncmp(azArg[0], "open", n)==0 && n>=2 ){
const char *zFN = 0; /* Pointer to constant filename */
char *zNewFilename = 0; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
@@ -20676,7 +23455,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Check for command-line arguments */
for(iName=1; iName<nArg; iName++){
const char *z = azArg[iName];
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
if( optionMatch(z,"new") ){
newFlag = 1;
#ifdef SQLITE_HAVE_ZLIB
@@ -20698,7 +23477,7 @@ static int do_meta_command(char *zLine, ShellState *p){
p->szMax = integerValue(azArg[++iName]);
#endif /* SQLITE_OMIT_DESERIALIZE */
}else
-#endif /* !SQLITE_SHELL_WASM_MODE */
+#endif /* !SQLITE_SHELL_FIDDLE */
if( z[0]=='-' ){
utf8_printf(stderr, "unknown option: %s\n", z);
rc = 1;
@@ -20726,11 +23505,11 @@ static int do_meta_command(char *zLine, ShellState *p){
/* If a filename is specified, try to open it first */
if( zFN || p->openMode==SHELL_OPEN_HEXDB ){
if( newFlag && zFN && !p->bSafeMode ) shellDeleteFile(zFN);
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
if( p->bSafeMode
&& p->openMode!=SHELL_OPEN_HEXDB
&& zFN
- && strcmp(zFN,":memory:")!=0
+ && cli_strcmp(zFN,":memory:")!=0
){
failIfSafeMode(p, "cannot open disk-based database files in safe mode");
}
@@ -20759,10 +23538,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
if( (c=='o'
- && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
- || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
+ && (cli_strncmp(azArg[0], "output", n)==0
+ || cli_strncmp(azArg[0], "once", n)==0))
+ || (c=='e' && n==5 && cli_strcmp(azArg[0],"excel")==0)
){
char *zFile = 0;
int bTxtMode = 0;
@@ -20776,21 +23556,21 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='e' ){
eMode = 'x';
bOnce = 2;
- }else if( strncmp(azArg[0],"once",n)==0 ){
+ }else if( cli_strncmp(azArg[0],"once",n)==0 ){
bOnce = 1;
}
for(i=1; i<nArg; i++){
char *z = azArg[i];
if( z[0]=='-' ){
if( z[1]=='-' ) z++;
- if( strcmp(z,"-bom")==0 ){
+ if( cli_strcmp(z,"-bom")==0 ){
zBOM[0] = 0xef;
zBOM[1] = 0xbb;
zBOM[2] = 0xbf;
zBOM[3] = 0;
- }else if( c!='e' && strcmp(z,"-x")==0 ){
+ }else if( c!='e' && cli_strcmp(z,"-x")==0 ){
eMode = 'x'; /* spreadsheet */
- }else if( c!='e' && strcmp(z,"-e")==0 ){
+ }else if( c!='e' && cli_strcmp(z,"-e")==0 ){
eMode = 'e'; /* text editor */
}else{
utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
@@ -20863,7 +23643,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
p->out = output_file_open(zFile, bTxtMode);
if( p->out==0 ){
- if( strcmp(zFile,"off")!=0 ){
+ if( cli_strcmp(zFile,"off")!=0 ){
utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
}
p->out = stdout;
@@ -20875,16 +23655,16 @@ static int do_meta_command(char *zLine, ShellState *p){
}
sqlite3_free(zFile);
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
+ if( c=='p' && n>=3 && cli_strncmp(azArg[0], "parameter", n)==0 ){
open_db(p,0);
if( nArg<=1 ) goto parameter_syntax_error;
/* .parameter clear
** Clear all bind parameters by dropping the TEMP table that holds them.
*/
- if( nArg==2 && strcmp(azArg[1],"clear")==0 ){
+ if( nArg==2 && cli_strcmp(azArg[1],"clear")==0 ){
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
0, 0, 0);
}else
@@ -20892,7 +23672,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .parameter list
** List all bind parameters.
*/
- if( nArg==2 && strcmp(azArg[1],"list")==0 ){
+ if( nArg==2 && cli_strcmp(azArg[1],"list")==0 ){
sqlite3_stmt *pStmt = 0;
int rx;
int len = 0;
@@ -20921,7 +23701,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** Make sure the TEMP table used to hold bind parameters exists.
** Create it if necessary.
*/
- if( nArg==2 && strcmp(azArg[1],"init")==0 ){
+ if( nArg==2 && cli_strcmp(azArg[1],"init")==0 ){
bind_table_init(p);
}else
@@ -20931,7 +23711,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** VALUE can be in either SQL literal notation, or if not it will be
** understood to be a text string.
*/
- if( nArg==4 && strcmp(azArg[1],"set")==0 ){
+ if( nArg==4 && cli_strcmp(azArg[1],"set")==0 ){
int rx;
char *zSql;
sqlite3_stmt *pStmt;
@@ -20969,7 +23749,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** Remove the NAME binding from the parameter binding table, if it
** exists.
*/
- if( nArg==3 && strcmp(azArg[1],"unset")==0 ){
+ if( nArg==3 && cli_strcmp(azArg[1],"unset")==0 ){
char *zSql = sqlite3_mprintf(
"DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
shell_check_oom(zSql);
@@ -20981,7 +23761,7 @@ static int do_meta_command(char *zLine, ShellState *p){
showHelp(p->out, "parameter");
}else
- if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
+ if( c=='p' && n>=3 && cli_strncmp(azArg[0], "print", n)==0 ){
int i;
for(i=1; i<nArg; i++){
if( i>1 ) raw_printf(p->out, " ");
@@ -20991,7 +23771,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( c=='p' && n>=3 && strncmp(azArg[0], "progress", n)==0 ){
+ if( c=='p' && n>=3 && cli_strncmp(azArg[0], "progress", n)==0 ){
int i;
int nn = 0;
p->flgProgress = 0;
@@ -21002,19 +23782,19 @@ static int do_meta_command(char *zLine, ShellState *p){
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
- if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
+ if( cli_strcmp(z,"quiet")==0 || cli_strcmp(z,"q")==0 ){
p->flgProgress |= SHELL_PROGRESS_QUIET;
continue;
}
- if( strcmp(z,"reset")==0 ){
+ if( cli_strcmp(z,"reset")==0 ){
p->flgProgress |= SHELL_PROGRESS_RESET;
continue;
}
- if( strcmp(z,"once")==0 ){
+ if( cli_strcmp(z,"once")==0 ){
p->flgProgress |= SHELL_PROGRESS_ONCE;
continue;
}
- if( strcmp(z,"limit")==0 ){
+ if( cli_strcmp(z,"limit")==0 ){
if( i+1>=nArg ){
utf8_printf(stderr, "Error: missing argument on --limit\n");
rc = 1;
@@ -21036,7 +23816,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
- if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
+ if( c=='p' && cli_strncmp(azArg[0], "prompt", n)==0 ){
if( nArg >= 2) {
strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
}
@@ -21045,14 +23825,14 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='q' && cli_strncmp(azArg[0], "quit", n)==0 ){
rc = 2;
}else
#endif
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='r' && n>=3 && cli_strncmp(azArg[0], "read", n)==0 ){
FILE *inSaved = p->in;
int savedLineno = p->lineno;
failIfSafeMode(p, "cannot run .read in safe mode");
@@ -21086,10 +23866,10 @@ static int do_meta_command(char *zLine, ShellState *p){
p->in = inSaved;
p->lineno = savedLineno;
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
-#ifndef SQLITE_SHELL_WASM_MODE
- if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
+#ifndef SQLITE_SHELL_FIDDLE
+ if( c=='r' && n>=3 && cli_strncmp(azArg[0], "restore", n)==0 ){
const char *zSrcFile;
const char *zDb;
sqlite3 *pSrc;
@@ -21140,9 +23920,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
close_db(pSrc);
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
+ if( c=='s' && cli_strncmp(azArg[0], "scanstats", n)==0 ){
if( nArg==2 ){
p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -21154,7 +23934,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+ if( c=='s' && cli_strncmp(azArg[0], "schema", n)==0 ){
ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
@@ -21297,15 +24077,15 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( (c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0)
- || (c=='t' && n==9 && strncmp(azArg[0], "treetrace", n)==0)
+ if( (c=='s' && n==11 && cli_strncmp(azArg[0], "selecttrace", n)==0)
+ || (c=='t' && n==9 && cli_strncmp(azArg[0], "treetrace", n)==0)
){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x);
}else
#if defined(SQLITE_ENABLE_SESSION)
- if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){
+ if( c=='s' && cli_strncmp(azArg[0],"session",n)==0 && n>=3 ){
struct AuxDb *pAuxDb = p->pAuxDb;
OpenSession *pSession = &pAuxDb->aSession[0];
char **azCmd = &azArg[1];
@@ -21316,7 +24096,7 @@ static int do_meta_command(char *zLine, ShellState *p){
open_db(p, 0);
if( nArg>=3 ){
for(iSes=0; iSes<pAuxDb->nSession; iSes++){
- if( strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break;
+ if( cli_strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break;
}
if( iSes<pAuxDb->nSession ){
pSession = &pAuxDb->aSession[iSes];
@@ -21332,7 +24112,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** Invoke the sqlite3session_attach() interface to attach a particular
** table so that it is never filtered.
*/
- if( strcmp(azCmd[0],"attach")==0 ){
+ if( cli_strcmp(azCmd[0],"attach")==0 ){
if( nCmd!=2 ) goto session_syntax_error;
if( pSession->p==0 ){
session_not_open:
@@ -21350,7 +24130,9 @@ static int do_meta_command(char *zLine, ShellState *p){
** .session patchset FILE
** Write a changeset or patchset into a file. The file is overwritten.
*/
- if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
+ if( cli_strcmp(azCmd[0],"changeset")==0
+ || cli_strcmp(azCmd[0],"patchset")==0
+ ){
FILE *out = 0;
failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
if( nCmd!=2 ) goto session_syntax_error;
@@ -21384,7 +24166,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session close
** Close the identified session
*/
- if( strcmp(azCmd[0], "close")==0 ){
+ if( cli_strcmp(azCmd[0], "close")==0 ){
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
session_close(pSession);
@@ -21395,7 +24177,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session enable ?BOOLEAN?
** Query or set the enable flag
*/
- if( strcmp(azCmd[0], "enable")==0 ){
+ if( cli_strcmp(azCmd[0], "enable")==0 ){
int ii;
if( nCmd>2 ) goto session_syntax_error;
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
@@ -21409,7 +24191,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session filter GLOB ....
** Set a list of GLOB patterns of table names to be excluded.
*/
- if( strcmp(azCmd[0], "filter")==0 ){
+ if( cli_strcmp(azCmd[0], "filter")==0 ){
int ii, nByte;
if( nCmd<2 ) goto session_syntax_error;
if( pAuxDb->nSession ){
@@ -21434,7 +24216,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session indirect ?BOOLEAN?
** Query or set the indirect flag
*/
- if( strcmp(azCmd[0], "indirect")==0 ){
+ if( cli_strcmp(azCmd[0], "indirect")==0 ){
int ii;
if( nCmd>2 ) goto session_syntax_error;
ii = nCmd==1 ? -1 : booleanValue(azCmd[1]);
@@ -21448,7 +24230,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session isempty
** Determine if the session is empty
*/
- if( strcmp(azCmd[0], "isempty")==0 ){
+ if( cli_strcmp(azCmd[0], "isempty")==0 ){
int ii;
if( nCmd!=1 ) goto session_syntax_error;
if( pAuxDb->nSession ){
@@ -21461,7 +24243,7 @@ static int do_meta_command(char *zLine, ShellState *p){
/* .session list
** List all currently open sessions
*/
- if( strcmp(azCmd[0],"list")==0 ){
+ if( cli_strcmp(azCmd[0],"list")==0 ){
for(i=0; i<pAuxDb->nSession; i++){
utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName);
}
@@ -21471,13 +24253,13 @@ static int do_meta_command(char *zLine, ShellState *p){
** Open a new session called NAME on the attached database DB.
** DB is normally "main".
*/
- if( strcmp(azCmd[0],"open")==0 ){
+ if( cli_strcmp(azCmd[0],"open")==0 ){
char *zName;
if( nCmd!=3 ) goto session_syntax_error;
zName = azCmd[2];
if( zName[0]==0 ) goto session_syntax_error;
for(i=0; i<pAuxDb->nSession; i++){
- if( strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
+ if( cli_strcmp(pAuxDb->aSession[i].zName,zName)==0 ){
utf8_printf(stderr, "Session \"%s\" already exists\n", zName);
goto meta_command_exit;
}
@@ -21508,15 +24290,15 @@ static int do_meta_command(char *zLine, ShellState *p){
#ifdef SQLITE_DEBUG
/* Undocumented commands for internal testing. Subject to change
** without notice. */
- if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
- if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
+ if( c=='s' && n>=10 && cli_strncmp(azArg[0], "selftest-", 9)==0 ){
+ if( cli_strncmp(azArg[0]+9, "boolean", n-9)==0 ){
int i, v;
for(i=1; i<nArg; i++){
v = booleanValue(azArg[i]);
utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
}
- if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
+ if( cli_strncmp(azArg[0]+9, "integer", n-9)==0 ){
int i; sqlite3_int64 v;
for(i=1; i<nArg; i++){
char zBuf[200];
@@ -21528,7 +24310,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
- if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
+ if( c=='s' && n>=4 && cli_strncmp(azArg[0],"selftest",n)==0 ){
int bIsInit = 0; /* True to initialize the SELFTEST table */
int bVerbose = 0; /* Verbose output */
int bSelftestExists; /* True if SELFTEST already exists */
@@ -21542,10 +24324,10 @@ static int do_meta_command(char *zLine, ShellState *p){
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( z[0]=='-' && z[1]=='-' ) z++;
- if( strcmp(z,"-init")==0 ){
+ if( cli_strcmp(z,"-init")==0 ){
bIsInit = 1;
}else
- if( strcmp(z,"-v")==0 ){
+ if( cli_strcmp(z,"-v")==0 ){
bVerbose++;
}else
{
@@ -21598,10 +24380,10 @@ static int do_meta_command(char *zLine, ShellState *p){
if( bVerbose>0 ){
printf("%d: %s %s\n", tno, zOp, zSql);
}
- if( strcmp(zOp,"memo")==0 ){
+ if( cli_strcmp(zOp,"memo")==0 ){
utf8_printf(p->out, "%s\n", zSql);
}else
- if( strcmp(zOp,"run")==0 ){
+ if( cli_strcmp(zOp,"run")==0 ){
char *zErrMsg = 0;
str.n = 0;
str.z[0] = 0;
@@ -21615,7 +24397,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
sqlite3_free(zErrMsg);
- }else if( strcmp(zAns,str.z)!=0 ){
+ }else if( cli_strcmp(zAns,str.z)!=0 ){
nErr++;
rc = 1;
utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
@@ -21635,7 +24417,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
}else
- if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
+ if( c=='s' && cli_strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
rc = 1;
@@ -21650,7 +24432,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
+ if( c=='s' && n>=4 && cli_strncmp(azArg[0],"sha3sum",n)==0 ){
const char *zLike = 0; /* Which table to checksum. 0 means everything */
int i; /* Loop counter */
int bSchema = 0; /* Also hash the schema */
@@ -21668,15 +24450,15 @@ static int do_meta_command(char *zLine, ShellState *p){
if( z[0]=='-' ){
z++;
if( z[0]=='-' ) z++;
- if( strcmp(z,"schema")==0 ){
+ if( cli_strcmp(z,"schema")==0 ){
bSchema = 1;
}else
- if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
- || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
+ if( cli_strcmp(z,"sha3-224")==0 || cli_strcmp(z,"sha3-256")==0
+ || cli_strcmp(z,"sha3-384")==0 || cli_strcmp(z,"sha3-512")==0
){
iSize = atoi(&z[5]);
}else
- if( strcmp(z,"debug")==0 ){
+ if( cli_strcmp(z,"debug")==0 ){
bDebug = 1;
}else
{
@@ -21716,20 +24498,20 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
if( zTab==0 ) continue;
if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
- if( strncmp(zTab, "sqlite_",7)!=0 ){
+ if( cli_strncmp(zTab, "sqlite_",7)!=0 ){
appendText(&sQuery,"SELECT * FROM ", 0);
appendText(&sQuery,zTab,'"');
appendText(&sQuery," NOT INDEXED;", 0);
- }else if( strcmp(zTab, "sqlite_schema")==0 ){
+ }else if( cli_strcmp(zTab, "sqlite_schema")==0 ){
appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
" ORDER BY name;", 0);
- }else if( strcmp(zTab, "sqlite_sequence")==0 ){
+ }else if( cli_strcmp(zTab, "sqlite_sequence")==0 ){
appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
" ORDER BY name;", 0);
- }else if( strcmp(zTab, "sqlite_stat1")==0 ){
+ }else if( cli_strcmp(zTab, "sqlite_stat1")==0 ){
appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
" ORDER BY tbl,idx;", 0);
- }else if( strcmp(zTab, "sqlite_stat4")==0 ){
+ }else if( cli_strcmp(zTab, "sqlite_stat4")==0 ){
appendText(&sQuery, "SELECT * FROM ", 0);
appendText(&sQuery, zTab, 0);
appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
@@ -21766,9 +24548,10 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zSql);
}else
-#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE)
+#if !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE)
if( c=='s'
- && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
+ && (cli_strncmp(azArg[0], "shell", n)==0
+ || cli_strncmp(azArg[0],"system",n)==0)
){
char *zCmd;
int i, x;
@@ -21787,9 +24570,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zCmd);
if( x ) raw_printf(stderr, "System command returns %d\n", x);
}else
-#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_NOHAVE_SYSTEM) && !defined(SQLITE_SHELL_FIDDLE) */
- if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
+ if( c=='s' && cli_strncmp(azArg[0], "show", n)==0 ){
static const char *azBool[] = { "off", "on", "trigger", "full"};
const char *zOut;
int i;
@@ -21842,11 +24625,11 @@ static int do_meta_command(char *zLine, ShellState *p){
p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : "");
}else
- if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
+ if( c=='s' && cli_strncmp(azArg[0], "stats", n)==0 ){
if( nArg==2 ){
- if( strcmp(azArg[1],"stmt")==0 ){
+ if( cli_strcmp(azArg[1],"stmt")==0 ){
p->statsOn = 2;
- }else if( strcmp(azArg[1],"vmstep")==0 ){
+ }else if( cli_strcmp(azArg[1],"vmstep")==0 ){
p->statsOn = 3;
}else{
p->statsOn = (u8)booleanValue(azArg[1]);
@@ -21859,9 +24642,9 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
- || (c=='i' && (strncmp(azArg[0], "indices", n)==0
- || strncmp(azArg[0], "indexes", n)==0) )
+ if( (c=='t' && n>1 && cli_strncmp(azArg[0], "tables", n)==0)
+ || (c=='i' && (cli_strncmp(azArg[0], "indices", n)==0
+ || cli_strncmp(azArg[0], "indexes", n)==0) )
){
sqlite3_stmt *pStmt;
char **azResult;
@@ -21967,9 +24750,9 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(azResult);
}else
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
/* Begin redirecting output to the file "testcase-out.txt" */
- if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
+ if( c=='t' && cli_strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
p->out = output_file_open("testcase-out.txt", 0);
if( p->out==0 ){
@@ -21981,10 +24764,10 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?");
}
}else
-#endif /* !defined(SQLITE_SHELL_WASM_MODE) */
+#endif /* !defined(SQLITE_SHELL_FIDDLE) */
#ifndef SQLITE_UNTESTABLE
- if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
+ if( c=='t' && n>=8 && cli_strncmp(azArg[0], "testctrl", n)==0 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
@@ -22031,7 +24814,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
/* --help lists all test-controls */
- if( strcmp(zCmd,"help")==0 ){
+ if( cli_strcmp(zCmd,"help")==0 ){
utf8_printf(p->out, "Available test-controls:\n");
for(i=0; i<ArraySize(aCtrl); i++){
utf8_printf(p->out, " .testctrl %s %s\n",
@@ -22045,7 +24828,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** of the option name, or a numerical value. */
n2 = strlen30(zCmd);
for(i=0; i<ArraySize(aCtrl); i++){
- if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
+ if( cli_strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
iCtrl = i;
@@ -22101,7 +24884,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg==3 || nArg==4 ){
int ii = (int)integerValue(azArg[2]);
sqlite3 *db;
- if( ii==0 && strcmp(azArg[2],"random")==0 ){
+ if( ii==0 && cli_strcmp(azArg[2],"random")==0 ){
sqlite3_randomness(sizeof(ii),&ii);
printf("-- random seed: %d\n", ii);
}
@@ -22217,12 +25000,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* !defined(SQLITE_UNTESTABLE) */
- if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
+ if( c=='t' && n>4 && cli_strncmp(azArg[0], "timeout", n)==0 ){
open_db(p, 0);
sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
}else
- if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
+ if( c=='t' && n>=5 && cli_strncmp(azArg[0], "timer", n)==0 ){
if( nArg==2 ){
enableTimer = booleanValue(azArg[1]);
if( enableTimer && !HAS_TIMER ){
@@ -22236,7 +25019,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#ifndef SQLITE_OMIT_TRACE
- if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
+ if( c=='t' && cli_strncmp(azArg[0], "trace", n)==0 ){
int mType = 0;
int jj;
open_db(p, 0);
@@ -22286,7 +25069,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif /* !defined(SQLITE_OMIT_TRACE) */
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
- if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){
+ if( c=='u' && cli_strncmp(azArg[0], "unmodule", n)==0 ){
int ii;
int lenOpt;
char *zOpt;
@@ -22299,7 +25082,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zOpt = azArg[1];
if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
lenOpt = (int)strlen(zOpt);
- if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
+ if( lenOpt>=3 && cli_strncmp(zOpt, "-allexcept",lenOpt)==0 ){
assert( azArg[nArg]==0 );
sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
}else{
@@ -22311,14 +25094,14 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif
#if SQLITE_USER_AUTHENTICATION
- if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
+ if( c=='u' && cli_strncmp(azArg[0], "user", n)==0 ){
if( nArg<2 ){
raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n");
rc = 1;
goto meta_command_exit;
}
open_db(p, 0);
- if( strcmp(azArg[1],"login")==0 ){
+ if( cli_strcmp(azArg[1],"login")==0 ){
if( nArg!=4 ){
raw_printf(stderr, "Usage: .user login USER PASSWORD\n");
rc = 1;
@@ -22330,7 +25113,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
rc = 1;
}
- }else if( strcmp(azArg[1],"add")==0 ){
+ }else if( cli_strcmp(azArg[1],"add")==0 ){
if( nArg!=5 ){
raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n");
rc = 1;
@@ -22342,7 +25125,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "User-Add failed: %d\n", rc);
rc = 1;
}
- }else if( strcmp(azArg[1],"edit")==0 ){
+ }else if( cli_strcmp(azArg[1],"edit")==0 ){
if( nArg!=5 ){
raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n");
rc = 1;
@@ -22354,7 +25137,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(stderr, "User-Edit failed: %d\n", rc);
rc = 1;
}
- }else if( strcmp(azArg[1],"delete")==0 ){
+ }else if( cli_strcmp(azArg[1],"delete")==0 ){
if( nArg!=3 ){
raw_printf(stderr, "Usage: .user delete USER\n");
rc = 1;
@@ -22373,7 +25156,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif /* SQLITE_USER_AUTHENTICATION */
- if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
+ if( c=='v' && cli_strncmp(azArg[0], "version", n)==0 ){
utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
#if SQLITE_HAVE_ZLIB
@@ -22392,7 +25175,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#endif
}else
- if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
+ if( c=='v' && cli_strncmp(azArg[0], "vfsinfo", n)==0 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
sqlite3_vfs *pVfs = 0;
if( p->db ){
@@ -22406,7 +25189,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){
+ if( c=='v' && cli_strncmp(azArg[0], "vfslist", n)==0 ){
sqlite3_vfs *pVfs;
sqlite3_vfs *pCurrent = 0;
if( p->db ){
@@ -22424,7 +25207,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
+ if( c=='v' && cli_strncmp(azArg[0], "vfsname", n)==0 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
char *zVfsName = 0;
if( p->db ){
@@ -22436,12 +25219,12 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
+ if( c=='w' && cli_strncmp(azArg[0], "wheretrace", n)==0 ){
unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff;
sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
}else
- if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
+ if( c=='w' && cli_strncmp(azArg[0], "width", n)==0 ){
int j;
assert( nArg<=ArraySize(azArg) );
p->nWidth = nArg-1;
@@ -22619,10 +25402,10 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
if( zErrMsg==0 ){
zErrorType = "Error";
zErrorTail = sqlite3_errmsg(p->db);
- }else if( strncmp(zErrMsg, "in prepare, ",12)==0 ){
+ }else if( cli_strncmp(zErrMsg, "in prepare, ",12)==0 ){
zErrorType = "Parse error";
zErrorTail = &zErrMsg[12];
- }else if( strncmp(zErrMsg, "stepping, ", 10)==0 ){
+ }else if( cli_strncmp(zErrMsg, "stepping, ", 10)==0 ){
zErrorType = "Runtime error";
zErrorTail = &zErrMsg[10];
}else{
@@ -22653,7 +25436,7 @@ static void echo_group_input(ShellState *p, const char *zDo){
if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo);
}
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
/*
** Alternate one_input_line() impl for wasm mode. This is not in the primary impl
** because we need the global shellState and cannot access it from that function
@@ -22664,7 +25447,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
const char *zBegin = shellState.wasm.zPos;
const char *z = zBegin;
char *zLine = 0;
- int nZ = 0;
+ i64 nZ = 0;
UNUSED_PARAMETER(in);
UNUSED_PARAMETER(isContinuation);
@@ -22680,11 +25463,11 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
shellState.wasm.zPos = z;
zLine = realloc(zPrior, nZ+1);
shell_check_oom(zLine);
- memcpy(zLine, zBegin, (size_t)nZ);
+ memcpy(zLine, zBegin, nZ);
zLine[nZ] = 0;
return zLine;
}
-#endif /* SQLITE_SHELL_WASM_MODE */
+#endif /* SQLITE_SHELL_FIDDLE */
/*
** Read input from *in and process it. If *in==0 then input
@@ -22698,12 +25481,12 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
static int process_input(ShellState *p){
char *zLine = 0; /* A single input line */
char *zSql = 0; /* Accumulated SQL text */
- int nLine; /* Length of current line */
- int nSql = 0; /* Bytes of zSql[] used */
- int nAlloc = 0; /* Allocated zSql[] space */
+ i64 nLine; /* Length of current line */
+ i64 nSql = 0; /* Bytes of zSql[] used */
+ i64 nAlloc = 0; /* Allocated zSql[] space */
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
- int startline = 0; /* Line number for start of current input */
+ i64 startline = 0; /* Line number for start of current input */
QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */
if( p->inputNesting==MAX_INPUT_NESTING ){
@@ -22753,7 +25536,7 @@ static int process_input(ShellState *p){
continue;
}
/* No single-line dispositions remain; accumulate line(s). */
- nLine = strlen30(zLine);
+ nLine = strlen(zLine);
if( nSql+nLine+2>=nAlloc ){
/* Grow buffer by half-again increments when big. */
nAlloc = nSql+(nSql>>1)+nLine+100;
@@ -22761,7 +25544,7 @@ static int process_input(ShellState *p){
shell_check_oom(zSql);
}
if( nSql==0 ){
- int i;
+ i64 i;
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
@@ -22861,7 +25644,7 @@ static char *find_home_dir(int clearFlag){
#endif /* !_WIN32_WCE */
if( home_dir ){
- int n = strlen30(home_dir) + 1;
+ i64 n = strlen(home_dir) + 1;
char *z = malloc( n );
if( z ) memcpy(z, home_dir, n);
home_dir = z;
@@ -23067,7 +25850,7 @@ static char *cmdline_option_value(int argc, char **argv, int i){
# endif
#endif
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
# define main fiddle_main
#endif
@@ -23081,7 +25864,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
sqlite3_int64 mem_main_enter = sqlite3_memory_used();
#endif
char *zErrMsg = 0;
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
# define data shellState
#else
ShellState data;
@@ -23101,9 +25884,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
setBinaryMode(stdin, 0);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
stdin_is_interactive = 0;
stdout_is_console = 1;
+ data.wasm.zDefaultDbName = "/fiddle.sqlite3";
#else
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
@@ -23131,7 +25915,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
#if USE_SYSTEM_SQLITE+0!=1
- if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
+ if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
sqlite3_sourceid(), SQLITE_SOURCE_ID);
exit(1);
@@ -23153,9 +25937,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
argv = argvToFree + argc;
for(i=0; i<argc; i++){
char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
- int n;
+ i64 n;
shell_check_oom(z);
- n = (int)strlen(z);
+ n = strlen(z);
argv[i] = malloc( n+1 );
shell_check_oom(argv[i]);
memcpy(argv[i], z, n+1);
@@ -23212,21 +25996,21 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}
if( z[1]=='-' ) z++;
- if( strcmp(z,"-separator")==0
- || strcmp(z,"-nullvalue")==0
- || strcmp(z,"-newline")==0
- || strcmp(z,"-cmd")==0
+ if( cli_strcmp(z,"-separator")==0
+ || cli_strcmp(z,"-nullvalue")==0
+ || cli_strcmp(z,"-newline")==0
+ || cli_strcmp(z,"-cmd")==0
){
(void)cmdline_option_value(argc, argv, ++i);
- }else if( strcmp(z,"-init")==0 ){
+ }else if( cli_strcmp(z,"-init")==0 ){
zInitFile = cmdline_option_value(argc, argv, ++i);
- }else if( strcmp(z,"-batch")==0 ){
+ }else if( cli_strcmp(z,"-batch")==0 ){
/* 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.
*/
stdin_is_interactive = 0;
- }else if( strcmp(z,"-heap")==0 ){
+ }else if( cli_strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
const char *zSize;
sqlite3_int64 szHeap;
@@ -23238,7 +26022,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#else
(void)cmdline_option_value(argc, argv, ++i);
#endif
- }else if( strcmp(z,"-pagecache")==0 ){
+ }else if( cli_strcmp(z,"-pagecache")==0 ){
sqlite3_int64 n, sz;
sz = integerValue(cmdline_option_value(argc,argv,++i));
if( sz>70000 ) sz = 70000;
@@ -23250,7 +26034,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
sqlite3_config(SQLITE_CONFIG_PAGECACHE,
(n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);
data.shellFlgs |= SHFLG_Pagecache;
- }else if( strcmp(z,"-lookaside")==0 ){
+ }else if( cli_strcmp(z,"-lookaside")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
if( sz<0 ) sz = 0;
@@ -23258,7 +26042,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( n<0 ) n = 0;
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
- }else if( strcmp(z,"-threadsafe")==0 ){
+ }else if( cli_strcmp(z,"-threadsafe")==0 ){
int n;
n = (int)integerValue(cmdline_option_value(argc,argv,++i));
switch( n ){
@@ -23267,7 +26051,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break;
}
#ifdef SQLITE_ENABLE_VFSTRACE
- }else if( strcmp(z,"-vfstrace")==0 ){
+ }else if( cli_strcmp(z,"-vfstrace")==0 ){
extern int vfstrace_register(
const char *zTraceName,
const char *zOldVfsName,
@@ -23278,50 +26062,50 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
- }else if( strcmp(z,"-multiplex")==0 ){
+ }else if( cli_strcmp(z,"-multiplex")==0 ){
extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1);
#endif
- }else if( strcmp(z,"-mmap")==0 ){
+ }else if( cli_strcmp(z,"-mmap")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
- }else if( strcmp(z,"-sorterref")==0 ){
+ }else if( cli_strcmp(z,"-sorterref")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
#endif
- }else if( strcmp(z,"-vfs")==0 ){
+ }else if( cli_strcmp(z,"-vfs")==0 ){
zVfs = cmdline_option_value(argc, argv, ++i);
#ifdef SQLITE_HAVE_ZLIB
- }else if( strcmp(z,"-zip")==0 ){
+ }else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
- }else if( strcmp(z,"-append")==0 ){
+ }else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
- }else if( strcmp(z,"-deserialize")==0 ){
+ }else if( cli_strcmp(z,"-deserialize")==0 ){
data.openMode = SHELL_OPEN_DESERIALIZE;
- }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
+ }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
data.szMax = integerValue(argv[++i]);
#endif
- }else if( strcmp(z,"-readonly")==0 ){
+ }else if( cli_strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
- }else if( strcmp(z,"-nofollow")==0 ){
+ }else if( cli_strcmp(z,"-nofollow")==0 ){
data.openFlags = SQLITE_OPEN_NOFOLLOW;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
- }else if( strncmp(z, "-A",2)==0 ){
+ }else if( cli_strncmp(z, "-A",2)==0 ){
/* All remaining command-line arguments are passed to the ".archive"
** command, so ignore them */
break;
#endif
- }else if( strcmp(z, "-memtrace")==0 ){
+ }else if( cli_strcmp(z, "-memtrace")==0 ){
sqlite3MemTraceActivate(stderr);
- }else if( strcmp(z,"-bail")==0 ){
+ }else if( cli_strcmp(z,"-bail")==0 ){
bail_on_error = 1;
- }else if( strcmp(z,"-nonce")==0 ){
+ }else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(argv[++i]);
- }else if( strcmp(z,"-safe")==0 ){
+ }else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}
}
@@ -23363,7 +26147,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}
data.out = stdout;
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
sqlite3_appendvfs_init(0,0,0);
#endif
@@ -23391,127 +26175,127 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
char *z = argv[i];
if( z[0]!='-' ) continue;
if( z[1]=='-' ){ z++; }
- if( strcmp(z,"-init")==0 ){
+ if( cli_strcmp(z,"-init")==0 ){
i++;
- }else if( strcmp(z,"-html")==0 ){
+ }else if( cli_strcmp(z,"-html")==0 ){
data.mode = MODE_Html;
- }else if( strcmp(z,"-list")==0 ){
+ }else if( cli_strcmp(z,"-list")==0 ){
data.mode = MODE_List;
- }else if( strcmp(z,"-quote")==0 ){
+ }else if( cli_strcmp(z,"-quote")==0 ){
data.mode = MODE_Quote;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
- }else if( strcmp(z,"-line")==0 ){
+ }else if( cli_strcmp(z,"-line")==0 ){
data.mode = MODE_Line;
- }else if( strcmp(z,"-column")==0 ){
+ }else if( cli_strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
- }else if( strcmp(z,"-json")==0 ){
+ }else if( cli_strcmp(z,"-json")==0 ){
data.mode = MODE_Json;
- }else if( strcmp(z,"-markdown")==0 ){
+ }else if( cli_strcmp(z,"-markdown")==0 ){
data.mode = MODE_Markdown;
- }else if( strcmp(z,"-table")==0 ){
+ }else if( cli_strcmp(z,"-table")==0 ){
data.mode = MODE_Table;
- }else if( strcmp(z,"-box")==0 ){
+ }else if( cli_strcmp(z,"-box")==0 ){
data.mode = MODE_Box;
- }else if( strcmp(z,"-csv")==0 ){
+ }else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
#ifdef SQLITE_HAVE_ZLIB
- }else if( strcmp(z,"-zip")==0 ){
+ }else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
- }else if( strcmp(z,"-append")==0 ){
+ }else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
- }else if( strcmp(z,"-deserialize")==0 ){
+ }else if( cli_strcmp(z,"-deserialize")==0 ){
data.openMode = SHELL_OPEN_DESERIALIZE;
- }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
+ }else if( cli_strcmp(z,"-maxsize")==0 && i+1<argc ){
data.szMax = integerValue(argv[++i]);
#endif
- }else if( strcmp(z,"-readonly")==0 ){
+ }else if( cli_strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
- }else if( strcmp(z,"-nofollow")==0 ){
+ }else if( cli_strcmp(z,"-nofollow")==0 ){
data.openFlags |= SQLITE_OPEN_NOFOLLOW;
- }else if( strcmp(z,"-ascii")==0 ){
+ }else if( cli_strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record);
- }else if( strcmp(z,"-tabs")==0 ){
+ }else if( cli_strcmp(z,"-tabs")==0 ){
data.mode = MODE_List;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Tab);
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Row);
- }else if( strcmp(z,"-separator")==0 ){
+ }else if( cli_strcmp(z,"-separator")==0 ){
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
"%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-newline")==0 ){
+ }else if( cli_strcmp(z,"-newline")==0 ){
sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
"%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-nullvalue")==0 ){
+ }else if( cli_strcmp(z,"-nullvalue")==0 ){
sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
"%s",cmdline_option_value(argc,argv,++i));
- }else if( strcmp(z,"-header")==0 ){
+ }else if( cli_strcmp(z,"-header")==0 ){
data.showHeader = 1;
ShellSetFlag(&data, SHFLG_HeaderSet);
- }else if( strcmp(z,"-noheader")==0 ){
+ }else if( cli_strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
ShellSetFlag(&data, SHFLG_HeaderSet);
- }else if( strcmp(z,"-echo")==0 ){
+ }else if( cli_strcmp(z,"-echo")==0 ){
ShellSetFlag(&data, SHFLG_Echo);
- }else if( strcmp(z,"-eqp")==0 ){
+ }else if( cli_strcmp(z,"-eqp")==0 ){
data.autoEQP = AUTOEQP_on;
- }else if( strcmp(z,"-eqpfull")==0 ){
+ }else if( cli_strcmp(z,"-eqpfull")==0 ){
data.autoEQP = AUTOEQP_full;
- }else if( strcmp(z,"-stats")==0 ){
+ }else if( cli_strcmp(z,"-stats")==0 ){
data.statsOn = 1;
- }else if( strcmp(z,"-scanstats")==0 ){
+ }else if( cli_strcmp(z,"-scanstats")==0 ){
data.scanstatsOn = 1;
- }else if( strcmp(z,"-backslash")==0 ){
+ }else if( cli_strcmp(z,"-backslash")==0 ){
/* Undocumented command-line option: -backslash
** Causes C-style backslash escapes to be evaluated in SQL statements
** prior to sending the SQL into SQLite. Useful for injecting
** crazy bytes in the middle of SQL statements for testing and debugging.
*/
ShellSetFlag(&data, SHFLG_Backslash);
- }else if( strcmp(z,"-bail")==0 ){
+ }else if( cli_strcmp(z,"-bail")==0 ){
/* No-op. The bail_on_error flag should already be set. */
- }else if( strcmp(z,"-version")==0 ){
+ }else if( cli_strcmp(z,"-version")==0 ){
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
return 0;
- }else if( strcmp(z,"-interactive")==0 ){
+ }else if( cli_strcmp(z,"-interactive")==0 ){
stdin_is_interactive = 1;
- }else if( strcmp(z,"-batch")==0 ){
+ }else if( cli_strcmp(z,"-batch")==0 ){
stdin_is_interactive = 0;
- }else if( strcmp(z,"-heap")==0 ){
+ }else if( cli_strcmp(z,"-heap")==0 ){
i++;
- }else if( strcmp(z,"-pagecache")==0 ){
+ }else if( cli_strcmp(z,"-pagecache")==0 ){
i+=2;
- }else if( strcmp(z,"-lookaside")==0 ){
+ }else if( cli_strcmp(z,"-lookaside")==0 ){
i+=2;
- }else if( strcmp(z,"-threadsafe")==0 ){
+ }else if( cli_strcmp(z,"-threadsafe")==0 ){
i+=2;
- }else if( strcmp(z,"-nonce")==0 ){
+ }else if( cli_strcmp(z,"-nonce")==0 ){
i += 2;
- }else if( strcmp(z,"-mmap")==0 ){
+ }else if( cli_strcmp(z,"-mmap")==0 ){
i++;
- }else if( strcmp(z,"-memtrace")==0 ){
+ }else if( cli_strcmp(z,"-memtrace")==0 ){
i++;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
- }else if( strcmp(z,"-sorterref")==0 ){
+ }else if( cli_strcmp(z,"-sorterref")==0 ){
i++;
#endif
- }else if( strcmp(z,"-vfs")==0 ){
+ }else if( cli_strcmp(z,"-vfs")==0 ){
i++;
#ifdef SQLITE_ENABLE_VFSTRACE
- }else if( strcmp(z,"-vfstrace")==0 ){
+ }else if( cli_strcmp(z,"-vfstrace")==0 ){
i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
- }else if( strcmp(z,"-multiplex")==0 ){
+ }else if( cli_strcmp(z,"-multiplex")==0 ){
i++;
#endif
- }else if( strcmp(z,"-help")==0 ){
+ }else if( cli_strcmp(z,"-help")==0 ){
usage(1);
- }else if( strcmp(z,"-cmd")==0 ){
+ }else if( cli_strcmp(z,"-cmd")==0 ){
/* Run commands that follow -cmd first and separately from commands
** that simply appear on the command-line. This seems goofy. It would
** be better if all commands ran in the order that they appear. But
@@ -23533,7 +26317,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
- }else if( strncmp(z, "-A", 2)==0 ){
+ }else if( cli_strncmp(z, "-A", 2)==0 ){
if( nCmd>0 ){
utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
" with \"%s\"\n", z);
@@ -23549,7 +26333,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
readStdin = 0;
break;
#endif
- }else if( strcmp(z,"-safe")==0 ){
+ }else if( cli_strcmp(z,"-safe")==0 ){
data.bSafeMode = data.bSafeModePersist = 1;
}else{
utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
@@ -23631,7 +26415,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
rc = process_input(&data);
}
}
-#ifndef SQLITE_SHELL_WASM_MODE
+#ifndef SQLITE_SHELL_FIDDLE
/* In WASM mode we have to leave the db state in place so that
** client code can "push" SQL into it after this call returns. */
free(azCmd);
@@ -23666,38 +26450,38 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
(unsigned int)(sqlite3_memory_used()-mem_main_enter));
}
#endif
-#endif /* !SQLITE_SHELL_WASM_MODE */
+#endif /* !SQLITE_SHELL_FIDDLE */
return rc;
}
-#ifdef SQLITE_SHELL_WASM_MODE
+#ifdef SQLITE_SHELL_FIDDLE
/* Only for emcc experimentation purposes. */
int fiddle_experiment(int a,int b){
- return a + b;
+ return a + b;
}
-/* Only for emcc experimentation purposes.
-
- Define this function in JS using:
-
- emcc ... --js-library somefile.js
-
- containing:
+/*
+** Returns a pointer to the current DB handle.
+*/
+sqlite3 * fiddle_db_handle(){
+ return globalDb;
+}
-mergeInto(LibraryManager.library, {
- my_foo: function(){
- console.debug("my_foo()",arguments);
- }
-});
+/*
+** Returns a pointer to the given DB name's VFS. If zDbName is 0 then
+** "main" is assumed. Returns 0 if no db with the given name is
+** open.
*/
-/*extern void my_foo(sqlite3 *);*/
-/* Only for emcc experimentation purposes. */
-sqlite3 * fiddle_the_db(){
- printf("fiddle_the_db(%p)\n", (const void*)globalDb);
- /*my_foo(globalDb);*/
- return globalDb;
+sqlite3_vfs * fiddle_db_vfs(const char *zDbName){
+ sqlite3_vfs * pVfs = 0;
+ if(globalDb){
+ sqlite3_file_control(globalDb, zDbName ? zDbName : "main",
+ SQLITE_FCNTL_VFS_POINTER, &pVfs);
+ }
+ return pVfs;
}
+
/* Only for emcc experimentation purposes. */
sqlite3 * fiddle_db_arg(sqlite3 *arg){
printf("fiddle_db_arg(%p)\n", (const void*)arg);
@@ -23711,7 +26495,7 @@ sqlite3 * fiddle_db_arg(sqlite3 *arg){
** portable enough to make real use of.
*/
void fiddle_interrupt(void){
- if(globalDb) sqlite3_interrupt(globalDb);
+ if( globalDb ) sqlite3_interrupt(globalDb);
}
/*
@@ -23725,71 +26509,72 @@ const char * fiddle_db_filename(const char * zDbName){
}
/*
-** Closes, unlinks, and reopens the db using its current filename (or
-** the default if the db is currently closed). It is assumed, for
-** purposes of the fiddle build, that the file is in a transient
-** virtual filesystem within the browser.
+** Completely wipes out the contents of the currently-opened database
+** but leaves its storage intact for reuse.
*/
void fiddle_reset_db(void){
- char *zFilename = 0;
- if(0==globalDb){
- shellState.pAuxDb->zDbFilename = "/fiddle.sqlite3";
- }else{
- zFilename =
- sqlite3_mprintf("%s", sqlite3_db_filename(globalDb, "main"));
- shell_check_oom(zFilename);
- close_db(globalDb);
- shellDeleteFile(zFilename);
- shellState.db = 0;
- shellState.pAuxDb->zDbFilename = zFilename;
+ if( globalDb ){
+ int rc = sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
+ if( 0==rc ) rc = sqlite3_exec(globalDb, "VACUUM", 0, 0, 0);
+ sqlite3_db_config(globalDb, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
+ }
+}
+
+/*
+** Uses the current database's VFS xRead to stream the db file's
+** contents out to the given callback. The callback gets a single
+** chunk of size n (its 2nd argument) on each call and must return 0
+** on success, non-0 on error. This function returns 0 on success,
+** SQLITE_NOTFOUND if no db is open, or propagates any other non-0
+** code from the callback. Note that this is not thread-friendly: it
+** expects that it will be the only thread reading the db file and
+** takes no measures to ensure that is the case.
+*/
+int fiddle_export_db( int (*xCallback)(unsigned const char *zOut, int n) ){
+ sqlite3_int64 nSize = 0;
+ sqlite3_int64 nPos = 0;
+ sqlite3_file * pFile = 0;
+ unsigned char buf[1024 * 8];
+ int nBuf = (int)sizeof(buf);
+ int rc = shellState.db
+ ? sqlite3_file_control(shellState.db, "main",
+ SQLITE_FCNTL_FILE_POINTER, &pFile)
+ : SQLITE_NOTFOUND;
+ if( rc ) return rc;
+ rc = pFile->pMethods->xFileSize(pFile, &nSize);
+ if( rc ) return rc;
+ if(nSize % nBuf){
+ /* DB size is not an even multiple of the buffer size. Reduce
+ ** buffer size so that we do not unduly inflate the db size when
+ ** exporting. */
+ if(0 == nSize % 4096) nBuf = 4096;
+ else if(0 == nSize % 2048) nBuf = 2048;
+ else if(0 == nSize % 1024) nBuf = 1024;
+ else nBuf = 512;
+ }
+ for( ; 0==rc && nPos<nSize; nPos += nBuf ){
+ rc = pFile->pMethods->xRead(pFile, buf, nBuf, nPos);
+ if(SQLITE_IOERR_SHORT_READ == rc){
+ rc = (nPos + nBuf) < nSize ? rc : 0/*assume EOF*/;
+ }
+ if( 0==rc ) rc = xCallback(buf, nBuf);
}
- open_db(&shellState, 0);
- sqlite3_free(zFilename);
+ return rc;
}
/*
-** Trivial exportable function for emscripten. Needs to be exported using:
-**
-** emcc ..flags... -sEXPORTED_FUNCTIONS=_fiddle_exec -sEXPORTED_RUNTIME_METHODS=ccall,cwrap
-**
-** (Note the underscore before the function name.) It processes zSql
-** as if it were input to the sqlite3 shell and redirects all output
-** to the wasm binding.
+** Trivial exportable function for emscripten. It processes zSql as if
+** it were input to the sqlite3 shell and redirects all output to the
+** wasm binding. fiddle_main() must have been called before this
+** is called, or results are undefined.
*/
void fiddle_exec(const char * zSql){
- static int once = 0;
- int rc = 0;
- if(!once){
- /* Simulate an argv array for main() */
- static char * argv[] = {"fiddle",
- "-bail",
- "-safe"};
- rc = fiddle_main((int)(sizeof(argv)/sizeof(argv[0])), argv);
- once = rc ? -1 : 1;
- memset(&shellState.wasm, 0, sizeof(shellState.wasm));
- printf(
- "SQLite version %s %.19s\n" /*extra-version-info*/,
- sqlite3_libversion(), sqlite3_sourceid()
- );
- puts("WASM shell");
- puts("Enter \".help\" for usage hints.");
- if(once>0){
- fiddle_reset_db();
- }
- if(shellState.db){
- printf("Connected to %s.\n", fiddle_db_filename(NULL));
- }else{
- fprintf(stderr,"ERROR initializing db!\n");
- return;
- }
- }
- if(once<0){
- puts("DB init failed. Not executing SQL.");
- }else if(zSql && *zSql){
+ if(zSql && *zSql){
+ if('.'==*zSql) puts(zSql);
shellState.wasm.zInput = zSql;
shellState.wasm.zPos = zSql;
process_input(&shellState);
- memset(&shellState.wasm, 0, sizeof(shellState.wasm));
+ shellState.wasm.zInput = shellState.wasm.zPos = 0;
}
}
-#endif /* SQLITE_SHELL_WASM_MODE */
+#endif /* SQLITE_SHELL_FIDDLE */
diff --git a/sqlite3.c b/sqlite3.c
index 451ca8e6a2ec..2763b1b49508 100644
--- a/sqlite3.c
+++ b/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.39.3. By combining all the individual C code files into this
+** version 3.40.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -452,9 +452,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.3"
-#define SQLITE_VERSION_NUMBER 3039003
-#define SQLITE_SOURCE_ID "2022-09-05 11:02:23 4635f4a69c8c2a8df242b384a992aea71224e39a2ccab42d8c0b0602f1e826e8"
+#define SQLITE_VERSION "3.40.0"
+#define SQLITE_VERSION_NUMBER 3040000
+#define SQLITE_SOURCE_ID "2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -976,13 +976,17 @@ SQLITE_API int sqlite3_exec(
**
** 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.
+** of an [sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#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
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -1060,7 +1064,14 @@ struct sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+* If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** 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
@@ -1165,9 +1176,8 @@ struct sqlite3_io_methods {
** 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 is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1560,6 +1570,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlite3_filename_database()
+** <li> sqlite3_filename_journal()
+** <li> sqlite3_filename_wal()
+** <li> sqlite3_uri_parameter()
+** <li> sqlite3_uri_boolean()
+** <li> sqlite3_uri_int64()
+** <li> sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1737,7 +1767,7 @@ struct sqlite3_vfs {
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 (*xOpen)(sqlite3_vfs*, sqlite3_filename 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);
@@ -2615,6 +2645,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -3730,6 +3761,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3745,7 +3779,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
@@ -4004,10 +4038,10 @@ SQLITE_API int sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -4036,9 +4070,9 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -4104,14 +4138,14 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API sqlite3_filename sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlite3_free_filename(char*);
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -5814,6 +5848,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** then the conversion is performed. Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
**
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
+** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X),
+** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or
+** sqlite3_value_bytes16(X) might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
+**
** ^Within the [xUpdate] method of a [virtual table], the
** sqlite3_value_nochange(X) interface returns true if and only if
** the column corresponding to X is unchanged by the UPDATE operation
@@ -5878,6 +5922,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -5931,7 +5976,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation 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
@@ -6136,9 +6181,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^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 any of the sqlite3_result_text* interfaces
+** other than sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for 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
@@ -6634,7 +6680,7 @@ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
** <li> [sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6771,7 +6817,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6892,6 +6938,11 @@ SQLITE_API void *sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -6990,7 +7041,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -9285,7 +9336,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9713,7 +9764,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
@@ -13154,7 +13205,7 @@ struct fts5_api {
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-#include "config.h"
+#include "sqlite_cfg.h"
#define SQLITECONFIG_H 1
#endif
@@ -14637,6 +14688,7 @@ typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
typedef struct Index Index;
+typedef struct IndexedExpr IndexedExpr;
typedef struct IndexSample IndexSample;
typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo;
@@ -14702,6 +14754,7 @@ typedef struct With With;
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
#define ALLBITS ((Bitmask)-1)
+#define TOPBIT (((Bitmask)1)<<(BMS-1))
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
@@ -14716,6 +14769,331 @@ typedef int VList;
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
+/************** Include os.h in the middle of sqliteInt.h ********************/
+/************** Begin file os.h **********************************************/
+/*
+** 2001 September 16
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This header file (together with is companion C source-code file
+** "os.c") attempt to abstract the underlying operating system so that
+** the SQLite library will work on both POSIX and windows systems.
+**
+** This header file is #include-ed by sqliteInt.h and thus ends up
+** being included by every source file.
+*/
+#ifndef _SQLITE_OS_H_
+#define _SQLITE_OS_H_
+
+/*
+** Attempt to automatically detect the operating system and setup the
+** necessary pre-processor macros for it.
+*/
+/************** Include os_setup.h in the middle of os.h *********************/
+/************** Begin file os_setup.h ****************************************/
+/*
+** 2013 November 25
+**
+** 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 pre-processor directives related to operating system
+** detection and/or setup.
+*/
+#ifndef SQLITE_OS_SETUP_H
+#define SQLITE_OS_SETUP_H
+
+/*
+** Figure out if we are dealing with Unix, Windows, or some other operating
+** system.
+**
+** After the following block of preprocess macros, all of
+**
+** SQLITE_OS_KV
+** SQLITE_OS_OTHER
+** SQLITE_OS_UNIX
+** SQLITE_OS_WIN
+**
+** will defined to either 1 or 0. One of them will be 1. The others will be 0.
+** If none of the macros are initially defined, then select either
+** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
+**
+** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
+** must provide its own VFS implementation together with sqlite3_os_init()
+** and sqlite3_os_end() routines.
+*/
+#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
+ !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
+# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
+ defined(__MINGW32__) || defined(__BORLANDC__)
+# define SQLITE_OS_WIN 1
+# define SQLITE_OS_UNIX 0
+# else
+# define SQLITE_OS_WIN 0
+# define SQLITE_OS_UNIX 1
+# endif
+#endif
+#if SQLITE_OS_OTHER+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_KV+1>1
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+# define SQLITE_OMIT_WAL 1
+# define SQLITE_OMIT_DEPRECATED 1
+# undef SQLITE_TEMP_STORE
+# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
+# define SQLITE_DQS 0
+# define SQLITE_OMIT_SHARED_CACHE 1
+# define SQLITE_OMIT_AUTOINIT 1
+#endif
+#if SQLITE_OS_UNIX+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_WIN+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+#endif
+
+
+#endif /* SQLITE_OS_SETUP_H */
+
+/************** End of os_setup.h ********************************************/
+/************** Continuing where we left off in os.h *************************/
+
+/* If the SET_FULLSYNC macro is not defined above, then make it
+** a no-op
+*/
+#ifndef SET_FULLSYNC
+# define SET_FULLSYNC(x,y)
+#endif
+
+/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
+*/
+#ifndef SQLITE_MAX_PATHLEN
+# define SQLITE_MAX_PATHLEN FILENAME_MAX
+#endif
+
+/* Maximum number of symlinks that will be resolved while trying to
+** expand a filename in xFullPathname() in the VFS.
+*/
+#ifndef SQLITE_MAX_SYMLINK
+# define SQLITE_MAX_SYMLINK 200
+#endif
+
+/*
+** The default size of a disk sector
+*/
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 4096
+#endif
+
+/*
+** Temporary files are named starting with this prefix followed by 16 random
+** alphanumeric characters, and no file extension. They are stored in the
+** OS's standard temporary file directory, and are deleted prior to exit.
+** If sqlite is being embedded in another program, you may wish to change the
+** prefix to reflect your program's name, so that if your program exits
+** prematurely, old temporary files can be easily identified. This can be done
+** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
+**
+** 2006-10-31: The default prefix used to be "sqlite_". But then
+** Mcafee started using SQLite in their anti-virus product and it
+** started putting files with the "sqlite" name in the c:/temp folder.
+** This annoyed many windows users. Those users would then do a
+** Google search for "sqlite", find the telephone numbers of the
+** developers and call to wake them up at night and complain.
+** For this reason, the default name prefix is changed to be "sqlite"
+** spelled backwards. So the temp files are still identified, but
+** anybody smart enough to figure out the code is also likely smart
+** enough to know that calling the developer will not help get rid
+** of the file.
+*/
+#ifndef SQLITE_TEMP_FILE_PREFIX
+# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
+#endif
+
+/*
+** The following values may be passed as the second argument to
+** sqlite3OsLock(). The various locks exhibit the following semantics:
+**
+** SHARED: Any number of processes may hold a SHARED lock simultaneously.
+** RESERVED: A single process may hold a RESERVED lock on a file at
+** any time. Other processes may hold and obtain new SHARED locks.
+** PENDING: A single process may hold a PENDING lock on a file at
+** any one time. Existing SHARED locks may persist, but no new
+** SHARED locks may be obtained by other processes.
+** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
+**
+** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
+** process that requests an EXCLUSIVE lock may actually obtain a PENDING
+** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
+** sqlite3OsLock().
+*/
+#define NO_LOCK 0
+#define SHARED_LOCK 1
+#define RESERVED_LOCK 2
+#define PENDING_LOCK 3
+#define EXCLUSIVE_LOCK 4
+
+/*
+** File Locking Notes: (Mostly about windows but also some info for Unix)
+**
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
+** those functions are not available. So we use only LockFile() and
+** UnlockFile().
+**
+** LockFile() prevents not just writing but also reading by other processes.
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
+** byte out of a specific range of bytes. The lock byte is obtained at
+** random so two separate readers can probably access the file at the
+** same time, unless they are unlucky and choose the same lock byte.
+** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
+** There can only be one writer. A RESERVED_LOCK is obtained by locking
+** a single byte of the file that is designated as the reserved lock byte.
+** A PENDING_LOCK is obtained by locking a designated byte different from
+** the RESERVED_LOCK byte.
+**
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
+** which means we can use reader/writer locks. When reader/writer locks
+** are used, the lock is placed on the same range of bytes that is used
+** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
+** will support two or more Win95 readers or two or more WinNT readers.
+** But a single Win95 reader will lock out all WinNT readers and a single
+** WinNT reader will lock out all other Win95 readers.
+**
+** The following #defines specify the range of bytes used for locking.
+** SHARED_SIZE is the number of bytes available in the pool from which
+** a random byte is selected for a shared lock. The pool of bytes for
+** shared locks begins at SHARED_FIRST.
+**
+** The same locking strategy and
+** byte ranges are used for Unix. This leaves open the possibility of having
+** clients on win95, winNT, and unix all talking to the same shared file
+** and all locking correctly. To do so would require that samba (or whatever
+** tool is being used for file sharing) implements locks correctly between
+** windows and unix. I'm guessing that isn't likely to happen, but by
+** using the same locking range we are at least open to the possibility.
+**
+** Locking in windows is manditory. For this reason, we cannot store
+** actual data in the bytes used for locking. The pager never allocates
+** the pages involved in locking therefore. SHARED_SIZE is selected so
+** that all locks will fit on a single page even at the minimum page size.
+** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
+** is set high so that we don't have to allocate an unused page except
+** for very large databases. But one should test the page skipping logic
+** by setting PENDING_BYTE low and running the entire regression suite.
+**
+** Changing the value of PENDING_BYTE results in a subtly incompatible
+** file format. Depending on how it is changed, you might not notice
+** the incompatibility right away, even running a full regression test.
+** The default location of PENDING_BYTE is the first byte past the
+** 1GB boundary.
+**
+*/
+#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
+
+/*
+** Wrapper around OS specific sqlite3_os_init() function.
+*/
+SQLITE_PRIVATE int sqlite3OsInit(void);
+
+/*
+** Functions for accessing sqlite3_file methods
+*/
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
+SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
+SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
+SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
+SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
+#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
+SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+#endif /* SQLITE_OMIT_WAL */
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
+
+
+/*
+** Functions for accessing sqlite3_vfs methods
+*/
+SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
+SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
+SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
+SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
+SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
+SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
+
+/*
+** Convenience functions for opening and closing files using
+** sqlite3_malloc() to obtain space for the file-handle structure.
+*/
+SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
+
+#endif /* _SQLITE_OS_H_ */
+
+/************** End of os.h **************************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include pager.h in the middle of sqliteInt.h *****************/
/************** Begin file pager.h *******************************************/
/*
@@ -15560,48 +15938,48 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Vacuum 5
#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 8 /* jump */
-#define OP_Gosub 9 /* jump */
-#define OP_InitCoroutine 10 /* jump */
-#define OP_Yield 11 /* jump */
-#define OP_MustBeInt 12 /* jump */
-#define OP_Jump 13 /* jump */
-#define OP_Once 14 /* jump */
-#define OP_If 15 /* jump */
-#define OP_IfNot 16 /* jump */
-#define OP_IsNullOrType 17 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */
-#define OP_IfNullRow 18 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_Init 8 /* jump, synopsis: Start at P2 */
+#define OP_Goto 9 /* jump */
+#define OP_Gosub 10 /* jump */
+#define OP_InitCoroutine 11 /* jump */
+#define OP_Yield 12 /* jump */
+#define OP_MustBeInt 13 /* jump */
+#define OP_Jump 14 /* jump */
+#define OP_Once 15 /* jump */
+#define OP_If 16 /* jump */
+#define OP_IfNot 17 /* jump */
+#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_SeekLT 20 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekLE 21 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGE 22 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGT 23 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IfNotOpen 24 /* jump, synopsis: if( !csr[P1] ) goto P2 */
-#define OP_IfNoHope 25 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NoConflict 26 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NotFound 27 /* jump, synopsis: key=r[P3@P4] */
-#define OP_Found 28 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 29 /* jump, synopsis: intkey=r[P3] */
-#define OP_NotExists 30 /* jump, synopsis: intkey=r[P3] */
-#define OP_Last 31 /* jump */
-#define OP_IfSmaller 32 /* jump */
-#define OP_SorterSort 33 /* jump */
-#define OP_Sort 34 /* jump */
-#define OP_Rewind 35 /* jump */
-#define OP_SorterNext 36 /* jump */
-#define OP_Prev 37 /* jump */
-#define OP_Next 38 /* jump */
-#define OP_IdxLE 39 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGT 40 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxLT 41 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGE 42 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
+#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
+#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */
+#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
+#define OP_Last 32 /* jump */
+#define OP_IfSmaller 33 /* jump */
+#define OP_SorterSort 34 /* jump */
+#define OP_Sort 35 /* jump */
+#define OP_Rewind 36 /* jump */
+#define OP_SorterNext 37 /* jump */
+#define OP_Prev 38 /* jump */
+#define OP_Next 39 /* jump */
+#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_RowSetRead 45 /* jump, synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 47 /* jump */
-#define OP_FkIfZero 48 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 48 /* jump */
+#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
@@ -15611,12 +15989,12 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
-#define OP_IfNotZero 59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
-#define OP_DecrJumpZero 60 /* jump, synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 61 /* jump */
-#define OP_VNext 62 /* jump */
-#define OP_Filter 63 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
-#define OP_Init 64 /* jump, synopsis: Start at P2 */
+#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 62 /* jump */
+#define OP_VNext 63 /* jump */
+#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Return 67
@@ -15752,13 +16130,13 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
-/* 8 */ 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x09, 0x09, 0x09, 0x09,\
-/* 24 */ 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01,\
+/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x09, 0x09, 0x09,\
+/* 24 */ 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\
-/* 48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\
+/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x01, 0x23, 0x0b,\
+/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
@@ -15850,6 +16228,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe*, int);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
@@ -15864,6 +16243,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
@@ -16212,297 +16592,6 @@ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache);
/************** End of pcache.h **********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
-/************** Include os.h in the middle of sqliteInt.h ********************/
-/************** Begin file os.h **********************************************/
-/*
-** 2001 September 16
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file (together with is companion C source-code file
-** "os.c") attempt to abstract the underlying operating system so that
-** the SQLite library will work on both POSIX and windows systems.
-**
-** This header file is #include-ed by sqliteInt.h and thus ends up
-** being included by every source file.
-*/
-#ifndef _SQLITE_OS_H_
-#define _SQLITE_OS_H_
-
-/*
-** Attempt to automatically detect the operating system and setup the
-** necessary pre-processor macros for it.
-*/
-/************** Include os_setup.h in the middle of os.h *********************/
-/************** Begin file os_setup.h ****************************************/
-/*
-** 2013 November 25
-**
-** 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 pre-processor directives related to operating system
-** detection and/or setup.
-*/
-#ifndef SQLITE_OS_SETUP_H
-#define SQLITE_OS_SETUP_H
-
-/*
-** Figure out if we are dealing with Unix, Windows, or some other operating
-** system.
-**
-** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
-** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
-** the three will be 1. The other two will be 0.
-*/
-#if defined(SQLITE_OS_OTHER)
-# if SQLITE_OS_OTHER==1
-# undef SQLITE_OS_UNIX
-# define SQLITE_OS_UNIX 0
-# undef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# else
-# undef SQLITE_OS_OTHER
-# endif
-#endif
-#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
-# define SQLITE_OS_OTHER 0
-# ifndef SQLITE_OS_WIN
-# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
- defined(__MINGW32__) || defined(__BORLANDC__)
-# define SQLITE_OS_WIN 1
-# define SQLITE_OS_UNIX 0
-# else
-# define SQLITE_OS_WIN 0
-# define SQLITE_OS_UNIX 1
-# endif
-# else
-# define SQLITE_OS_UNIX 0
-# endif
-#else
-# ifndef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# endif
-#endif
-
-#endif /* SQLITE_OS_SETUP_H */
-
-/************** End of os_setup.h ********************************************/
-/************** Continuing where we left off in os.h *************************/
-
-/* If the SET_FULLSYNC macro is not defined above, then make it
-** a no-op
-*/
-#ifndef SET_FULLSYNC
-# define SET_FULLSYNC(x,y)
-#endif
-
-/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
-*/
-#ifndef SQLITE_MAX_PATHLEN
-# define SQLITE_MAX_PATHLEN FILENAME_MAX
-#endif
-
-/* Maximum number of symlinks that will be resolved while trying to
-** expand a filename in xFullPathname() in the VFS.
-*/
-#ifndef SQLITE_MAX_SYMLINK
-# define SQLITE_MAX_SYMLINK 200
-#endif
-
-/*
-** The default size of a disk sector
-*/
-#ifndef SQLITE_DEFAULT_SECTOR_SIZE
-# define SQLITE_DEFAULT_SECTOR_SIZE 4096
-#endif
-
-/*
-** Temporary files are named starting with this prefix followed by 16 random
-** alphanumeric characters, and no file extension. They are stored in the
-** OS's standard temporary file directory, and are deleted prior to exit.
-** If sqlite is being embedded in another program, you may wish to change the
-** prefix to reflect your program's name, so that if your program exits
-** prematurely, old temporary files can be easily identified. This can be done
-** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-**
-** 2006-10-31: The default prefix used to be "sqlite_". But then
-** Mcafee started using SQLite in their anti-virus product and it
-** started putting files with the "sqlite" name in the c:/temp folder.
-** This annoyed many windows users. Those users would then do a
-** Google search for "sqlite", find the telephone numbers of the
-** developers and call to wake them up at night and complain.
-** For this reason, the default name prefix is changed to be "sqlite"
-** spelled backwards. So the temp files are still identified, but
-** anybody smart enough to figure out the code is also likely smart
-** enough to know that calling the developer will not help get rid
-** of the file.
-*/
-#ifndef SQLITE_TEMP_FILE_PREFIX
-# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
-#endif
-
-/*
-** The following values may be passed as the second argument to
-** sqlite3OsLock(). The various locks exhibit the following semantics:
-**
-** SHARED: Any number of processes may hold a SHARED lock simultaneously.
-** RESERVED: A single process may hold a RESERVED lock on a file at
-** any time. Other processes may hold and obtain new SHARED locks.
-** PENDING: A single process may hold a PENDING lock on a file at
-** any one time. Existing SHARED locks may persist, but no new
-** SHARED locks may be obtained by other processes.
-** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
-**
-** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
-** process that requests an EXCLUSIVE lock may actually obtain a PENDING
-** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
-** sqlite3OsLock().
-*/
-#define NO_LOCK 0
-#define SHARED_LOCK 1
-#define RESERVED_LOCK 2
-#define PENDING_LOCK 3
-#define EXCLUSIVE_LOCK 4
-
-/*
-** File Locking Notes: (Mostly about windows but also some info for Unix)
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
-** There can only be one writer. A RESERVED_LOCK is obtained by locking
-** a single byte of the file that is designated as the reserved lock byte.
-** A PENDING_LOCK is obtained by locking a designated byte different from
-** the RESERVED_LOCK byte.
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader/writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** The following #defines specify the range of bytes used for locking.
-** SHARED_SIZE is the number of bytes available in the pool from which
-** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
-**
-** The same locking strategy and
-** byte ranges are used for Unix. This leaves open the possibility of having
-** clients on win95, winNT, and unix all talking to the same shared file
-** and all locking correctly. To do so would require that samba (or whatever
-** tool is being used for file sharing) implements locks correctly between
-** windows and unix. I'm guessing that isn't likely to happen, but by
-** using the same locking range we are at least open to the possibility.
-**
-** Locking in windows is manditory. For this reason, we cannot store
-** actual data in the bytes used for locking. The pager never allocates
-** the pages involved in locking therefore. SHARED_SIZE is selected so
-** that all locks will fit on a single page even at the minimum page size.
-** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
-** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
-** by setting PENDING_BYTE low and running the entire regression suite.
-**
-** Changing the value of PENDING_BYTE results in a subtly incompatible
-** file format. Depending on how it is changed, you might not notice
-** the incompatibility right away, even running a full regression test.
-** The default location of PENDING_BYTE is the first byte past the
-** 1GB boundary.
-**
-*/
-#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
-
-/*
-** Wrapper around OS specific sqlite3_os_init() function.
-*/
-SQLITE_PRIVATE int sqlite3OsInit(void);
-
-/*
-** Functions for accessing sqlite3_file methods
-*/
-SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
-SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
-SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
-SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
-SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
-SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
-SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
-SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
-#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
-SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
-SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
-SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
-#endif /* SQLITE_OMIT_WAL */
-SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
-SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
-
-
-/*
-** Functions for accessing sqlite3_vfs methods
-*/
-SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
-SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
-SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
-SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
-SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
-SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
-SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
-
-/*
-** Convenience functions for opening and closing files using
-** sqlite3_malloc() to obtain space for the file-handle structure.
-*/
-SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
-SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
-
-#endif /* _SQLITE_OS_H_ */
-
-/************** End of os.h **************************************************/
-/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include mutex.h in the middle of sqliteInt.h *****************/
/************** Begin file mutex.h *******************************************/
/*
@@ -16748,6 +16837,7 @@ struct Lookaside {
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
+ void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
@@ -17092,6 +17182,7 @@ struct sqlite3 {
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
+#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17664,7 +17755,7 @@ struct Table {
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB)
# define ExprIsVtab(X) \
- ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB)
+ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB)
#else
# define IsVirtual(X) 0
# define ExprIsVtab(X) 0
@@ -17881,10 +17972,22 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
-** algorithm to employ whenever an attempt is made to insert a non-unique
+** and the value of Index.onError indicates which conflict resolution
+** algorithm to employ when an attempt is made to insert a non-unique
** element.
**
+** The colNotIdxed bitmask is used in combination with SrcItem.colUsed
+** for a fast test to see if an index can serve as a covering index.
+** colNotIdxed has a 1 bit for every column of the original table that
+** is *not* available in the index. Thus the expression
+** "colUsed & colNotIdxed" will be non-zero if the index is not a
+** covering index. The most significant bit of of colNotIdxed will always
+** be true (note-20221022-a). If a column beyond the 63rd column of the
+** table is used, the "colUsed & colNotIdxed" test will always be non-zero
+** and we have to assume either that the index is not covering, or use
+** an alternative (slower) algorithm to determine whether or not
+** the index is covering.
+**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
@@ -17920,6 +18023,8 @@ struct Index {
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
+ unsigned bHasExpr:1; /* Index contains an expression, either a literal
+ ** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
@@ -17928,7 +18033,7 @@ struct Index {
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
- Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
+ Bitmask colNotIdxed; /* Unindexed columns in pTab */
};
/*
@@ -18196,7 +18301,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_MemToken 0x020000 /* Need to sqlite3DbFree() Expr.zToken */
+ /* 0x020000 // Available for reuse */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -18381,6 +18486,14 @@ struct IdList {
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
**
+** The jointype starts out showing the join type between the current table
+** 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.
+**
** Union member validity:
**
** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
@@ -18420,14 +18533,14 @@ struct SrcItem {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
- Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
+ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
- CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */
+ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
};
@@ -18441,23 +18554,11 @@ struct OnOrUsing {
};
/*
-** The following structure describes the FROM clause of a SELECT statement.
-** Each table or subquery in the FROM clause is a separate element of
-** the SrcList.a[] array.
-**
-** With the addition of multiple database support, the following structure
-** can also be used to describe a particular table such as the table that
-** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
-** such a table must be a simple name: ID. But in SQLite, the table can
-** now be identified by a database name, a dot, then the table name: ID.ID.
-**
-** The jointype starts out showing the join type between the current table
-** 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.
+** This object represents one or more tables that are the source of
+** content for an SQL statement. For example, a single SrcList object
+** is used to hold the FROM clause of a SELECT statement. SrcList also
+** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
-** 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 {
int nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -18802,7 +18903,7 @@ struct SelectDest {
int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
+ char *zAffSdst; /* Affinity used for SRT_Set, SRT_Table, and similar */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
@@ -18868,6 +18969,28 @@ struct TriggerPrg {
#endif
/*
+** For each index X that has as one of its arguments either an expression
+** or the name of a virtual generated column, and if X is in scope such that
+** the value of the expression can simply be read from the index, then
+** there is an instance of this object on the Parse.pIdxExpr list.
+**
+** During code generation, while generating code to evaluate expressions,
+** this list is consulted and if a matching expression is found, the value
+** is read from the index rather than being recomputed.
+*/
+struct IndexedExpr {
+ Expr *pExpr; /* The expression contained in the index */
+ int iDataCur; /* The data cursor associated with the index */
+ int iIdxCur; /* The index cursor */
+ int iIdxCol; /* The index column that contains value of pExpr */
+ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
+ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ const char *zIdxName; /* Name of index, used only for bytecode comments */
+#endif
+};
+
+/*
** An instance of the ParseCleanup object specifies an operation that
** should be performed after parsing to deallocation resources obtained
** during the parse and which are no longer needed.
@@ -18908,7 +19031,7 @@ struct Parse {
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
- u8 disableVtab; /* Disable all virtual tables for this parse */
+ u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
@@ -18925,6 +19048,7 @@ struct Parse {
int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
+ IndexedExpr *pIdxExpr;/* List of expressions used by active indexes */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
@@ -19360,15 +19484,15 @@ struct Walker {
struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
- struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */
ExprList *pGroupBy; /* GROUP BY clause */
Select *pSelect; /* HAVING to WHERE clause ctx */
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
struct Table *pTab; /* Table of generated column */
+ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
- DbFixer *pFix;
+ DbFixer *pFix; /* See sqlite3FixSelect() */
} u;
};
@@ -19674,6 +19798,7 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(const void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
@@ -19694,12 +19819,16 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
*/
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
+# define sqlite3StackAllocRawNN(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
# define sqlite3StackFree(D,P)
+# define sqlite3StackFreeNN(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
+# define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N)
# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
# define sqlite3StackFree(D,P) sqlite3DbFree(D,P)
+# define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P)
#endif
/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they
@@ -20198,6 +20327,7 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
+SQLITE_PRIVATE i64 sqlite3RealToI64(double);
SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*);
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
@@ -20243,6 +20373,7 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3*,const Table*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
@@ -20314,7 +20445,6 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[];
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[];
-SQLITE_PRIVATE const char sqlite3StdTypeMap[];
SQLITE_PRIVATE const char *sqlite3StdType[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char *sqlite3aLTb;
@@ -20758,6 +20888,10 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
#endif
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlite3KvvfsInit(void);
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -20989,7 +21123,7 @@ SQLITE_API extern int sqlite3_open_file_count;
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-/* #include "config.h" */
+/* #include "sqlite_cfg.h" */
#define SQLITECONFIG_H 1
#endif
@@ -21154,6 +21288,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
"DISABLE_SKIPAHEAD_DISTINCT",
#endif
+#ifdef SQLITE_DQS
+ "DQS=" CTIMEOPT_VAL(SQLITE_DQS),
+#endif
#ifdef SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
@@ -21644,9 +21781,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
#endif
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- "PCACHE_SEPARATE_HEADER",
-#endif
#ifdef SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
@@ -22126,10 +22260,6 @@ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
**
** sqlite3StdTypeAffinity[] The affinity associated with each entry
** in sqlite3StdType[].
-**
-** sqlite3StdTypeMap[] The type value (as returned from
-** sqlite3_column_type() or sqlite3_value_type())
-** for each entry in sqlite3StdType[].
*/
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
@@ -22140,14 +22270,6 @@ SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
SQLITE_AFF_REAL,
SQLITE_AFF_TEXT
};
-SQLITE_PRIVATE const char sqlite3StdTypeMap[] = {
- 0,
- SQLITE_BLOB,
- SQLITE_INTEGER,
- SQLITE_INTEGER,
- SQLITE_FLOAT,
- SQLITE_TEXT
-};
SQLITE_PRIVATE const char *sqlite3StdType[] = {
"ANY",
"BLOB",
@@ -22599,7 +22721,7 @@ struct DblquoteStr {
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+ Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
int nMem; /* Number of memory locations currently allocated */
@@ -23157,6 +23279,8 @@ SQLITE_API int sqlite3_db_status(
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
@@ -23182,6 +23306,7 @@ SQLITE_API int sqlite3_db_status(
}
}
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
@@ -23199,9 +23324,12 @@ SQLITE_API int sqlite3_db_status(
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
sqlite3VdbeDelete(pVdbe);
}
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
db->pnBytesFreed = 0;
*pHighwater = 0; /* IMP: R-64479-57858 */
@@ -23537,7 +23665,7 @@ static void computeJD(DateTime *p){
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
if( p->validHMS ){
- p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
+ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
if( p->validTZ ){
p->iJD -= p->tz*60000;
p->validYMD = 0;
@@ -24046,7 +24174,7 @@ static int parseModifier(
*/
if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
- && (n=(int)r)==r && n>=0 && r<7 ){
+ && r>=0.0 && r<7.0 && (n=(int)r)==r ){
sqlite3_int64 Z;
computeYMD_HMS(p);
p->validTZ = 0;
@@ -24727,9 +24855,11 @@ SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
}
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id);
+ assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
return id->pMethods->xLock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+ assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
return id->pMethods->xUnlock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
@@ -24844,6 +24974,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
+ assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
@@ -29063,17 +29194,33 @@ static void mallocWithAlarm(int n, void **pp){
}
/*
+** Maximum size of any single memory allocation.
+**
+** This is not a limit on the total amount of memory used. This is
+** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
+**
+** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
+** This provides a 256-byte safety margin for defense against 32-bit
+** signed integer overflow bugs when computing memory allocation sizes.
+** Parnoid applications might want to reduce the maximum allocation size
+** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
+** or even smaller would be reasonable upper bounds on the size of a memory
+** allocations for most applications.
+*/
+#ifndef SQLITE_MAX_ALLOCATION_SIZE
+# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
+#endif
+#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
+# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
+#endif
+
+/*
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
void *p;
- if( n==0 || n>=0x7fffff00 ){
- /* A memory allocation of a number of bytes which is near the maximum
- ** signed integer value might cause an integer overflow inside of the
- ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
- ** 255 bytes of overhead. SQLite itself will never use anything near
- ** this amount. The only way to reach the limit is with sqlite3_malloc() */
+ if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
@@ -29109,7 +29256,7 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, const void *p){
- return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
+ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
}
#else
#define isLookaside(A,B) 0
@@ -29133,18 +29280,16 @@ static int lookasideMallocSize(sqlite3 *db, const void *p){
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
assert( p!=0 );
#ifdef SQLITE_DEBUG
- if( db==0 || !isLookaside(db,p) ){
- if( db==0 ){
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- }else{
- assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- }
+ if( db==0 ){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ }else if( !isLookaside(db,p) ){
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
#endif
if( db ){
- if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
assert( sqlite3_mutex_held(db->mutex) );
@@ -29200,14 +29345,11 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( db ){
- if( db->pnBytesFreed ){
- measureAllocationSize(db, p);
- return;
- }
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
@@ -29218,6 +29360,7 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
@@ -29226,6 +29369,10 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
return;
}
}
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@@ -29233,6 +29380,43 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3 *db, void *p){
+ assert( db!=0 );
+ assert( sqlite3_mutex_held(db->mutex) );
+ assert( p!=0 );
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = pBuf;
+ return;
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pFree;
+ db->lookaside.pFree = pBuf;
+ return;
+ }
+ }
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ sqlite3_free(p);
+}
SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p ) sqlite3DbFreeNN(db, p);
@@ -32344,16 +32528,41 @@ SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlite3PrngType {
- unsigned char isInit; /* True if initialized */
- unsigned char i, j; /* State variables */
- unsigned char s[256]; /* State variables */
+ u32 s[16]; /* 64 bytes of chacha20 state */
+ u8 out[64]; /* Output bytes */
+ u8 n; /* Output bytes remaining */
} sqlite3Prng;
+
+/* The RFC-7539 ChaCha20 block function
+*/
+#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+#define QR(a, b, c, d) ( \
+ a += b, d ^= a, d = ROTL(d,16), \
+ c += d, b ^= c, b = ROTL(b,12), \
+ a += b, d ^= a, d = ROTL(d, 8), \
+ c += d, b ^= c, b = ROTL(b, 7))
+static void chacha_block(u32 *out, const u32 *in){
+ int i;
+ u32 x[16];
+ memcpy(x, in, 64);
+ for(i=0; i<10; i++){
+ QR(x[0], x[4], x[ 8], x[12]);
+ QR(x[1], x[5], x[ 9], x[13]);
+ QR(x[2], x[6], x[10], x[14]);
+ QR(x[3], x[7], x[11], x[15]);
+ QR(x[0], x[5], x[10], x[15]);
+ QR(x[1], x[6], x[11], x[12]);
+ QR(x[2], x[7], x[ 8], x[13]);
+ QR(x[3], x[4], x[ 9], x[14]);
+ }
+ for(i=0; i<16; i++) out[i] = x[i]+in[i];
+}
+
/*
** Return N random bytes.
*/
SQLITE_API void sqlite3_randomness(int N, void *pBuf){
- unsigned char t;
unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
@@ -32383,53 +32592,46 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
- wsdPrng.isInit = 0;
+ wsdPrng.s[0] = 0;
sqlite3_mutex_leave(mutex);
return;
}
/* Initialize the state of the random number generator once,
- ** the first time this routine is called. The seed value does
- ** not need to contain a lot of randomness since we are not
- ** trying to do secure encryption or anything like that...
- **
- ** Nothing in this file or anywhere else in SQLite does any kind of
- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
- ** number generator) not as an encryption device.
+ ** the first time this routine is called.
*/
- if( !wsdPrng.isInit ){
+ if( wsdPrng.s[0]==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
- int i;
- char k[256];
- wsdPrng.j = 0;
- wsdPrng.i = 0;
+ static const u32 chacha20_init[] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+ };
+ memcpy(&wsdPrng.s[0], chacha20_init, 16);
if( NEVER(pVfs==0) ){
- memset(k, 0, sizeof(k));
+ memset(&wsdPrng.s[4], 0, 44);
}else{
- sqlite3OsRandomness(pVfs, 256, k);
- }
- for(i=0; i<256; i++){
- wsdPrng.s[i] = (u8)i;
- }
- for(i=0; i<256; i++){
- wsdPrng.j += wsdPrng.s[i] + k[i];
- t = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
- wsdPrng.s[i] = t;
+ sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
}
- wsdPrng.isInit = 1;
+ wsdPrng.s[15] = wsdPrng.s[12];
+ wsdPrng.s[12] = 0;
+ wsdPrng.n = 0;
}
assert( N>0 );
- do{
- wsdPrng.i++;
- t = wsdPrng.s[wsdPrng.i];
- wsdPrng.j += t;
- wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = t;
- t += wsdPrng.s[wsdPrng.i];
- *(zBuf++) = wsdPrng.s[t];
- }while( --N );
+ while( 1 /* exit by break */ ){
+ if( N<=wsdPrng.n ){
+ memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
+ wsdPrng.n -= N;
+ break;
+ }
+ if( wsdPrng.n>0 ){
+ memcpy(zBuf, wsdPrng.out, wsdPrng.n);
+ N -= wsdPrng.n;
+ zBuf += wsdPrng.n;
+ }
+ wsdPrng.s[12]++;
+ chacha_block((u32*)wsdPrng.out, wsdPrng.s);
+ wsdPrng.n = 64;
+ }
sqlite3_mutex_leave(mutex);
}
@@ -35287,48 +35489,48 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
- /* 8 */ "Goto" OpHelp(""),
- /* 9 */ "Gosub" OpHelp(""),
- /* 10 */ "InitCoroutine" OpHelp(""),
- /* 11 */ "Yield" OpHelp(""),
- /* 12 */ "MustBeInt" OpHelp(""),
- /* 13 */ "Jump" OpHelp(""),
- /* 14 */ "Once" OpHelp(""),
- /* 15 */ "If" OpHelp(""),
- /* 16 */ "IfNot" OpHelp(""),
- /* 17 */ "IsNullOrType" OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"),
- /* 18 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 8 */ "Init" OpHelp("Start at P2"),
+ /* 9 */ "Goto" OpHelp(""),
+ /* 10 */ "Gosub" OpHelp(""),
+ /* 11 */ "InitCoroutine" OpHelp(""),
+ /* 12 */ "Yield" OpHelp(""),
+ /* 13 */ "MustBeInt" OpHelp(""),
+ /* 14 */ "Jump" OpHelp(""),
+ /* 15 */ "Once" OpHelp(""),
+ /* 16 */ "If" OpHelp(""),
+ /* 17 */ "IfNot" OpHelp(""),
+ /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 21 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 22 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 23 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
- /* 25 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
- /* 26 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 27 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 28 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 29 */ "SeekRowid" OpHelp("intkey=r[P3]"),
- /* 30 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 31 */ "Last" OpHelp(""),
- /* 32 */ "IfSmaller" OpHelp(""),
- /* 33 */ "SorterSort" OpHelp(""),
- /* 34 */ "Sort" OpHelp(""),
- /* 35 */ "Rewind" OpHelp(""),
- /* 36 */ "SorterNext" OpHelp(""),
- /* 37 */ "Prev" OpHelp(""),
- /* 38 */ "Next" OpHelp(""),
- /* 39 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 40 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 41 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 42 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
+ /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
+ /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 29 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 32 */ "Last" OpHelp(""),
+ /* 33 */ "IfSmaller" OpHelp(""),
+ /* 34 */ "SorterSort" OpHelp(""),
+ /* 35 */ "Sort" OpHelp(""),
+ /* 36 */ "Rewind" OpHelp(""),
+ /* 37 */ "SorterNext" OpHelp(""),
+ /* 38 */ "Prev" OpHelp(""),
+ /* 39 */ "Next" OpHelp(""),
+ /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 45 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 46 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 47 */ "Program" OpHelp(""),
- /* 48 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 49 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 48 */ "Program" OpHelp(""),
+ /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
@@ -35338,12 +35540,12 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
/* 58 */ "ElseEq" OpHelp(""),
- /* 59 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
- /* 60 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 61 */ "IncrVacuum" OpHelp(""),
- /* 62 */ "VNext" OpHelp(""),
- /* 63 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
- /* 64 */ "Init" OpHelp("Start at P2"),
+ /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 62 */ "IncrVacuum" OpHelp(""),
+ /* 63 */ "VNext" OpHelp(""),
+ /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
/* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
/* 67 */ "Return" OpHelp(""),
@@ -35472,6 +35674,981 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
/************** End of opcodes.c *********************************************/
+/************** Begin file os_kv.c *******************************************/
+/*
+** 2022-09-06
+**
+** 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 an experimental VFS layer that operates on a
+** Key/Value storage engine where both keys and values must be pure
+** text.
+*/
+/* #include <sqliteInt.h> */
+#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
+
+/*****************************************************************************
+** Debugging logic
+*/
+
+/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
+#if 0
+#define SQLITE_KV_TRACE(X) printf X
+#else
+#define SQLITE_KV_TRACE(X)
+#endif
+
+/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
+#if 0
+#define SQLITE_KV_LOG(X) printf X
+#else
+#define SQLITE_KV_LOG(X)
+#endif
+
+
+/*
+** Forward declaration of objects used by this VFS implementation
+*/
+typedef struct KVVfsFile KVVfsFile;
+
+/* A single open file. There are only two files represented by this
+** VFS - the database and the rollback journal.
+*/
+struct KVVfsFile {
+ sqlite3_file base; /* IO methods */
+ const char *zClass; /* Storage class */
+ int isJournal; /* True if this is a journal file */
+ unsigned int nJrnl; /* Space allocated for aJrnl[] */
+ char *aJrnl; /* Journal content */
+ int szPage; /* Last known page size */
+ sqlite3_int64 szDb; /* Database file size. -1 means unknown */
+};
+
+/*
+** Methods for KVVfsFile
+*/
+static int kvvfsClose(sqlite3_file*);
+static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
+static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
+static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
+static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
+static int kvvfsSyncDb(sqlite3_file*, int flags);
+static int kvvfsSyncJrnl(sqlite3_file*, int flags);
+static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
+static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
+static int kvvfsLock(sqlite3_file*, int);
+static int kvvfsUnlock(sqlite3_file*, int);
+static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
+static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
+static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
+static int kvvfsSectorSize(sqlite3_file*);
+static int kvvfsDeviceCharacteristics(sqlite3_file*);
+
+/*
+** Methods for sqlite3_vfs
+*/
+static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
+static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int kvvfsSleep(sqlite3_vfs*, int microseconds);
+static int kvvfsCurrentTime(sqlite3_vfs*, double*);
+static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+
+static sqlite3_vfs sqlite3OsKvvfsObject = {
+ 1, /* iVersion */
+ sizeof(KVVfsFile), /* szOsFile */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "kvvfs", /* zName */
+ 0, /* pAppData */
+ kvvfsOpen, /* xOpen */
+ kvvfsDelete, /* xDelete */
+ kvvfsAccess, /* xAccess */
+ kvvfsFullPathname, /* xFullPathname */
+ kvvfsDlOpen, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+ kvvfsRandomness, /* xRandomness */
+ kvvfsSleep, /* xSleep */
+ kvvfsCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
+};
+
+/* Methods for sqlite3_file objects referencing a database file
+*/
+static sqlite3_io_methods kvvfs_db_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadDb, /* xRead */
+ kvvfsWriteDb, /* xWrite */
+ kvvfsTruncateDb, /* xTruncate */
+ kvvfsSyncDb, /* xSync */
+ kvvfsFileSizeDb, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlDb, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/* Methods for sqlite3_file objects referencing a rollback journal
+*/
+static sqlite3_io_methods kvvfs_jrnl_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadJrnl, /* xRead */
+ kvvfsWriteJrnl, /* xWrite */
+ kvvfsTruncateJrnl, /* xTruncate */
+ kvvfsSyncJrnl, /* xSync */
+ kvvfsFileSizeJrnl, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlJrnl, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/****** Storage subsystem **************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Forward declarations for the low-level storage engine
+*/
+static int kvstorageWrite(const char*, const char *zKey, const char *zData);
+static int kvstorageDelete(const char*, const char *zKey);
+static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
+#define KVSTORAGE_KEY_SZ 32
+
+/* Expand the key name with an appropriate prefix and put the result
+** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
+** KVSTORAGE_KEY_SZ bytes.
+*/
+static void kvstorageMakeKey(
+ const char *zClass,
+ const char *zKeyIn,
+ char *zKeyOut
+){
+ sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
+}
+
+/* Write content into a key. zClass is the particular namespace of the
+** underlying key/value store to use - either "local" or "session".
+**
+** Both zKey and zData are zero-terminated pure text strings.
+**
+** Return the number of errors.
+*/
+static int kvstorageWrite(
+ const char *zClass,
+ const char *zKey,
+ const char *zData
+){
+ FILE *fd;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ fd = fopen(zXKey, "wb");
+ if( fd ){
+ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
+ (int)strlen(zData), zData,
+ strlen(zData)>50 ? "..." : ""));
+ fputs(zData, fd);
+ fclose(fd);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+/* Delete a key (with its corresponding data) from the key/value
+** namespace given by zClass. If the key does not previously exist,
+** this routine is a no-op.
+*/
+static int kvstorageDelete(const char *zClass, const char *zKey){
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ unlink(zXKey);
+ SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
+ return 0;
+}
+
+/* Read the value associated with a zKey from the key/value namespace given
+** by zClass and put the text data associated with that key in the first
+** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
+** enough to hold it all. The value put into zBuf must always be zero
+** terminated, even if it gets truncated because nBuf is not large enough.
+**
+** Return the total number of bytes in the data, without truncation, and
+** not counting the final zero terminator. Return -1 if the key does
+** not exist.
+**
+** If nBuf<=0 then this routine simply returns the size of the data without
+** actually reading it.
+*/
+static int kvstorageRead(
+ const char *zClass,
+ const char *zKey,
+ char *zBuf,
+ int nBuf
+){
+ FILE *fd;
+ struct stat buf;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ if( access(zXKey, R_OK)!=0
+ || stat(zXKey, &buf)!=0
+ || !S_ISREG(buf.st_mode)
+ ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }
+ if( nBuf<=0 ){
+ return (int)buf.st_size;
+ }else if( nBuf==1 ){
+ zBuf[0] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
+ (int)buf.st_size));
+ return (int)buf.st_size;
+ }
+ if( nBuf > buf.st_size + 1 ){
+ nBuf = buf.st_size + 1;
+ }
+ fd = fopen(zXKey, "rb");
+ if( fd==0 ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }else{
+ sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
+ fclose(fd);
+ zBuf[n] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
+ n, zBuf, n>50 ? "..." : ""));
+ return (int)n;
+ }
+}
+
+/*
+** An internal level of indirection which enables us to replace the
+** kvvfs i/o methods with JavaScript implementations in WASM builds.
+** Maintenance reminder: if this struct changes in any way, the JSON
+** rendering of its structure must be updated in
+** sqlite3_wasm_enum_json(). There are no binary compatibility
+** concerns, so it does not need an iVersion member. This file is
+** necessarily always compiled together with sqlite3_wasm_enum_json(),
+** and JS code dynamically creates the mapping of members based on
+** that JSON description.
+*/
+typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
+struct sqlite3_kvvfs_methods {
+ int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
+ int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
+ int (*xDelete)(const char *zClass, const char *zKey);
+ const int nKeySize;
+};
+
+/*
+** This object holds the kvvfs I/O methods which may be swapped out
+** for JavaScript-side implementations in WASM builds. In such builds
+** it cannot be const, but in native builds it should be so that
+** the compiler can hopefully optimize this level of indirection out.
+** That said, kvvfs is intended primarily for use in WASM builds.
+**
+** Note that this is not explicitly flagged as static because the
+** amalgamation build will tag it with SQLITE_PRIVATE.
+*/
+#ifndef SQLITE_WASM
+const
+#endif
+SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
+kvstorageRead,
+kvstorageWrite,
+kvstorageDelete,
+KVSTORAGE_KEY_SZ
+};
+
+/****** Utility subroutines ************************************************/
+
+/*
+** Encode binary into the text encoded used to persist on disk.
+** The output text is stored in aOut[], which must be at least
+** nData+1 bytes in length.
+**
+** Return the actual length of the encoded text, not counting the
+** zero terminator at the end.
+**
+** Encoding format
+** ---------------
+**
+** * Non-zero bytes are encoded as upper-case hexadecimal
+**
+** * A sequence of one or more zero-bytes that are not at the
+** beginning of the buffer are encoded as a little-endian
+** base-26 number using a..z. "a" means 0. "b" means 1,
+** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
+**
+** * Because there is no overlap between the encoding characters
+** of hexadecimal and base-26 numbers, it is always clear where
+** one stops and the next begins.
+*/
+static int kvvfsEncode(const char *aData, int nData, char *aOut){
+ int i, j;
+ const unsigned char *a = (const unsigned char*)aData;
+ for(i=j=0; i<nData; i++){
+ unsigned char c = a[i];
+ if( c!=0 ){
+ aOut[j++] = "0123456789ABCDEF"[c>>4];
+ aOut[j++] = "0123456789ABCDEF"[c&0xf];
+ }else{
+ /* A sequence of 1 or more zeros is stored as a little-endian
+ ** base-26 number using a..z as the digits. So one zero is "b".
+ ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
+ ** and so forth.
+ */
+ int k;
+ for(k=1; i+k<nData && a[i+k]==0; k++){}
+ i += k-1;
+ while( k>0 ){
+ aOut[j++] = 'a'+(k%26);
+ k /= 26;
+ }
+ }
+ }
+ aOut[j] = 0;
+ return j;
+}
+
+static const signed char kvvfsHexValue[256] = {
+ -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,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -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, -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
+};
+
+/*
+** Decode the text encoding back to binary. The binary content is
+** written into pOut, which must be at least nOut bytes in length.
+**
+** The return value is the number of bytes actually written into aOut[].
+*/
+static int kvvfsDecode(const char *a, char *aOut, int nOut){
+ int i, j;
+ int c;
+ const unsigned char *aIn = (const unsigned char*)a;
+ i = 0;
+ j = 0;
+ while( 1 ){
+ c = kvvfsHexValue[aIn[i]];
+ if( c<0 ){
+ int n = 0;
+ int mult = 1;
+ c = aIn[i];
+ if( c==0 ) break;
+ while( c>='a' && c<='z' ){
+ n += (c - 'a')*mult;
+ mult *= 26;
+ c = aIn[++i];
+ }
+ if( j+n>nOut ) return -1;
+ memset(&aOut[j], 0, n);
+ j += n;
+ c = aIn[i];
+ if( c==0 ) break;
+ }else{
+ aOut[j] = c<<4;
+ c = kvvfsHexValue[aIn[++i]];
+ if( c<0 ) break;
+ aOut[j++] += c;
+ i++;
+ }
+ }
+ return j;
+}
+
+/*
+** Decode a complete journal file. Allocate space in pFile->aJrnl
+** and store the decoding there. Or leave pFile->aJrnl set to NULL
+** if an error is encountered.
+**
+** The first few characters of the text encoding will be a little-endian
+** base-26 number (digits a..z) that is the total number of bytes
+** in the decoded journal file image. This base-26 number is followed
+** by a single space, then the encoding of the journal. The space
+** separator is required to act as a terminator for the base-26 number.
+*/
+static void kvvfsDecodeJournal(
+ KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
+ const char *zTxt, /* Text encoding. Zero-terminated */
+ int nTxt /* Bytes in zTxt, excluding zero terminator */
+){
+ unsigned int n = 0;
+ int c, i, mult;
+ i = 0;
+ mult = 1;
+ while( (c = zTxt[i++])>='a' && c<='z' ){
+ n += (zTxt[i] - 'a')*mult;
+ mult *= 26;
+ }
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = sqlite3_malloc64( n );
+ if( pFile->aJrnl==0 ){
+ pFile->nJrnl = 0;
+ return;
+ }
+ pFile->nJrnl = n;
+ n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
+ if( n<pFile->nJrnl ){
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ }
+}
+
+/*
+** Read or write the "sz" element, containing the database file size.
+*/
+static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
+ char zData[50];
+ zData[0] = 0;
+ sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
+ return strtoll(zData, 0, 0);
+}
+static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
+ char zData[50];
+ sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
+ return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
+}
+
+/****** sqlite3_io_methods methods ******************************************/
+
+/*
+** Close an kvvfs-file.
+*/
+static int kvvfsClose(sqlite3_file *pProtoFile){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+
+ SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
+ pFile->isJournal ? "journal" : "db"));
+ sqlite3_free(pFile->aJrnl);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the -journal file.
+*/
+static int kvvfsReadJrnl(
+ sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ assert( pFile->isJournal );
+ SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( pFile->aJrnl==0 ){
+ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
+ char *aTxt;
+ if( szTxt<=4 ){
+ return SQLITE_IOERR;
+ }
+ aTxt = sqlite3_malloc64( szTxt+1 );
+ if( aTxt==0 ) return SQLITE_NOMEM;
+ kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
+ kvvfsDecodeJournal(pFile, aTxt, szTxt);
+ sqlite3_free(aTxt);
+ if( pFile->aJrnl==0 ) return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt>pFile->nJrnl ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the database file.
+*/
+static int kvvfsReadDb(
+ sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ int got, n;
+ char zKey[30];
+ char aData[133073];
+ assert( iOfst>=0 );
+ assert( iAmt>=0 );
+ SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iOfst+iAmt>=512 ){
+ if( (iOfst % iAmt)!=0 ){
+ return SQLITE_IOERR_READ;
+ }
+ if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
+ return SQLITE_IOERR_READ;
+ }
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ }else{
+ pgno = 1;
+ }
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
+ if( got<0 ){
+ n = 0;
+ }else{
+ aData[got] = 0;
+ if( iOfst+iAmt<512 ){
+ int k = iOfst+iAmt;
+ aData[k*2] = 0;
+ n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000);
+ if( n>=iOfst+iAmt ){
+ memcpy(zBuf, &aData[2000+iOfst], iAmt);
+ n = iAmt;
+ }else{
+ n = 0;
+ }
+ }else{
+ n = kvvfsDecode(aData, zBuf, iAmt);
+ }
+ }
+ if( n<iAmt ){
+ memset(zBuf+n, 0, iAmt-n);
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Write into the -journal file.
+*/
+static int kvvfsWriteJrnl(
+ sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ sqlite3_int64 iEnd = iOfst+iAmt;
+ SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iEnd>=0x10000000 ) return SQLITE_FULL;
+ if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
+ char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
+ if( aNew==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ pFile->aJrnl = aNew;
+ if( pFile->nJrnl<iOfst ){
+ memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
+ }
+ pFile->nJrnl = iEnd;
+ }
+ memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Write into the database file.
+*/
+static int kvvfsWriteDb(
+ sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ char zKey[30];
+ char aData[131073];
+ SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ assert( iAmt>=512 && iAmt<=65536 );
+ assert( (iAmt & (iAmt-1))==0 );
+ assert( pFile->szPage<0 || pFile->szPage==iAmt );
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ kvvfsEncode(zBuf, iAmt, aData);
+ if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
+ return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt > pFile->szDb ){
+ pFile->szDb = iOfst + iAmt;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Truncate an kvvfs-file.
+*/
+static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
+ assert( size==0 );
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ return SQLITE_OK;
+}
+static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ if( pFile->szDb>size
+ && pFile->szPage>0
+ && (size % pFile->szPage)==0
+ ){
+ char zKey[50];
+ unsigned int pgno, pgnoMax;
+ SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
+ pgno = 1 + size/pFile->szPage;
+ pgnoMax = 2 + pFile->szDb/pFile->szPage;
+ while( pgno<=pgnoMax ){
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
+ pgno++;
+ }
+ pFile->szDb = size;
+ return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
+ }
+ return SQLITE_IOERR;
+}
+
+/*
+** Sync an kvvfs-file.
+*/
+static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
+ int i, n;
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ char *zOut;
+ SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
+ if( pFile->nJrnl<=0 ){
+ return kvvfsTruncateJrnl(pProtoFile, 0);
+ }
+ zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
+ if( zOut==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ n = pFile->nJrnl;
+ i = 0;
+ do{
+ zOut[i++] = 'a' + (n%26);
+ n /= 26;
+ }while( n>0 );
+ zOut[i++] = ' ';
+ kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
+ i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
+ sqlite3_free(zOut);
+ return i ? SQLITE_IOERR : SQLITE_OK;
+}
+static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current file-size of an kvvfs-file.
+*/
+static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
+ *pSize = pFile->nJrnl;
+ return SQLITE_OK;
+}
+static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>=0 ){
+ *pSize = pFile->szDb;
+ }else{
+ *pSize = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Lock an kvvfs-file.
+*/
+static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
+
+ if( eLock!=SQLITE_LOCK_NONE ){
+ pFile->szDb = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Unlock an kvvfs-file.
+*/
+static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
+ if( eLock==SQLITE_LOCK_NONE ){
+ pFile->szDb = -1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
+*/
+static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
+ SQLITE_KV_LOG(("xCheckReservedLock\n"));
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** File control method. For custom operations on an kvvfs-file.
+*/
+static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
+ return SQLITE_NOTFOUND;
+}
+static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
+ if( op==SQLITE_FCNTL_SYNC ){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ int rc = SQLITE_OK;
+ SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
+ rc = SQLITE_IOERR;
+ }
+ return rc;
+ }
+ return SQLITE_NOTFOUND;
+}
+
+/*
+** Return the sector-size in bytes for an kvvfs-file.
+*/
+static int kvvfsSectorSize(sqlite3_file *pFile){
+ return 512;
+}
+
+/*
+** Return the device characteristic flags supported by an kvvfs-file.
+*/
+static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
+ return 0;
+}
+
+/****** sqlite3_vfs methods *************************************************/
+
+/*
+** Open an kvvfs file handle.
+*/
+static int kvvfsOpen(
+ sqlite3_vfs *pProtoVfs,
+ const char *zName,
+ sqlite3_file *pProtoFile,
+ int flags,
+ int *pOutFlags
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ if( zName==0 ) zName = "";
+ SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
+ if( strcmp(zName, "local")==0
+ || strcmp(zName, "session")==0
+ ){
+ pFile->isJournal = 0;
+ pFile->base.pMethods = &kvvfs_db_io_methods;
+ }else
+ if( strcmp(zName, "local-journal")==0
+ || strcmp(zName, "session-journal")==0
+ ){
+ pFile->isJournal = 1;
+ pFile->base.pMethods = &kvvfs_jrnl_io_methods;
+ }else{
+ return SQLITE_CANTOPEN;
+ }
+ if( zName[0]=='s' ){
+ pFile->zClass = "session";
+ }else{
+ pFile->zClass = "local";
+ }
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ pFile->szPage = -1;
+ pFile->szDb = -1;
+ return SQLITE_OK;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ if( strcmp(zPath, "local-journal")==0 ){
+ sqlite3KvvfsMethods.xDelete("local", "jrnl");
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ sqlite3KvvfsMethods.xDelete("session", "jrnl");
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int kvvfsAccess(
+ sqlite3_vfs *pProtoVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
+ if( strcmp(zPath, "local-journal")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "local")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
+ }else
+ {
+ *pResOut = 0;
+ }
+ SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
+ return SQLITE_OK;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int kvvfsFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ size_t nPath;
+#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
+ zPath = "local";
+#endif
+ nPath = strlen(zPath);
+ SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
+ if( nOut<nPath+1 ) nPath = nOut - 1;
+ memcpy(zOut, zPath, nPath);
+ zOut[nPath] = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return 0;
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ memset(zBufOut, 0, nByte);
+ return nByte;
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ sqlite3_int64 i = 0;
+ int rc;
+ rc = kvvfsCurrentTimeInt64(0, &i);
+ *pTimeOut = i/86400000.0;
+ return rc;
+}
+#include <sys/time.h>
+static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+ struct timeval sNow;
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
+ *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
+
+#if SQLITE_OS_KV
+/*
+** This routine is called initialize the KV-vfs as the default VFS.
+*/
+SQLITE_API int sqlite3_os_init(void){
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
+}
+SQLITE_API int sqlite3_os_end(void){
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV */
+
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlite3KvvfsInit(void){
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
+}
+#endif
+
+/************** End of os_kv.c ***********************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
@@ -35562,13 +36739,13 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/*
** standard include files.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <sys/types.h> /* amalgamator: keep */
+#include <sys/stat.h> /* amalgamator: keep */
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <unistd.h>
+#include <unistd.h> /* amalgamator: keep */
/* #include <time.h> */
-#include <sys/time.h>
+#include <sys/time.h> /* amalgamator: keep */
#include <errno.h>
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
# include <sys/mman.h>
@@ -43533,8 +44710,16 @@ SQLITE_API int sqlite3_os_init(void){
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
+#ifdef SQLITE_DEFAULT_UNIX_VFS
+ sqlite3_vfs_register(&aVfs[i],
+ 0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
+#else
sqlite3_vfs_register(&aVfs[i], i==0);
+#endif
}
+#ifdef SQLITE_OS_KV_OPTIONAL
+ sqlite3KvvfsInit();
+#endif
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
@@ -45497,8 +46682,9 @@ SQLITE_API int sqlite3_win32_set_directory8(
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
+ int rc;
#ifndef SQLITE_OMIT_AUTOINIT
- int rc = sqlite3_initialize();
+ rc = sqlite3_initialize();
if( rc ) return rc;
#endif
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
@@ -48303,9 +49489,10 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
}
/*
-** If sqlite3_temp_directory is not, take the mutex and return true.
+** If sqlite3_temp_directory is defined, take the mutex and return true.
**
-** If sqlite3_temp_directory is NULL, omit the mutex and return false.
+** If sqlite3_temp_directory is NULL (undefined), omit the mutex and
+** return false.
*/
static int winTempDirDefined(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
@@ -49341,7 +50528,8 @@ static int winFullPathname(
char *zFull /* Output buffer */
){
int rc;
- sqlite3_mutex *pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR);
+ MUTEX_LOGIC( sqlite3_mutex *pMutex; )
+ MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
sqlite3_mutex_enter(pMutex);
rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
sqlite3_mutex_leave(pMutex);
@@ -51135,12 +52323,20 @@ struct PCache {
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
- void pcacheDump(PCache *pCache){
- int N;
- int i, j;
- sqlite3_pcache_page *pLower;
+ static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
PgHdr *pPg;
unsigned char *a;
+ int j;
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
+ static void pcacheDump(PCache *pCache){
+ int N;
+ int i;
+ sqlite3_pcache_page *pLower;
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
@@ -51149,22 +52345,33 @@ struct PCache {
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf("\n");
- if( pPg->pPage==0 ){
+ pcachePageTrace(i, pLower);
+ if( ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
- #else
+#else
# define pcacheTrace(X)
+# define pcachePageTrace(PGNO, X)
# define pcacheDump(X)
#endif
/*
+** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
+** This routine runs inside of assert() statements only.
+*/
+#ifdef SQLITE_DEBUG
+static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
@@ -51182,8 +52389,13 @@ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
- assert( pCache->pDirtyTail!=pPg );
+ assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
+ }else{
+ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
+ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
+ assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
+ assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
+ assert( pageOnDirtyList(pCache, pPg) );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
@@ -51457,8 +52669,9 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
- pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
+ pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes));
+ pcachePageTrace(pgno, pRes);
return pRes;
}
@@ -51586,6 +52799,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+ assert( sqlite3PcachePageSanity(p) );
}
}
}
@@ -51629,6 +52843,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
+ assert( sqlite3PcachePageSanity(p) );
}
assert( sqlite3PcachePageSanity(p) );
}
@@ -51691,14 +52906,24 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
+ sqlite3_pcache_page *pOther;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
+ pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
+ if( pOther ){
+ PgHdr *pXPage = (PgHdr*)pOther->pExtra;
+ assert( pXPage->nRef==0 );
+ pXPage->nRef++;
+ pCache->nRefSum++;
+ sqlite3PcacheDrop(pXPage);
+ }
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+ assert( sqlite3PcachePageSanity(p) );
}
}
@@ -51996,12 +53221,13 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** size can vary according to architecture, compile-time options, and
** SQLite library version number.
**
-** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
-** using a separate memory allocation from the database page content. This
-** seeks to overcome the "clownshoe" problem (also called "internal
-** fragmentation" in academic literature) of allocating a few bytes more
-** than a power of two with the memory allocator rounding up to the next
-** power of two, and leaving the rounded-up space unused.
+** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER
+** was defined, then the page content would be held in a separate memory
+** allocation from the PgHdr1. This was intended to avoid clownshoe memory
+** allocations. However, the btree layer needs a small (16-byte) overrun
+** area after the page content buffer. The header serves as that overrun
+** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid
+** any possibility of a memory error.
**
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
** with this module. Information is passed back and forth as PgHdr1 pointers.
@@ -52046,30 +53272,40 @@ typedef struct PGroup PGroup;
/*
** Each cache entry is represented by an instance of the following
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
-** in memory.
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
+** directly before this structure and is used to cache the page content.
+**
+** When reading a corrupt database file, it is possible that SQLite might
+** read a few bytes (no more than 16 bytes) past the end of the page buffer.
+** It will only read past the end of the page buffer, never write. This
+** object is positioned immediately after the page buffer to serve as an
+** overrun area, so that overreads are harmless.
**
-** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
+** Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
** can cause a valgrind error if the unitialized gap is accessed. Using u16
-** ensures there is no such gap, and therefore no bytes of unitialized memory
-** in the structure.
+** ensures there is no such gap, and therefore no bytes of uninitialized
+** memory in the structure.
+**
+** The pLruNext and pLruPrev pointers form a double-linked circular list
+** of all pages that are unpinned. The PGroup.lru element (which should be
+** the only element on the list with PgHdr1.isAnchor set to 1) forms the
+** beginning and the end of the list.
*/
struct PgHdr1 {
- sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
- unsigned int iKey; /* Key value (page number) */
- u16 isBulkLocal; /* This page from bulk local storage */
- u16 isAnchor; /* This is the PGroup.lru element */
- PgHdr1 *pNext; /* Next in hash table chain */
- PCache1 *pCache; /* Cache that currently owns this page */
- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
- /* NB: pLruPrev is only valid if pLruNext!=0 */
+ sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
+ unsigned int iKey; /* Key value (page number) */
+ u16 isBulkLocal; /* This page from bulk local storage */
+ u16 isAnchor; /* This is the PGroup.lru element */
+ PgHdr1 *pNext; /* Next in hash table chain */
+ PCache1 *pCache; /* Cache that currently owns this page */
+ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
+ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+ /* NB: pLruPrev is only valid if pLruNext!=0 */
};
/*
@@ -52395,25 +53631,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
pcache1LeaveMutex(pCache->pGroup);
#endif
if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- pPg = pcache1Alloc(pCache->szPage);
- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
- if( !pPg || !p ){
- pcache1Free(pPg);
- sqlite3_free(p);
- pPg = 0;
- }
-#else
pPg = pcache1Alloc(pCache->szAlloc);
-#endif
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
-#ifndef SQLITE_PCACHE_SEPARATE_HEADER
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
-#endif
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
@@ -52437,9 +53661,6 @@ static void pcache1FreePage(PgHdr1 *p){
pCache->pFree = p;
}else{
pcache1Free(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- sqlite3_free(p);
-#endif
}
(*pCache->pnPurgeable)--;
}
@@ -53080,23 +54301,26 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
- unsigned int h;
+ unsigned int hOld, hNew;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
+ assert( iOld!=iNew ); /* The page number really is changing */
pcache1EnterMutex(pCache->pGroup);
- h = iOld%pCache->nHash;
- pp = &pCache->apHash[h];
+ assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
+ hOld = iOld%pCache->nHash;
+ pp = &pCache->apHash[hOld];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
- h = iNew%pCache->nHash;
+ assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
+ hNew = iNew%pCache->nHash;
pPage->iKey = iNew;
- pPage->pNext = pCache->apHash[h];
- pCache->apHash[h] = pPage;
+ pPage->pNext = pCache->apHash[hNew];
+ pCache->apHash[hNew] = pPage;
if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew;
}
@@ -53203,9 +54427,6 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
&& p->isAnchor==0
){
nFree += pcache1MemSize(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- nFree += sqlite3MemSize(p);
-#endif
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
@@ -59694,6 +60915,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+ flags |= SQLITE_OPEN_EXCLUSIVE;
nSpill = sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
@@ -61285,7 +62507,7 @@ SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager *pPager){
SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
assert( assert_pager_state(pPager) );
if( pPager->eState>=PAGER_WRITER_CACHEMOD ) return 0;
- if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0;
+ if( NEVER(isOpen(pPager->jfd) && pPager->journalOff>0) ) return 0;
return 1;
}
@@ -66793,6 +68015,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
+ if( db->pVfs==0 && db->nDb==0 ) return 1;
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
@@ -68365,8 +69588,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- temp = 0;
- src = data = pPage->aData;
+ data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
@@ -68400,7 +69622,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
- }else if( NEVER(iFree+sz>usableSize) ){
+ }else if( iFree+sz>usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -68420,39 +69642,38 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
cbrk = usableSize;
iCellLast = usableSize - 4;
iCellStart = get2byte(&data[hdr+5]);
- for(i=0; i<nCell; i++){
- u8 *pAddr; /* The i-th cell pointer */
- pAddr = &data[cellOffset + i*2];
- pc = get2byte(pAddr);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- /* These conditions have already been verified in btreeInitPage()
- ** if PRAGMA cell_size_check=ON.
- */
- if( pc<iCellStart || pc>iCellLast ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( pc>=iCellStart && pc<=iCellLast );
- size = pPage->xCellSize(pPage, &src[pc]);
- cbrk -= size;
- if( cbrk<iCellStart || pc+size>usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( cbrk+size<=usableSize && cbrk>=iCellStart );
- testcase( cbrk+size==usableSize );
- testcase( pc+size==usableSize );
- put2byte(pAddr, cbrk);
- if( temp==0 ){
- if( cbrk==pc ) continue;
- temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
- src = temp;
+ if( nCell>0 ){
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
+ memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
+ src = temp;
+ for(i=0; i<nCell; i++){
+ u8 *pAddr; /* The i-th cell pointer */
+ pAddr = &data[cellOffset + i*2];
+ pc = get2byte(pAddr);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ /* These conditions have already been verified in btreeInitPage()
+ ** if PRAGMA cell_size_check=ON.
+ */
+ if( pc<iCellStart || pc>iCellLast ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( pc>=iCellStart && pc<=iCellLast );
+ size = pPage->xCellSize(pPage, &src[pc]);
+ cbrk -= size;
+ if( cbrk<iCellStart || pc+size>usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( cbrk+size<=usableSize && cbrk>=iCellStart );
+ testcase( cbrk+size==usableSize );
+ testcase( pc+size==usableSize );
+ put2byte(pAddr, cbrk);
+ memcpy(&data[cbrk], &src[pc], size);
}
- memcpy(&data[cbrk], &src[pc], size);
}
data[hdr+7] = 0;
- defragment_out:
+defragment_out:
assert( pPage->nFree>=0 );
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
return SQLITE_CORRUPT_PAGE(pPage);
@@ -68509,7 +69730,6 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
- testcase( pc+x>maxPC );
return &aData[pc];
}else if( x+pc > maxPC ){
/* This slot extends off the end of the usable part of the page */
@@ -68525,9 +69745,9 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
iAddr = pc;
pTmp = &aData[pc];
pc = get2byte(pTmp);
- if( pc<=iAddr+size ){
+ if( pc<=iAddr ){
if( pc ){
- /* The next slot in the chain is not past the end of the current slot */
+ /* The next slot in the chain comes before the current slot */
*pRc = SQLITE_CORRUPT_PAGE(pPg);
}
return 0;
@@ -68679,7 +69899,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
- if( iFreeBlk<iPtr+4 ){
+ if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -69161,9 +70381,7 @@ getAndInitPage_error1:
pCur->pPage = pCur->apPage[pCur->iPage];
}
testcase( pgno==0 );
- assert( pgno!=0 || rc==SQLITE_CORRUPT
- || rc==SQLITE_IOERR_NOMEM
- || rc==SQLITE_NOMEM );
+ assert( pgno!=0 || rc!=SQLITE_OK );
return rc;
}
@@ -70599,6 +71817,9 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}
}else{
+ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
@@ -72105,8 +73326,6 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
- BtShared *pBt = pCur->pBt;
-
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -72120,7 +73339,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
+ return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
+ pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -72226,7 +73446,7 @@ static int moveToRoot(BtCursor *pCur){
}
sqlite3BtreeClearCursor(pCur);
}
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
+ rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
@@ -72934,14 +74154,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( !pPage->isInit || sqlite3FaultSim(412) ){
- /* The only known way for this to happen is for there to be a
- ** recursive SQL function that does a DELETE operation as part of a
- ** SELECT which deletes content out from under an active cursor
- ** in a corrupt database file where the table being DELETE-ed from
- ** has pages in common with the table being queried. See TH3
- ** module cov1/btree78.test testcase 220 (2018-06-08) for an
- ** example. */
+ if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -73117,8 +74330,8 @@ static int allocateBtreePage(
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
- /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
- ** stores stores the total number of pages on the freelist. */
+ /* EVIDENCE-OF: R-21003-45125 The 4-byte big-endian integer at offset 36
+ ** stores the total number of pages on the freelist. */
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -73867,12 +75080,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
assert( pPage->pBt->usableSize > (u32)(ptr-data) );
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
-#if 0 /* Not required. Omit for efficiency */
- if( pc<hdr+pPage->nCell*2 ){
- *pRC = SQLITE_CORRUPT_BKPT;
- return;
- }
-#endif
testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
@@ -74756,8 +75963,6 @@ static int balance_nonroot(
Pgno pgno; /* Temp var to store a page number in */
u8 abDone[NB+2]; /* True after i'th new page is populated */
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
- Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
- u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
@@ -75181,42 +76386,39 @@ static int balance_nonroot(
** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
- ** An O(n^2) insertion sort algorithm is used, but since n is never more
- ** than (NB+2) (a small constant), that should not be a problem.
+ ** An O(N*N) sort algorithm is used, but since N is never more than NB+2
+ ** (5), that is not a performance concern.
**
** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
for(i=0; i<nNew; i++){
- aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
- aPgFlags[i] = apNew[i]->pDbPage->flags;
- for(j=0; j<i; j++){
- if( NEVER(aPgno[j]==aPgno[i]) ){
- /* This branch is taken if the set of sibling pages somehow contains
- ** duplicate entries. This can happen if the database is corrupt.
- ** It would be simpler to detect this as part of the loop below, but
- ** we do the detection here in order to avoid populating the pager
- ** cache with two separate objects associated with the same
- ** page number. */
- assert( CORRUPT_DB );
- rc = SQLITE_CORRUPT_BKPT;
- goto balance_cleanup;
- }
- }
+ aPgno[i] = apNew[i]->pgno;
+ assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
+ assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
}
- for(i=0; i<nNew; i++){
- int iBest = 0; /* aPgno[] index of page number to use */
- for(j=1; j<nNew; j++){
- if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
+ for(i=0; i<nNew-1; i++){
+ int iB = i;
+ for(j=i+1; j<nNew; j++){
+ if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
}
- pgno = aPgOrder[iBest];
- aPgOrder[iBest] = 0xffffffff;
- if( iBest!=i ){
- if( iBest>i ){
- sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
- }
- sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
- apNew[i]->pgno = pgno;
+
+ /* If apNew[i] has a page number that is bigger than any of the
+ ** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
+ ** entry that has the smallest page number (which we know to be
+ ** entry apNew[iB]).
+ */
+ if( iB!=i ){
+ Pgno pgnoA = apNew[i]->pgno;
+ Pgno pgnoB = apNew[iB]->pgno;
+ Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
+ u16 fgA = apNew[i]->pDbPage->flags;
+ u16 fgB = apNew[iB]->pDbPage->flags;
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
+ sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
+ apNew[i]->pgno = pgnoB;
+ apNew[iB]->pgno = pgnoA;
}
}
@@ -75642,6 +76844,11 @@ static int balance(BtCursor *pCur){
}else{
break;
}
+ }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){
+ /* The page being written is not a root page, and there is currently
+ ** more than one reference to it. This only happens if the page is one
+ ** of its own ancestor pages. Corruption. */
+ rc = SQLITE_CORRUPT_BKPT;
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
@@ -79485,6 +80692,16 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
&& i >= -2251799813685248LL && i < 2251799813685248LL);
}
+/* Convert a floating point value to its closest integer. Do so in
+** a way that avoids 'outside the range of representable values' warnings
+** from UBSAN.
+*/
+SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
+ if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
+ if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
+ return (i64)r;
+}
+
/*
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
@@ -79506,7 +80723,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
- || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r))
+ || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
){
pMem->u.i = ix;
MemSetTypeFlag(pMem, MEM_Int);
@@ -79558,6 +80775,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
+ if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
@@ -80693,6 +81911,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
return p->n;
}
+ if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){
+ return p->n;
+ }
if( (p->flags & MEM_Blob)!=0 ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
@@ -80738,10 +81959,10 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
- db->pVdbe->pPrev = p;
+ db->pVdbe->ppVPrev = &p->pVNext;
}
- p->pNext = db->pVdbe;
- p->pPrev = 0;
+ p->pVNext = db->pVdbe;
+ p->ppVPrev = &db->pVdbe;
db->pVdbe = p;
assert( p->eVdbeState==VDBE_INIT_STATE );
p->pParse = pParse;
@@ -80823,21 +82044,28 @@ SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(
#endif
/*
-** Swap all content between two VDBE structures.
+** Swap byte-code between two VDBE structures.
+**
+** This happens after pB was previously run and returned
+** SQLITE_SCHEMA. The statement was then reprepared in pA.
+** This routine transfers the new bytecode in pA over to pB
+** so that pB can be run again. The old pB byte code is
+** moved back to pA so that it will be cleaned up when pA is
+** finalized.
*/
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
- Vdbe tmp, *pTmp;
+ Vdbe tmp, *pTmp, **ppTmp;
char *zTmp;
assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
- pTmp = pA->pNext;
- pA->pNext = pB->pNext;
- pB->pNext = pTmp;
- pTmp = pA->pPrev;
- pA->pPrev = pB->pPrev;
- pB->pPrev = pTmp;
+ pTmp = pA->pVNext;
+ pA->pVNext = pB->pVNext;
+ pB->pVNext = pTmp;
+ ppTmp = pA->ppVPrev;
+ pA->ppVPrev = pB->ppVPrev;
+ pB->ppVPrev = ppTmp;
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
@@ -81158,7 +82386,7 @@ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt
iThis = v->nOp;
sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
- sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z);
+ sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z);
if( bPush){
pParse->addrExplain = iThis;
}
@@ -81516,8 +82744,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
- while(1){
-
+ assert( p->aOp[0].opcode==OP_Init );
+ while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
@@ -81546,6 +82774,10 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Init: {
+ assert( pOp->p2>=0 );
+ goto resolve_p2_values_loop_exit;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -81578,11 +82810,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
- if( pOp==p->aOp ) break;
+ assert( pOp>p->aOp );
pOp--;
}
+resolve_p2_values_loop_exit:
if( aLabel ){
- sqlite3DbFreeNN(p->db, pParse->aLabel);
+ sqlite3DbNNFreeNN(p->db, pParse->aLabel);
pParse->aLabel = 0;
}
pParse->nLabel = 0;
@@ -81831,15 +83064,19 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
** for a specific instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p1 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
+ assert( addr>=0 || p->db->mallocFailed );
sqlite3VdbeGetOp(p,addr)->p2 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
@@ -81848,6 +83085,18 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
}
/*
+** If the previous opcode is an OP_Column that delivers results
+** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
+** opcode.
+*/
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
+ if( pOp->p3==iDest && pOp->opcode==OP_Column ){
+ pOp->p5 |= OPFLAG_TYPEOFARG;
+ }
+}
+
+/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
@@ -81875,7 +83124,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
|| p->aOp[addr].opcode==OP_FkIfZero );
assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
- sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
+ sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
#endif
p->nOp--;
}else{
@@ -81889,8 +83138,9 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
+ assert( db!=0 );
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
- sqlite3DbFreeNN(db, pDef);
+ sqlite3DbNNFreeNN(db, pDef);
}
}
@@ -81899,11 +83149,12 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
*/
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
+ assert( db!=0 );
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -81916,7 +83167,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
case P4_INT64:
case P4_DYNAMIC:
case P4_INTARRAY: {
- sqlite3DbFree(db, p4);
+ if( p4 ) sqlite3DbNNFreeNN(db, p4);
break;
}
case P4_KEYINFO: {
@@ -81955,6 +83206,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
+ assert( db!=0 );
if( aOp ){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
@@ -81965,7 +83217,7 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( pOp==aOp ) break;
pOp--;
}
- sqlite3DbFreeNN(db, aOp);
+ sqlite3DbNNFreeNN(db, aOp);
}
}
@@ -82196,13 +83448,13 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
** Set the value if the iSrcLine field for the previously coded instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
- sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine;
+ sqlite3VdbeGetLastOp(v)->iSrcLine = iLine;
}
#endif /* SQLITE_VDBE_COVERAGE */
/*
-** Return the opcode for a given address. If the address is -1, then
-** return the most recently inserted opcode.
+** Return the opcode for a given address. The address must be non-negative.
+** See sqlite3VdbeGetLastOp() to get the most recently added opcode.
**
** 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
@@ -82218,9 +83470,6 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->eVdbeState==VDBE_INIT_STATE );
- if( addr<0 ){
- addr = p->nOp - 1;
- }
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
return (VdbeOp*)&dummy;
@@ -82229,6 +83478,12 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
}
}
+/* Return the most recently added opcode
+*/
+VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
+ return sqlite3VdbeGetOp(p, p->nOp - 1);
+}
+
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
@@ -82716,7 +83971,7 @@ static void releaseMemArray(Mem *p, int N){
sqlite3VdbeMemRelease(p);
p->flags = MEM_Undefined;
}else if( p->szMalloc ){
- sqlite3DbFreeNN(db, p->zMalloc);
+ sqlite3DbNNFreeNN(db, p->zMalloc);
p->szMalloc = 0;
p->flags = MEM_Undefined;
}
@@ -83708,7 +84963,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
- p = p->pNext;
+ p = p->pVNext;
}
assert( cnt==db->nVdbeActive );
assert( nWrite==db->nVdbeWrite );
@@ -84237,10 +85492,11 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
*/
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
+ assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlite3DbFreeNN(db, p->aColName);
+ sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
@@ -84249,11 +85505,11 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
}
if( p->eVdbeState!=VDBE_INIT_STATE ){
releaseMemArray(p->aVar, p->nVar);
- if( p->pVList ) sqlite3DbFreeNN(db, p->pVList);
- if( p->pFree ) sqlite3DbFreeNN(db, p->pFree);
+ if( p->pVList ) sqlite3DbNNFreeNN(db, p->pVList);
+ if( p->pFree ) sqlite3DbNNFreeNN(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
- sqlite3DbFree(db, p->zSql);
+ if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
@@ -84283,20 +85539,17 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
assert( p!=0 );
db = p->db;
+ assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
if( db->pnBytesFreed==0 ){
- if( p->pPrev ){
- p->pPrev->pNext = p->pNext;
- }else{
- assert( db->pVdbe==p );
- db->pVdbe = p->pNext;
- }
- if( p->pNext ){
- p->pNext->pPrev = p->pPrev;
+ assert( p->ppVPrev!=0 );
+ *p->ppVPrev = p->pVNext;
+ if( p->pVNext ){
+ p->pVNext->ppVPrev = p->ppVPrev;
}
}
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
/*
@@ -85251,7 +86504,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
assert( pPKey2->pKeyInfo->aSortFlags!=0 );
assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
- do{
+ while( 1 /*exit-by-break*/ ){
u32 serial_type;
/* RHS is an integer */
@@ -85261,7 +86514,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
- rc = +1;
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
@@ -85286,7 +86539,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
** them to numberic values are. */
- rc = +1;
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
@@ -85367,7 +86620,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
- rc = (serial_type!=0);
+ rc = (serial_type!=0 && serial_type!=10);
}
if( rc!=0 ){
@@ -85389,8 +86642,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
if( i==pPKey2->nField ) break;
pRhs++;
d1 += sqlite3VdbeSerialTypeLen(serial_type);
+ if( d1>(unsigned)nKey1 ) break;
idx1 += sqlite3VarintLen(serial_type);
- }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
+ if( idx1>=(unsigned)szHdr1 ){
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
+ return 0; /* Corrupt index */
+ }
+ }
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
@@ -85791,7 +87049,7 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){
*/
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
Vdbe *p;
- for(p = db->pVdbe; p; p=p->pNext){
+ for(p = db->pVdbe; p; p=p->pVNext){
p->expired = iCode+1;
}
}
@@ -85912,13 +87170,14 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
+ assert( db!=0 );
if( p ){
int i;
for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem);
}
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -85989,7 +87248,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
- sqlite3DbFreeNN(db, preupdate.aNew);
+ sqlite3DbNNFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -86106,7 +87365,9 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db, v);
- rc = sqlite3VdbeFinalize(v);
+ assert( v->eVdbeState>=VDBE_READY_STATE );
+ rc = sqlite3VdbeReset(v);
+ sqlite3VdbeDelete(v);
rc = sqlite3ApiExit(db, rc);
sqlite3LeaveMutexAndCloseZombie(db);
}
@@ -86314,6 +87575,9 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
#endif
return aType[pVal->flags&MEM_AffMask];
}
+SQLITE_API int sqlite3_value_encoding(sqlite3_value *pVal){
+ return pVal->enc;
+}
/* Return true if a parameter to xUpdate represents an unchanged column */
SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
@@ -87428,7 +88692,7 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
-static int vdbeUnbind(Vdbe *p, int i){
+static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
if( vdbeSafetyNotNull(p) ){
return SQLITE_MISUSE_BKPT;
@@ -87441,12 +88705,11 @@ static int vdbeUnbind(Vdbe *p, int i){
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
- if( i<1 || i>p->nVar ){
+ if( i>=(unsigned int)p->nVar ){
sqlite3Error(p->db, SQLITE_RANGE);
sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
- i--;
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
@@ -87483,7 +88746,7 @@ static int bindText(
Mem *pVar;
int rc;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
if( zData!=0 ){
pVar = &p->aVar[i-1];
@@ -87532,7 +88795,7 @@ SQLITE_API int sqlite3_bind_blob64(
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
sqlite3_mutex_leave(p->db->mutex);
@@ -87545,7 +88808,7 @@ SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
sqlite3_mutex_leave(p->db->mutex);
@@ -87555,7 +88818,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3_mutex_leave(p->db->mutex);
}
@@ -87570,7 +88833,7 @@ SQLITE_API int sqlite3_bind_pointer(
){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
@@ -87648,7 +88911,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_INCRBLOB
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
@@ -87808,7 +89071,7 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
}else{
- pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext;
+ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pVNext;
}
sqlite3_mutex_leave(pDb->mutex);
return pNext;
@@ -87833,8 +89096,11 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3_mutex_leave(db->mutex);
}else{
v = pVdbe->aCounter[op];
@@ -88674,7 +89940,8 @@ static VdbeCursor *allocateCursor(
** return false.
*/
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
- i64 iValue = (double)rValue;
+ i64 iValue;
+ iValue = sqlite3RealToI64(rValue);
if( sqlite3RealSameAsInt(rValue,iValue) ){
*piValue = iValue;
return 1;
@@ -88836,17 +90103,18 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
- if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
+ assert( (pMem->flags & MEM_Null)==0
+ || pMem->db==0 || pMem->db->mallocFailed );
+ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){
testcase( pMem->flags & MEM_Int );
testcase( pMem->flags & MEM_Real );
testcase( pMem->flags & MEM_IntReal );
- return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
- }
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
- testcase( pMem->flags & MEM_Str );
- testcase( pMem->flags & MEM_Blob );
- return computeNumericType(pMem);
+ return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null);
}
+ assert( pMem->flags & (MEM_Str|MEM_Blob) );
+ testcase( pMem->flags & MEM_Str );
+ testcase( pMem->flags & MEM_Blob );
+ return computeNumericType(pMem);
return 0;
}
@@ -90091,7 +91359,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
- u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
@@ -90100,12 +91367,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
- type1 = numericType(pIn1);
+ type1 = pIn1->flags;
pIn2 = &aMem[pOp->p2];
- type2 = numericType(pIn2);
+ type2 = pIn2->flags;
pOut = &aMem[pOp->p3];
- flags = pIn1->flags | pIn2->flags;
if( (type1 & type2 & MEM_Int)!=0 ){
+int_math:
iA = pIn1->u.i;
iB = pIn2->u.i;
switch( pOp->opcode ){
@@ -90127,9 +91394,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
- }else if( (flags & MEM_Null)!=0 ){
+ }else if( ((type1 | type2) & MEM_Null)!=0 ){
goto arithmetic_result_is_null;
}else{
+ type1 = numericType(pIn1);
+ type2 = numericType(pIn2);
+ if( (type1 & type2 & MEM_Int)!=0 ) goto int_math;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
@@ -90944,19 +92214,90 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
break;
}
-/* Opcode: IsNullOrType P1 P2 P3 * *
-** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2
+/* Opcode: IsType P1 P2 P3 P4 P5
+** Synopsis: if typeof(P1.P3) in P5 goto P2
+**
+** Jump to P2 if the type of a column in a btree is one of the types specified
+** by the P5 bitmask.
+**
+** P1 is normally a cursor on a btree for which the row decode cache is
+** valid through at least column P3. In other words, there should have been
+** a prior OP_Column for column P3 or greater. If the cursor is not valid,
+** then this opcode might give spurious results.
+** The the btree row has fewer than P3 columns, then use P4 as the
+** datatype.
+**
+** If P1 is -1, then P3 is a register number and the datatype is taken
+** from the value in that register.
+**
+** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant
+** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
+** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
+**
+** Take the jump to address P2 if and only if the datatype of the
+** value determined by P1 and P3 corresponds to one of the bits in the
+** P5 bitmask.
**
-** Jump to P2 if the value in register P1 is NULL or has a datatype P3.
-** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT,
-** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT.
*/
-case OP_IsNullOrType: { /* jump, in1 */
- int doTheJump;
- pIn1 = &aMem[pOp->p1];
- doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3;
- VdbeBranchTaken( doTheJump, 2);
- if( doTheJump ) goto jump_to_p2;
+case OP_IsType: { /* jump */
+ VdbeCursor *pC;
+ u16 typeMask;
+ u32 serialType;
+
+ assert( pOp->p1>=(-1) && pOp->p1<p->nCursor );
+ assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) );
+ if( pOp->p1>=0 ){
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pOp->p3>=0 );
+ if( pOp->p3<pC->nHdrParsed ){
+ serialType = pC->aType[pOp->p3];
+ if( serialType>=12 ){
+ if( serialType&1 ){
+ typeMask = 0x04; /* SQLITE_TEXT */
+ }else{
+ typeMask = 0x08; /* SQLITE_BLOB */
+ }
+ }else{
+ static const unsigned char aMask[] = {
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2,
+ 0x01, 0x01, 0x10, 0x10
+ };
+ testcase( serialType==0 );
+ testcase( serialType==1 );
+ testcase( serialType==2 );
+ testcase( serialType==3 );
+ testcase( serialType==4 );
+ testcase( serialType==5 );
+ testcase( serialType==6 );
+ testcase( serialType==7 );
+ testcase( serialType==8 );
+ testcase( serialType==9 );
+ testcase( serialType==10 );
+ testcase( serialType==11 );
+ typeMask = aMask[serialType];
+ }
+ }else{
+ typeMask = 1 << (pOp->p4.i - 1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ }else{
+ assert( memIsValid(&aMem[pOp->p3]) );
+ typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2);
+ if( typeMask & pOp->p5 ){
+ goto jump_to_p2;
+ }
break;
}
@@ -90999,11 +92340,14 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** If it is, then set register P3 to NULL and jump immediately to P2.
** If P1 is not on a NULL row, then fall through without making any
** changes.
+**
+** If P1 is not an open cursor, then this opcode is a no-op.
*/
case OP_IfNullRow: { /* jump */
+ VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( p->apCsr[pOp->p1]!=0 );
- if( p->apCsr[pOp->p1]->nullRow ){
+ pC = p->apCsr[pOp->p1];
+ if( ALWAYS(pC) && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -91054,7 +92398,7 @@ case OP_Offset: { /* out3 */
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
-** from this record. If there are less that (P2+1)
+** from this record. If there are less than (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
@@ -91063,10 +92407,12 @@ case OP_Offset: { /* out3 */
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
-** the result is guaranteed to only be used as the argument of a length()
-** or typeof() function, respectively. The loading of large blobs can be
-** skipped for length() and all content loading can be skipped for typeof().
+** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed
+** to only be used by the length() function or the equivalent. The content
+** of large blobs is not loaded, thus saving CPU cycles. If the
+** OPFLAG_TYPEOFARG bit is set then the result will only be used by the
+** typeof() function or the IS NULL or IS NOT NULL operators or the
+** equivalent. In this case, all content loading can be omitted.
*/
case OP_Column: {
u32 p2; /* column number to retrieve */
@@ -93005,7 +94351,13 @@ case OP_SeekGT: { /* jump, in3, group */
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+ {
+ int i;
+ for(i=0; i<r.nField; i++){
+ assert( memIsValid(&r.aMem[i]) );
+ if( i>0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
+ }
+ }
#endif
r.eqSeen = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
@@ -93068,7 +94420,7 @@ seek_not_found:
}
-/* Opcode: SeekScan P1 P2 * * *
+/* Opcode: SeekScan P1 P2 * * P5
** Synopsis: Scan-ahead up to P1 rows
**
** This opcode is a prefix opcode to OP_SeekGE. In other words, this
@@ -93078,8 +94430,8 @@ seek_not_found:
** This opcode uses the P1 through P4 operands of the subsequent
** OP_SeekGE. In the text that follows, the operands of the subsequent
** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
-** the P1 and P2 operands of this opcode are also used, and are called
-** This.P1 and This.P2.
+** the P1, P2 and P5 operands of this opcode are also used, and are called
+** This.P1, This.P2 and This.P5.
**
** This opcode helps to optimize IN operators on a multi-column index
** where the IN operator is on the later terms of the index by avoiding
@@ -93089,29 +94441,51 @@ seek_not_found:
**
** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
** is the desired entry that we want the cursor SeekGE.P1 to be pointing
-** to. Call this SeekGE.P4/P5 row the "target".
+** to. Call this SeekGE.P3/P4 row the "target".
**
** If the SeekGE.P1 cursor is not currently pointing to a valid row,
** then this opcode is a no-op and control passes through into the OP_SeekGE.
**
** If the SeekGE.P1 cursor is pointing to a valid row, then that row
** might be the target row, or it might be near and slightly before the
-** target row. This opcode attempts to position the cursor on the target
-** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
-** between 0 and This.P1 times.
-**
-** There are three possible outcomes from this opcode:<ol>
-**
-** <li> If after This.P1 steps, the cursor is still pointing to a place that
-** is earlier in the btree than the target row, then fall through
-** into the subsquence OP_SeekGE opcode.
-**
-** <li> If the cursor is successfully moved to the target row by 0 or more
-** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
-** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE.
-**
-** <li> If the cursor ends up past the target row (indicating the the target
-** row does not exist in the btree) then jump to SeekOP.P2.
+** target row, or it might be after the target row. If the cursor is
+** currently before the target row, then this opcode attempts to position
+** the cursor on or after the target row by invoking sqlite3BtreeStep()
+** on the cursor between 1 and This.P1 times.
+**
+** The This.P5 parameter is a flag that indicates what to do if the
+** cursor ends up pointing at a valid row that is past the target
+** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
+** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
+** case occurs when there are no inequality constraints to the right of
+** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** occurs when there are inequality constraints to the right of the IN
+** operator. In that case, the This.P2 will point either directly to or
+** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
+** loop terminate.
+**
+** Possible outcomes from this opcode:<ol>
+**
+** <li> If the cursor is initally not pointed to any valid row, then
+** fall through into the subsequent OP_SeekGE opcode.
+**
+** <li> If the cursor is left pointing to a row that is before the target
+** row, even after making as many as This.P1 calls to
+** sqlite3BtreeNext(), then also fall through into OP_SeekGE.
+**
+** <li> If the cursor is left pointing at the target row, either because it
+** was at the target row to begin with or because one or more
+** sqlite3BtreeNext() calls moved the cursor to the target row,
+** then jump to This.P2..,
+**
+** <li> If the cursor started out before the target row and a call to
+** to sqlite3BtreeNext() moved the cursor off the end of the index
+** (indicating that the target row definitely does not exist in the
+** btree) then jump to SeekGE.P2, ending the loop.
+**
+** <li> If the cursor ends up on a valid row that is past the target row
+** (indicating that the target row does not exist in the btree) then
+** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0.
** </ol>
*/
case OP_SeekScan: {
@@ -93122,14 +94496,25 @@ case OP_SeekScan: {
assert( pOp[1].opcode==OP_SeekGE );
- /* pOp->p2 points to the first instruction past the OP_IdxGT that
- ** follows the OP_SeekGE. */
+ /* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the
+ ** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first
+ ** opcode past the OP_SeekGE itself. */
assert( pOp->p2>=(int)(pOp-aOp)+2 );
- assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
- testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
- assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
- assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
- assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+#ifdef SQLITE_DEBUG
+ if( pOp->p5==0 ){
+ /* There are no inequality constraints following the IN constraint. */
+ assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
+ assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
+ assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT
+ || aOp[pOp->p2-1].opcode==OP_IdxGE );
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
+ }else{
+ /* There are inequality constraints. */
+ assert( pOp->p2==(int)(pOp-aOp)+2 );
+ assert( aOp[pOp->p2-1].opcode==OP_SeekGE );
+ }
+#endif
assert( pOp->p1>0 );
pC = p->apCsr[pOp[1].p1];
@@ -93163,8 +94548,9 @@ case OP_SeekScan: {
while(1){
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
- if( res>0 ){
+ if( res>0 && pOp->p5==0 ){
seekscan_search_fail:
+ /* Jump to SeekGE.P2, ending the loop */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then skip\n", pOp->p1 - nStep);
@@ -93174,7 +94560,8 @@ case OP_SeekScan: {
pOp++;
goto jump_to_p2;
}
- if( res==0 ){
+ if( res>=0 ){
+ /* Jump to This.P2, bypassing the OP_SeekGE opcode */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then success\n", pOp->p1 - nStep);
@@ -93250,12 +94637,16 @@ case OP_SeekHit: {
/* Opcode: IfNotOpen P1 P2 * * *
** Synopsis: if( !csr[P1] ) goto P2
**
-** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
+** If cursor P1 is not open or if P1 is set to a NULL row using the
+** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through.
*/
case OP_IfNotOpen: { /* jump */
+ VdbeCursor *pCur;
+
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
- if( !p->apCsr[pOp->p1] ){
+ pCur = p->apCsr[pOp->p1];
+ VdbeBranchTaken(pCur==0 || pCur->nullRow, 2);
+ if( pCur==0 || pCur->nullRow ){
goto jump_to_p2_and_check_for_interrupt;
}
break;
@@ -94446,7 +95837,9 @@ case OP_SorterNext: { /* jump */
case OP_Prev: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -94459,7 +95852,9 @@ case OP_Prev: /* jump */
case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -94666,10 +96061,10 @@ case OP_IdxRowid: { /* out2 */
** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
rc = sqlite3VdbeCursorRestore(pC);
- /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
- ** out from under the cursor. That will never happens for an IdxRowid
- ** or Seek opcode */
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+ /* sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed
+ ** since it was last positioned and an error (e.g. OOM or an IO error)
+ ** occurs while trying to reposition it. */
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
@@ -95571,7 +96966,7 @@ case OP_IfPos: { /* jump, in1 */
** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
**
** This opcode performs a commonly used computation associated with
-** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
+** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3]
** holds the offset counter. The opcode computes the combined value
** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
** value computed is the total number of rows that will need to be
@@ -101169,6 +102564,8 @@ SQLITE_PRIVATE int sqlite3JournalOpen(
){
MemJournal *p = (MemJournal*)pJfd;
+ assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
+
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
@@ -101610,9 +103007,7 @@ static void resolveAlias(
pExpr->y.pWin->pOwner = pExpr;
}
}
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3ExprDelete,
- pDup);
+ sqlite3ExprDeferredDelete(pParse, pDup);
}
}
@@ -103706,9 +105101,8 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
if( op==TK_REGISTER ) op = pExpr->op2;
if( op==TK_COLUMN || op==TK_AGG_COLUMN ){
assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
- return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
- }
+ assert( pExpr->y.pTab!=0 );
+ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
}
if( op==TK_SELECT ){
assert( ExprUseXSelect(pExpr) );
@@ -103826,17 +105220,14 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
int op = p->op;
if( op==TK_REGISTER ) op = p->op2;
if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){
+ int j;
assert( ExprUseYTab(p) );
- if( p->y.pTab!=0 ){
- /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
- ** a TK_COLUMN but was previously evaluated and cached in a register */
- int j = p->iColumn;
- if( j>=0 ){
- const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
- pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
- }
- break;
+ assert( p->y.pTab!=0 );
+ if( (j = p->iColumn)>=0 ){
+ const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
+ pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
}
+ break;
}
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
@@ -104421,7 +105812,9 @@ static void heightOfSelect(const Select *pSelect, int *pnHeight){
*/
static void exprSetHeight(Expr *p){
int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
- if( p->pRight && p->pRight->nHeight>nHeight ) nHeight = p->pRight->nHeight;
+ if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){
+ nHeight = p->pRight->nHeight;
+ }
if( ExprUseXSelect(p) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else if( p->x.pList ){
@@ -104564,15 +105957,26 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
}else{
+ assert( ExprUseXList(pRoot) );
+ assert( pRoot->x.pSelect==0 );
if( pRight ){
pRoot->pRight = pRight;
pRoot->flags |= EP_Propagate & pRight->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ pRoot->nHeight = pRight->nHeight+1;
+ }else{
+ pRoot->nHeight = 1;
+#endif
}
if( pLeft ){
pRoot->pLeft = pLeft;
pRoot->flags |= EP_Propagate & pLeft->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ if( pLeft->nHeight>=pRoot->nHeight ){
+ pRoot->nHeight = pLeft->nHeight+1;
+ }
+#endif
}
- exprSetHeight(pRoot);
}
}
@@ -104858,6 +106262,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
*/
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p!=0 );
+ assert( db!=0 );
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
@@ -104889,12 +106294,8 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
#endif
}
}
- if( ExprHasProperty(p, EP_MemToken) ){
- assert( !ExprHasProperty(p, EP_IntValue) );
- sqlite3DbFree(db, p->u.zToken);
- }
if( !ExprHasProperty(p, EP_Static) ){
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
@@ -104925,8 +106326,9 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
** pExpr to the pParse->pConstExpr list with a register number of 0.
*/
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- pParse->pConstExpr =
- sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ sqlite3ParserAddCleanup(pParse,
+ (void(*)(sqlite3*,void*))sqlite3ExprDelete,
+ pExpr);
}
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
@@ -105000,7 +106402,6 @@ static int dupedExprStructSize(const Expr *p, int flags){
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_OuterON) );
- assert( !ExprHasProperty(p, EP_MemToken) );
assert( !ExprHasVVAProperty(p, EP_NoReduce) );
if( p->pLeft || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
@@ -105104,7 +106505,7 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
ExprClearVVAProperties(pNew);
@@ -105680,12 +107081,13 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
assert( pList->nExpr>0 );
+ assert( db!=0 );
do{
sqlite3ExprDelete(db, pItem->pExpr);
- sqlite3DbFree(db, pItem->zEName);
+ if( pItem->zEName ) sqlite3DbNNFreeNN(db, pItem->zEName);
pItem++;
}while( --i>0 );
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
@@ -106863,6 +108265,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
if( addrOnce ){
+ sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
sqlite3VdbeJumpHere(v, addrOnce);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
@@ -106976,7 +108379,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
pLimit = sqlite3PExpr(pParse, TK_NE,
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
- sqlite3ExprDelete(db, pSel->pLimit->pLeft);
+ sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft);
pSel->pLimit->pLeft = pLimit;
}else{
/* If there is no pre-existing limit add a limit of 1 */
@@ -107429,10 +108832,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
){
Column *pCol;
assert( v!=0 );
- if( pTab==0 ){
- sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
- return;
- }
+ assert( pTab!=0 );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -107490,7 +108890,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
assert( pParse->pVdbe!=0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
- VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
}
return iReg;
@@ -107559,7 +108959,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
- if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
+ if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
}
}
@@ -107682,6 +109082,53 @@ static int exprCodeInlineFunction(
return target;
}
+/*
+** Check to see if pExpr is one of the indexed expressions on pParse->pIdxExpr.
+** If it is, then resolve the expression by reading from the index and
+** return the register into which the value has been read. If pExpr is
+** not an indexed expression, then return negative.
+*/
+static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
+ Parse *pParse, /* The parsing context */
+ Expr *pExpr, /* The expression to potentially bypass */
+ int target /* Where to store the result of the expression */
+){
+ IndexedExpr *p;
+ Vdbe *v;
+ for(p=pParse->pIdxExpr; p; p=p->pIENext){
+ int iDataCur = p->iDataCur;
+ if( iDataCur<0 ) continue;
+ if( pParse->iSelfTab ){
+ if( p->iDataCur!=pParse->iSelfTab-1 ) continue;
+ iDataCur = -1;
+ }
+ if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ if( p->bMaybeNullRow ){
+ /* If the index is on a NULL row due to an outer join, then we
+ ** cannot extract the value from the index. The value must be
+ ** computed using the original expression. */
+ int addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ sqlite3VdbeGoto(v, 0);
+ p = pParse->pIdxExpr;
+ pParse->pIdxExpr = 0;
+ sqlite3ExprCode(pParse, pExpr, target);
+ pParse->pIdxExpr = p;
+ sqlite3VdbeJumpHere(v, addr+2);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ }
+ return target;
+ }
+ return -1; /* Not found */
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
@@ -107710,6 +109157,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
+ }else if( pParse->pIdxExpr!=0
+ && !ExprHasProperty(pExpr, EP_Leaf)
+ && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0
+ ){
+ return r1;
}else{
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
@@ -107730,7 +109182,7 @@ expr_code_doover:
pCol->iSorterColumn, target);
if( pCol->iColumn<0 ){
VdbeComment((v,"%s.rowid",pTab->zName));
- }else{
+ }else if( ALWAYS(pTab!=0) ){
VdbeComment((v,"%s.%s",
pTab->zName, pTab->aCol[pCol->iColumn].zCnName));
if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){
@@ -107755,11 +109207,8 @@ expr_code_doover:
int aff;
iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
- aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
- }else{
- aff = pExpr->affExpr;
- }
+ assert( pExpr->y.pTab!=0 );
+ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
if( aff>SQLITE_AFF_BLOB ){
static const char zAff[] = "B\000C\000D\000E";
assert( SQLITE_AFF_BLOB=='A' );
@@ -107821,12 +109270,10 @@ expr_code_doover:
}
}
assert( ExprUseYTab(pExpr) );
+ assert( pExpr->y.pTab!=0 );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
- if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
- sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
- }
return iReg;
}
case TK_INTEGER: {
@@ -108325,6 +109772,21 @@ expr_code_doover:
case TK_IF_NULL_ROW: {
int addrINR;
u8 okConstFactor = pParse->okConstFactor;
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ if( pAggInfo ){
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( !pAggInfo->directMode ){
+ inReg = pAggInfo->aCol[pExpr->iAgg].iMem;
+ break;
+ }
+ if( pExpr->pAggInfo->useSortingIdx ){
+ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
+ pAggInfo->aCol[pExpr->iAgg].iSorterColumn,
+ target);
+ inReg = target;
+ break;
+ }
+ }
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
/* Temporarily disable factoring of constant expressions, since
** even though expressions may appear to be constant, they are not
@@ -108666,7 +110128,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
if( inReg!=target+i ){
VdbeOp *pOp;
if( copyOp==OP_Copy
- && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
+ && (pOp=sqlite3VdbeGetLastOp(v))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
&& pOp->p5==0 /* The do-not-merge flag must be clear */
@@ -108865,6 +110327,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -109039,6 +110502,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -109192,7 +110656,13 @@ SQLITE_PRIVATE int sqlite3ExprCompare(
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
- return 2;
+ if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN
+ && pB->iTable<0 && pA->iTable==iTab
+ ){
+ /* fall through */
+ }else{
+ return 2;
+ }
}
assert( !ExprHasProperty(pA, EP_IntValue) );
assert( !ExprHasProperty(pB, EP_IntValue) );
@@ -109494,10 +110964,10 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
if( (pLeft->op==TK_COLUMN
- && pLeft->y.pTab!=0
+ && ALWAYS(pLeft->y.pTab!=0)
&& IsVirtual(pLeft->y.pTab))
|| (pRight->op==TK_COLUMN
- && pRight->y.pTab!=0
+ && ALWAYS(pRight->y.pTab!=0)
&& IsVirtual(pRight->y.pTab))
){
return WRC_Prune;
@@ -109702,6 +111172,7 @@ static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){
SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
Walker w;
struct RefSrcList x;
+ assert( pParse->db!=0 );
memset(&w, 0, sizeof(w));
memset(&x, 0, sizeof(x));
w.xExprCallback = exprRefToSrcList;
@@ -109718,7 +111189,7 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
}
#endif
- sqlite3DbFree(pParse->db, x.aiExclude);
+ if( x.aiExclude ) sqlite3DbNNFreeNN(pParse->db, x.aiExclude);
if( w.eCode & 0x01 ){
return 1;
}else if( w.eCode ){
@@ -109749,8 +111220,8 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
- assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
- if( pExpr->op==TK_AGG_COLUMN ){
+ if( pExpr->op!=TK_AGG_FUNCTION ){
+ assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_IF_NULL_ROW );
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
@@ -109760,6 +111231,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
}
}
}else{
+ assert( pExpr->op==TK_AGG_FUNCTION );
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
@@ -109830,10 +111302,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
assert( pNC->ncFlags & NC_UAggInfo );
switch( pExpr->op ){
+ case TK_IF_NULL_ROW:
case TK_AGG_COLUMN:
case TK_COLUMN: {
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
+ testcase( pExpr->op==TK_IF_NULL_ROW );
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
if( ALWAYS(pSrcList!=0) ){
@@ -109851,8 +111325,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
int k;
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
- if( pCol->iTable==pExpr->iTable &&
- pCol->iColumn==pExpr->iColumn ){
+ if( pCol->iTable==pExpr->iTable
+ && pCol->iColumn==pExpr->iColumn
+ && pExpr->op!=TK_IF_NULL_ROW
+ ){
break;
}
}
@@ -109867,15 +111343,17 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
pCol->pCExpr = pExpr;
- if( pAggInfo->pGroupBy ){
+ if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
struct ExprList_item *pTerm = pGB->a;
n = pGB->nExpr;
for(j=0; j<n; j++, pTerm++){
Expr *pE = pTerm->pExpr;
- if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
- pE->iColumn==pExpr->iColumn ){
+ if( pE->op==TK_COLUMN
+ && pE->iTable==pExpr->iTable
+ && pE->iColumn==pExpr->iColumn
+ ){
pCol->iSorterColumn = j;
break;
}
@@ -109892,7 +111370,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
*/
ExprSetVVAProperty(pExpr, EP_NoReduce);
pExpr->pAggInfo = pAggInfo;
- pExpr->op = TK_AGG_COLUMN;
+ if( pExpr->op==TK_COLUMN ){
+ pExpr->op = TK_AGG_COLUMN;
+ }
pExpr->iAgg = (i16)k;
break;
} /* endif pExpr->iTable==pItem->iCursor */
@@ -113312,6 +114792,7 @@ static void analyzeVdbeCommentIndexWithColumnName(
if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){
+ assert( pIdx->bHasExpr );
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
@@ -115314,6 +116795,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
+ int iDb, i;
assert( pParse->pToplevel==0 );
db = pParse->db;
@@ -115343,7 +116825,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pReturning = pParse->u1.pReturning;
int addrRewind;
- int i;
int reg;
if( pReturning->nRetCol ){
@@ -115380,76 +116861,69 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
- if( db->mallocFailed==0
- && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
- ){
- int iDb, i;
- assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
- sqlite3VdbeJumpHere(v, 0);
- assert( db->nDb>0 );
- iDb = 0;
- do{
- Schema *pSchema;
- if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
- sqlite3VdbeUsesBtree(v, iDb);
- pSchema = db->aDb[iDb].pSchema;
- sqlite3VdbeAddOp4Int(v,
- OP_Transaction, /* Opcode */
- iDb, /* P1 */
- DbMaskTest(pParse->writeMask,iDb), /* P2 */
- pSchema->schema_cookie, /* P3 */
- pSchema->iGeneration /* P4 */
- );
- if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
- VdbeComment((v,
- "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
- }while( ++iDb<db->nDb );
+ assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
+ sqlite3VdbeJumpHere(v, 0);
+ assert( db->nDb>0 );
+ iDb = 0;
+ do{
+ Schema *pSchema;
+ if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
+ sqlite3VdbeUsesBtree(v, iDb);
+ pSchema = db->aDb[iDb].pSchema;
+ sqlite3VdbeAddOp4Int(v,
+ OP_Transaction, /* Opcode */
+ iDb, /* P1 */
+ DbMaskTest(pParse->writeMask,iDb), /* P2 */
+ pSchema->schema_cookie, /* P3 */
+ pSchema->iGeneration /* P4 */
+ );
+ if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
+ VdbeComment((v,
+ "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
+ }while( ++iDb<db->nDb );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- for(i=0; i<pParse->nVtabLock; i++){
- char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
- sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
- }
- pParse->nVtabLock = 0;
+ for(i=0; i<pParse->nVtabLock; i++){
+ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
+ sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
+ }
+ pParse->nVtabLock = 0;
#endif
- /* Once all the cookies have been verified and transactions opened,
- ** obtain the required table-locks. This is a no-op unless the
- ** shared-cache feature is enabled.
- */
- codeTableLocks(pParse);
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
+ ** shared-cache feature is enabled.
+ */
+ codeTableLocks(pParse);
- /* Initialize any AUTOINCREMENT data structures required.
- */
- sqlite3AutoincrementBegin(pParse);
+ /* Initialize any AUTOINCREMENT data structures required.
+ */
+ sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
- */
- if( pParse->pConstExpr ){
- ExprList *pEL = pParse->pConstExpr;
- pParse->okConstFactor = 0;
- for(i=0; i<pEL->nExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- if( iReg>0 ){
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
- }
- }
+ /* Code constant expressions that where factored out of inner loops.
+ **
+ ** The pConstExpr list might also contain expressions that we simply
+ ** want to keep around until the Parse object is deleted. Such
+ ** expressions have iConstExprReg==0. Do not generate code for
+ ** those expressions, of course.
+ */
+ if( pParse->pConstExpr ){
+ ExprList *pEL = pParse->pConstExpr;
+ pParse->okConstFactor = 0;
+ for(i=0; i<pEL->nExpr; i++){
+ int iReg = pEL->a[i].u.iConstExprReg;
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
}
+ }
- if( pParse->bReturning ){
- Returning *pRet = pParse->u1.pReturning;
- if( pRet->nRetCol ){
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
- }
+ if( pParse->bReturning ){
+ Returning *pRet = pParse->u1.pReturning;
+ if( pRet->nRetCol ){
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
-
- /* Finally, jump back to the beginning of the executable code. */
- sqlite3VdbeGoto(v, 1);
}
+
+ /* Finally, jump back to the beginning of the executable code. */
+ sqlite3VdbeGoto(v, 1);
}
/* Get the VDBE program ready for execution
@@ -115634,7 +117108,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
- if( pParse->disableVtab==0 && db->init.busy==0 ){
+ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
pMod = sqlite3PragmaVtabRegister(db, zName);
@@ -115647,7 +117121,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
#endif
if( flags & LOCATE_NOERR ) return 0;
pParse->checkSchema = 1;
- }else if( IsVirtual(p) && pParse->disableVtab ){
+ }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){
p = 0;
}
@@ -115956,16 +117430,17 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
int i;
Column *pCol;
assert( pTable!=0 );
+ assert( db!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
sqlite3DbFree(db, pCol->zCnName);
}
- sqlite3DbFree(db, pTable->aCol);
+ sqlite3DbNNFreeNN(db, pTable->aCol);
if( IsOrdinaryTable(pTable) ){
sqlite3ExprListDelete(db, pTable->u.tab.pDfltList);
}
- if( db==0 || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
pTable->aCol = 0;
pTable->nCol = 0;
if( IsOrdinaryTable(pTable) ){
@@ -116002,7 +117477,8 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
** a Table object that was going to be marked ephemeral. So do not check
** that no lookaside memory is used in this case either. */
int nLookaside = 0;
- if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ assert( db!=0 );
+ if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
nLookaside = sqlite3LookasideUsed(db, 0);
}
#endif
@@ -116012,7 +117488,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
- if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
+ if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
@@ -116049,8 +117525,9 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
+ assert( db!=0 );
if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
+ if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
@@ -117454,7 +118931,8 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
/* Recompute the colNotIdxed field of the Index.
**
** colNotIdxed is a bitmask that has a 0 bit representing each indexed
-** columns that are within the first 63 columns of the table. The
+** columns that are within the first 63 columns of the table and a 1 for
+** all other bits (all columns that are not in the index). The
** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1.
**
@@ -117482,7 +118960,7 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
}
}
pIdx->colNotIdxed = ~m;
- assert( (pIdx->colNotIdxed>>63)==1 );
+ assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */
}
/*
@@ -118223,7 +119701,7 @@ create_view_fail:
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
-SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
@@ -118248,9 +119726,10 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
- ** already known.
+ ** already known. This routine is not called unless either the
+ ** table is virtual or nCol is zero.
*/
- if( pTable->nCol>0 ) return 0;
+ assert( pTable->nCol<=0 );
/* A negative nCol is a special marker meaning that we are currently
** trying to compute the column names. If we enter this routine with
@@ -118346,6 +119825,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
+SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+ assert( pTable!=0 );
+ if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0;
+ return viewGetColumnNames(pParse, pTable);
+}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
@@ -119211,7 +120695,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
- if( sqlite3FindTable(db, zName, 0)!=0 ){
+ if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
@@ -119364,6 +120848,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
+ pIndex->bHasExpr = 1;
}else{
j = pCExpr->iColumn;
assert( j<=0x7fff );
@@ -119375,6 +120860,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
+ pIndex->bHasExpr = 1;
}
}
pIndex->aiColumn[i] = (i16)j;
@@ -119864,12 +121350,13 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *
*/
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
+ assert( db!=0 );
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -120072,11 +121559,12 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
int i;
SrcItem *pItem;
+ assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase);
- sqlite3DbFree(db, pItem->zName);
- if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias);
+ if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
+ if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
+ if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
@@ -120087,7 +121575,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -121339,19 +122827,21 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
+ sqlite3 xdb;
+ memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
+ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(0, pTab);
+ sqlite3DeleteTable(&xdb, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
@@ -121450,18 +122940,42 @@ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
-** 2) It is a system table (i.e. sqlite_schema), this call is not
+** 2) A trigger is currently being coded and the table is a virtual table
+** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
+** the table is not SQLITE_VTAB_INNOCUOUS.
+**
+** 3) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
-** 3) The table is a shadow table, the database connection is in
+** 4) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlite3_prepare()
** is for a top-level SQL statement.
*/
+static int vtabIsReadOnly(Parse *pParse, Table *pTab){
+ if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
+ return 1;
+ }
+
+ /* Within triggers:
+ ** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
+ ** virtual tables
+ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
+ ** virtual tables if PRAGMA trusted_schema=ON.
+ */
+ if( pParse->pToplevel!=0
+ && pTab->u.vtab.p->eVtabRisk >
+ ((pParse->db->flags & SQLITE_TrustedSchema)!=0)
+ ){
+ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
+ pTab->zName);
+ }
+ return 0;
+}
static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlite3 *db;
if( IsVirtual(pTab) ){
- return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
+ return vtabIsReadOnly(pParse, pTab);
}
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db;
@@ -121473,9 +122987,11 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
}
/*
-** Check to make sure the given table is writable. If it is not
-** writable, generate an error message and return 1. If it is
-** writable return 0;
+** Check to make sure the given table is writable.
+**
+** If pTab is not writable -> generate an error message and return 1.
+** If pTab is writable but other errors have occurred -> return 1.
+** If pTab is writable and no prior errors -> return 0;
*/
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( tabIsReadOnly(pParse, pTab) ){
@@ -121836,9 +123352,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
- sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- sqlite3VdbeChangeP3(v, -1, memCnt ? memCnt : -1);
+ sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
}
}else
@@ -122038,7 +123555,7 @@ delete_from_cleanup:
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
#endif
- sqlite3DbFree(db, aToOpen);
+ if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen);
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -123121,7 +124638,7 @@ static int patternCompare(
** c but in the other case and search the input string for either
** c or cx.
*/
- if( c<=0x80 ){
+ if( c<0x80 ){
char zStop[3];
int bMatch;
if( noCase ){
@@ -123204,7 +124721,13 @@ static int patternCompare(
** non-zero if there is no match.
*/
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ if( zString==0 ){
+ return zGlobPattern!=0;
+ }else if( zGlobPattern==0 ){
+ return 1;
+ }else {
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ }
}
/*
@@ -123212,7 +124735,13 @@ SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
** a miss - like strcmp().
*/
SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ if( zStr==0 ){
+ return zPattern!=0;
+ }else if( zPattern==0 ){
+ return 1;
+ }else{
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ }
}
/*
@@ -126206,11 +127735,12 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( IsOrdinaryTable(pTab) );
+ assert( db!=0 );
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */
- if( !db || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
@@ -126340,6 +127870,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
aff = SQLITE_AFF_INTEGER;
}else{
assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
@@ -126354,6 +127885,28 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
}
/*
+** Compute an affinity string for a table. Space is obtained
+** from sqlite3DbMalloc(). The caller is responsible for freeing
+** the space when done.
+*/
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
+ char *zColAff;
+ zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
+ if( zColAff ){
+ int i, j;
+ for(i=j=0; i<pTab->nCol; i++){
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
+ }
+ }
+ do{
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
+ }
+ return zColAff;
+}
+
+/*
** Make changes to the evolving bytecode to do affinity transformations
** of values that are about to be gathered into a row for table pTab.
**
@@ -126394,7 +127947,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
** Apply the type checking to that array of registers.
*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i, j;
+ int i;
char *zColAff;
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
@@ -126403,7 +127956,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
- pPrev = sqlite3VdbeGetOp(v, -1);
+ pPrev = sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
@@ -126417,22 +127970,11 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
}
zColAff = pTab->zColAff;
if( zColAff==0 ){
- sqlite3 *db = sqlite3VdbeDb(v);
- zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
+ zColAff = sqlite3TableAffinityStr(0, pTab);
if( !zColAff ){
- sqlite3OomFault(db);
+ sqlite3OomFault(sqlite3VdbeDb(v));
return;
}
-
- for(i=j=0; i<pTab->nCol; i++){
- assert( pTab->aCol[i].affinity!=0 || sqlite3VdbeParser(v)->nErr>0 );
- if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
- zColAff[j++] = pTab->aCol[i].affinity;
- }
- }
- do{
- zColAff[j--] = 0;
- }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
@@ -126441,7 +127983,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
- assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord
+ assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlite3VdbeDb(v)->mallocFailed );
sqlite3VdbeChangeP4(v, -1, zColAff, i);
}
@@ -126527,7 +128069,7 @@ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
*/
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
- pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Affinity ){
/* Change the OP_Affinity argument to '@' (NONE) for all stored
** columns. '@' is the no-op affinity and those columns have not
@@ -127433,7 +128975,12 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
- sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
+ Expr *pX = pList->a[k].pExpr;
+ int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
+ if( y!=iRegStore ){
+ sqlite3VdbeAddOp2(v,
+ ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
+ }
}
}
@@ -127570,7 +129117,9 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
- sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ if( db->flags & SQLITE_ForeignKeys ){
+ sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ }
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a
@@ -127654,7 +129203,7 @@ insert_cleanup:
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
- sqlite3DbFree(db, aRegIdx);
+ if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -129881,9 +131430,9 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
- char *(*create_filename)(const char*,const char*,const char*,
+ const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
- void (*free_filename)(char*);
+ void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
@@ -129907,6 +131456,8 @@ struct sqlite3_api_routines {
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
+ /* Version 3.40.0 and later */
+ int (*value_encoding)(sqlite3_value*);
};
/*
@@ -130231,6 +131782,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
+/* Version 3.40.0 and later */
+#define sqlite3_value_encoding sqlite3_api->value_encoding
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -130743,7 +132296,9 @@ static const sqlite3_api_routines sqlite3Apis = {
0,
0,
#endif
- sqlite3_db_name
+ sqlite3_db_name,
+ /* Version 3.40.0 and later */
+ sqlite3_value_type
};
/* True if x is the directory separator character
@@ -133543,15 +135098,24 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
- Index *pPrior = 0;
+ Index *pPrior = 0; /* Previous index */
int loopTop;
int iDataCur, iIdxCur;
int r1 = -1;
- int bStrict;
+ int bStrict; /* True for a STRICT table */
+ int r2; /* Previous key for WITHOUT ROWID tables */
+ int mxCol; /* Maximum non-virtual column number */
if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
- pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
+ if( isQuick || HasRowid(pTab) ){
+ pPk = 0;
+ r2 = 0;
+ }else{
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
+ }
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
@@ -133565,52 +135129,157 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+
+ /* Fetch the right-most column from the table. This will cause
+ ** the entire record header to be parsed and sanity checked. It
+ ** will also prepopulate the cursor column cache that is used
+ ** by the OP_IsType code, so it is a required step.
+ */
+ mxCol = pTab->nCol-1;
+ while( mxCol>=0
+ && ((pTab->aCol[mxCol].colFlags & COLFLAG_VIRTUAL)!=0
+ || pTab->iPKey==mxCol) ) mxCol--;
+ if( mxCol>=0 ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, mxCol, 3);
+ sqlite3VdbeTypeofColumn(v, 3);
+ }
+
if( !isQuick ){
- /* Sanity check on record header decoding */
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
- VdbeComment((v, "(right-most column)"));
+ if( pPk ){
+ /* Verify WITHOUT ROWID keys are in ascending order */
+ int a1;
+ char *zErr;
+ a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db,
+ "row not in PRIMARY KEY order for %s",
+ pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, a1);
+ sqlite3VdbeJumpHere(v, a1+1);
+ for(j=0; j<pPk->nKeyCol; j++){
+ sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
+ }
+ }
}
- /* Verify that all NOT NULL columns really are NOT NULL. At the
- ** same time verify the type of the content of STRICT tables */
+ /* Verify datatypes for all columns:
+ **
+ ** (1) NOT NULL columns may not contain a NULL
+ ** (2) Datatype must be exact for non-ANY columns in STRICT tables
+ ** (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB.
+ ** (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be losslessly converted to numeric.
+ */
bStrict = (pTab->tabFlags & TF_Strict)!=0;
for(j=0; j<pTab->nCol; j++){
char *zErr;
- Column *pCol = pTab->aCol + j;
- int doError, jmp2;
+ Column *pCol = pTab->aCol + j; /* The column to be checked */
+ int labelError; /* Jump here to report an error */
+ int labelOk; /* Jump here if all looks ok */
+ int p1, p3, p4; /* Operands to the OP_IsType opcode */
+ int doTypeCheck; /* Check datatypes (besides NOT NULL) */
+
if( j==pTab->iPKey ) continue;
- if( pCol->notNull==0 && !bStrict ) continue;
- doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0;
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
- if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ if( bStrict ){
+ doTypeCheck = pCol->eCType>COLTYPE_ANY;
+ }else{
+ doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
+ }
+ if( pCol->notNull==0 && !doTypeCheck ) continue;
+
+ /* Compute the operands that will be needed for OP_IsType */
+ p4 = SQLITE_NULL;
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ p1 = -1;
+ p3 = 3;
+ }else{
+ if( pCol->iDflt ){
+ sqlite3_value *pDfltValue = 0;
+ sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db),
+ pCol->affinity, &pDfltValue);
+ if( pDfltValue ){
+ p4 = sqlite3_value_type(pDfltValue);
+ sqlite3ValueFree(pDfltValue);
+ }
+ }
+ p1 = iDataCur;
+ if( !HasRowid(pTab) ){
+ testcase( j!=sqlite3TableColumnToStorage(pTab, j) );
+ p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j);
+ }else{
+ p3 = sqlite3TableColumnToStorage(pTab,j);
+ testcase( p3!=j);
+ }
}
+
+ labelError = sqlite3VdbeMakeLabel(pParse);
+ labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
- jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
+ /* (1) NOT NULL columns may not contain a NULL */
+ int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x0f);
+ VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- if( bStrict && pCol->eCType!=COLTYPE_ANY ){
- sqlite3VdbeGoto(v, doError);
+ if( doTypeCheck ){
+ sqlite3VdbeGoto(v, labelError);
+ sqlite3VdbeJumpHere(v, jmp2);
}else{
- integrityCheckResultRow(v);
+ /* VDBE byte code will fall thru */
}
- sqlite3VdbeJumpHere(v, jmp2);
}
- if( (pTab->tabFlags & TF_Strict)!=0
- && pCol->eCType!=COLTYPE_ANY
- ){
- jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0,
- sqlite3StdTypeMap[pCol->eCType-1]);
+ if( bStrict && doTypeCheck ){
+ /* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
+ static unsigned char aStdTypeMask[] = {
+ 0x1f, /* ANY */
+ 0x18, /* BLOB */
+ 0x11, /* INT */
+ 0x11, /* INTEGER */
+ 0x13, /* REAL */
+ 0x14 /* TEXT */
+ };
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
+ sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
sqlite3StdType[pCol->eCType-1],
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- sqlite3VdbeResolveLabel(v, doError);
- integrityCheckResultRow(v);
- sqlite3VdbeJumpHere(v, jmp2);
+ }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
+ /* (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB. */
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
+ /* (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be converted to numeric. */
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
+ VdbeCoverage(v);
+ if( p1>=0 ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ }
+ sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
+ sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db, "TEXT value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}
+ sqlite3VdbeResolveLabel(v, labelError);
+ integrityCheckResultRow(v);
+ sqlite3VdbeResolveLabel(v, labelOk);
}
/* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
@@ -133698,6 +135367,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
+ if( pPk ){
+ sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
+ }
}
}
}
@@ -133848,6 +135520,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight);
aOp[1].p5 = 1;
+ if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){
+ /* Do not allow the use of PRAGMA schema_version=VALUE in defensive
+ ** mode. Change the OP_SetCookie opcode into a no-op. */
+ aOp[1].opcode = OP_Noop;
+ }
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -135096,15 +136773,15 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
- sqlite3DbFree(db, pParse->aTableLock);
+ if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock);
#endif
while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext;
pCleanup->xCleanup(db, pCleanup->pPtr);
- sqlite3DbFreeNN(db, pCleanup);
+ sqlite3DbNNFreeNN(db, pCleanup);
}
- sqlite3DbFree(db, pParse->aLabel);
+ if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel);
if( pParse->pConstExpr ){
sqlite3ExprListDelete(db, pParse->pConstExpr);
}
@@ -135227,7 +136904,7 @@ static int sqlite3Prepare(
sParse.disableLookaside++;
DisableLookaside;
}
- sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
+ sParse.prepFlags = prepFlags & 0xff;
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
@@ -135268,7 +136945,9 @@ static int sqlite3Prepare(
}
}
- sqlite3VtabUnlockList(db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( db->pDisconnect ) sqlite3VtabUnlockList(db);
+#endif
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
@@ -135663,6 +137342,7 @@ struct SortCtx {
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
+ assert( db!=0 );
while( p ){
Select *pPrior = p->pPrior;
sqlite3ExprListDelete(db, p->pEList);
@@ -135682,7 +137362,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3WindowUnlinkFromSelect(p->pWin);
}
#endif
- if( bFree ) sqlite3DbFreeNN(db, p);
+ if( bFree ) sqlite3DbNNFreeNN(db, p);
p = pPrior;
bFree = 1;
}
@@ -136873,6 +138553,9 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
+ if( pDest->zAffSdst ){
+ sqlite3VdbeChangeP4(v, -1, pDest->zAffSdst, nResultCol);
+ }
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -137088,9 +138771,10 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
*/
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
+ assert( p->db!=0 );
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
+ if( p->nRef==0 ) sqlite3DbNNFreeNN(p->db, p);
}
}
@@ -137410,9 +139094,6 @@ static void generateSortTail(
** Return a pointer to a string containing the 'declaration type' of the
** expression pExpr. The string may be treated as static by the caller.
**
-** Also try to estimate the size of the returned value and return that
-** result in *pEstWidth.
-**
** The declaration type is the exact datatype definition extracted from the
** original CREATE TABLE statement if the expression is a column. The
** declaration type for a ROWID field is INTEGER. Exactly when an expression
@@ -139278,8 +140959,8 @@ static int multiSelectOrderBy(
*/
sqlite3VdbeResolveLabel(v, labelEnd);
- /* Reassemble the compound query so that it will be freed correctly
- ** by the calling function */
+ /* Make arrangements to free the 2nd and subsequent arms of the compound
+ ** after the parse has finished */
if( pSplit->pPrior ){
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
@@ -139312,7 +140993,7 @@ static int multiSelectOrderBy(
** the left operands of a RIGHT JOIN. In either case, we need to potentially
** bypass the substituted expression with OP_IfNullRow.
**
-** Suppose the original expression integer constant. Even though the table
+** Suppose the original expression is an integer constant. Even though the table
** has the nullRow flag set, because the expression is an integer constant,
** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode
** that checks to see if the nullRow flag is set on the table. If the nullRow
@@ -139338,6 +141019,7 @@ typedef struct SubstContext {
int iNewTable; /* New table number */
int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
ExprList *pEList; /* Replacement expressions */
+ ExprList *pCList; /* Collation sequences for replacement expr */
} SubstContext;
/* Forward Declarations */
@@ -139379,9 +141061,10 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
+ int iColumn = pExpr->iColumn;
+ Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
Expr ifNullRow;
- assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
+ assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
if( sqlite3ExprIsVector(pCopy) ){
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
@@ -139392,6 +141075,7 @@ static Expr *substExpr(
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
+ ifNullRow.iColumn = -99;
ifNullRow.flags = EP_IfNullRow;
pCopy = &ifNullRow;
}
@@ -139418,11 +141102,16 @@ static Expr *substExpr(
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
- if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
- CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
- pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
- (pColl ? pColl->zName : "BINARY")
+ {
+ CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
+ pSubst->pCList->a[iColumn].pExpr
);
+ if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
+ pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ (pColl ? pColl->zName : "BINARY")
+ );
+ }
}
ExprClearProperty(pExpr, EP_Collate);
}
@@ -139615,6 +141304,18 @@ static void renumberCursors(
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+/*
+** If pSel is not part of a compound SELECT, return a pointer to its
+** expression list. Otherwise, return a pointer to the expression list
+** of the leftmost SELECT in the compound.
+*/
+static ExprList *findLeftmostExprlist(Select *pSel){
+ while( pSel->pPrior ){
+ pSel = pSel->pPrior;
+ }
+ return pSel->pEList;
+}
+
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
@@ -139659,7 +141360,8 @@ static void renumberCursors(
** (3a) the subquery may not be a join and
** (3b) the FROM clause of the subquery may not contain a virtual
** table and
-** (3c) the outer query may not be an aggregate.
+** (**) Was: "The outer query may not have a GROUP BY." This case
+** is now managed correctly
** (3d) the outer query may not be DISTINCT.
** See also (26) for restrictions on RIGHT JOIN.
**
@@ -139716,6 +141418,8 @@ static void renumberCursors(
** (17g) either the subquery is the first element of the outer
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
+** (17h) The corresponding result set expressions in all arms of the
+** compound must have the same affinity.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -139767,19 +141471,13 @@ static void renumberCursors(
** See also (3) for restrictions on LEFT JOIN.
**
** (27) The subquery may not contain a FULL or RIGHT JOIN unless it
-** is the first element of the parent query. This must be the
-** the case if:
-** (27a) the subquery is not compound query, and
+** is the first element of the parent query. Two subcases:
+** (27a) the subquery is not a compound query.
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
** (28) The subquery is not a MATERIALIZED CTE.
**
-** (29) Either the subquery is not the right-hand operand of a join with an
-** ON or USING clause nor the right-hand operand of a NATURAL JOIN, or
-** the right-most table within the FROM clause of the subquery
-** is not part of an outer join.
-**
**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
@@ -139871,16 +141569,10 @@ static int flattenSubquery(
**
** which is not at all the same thing.
**
- ** If the subquery is the right operand of a LEFT JOIN, then the outer
- ** query cannot be an aggregate. (3c) This is an artifact of the way
- ** aggregates are processed - there is no mechanism to determine if
- ** the LEFT JOIN table should be all-NULL.
- **
** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || isAgg /* (3c) */
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
@@ -139889,15 +141581,6 @@ static int flattenSubquery(
}
isOuterJoin = 1;
}
-#ifdef SQLITE_EXTRA_IFNULLROW
- else if( iFrom>0 && !isAgg ){
- /* Setting isOuterJoin to -1 causes OP_IfNullRow opcodes to be generated for
- ** every reference to any result column from subquery in a join, even
- ** though they are not necessary. This will stress-test the OP_IfNullRow
- ** opcode. */
- isOuterJoin = -1;
- }
-#endif
assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
@@ -139907,41 +141590,13 @@ static int flattenSubquery(
return 0; /* (28) */
}
- /* Restriction (29):
- **
- ** We do not want two constraints on the same term of the flattened
- ** query where one constraint has EP_InnerON and the other is EP_OuterON.
- ** To prevent this, one or the other of the following conditions must be
- ** false:
- **
- ** (29a) The right-most entry in the FROM clause of the subquery
- ** must not be part of an outer join.
- **
- ** (29b) The subquery itself must not be the right operand of a
- ** NATURAL join or a join that as an ON or USING clause.
- **
- ** These conditions are sufficient to keep an EP_OuterON from being
- ** flattened into an EP_InnerON. Restrictions (3a) and (27a) prevent
- ** an EP_InnerON from being flattened into an EP_OuterON.
- */
- if( pSubSrc->nSrc>=2
- && (pSubSrc->a[pSubSrc->nSrc-1].fg.jointype & JT_OUTER)!=0
- ){
- if( (pSubitem->fg.jointype & JT_NATURAL)!=0
- || pSubitem->fg.isUsing
- || NEVER(pSubitem->u3.pOn!=0) /* ON clause already shifted into WHERE */
- || pSubitem->fg.isOn
- ){
- return 0;
- }
- }
-
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
+ int ii;
if( pSub->pOrderBy ){
return 0; /* Restriction (20) */
}
@@ -139974,7 +141629,6 @@ static int flattenSubquery(
/* Restriction (18). */
if( p->pOrderBy ){
- int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
}
@@ -139983,6 +141637,21 @@ static int flattenSubquery(
/* Restriction (23) */
if( (p->selFlags & SF_Recursive) ) return 0;
+ /* Restriction (17h) */
+ for(ii=0; ii<pSub->pEList->nExpr; ii++){
+ char aff;
+ assert( pSub->pEList->a[ii].pExpr!=0 );
+ aff = sqlite3ExprAffinity(pSub->pEList->a[ii].pExpr);
+ for(pSub1=pSub->pPrior; pSub1; pSub1=pSub1->pPrior){
+ assert( pSub1->pEList!=0 );
+ assert( pSub1->pEList->nExpr>ii );
+ assert( pSub1->pEList->a[ii].pExpr!=0 );
+ if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){
+ return 0;
+ }
+ }
+ }
+
if( pSrc->nSrc>1 ){
if( pParse->nSelect>500 ) return 0;
if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
@@ -140216,6 +141885,7 @@ static int flattenSubquery(
x.iNewTable = iNewParent;
x.isOuterJoin = isOuterJoin;
x.pEList = pSub->pEList;
+ x.pCList = findLeftmostExprlist(pSub);
substSelect(&x, pParent, 0);
}
@@ -140235,7 +141905,7 @@ static int flattenSubquery(
pSub->pLimit = 0;
}
- /* Recompute the SrcList_item.colUsed masks for the flattened
+ /* Recompute the SrcItem.colUsed masks for the flattened
** tables. */
for(i=0; i<nSubSrc; i++){
recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
@@ -140625,6 +142295,13 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** be materialized. (This restriction is implemented in the calling
** routine.)
**
+** (8) The subquery may not be a compound that uses UNION, INTERSECT,
+** or EXCEPT. (We could, perhaps, relax this restriction to allow
+** this case if none of the comparisons operators between left and
+** right arms of the compound use a collation other than BINARY.
+** But it is a lot of work to check that case for an obscure and
+** minor optimization, so we omit it for now.)
+**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
@@ -140644,6 +142321,10 @@ static int pushDownWhereTerms(
if( pSubq->pPrior ){
Select *pSel;
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ u8 op = pSel->op;
+ assert( op==TK_ALL || op==TK_SELECT
+ || op==TK_UNION || op==TK_INTERSECT || op==TK_EXCEPT );
+ if( op!=TK_ALL && op!=TK_SELECT ) return 0; /* restriction (8) */
if( pSel->pWin ) return 0; /* restriction (6b) */
}
}else{
@@ -140698,6 +142379,7 @@ static int pushDownWhereTerms(
x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
+ x.pCList = findLeftmostExprlist(pSubq);
pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
@@ -141222,9 +142904,9 @@ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){
#endif
/*
-** The SrcList_item structure passed as the second argument represents a
+** The SrcItem structure passed as the second argument represents a
** sub-query in the FROM clause of a SELECT statement. This function
-** allocates and populates the SrcList_item.pTab object. If successful,
+** allocates and populates the SrcItem.pTab object. If successful,
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
** SQLITE_NOMEM.
*/
@@ -142057,7 +143739,7 @@ static void havingToWhere(Parse *pParse, Select *p){
/*
** Check to see if the pThis entry of pTabList is a self-join of a prior view.
-** If it is, then return the SrcList_item for the prior view. If it is not,
+** If it is, then return the SrcItem for the prior view. If it is not,
** then return 0.
*/
static SrcItem *isSelfJoinView(
@@ -142675,7 +144357,10 @@ SQLITE_PRIVATE int sqlite3Select(
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem));
+ dest.zAffSdst = sqlite3TableAffinityStr(db, pItem->pTab);
sqlite3Select(pParse, pSub, &dest);
+ sqlite3DbFree(db, dest.zAffSdst);
+ dest.zAffSdst = 0;
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
@@ -142795,7 +144480,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( (p->selFlags & SF_FixedLimit)==0 ){
p->nSelectRow = 320; /* 4 billion rows */
}
- computeLimitRegisters(pParse, p, iEnd);
+ if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
sSort.sortFlags |= SORTFLAG_UseSorter;
@@ -143017,8 +144702,13 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
}
for(ii=0; ii<pAggInfo->nColumn; ii++){
- sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
- ii, pAggInfo->aCol[ii].iMem);
+ struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
+ sqlite3DebugPrintf(
+ "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
+ " iSorterColumn=%d\n",
+ ii, pCol->pTab ? pCol->pTab->zName : "NULL",
+ pCol->iTable, pCol->iColumn, pCol->iMem,
+ pCol->iSorterColumn);
sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
}
for(ii=0; ii<pAggInfo->nFunc; ii++){
@@ -143096,7 +144786,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
- 0, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
+ p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
| (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
);
if( pWInfo==0 ){
@@ -143139,15 +144829,15 @@ SQLITE_PRIVATE int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
+ pAggInfo->directMode = 1;
for(i=0; i<pAggInfo->nColumn; i++){
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
- int r1 = j + regBase;
- sqlite3ExprCodeGetColumnOfTable(v,
- pCol->pTab, pCol->iTable, pCol->iColumn, r1);
+ sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase);
j++;
}
}
+ pAggInfo->directMode = 0;
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
@@ -143395,7 +145085,7 @@ SQLITE_PRIVATE int sqlite3Select(
SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
- pDistinct, 0, minMaxFlag|distFlag, 0);
+ pDistinct, p, minMaxFlag|distFlag, 0);
if( pWInfo==0 ){
goto select_end;
}
@@ -144039,6 +145729,23 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
Vdbe *v;
char *z;
+ /* If this is a new CREATE TABLE statement, and if shadow tables
+ ** are read-only, and the trigger makes a change to a shadow table,
+ ** then raise an error - do not allow the trigger to be created. */
+ if( sqlite3ReadOnlyShadowTables(db) ){
+ TriggerStep *pStep;
+ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget!=0
+ && sqlite3ShadowTableName(db, pStep->zTarget)
+ ){
+ sqlite3ErrorMsg(pParse,
+ "trigger \"%s\" may not write to shadow table \"%s\"",
+ pTrig->zName, pStep->zTarget);
+ goto triggerfinish_cleanup;
+ }
+ }
+ }
+
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
@@ -144862,7 +146569,7 @@ static TriggerPrg *codeRowTrigger(
sSubParse.zAuthContext = pTrigger->zName;
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
- sSubParse.disableVtab = pParse->disableVtab;
+ sSubParse.prepFlags = pParse->prepFlags;
v = sqlite3GetVdbe(&sSubParse);
if( v ){
@@ -145208,11 +146915,14 @@ static void updateVirtualTable(
** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
+ Column *pCol;
assert( pTab!=0 );
- if( !IsView(pTab) ){
+ assert( pTab->nCol>i );
+ pCol = &pTab->aCol[i];
+ if( pCol->iDflt ){
sqlite3_value *pValue = 0;
u8 enc = ENC(sqlite3VdbeDb(v));
- Column *pCol = &pTab->aCol[i];
+ assert( !IsView(pTab) );
VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName));
assert( i<pTab->nCol );
sqlite3ValueFromExpr(sqlite3VdbeDb(v),
@@ -145223,7 +146933,7 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
+ if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
@@ -146663,6 +148373,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
+ assert( pIdx->bHasExpr );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
@@ -146976,6 +148687,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
+ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -147047,12 +148759,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
+
+ /* For a VACUUM INTO, the pager-flags are set to the same values as
+ ** they are for the database being vacuumed, except that PAGER_CACHESPILL
+ ** is always set. */
+ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
}
nRes = sqlite3BtreeGetRequestedReserve(pMain);
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
- sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
+ sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
@@ -147565,7 +149282,8 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
assert( IsVirtual(p) );
- if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
+ assert( db!=0 );
+ if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
if( p->u.vtab.azArg ){
int i;
for(i=0; i<p->u.vtab.nArg; i++){
@@ -148365,7 +150083,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
if( pExpr->op!=TK_COLUMN ) return pDef;
assert( ExprUseYTab(pExpr) );
pTab = pExpr->y.pTab;
- if( pTab==0 ) return pDef;
+ if( NEVER(pTab==0) ) return pDef;
if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
@@ -148972,7 +150690,7 @@ struct WhereAndInfo {
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
**
** The VDBE cursor numbers are small integers contained in
-** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
+** SrcItem.iCursor and Expr.iTable fields. For any given WHERE
** clause, the cursor numbers might not begin with 0 and they might
** contain gaps in the numbering sequence. But we want to make maximum
** use of the bits in our bitmasks. This structure provides a mapping
@@ -149044,20 +150762,6 @@ struct WhereLoopBuilder {
#endif
/*
-** Each instance of this object records a change to a single node
-** in an expression tree to cause that node to point to a column
-** of an index rather than an expression or a virtual column. All
-** such transformations need to be undone at the end of WHERE clause
-** processing.
-*/
-typedef struct WhereExprMod WhereExprMod;
-struct WhereExprMod {
- WhereExprMod *pNext; /* Next translation on a list of them all */
- Expr *pExpr; /* The Expr node that was transformed */
- Expr orig; /* Original value of the Expr node */
-};
-
-/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop. An instance of
@@ -149072,10 +150776,10 @@ struct WhereInfo {
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
+#if WHERETRACE_ENABLED
Expr *pWhere; /* The complete WHERE clause */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */
#endif
+ Select *pSelect; /* The entire SELECT statement containing WHERE */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
@@ -149094,7 +150798,6 @@ struct WhereInfo {
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
- WhereExprMod *pExprMods; /* Expression modifications */
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
@@ -149242,6 +150945,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
+#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -150121,7 +151825,7 @@ static void whereLikeOptimizationStringFixup(
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
- pOp = sqlite3VdbeGetOp(v, -1);
+ pOp = sqlite3VdbeGetLastOp(v);
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
@@ -150445,143 +152149,6 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
}
}
-/* An instance of the IdxExprTrans object carries information about a
-** mapping from an expression on table columns into a column in an index
-** down through the Walker.
-*/
-typedef struct IdxExprTrans {
- Expr *pIdxExpr; /* The index expression */
- int iTabCur; /* The cursor of the corresponding table */
- int iIdxCur; /* The cursor for the index */
- int iIdxCol; /* The column for the index */
- int iTabCol; /* The column for the table */
- WhereInfo *pWInfo; /* Complete WHERE clause information */
- sqlite3 *db; /* Database connection (for malloc()) */
-} IdxExprTrans;
-
-/*
-** Preserve pExpr on the WhereETrans list of the WhereInfo.
-*/
-static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
- WhereExprMod *pNew;
- pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
- if( pNew==0 ) return;
- pNew->pNext = pTrans->pWInfo->pExprMods;
- pTrans->pWInfo->pExprMods = pNew;
- pNew->pExpr = pExpr;
- memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
-}
-
-/* The walker node callback used to transform matching expressions into
-** a reference to an index column for an index on an expression.
-**
-** If pExpr matches, then transform it into a reference to the index column
-** that contains the value of pExpr.
-*/
-static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
- pExpr = sqlite3ExprSkipCollate(pExpr);
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlite3ExprAffinity(pExpr);
- pExpr->op = TK_COLUMN;
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- testcase( ExprHasProperty(pExpr, EP_Unlikely) );
- ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn);
- pExpr->y.pTab = 0;
- return WRC_Prune;
- }else{
- return WRC_Continue;
- }
-}
-
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
-/* A walker node callback that translates a column reference to a table
-** into a corresponding column reference of an index.
-*/
-static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
- if( pExpr->op==TK_COLUMN ){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
- assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 );
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- pExpr->y.pTab = 0;
- }
- }
- return WRC_Continue;
-}
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
-
-/*
-** For an indexes on expression X, locate every instance of expression X
-** in pExpr and change that subexpression into a reference to the appropriate
-** column of the index.
-**
-** 2019-10-24: Updated to also translate references to a VIRTUAL column in
-** the table into references to the corresponding (stored) column of the
-** index.
-*/
-static void whereIndexExprTrans(
- Index *pIdx, /* The Index */
- int iTabCur, /* Cursor of the table that is being indexed */
- int iIdxCur, /* Cursor of the index itself */
- WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
-){
- int iIdxCol; /* Column number of the index */
- ExprList *aColExpr; /* Expressions that are indexed */
- Table *pTab;
- Walker w;
- IdxExprTrans x;
- aColExpr = pIdx->aColExpr;
- if( aColExpr==0 && !pIdx->bHasVCol ){
- /* The index does not reference any expressions or virtual columns
- ** so no translations are needed. */
- return;
- }
- pTab = pIdx->pTable;
- memset(&w, 0, sizeof(w));
- w.u.pIdxTrans = &x;
- x.iTabCur = iTabCur;
- x.iIdxCur = iIdxCur;
- x.pWInfo = pWInfo;
- x.db = pWInfo->pParse->db;
- for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
- i16 iRef = pIdx->aiColumn[iIdxCol];
- if( iRef==XN_EXPR ){
- assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 );
- x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
- if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
- w.xExprCallback = whereIndexExprTransNode;
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- }else if( iRef>=0
- && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
- && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0
- || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]),
- sqlite3StrBINARY)==0)
- ){
- /* Check to see if there are direct references to generated columns
- ** that are contained in the index. Pulling the generated column
- ** out of the index is an optimization only - the main table is always
- ** available if the index cannot be used. To avoid unnecessary
- ** complication, omit this optimization if the collating sequence for
- ** the column is non-standard */
- x.iTabCol = iRef;
- w.xExprCallback = whereIndexExprTransColumn;
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
- }else{
- continue;
- }
- x.iIdxCol = iIdxCol;
- sqlite3WalkExpr(&w, pWInfo->pWhere);
- sqlite3WalkExprList(&w, pWInfo->pOrderBy);
- sqlite3WalkExprList(&w, pWInfo->pResultSet);
- }
-}
-
/*
** The pTruth expression is always true because it is the WHERE clause
** a partial index that is driving a query loop. Look through all of the
@@ -150650,6 +152217,8 @@ static SQLITE_NOINLINE void filterPullDown(
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
+ VdbeCoverage(pParse->pVdbe);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
@@ -150801,9 +152370,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
- assert( pWInfo->pLimit!=0 );
- assert( pWInfo->pLimit->iOffset>0 );
- sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pLimit->iOffset);
+ assert( pWInfo->pSelect!=0 );
+ assert( pWInfo->pSelect->iOffset>0 );
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
VdbeComment((v,"Zero OFFSET counter"));
}
}
@@ -150911,6 +152480,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
+ VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
@@ -151262,6 +152833,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
+ if( pRangeStart ){
+ sqlite3VdbeChangeP5(v, 1);
+ sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
+ addrSeekScan = 0;
+ }
VdbeCoverage(v);
}
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -151337,8 +152913,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
nConstraint++;
}
- sqlite3DbFree(db, zStartAff);
- sqlite3DbFree(db, zEndAff);
+ if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff);
+ if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -151400,27 +152976,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
if( pLevel->iLeftJoin==0 ){
- /* If pIdx is an index on one or more expressions, then look through
- ** all the expressions in pWInfo and try to transform matching expressions
- ** into reference to index columns. Also attempt to translate references
- ** to virtual columns in the table into references to (stored) columns
- ** of the index.
- **
- ** Do not do this for the RHS of a LEFT JOIN. This is because the
- ** expression may be evaluated after OP_NullRow has been executed on
- ** the cursor. In this case it is important to do the full evaluation,
- ** as the result of the expression may not be NULL, even if all table
- ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
- **
- ** Also, do not do this when processing one index an a multi-index
- ** OR clause, since the transformation will become invalid once we
- ** move forward to the next index.
- ** https://sqlite.org/src/info/4e8e4857d32d401f
- */
- if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){
- whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
- }
-
/* If a partial index is driving the loop, try to eliminate WHERE clause
** terms from the query that must be true due to the WHERE clause of
** the partial index.
@@ -151533,7 +153088,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlite3StackAllocRaw(db,
+ pOrTab = sqlite3DbMallocRawNN(db,
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
@@ -151786,7 +153341,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
+ if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -152414,7 +153969,7 @@ static int isLikeOrGlob(
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| (ALWAYS( ExprUseYTab(pLeft) )
- && pLeft->y.pTab
+ && ALWAYS(pLeft->y.pTab)
&& IsVirtual(pLeft->y.pTab)) /* Might be numeric */
){
int isNum;
@@ -152531,8 +154086,7 @@ static int isAuxiliaryVtabOperator(
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
- assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
for(i=0; i<ArraySize(aOp); i++){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
@@ -152557,7 +154111,7 @@ static int isAuxiliaryVtabOperator(
*/
pCol = pList->a[0].pExpr;
assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
@@ -152582,13 +154136,12 @@ static int isAuxiliaryVtabOperator(
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
- assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
- testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
+ assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) );
if( ExprIsVtab(pLeft) ){
res++;
}
- assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
- testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
+ assert( pRight==0 || pRight->op!=TK_COLUMN
+ || (ExprUseYTab(pRight) && pRight->y.pTab!=0) );
if( pRight && ExprIsVtab(pRight) ){
res++;
SWAP(Expr*, pLeft, pRight);
@@ -153137,6 +154690,7 @@ static SQLITE_NOINLINE int exprMightBeIndexed2(
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
+ assert( pIdx->bHasExpr );
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
@@ -153750,9 +155304,9 @@ static void whereAddLimitExpr(
** exist only so that they may be passed to the xBestIndex method of the
** single virtual table in the FROM clause of the SELECT.
*/
-SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
- assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) );
- if( (p && p->pLimit) /* 1 */
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
+ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
+ if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
){
@@ -154745,6 +156299,43 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
#define whereTraceIndexInfoOutputs(A)
#endif
+/*
+** We know that pSrc is an operand of an outer join. Return true if
+** pTerm is a constraint that is compatible with that join.
+**
+** pTerm must be EP_OuterON if pSrc is the right operand of an
+** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
+** is the left operand of a RIGHT join.
+**
+** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
+** for an example of a WHERE clause constraints that may not be used on
+** the right table of a RIGHT JOIN because the constraint implies a
+** not-NULL condition on the left table of the RIGHT JOIN.
+*/
+static int constraintCompatibleWithOuterJoin(
+ const WhereTerm *pTerm, /* WHERE clause term to check */
+ const SrcItem *pSrc /* Table we are trying to access */
+){
+ assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
+ testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
+ testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
+ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
+ || pTerm->pExpr->w.iJoin != pSrc->iCursor
+ ){
+ return 0;
+ }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ ){
+ return 0;
+ }
+ return 1;
+}
+
+
+
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
@@ -154760,16 +156351,10 @@ static int termCanDriveIndex(
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- return 0; /* See tag-20191211-001 */
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
@@ -155181,22 +156766,10 @@ static sqlite3_index_info *allocateIndexInfo(
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pTerm->u.x.leftColumn>=XN_ROWID );
assert( pTerm->u.x.leftColumn<pTab->nCol );
-
- /* tag-20191211-002: WHERE-clause constraints are not useful to the
- ** right-hand table of a LEFT JOIN nor to the either table of a
- ** RIGHT JOIN. See tag-20191211-001 for the
- ** equivalent restriction for ordinary tables. */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) );
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
nTerm++;
pTerm->wtFlags |= TERM_OK;
@@ -155569,7 +157142,7 @@ static int whereKeyStats(
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
if( i>=pIdx->nSample ){
- iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
+ iUpper = pIdx->nRowEst0;
}else{
iUpper = aSample[i].anLt[iCol];
}
@@ -156198,12 +157771,18 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
}
/*
-** Deallocate internal memory used by a WhereLoop object
+** Deallocate internal memory used by a WhereLoop object. Leave the
+** object in an initialized state, as if it had been newly allocated.
*/
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ){
+ sqlite3DbFreeNN(db, p->aLTerm);
+ p->aLTerm = p->aLTermSpace;
+ p->nLSlot = ArraySize(p->aLTermSpace);
+ }
whereLoopClearUnion(db, p);
- whereLoopInit(p);
+ p->nLTerm = 0;
+ p->wsFlags = 0;
}
/*
@@ -156227,7 +157806,9 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
*/
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
- if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
+ if( pFrom->nLTerm > pTo->nLSlot
+ && whereLoopResize(db, pTo, pFrom->nLTerm)
+ ){
memset(pTo, 0, WHERE_LOOP_XFER_SZ);
return SQLITE_NOMEM_BKPT;
}
@@ -156245,8 +157826,9 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
** Delete a WhereLoop object
*/
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
+ assert( db!=0 );
whereLoopClear(db, p);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
/*
@@ -156254,30 +157836,19 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
assert( pWInfo!=0 );
+ assert( db!=0 );
sqlite3WhereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
- assert( pWInfo->pExprMods==0 );
while( pWInfo->pMemToFree ){
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
- sqlite3DbFreeNN(db, pWInfo->pMemToFree);
+ sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
pWInfo->pMemToFree = pNext;
}
- sqlite3DbFreeNN(db, pWInfo);
-}
-
-/* Undo all Expr node modifications
-*/
-static void whereUndoExprMods(WhereInfo *pWInfo){
- while( pWInfo->pExprMods ){
- WhereExprMod *p = pWInfo->pExprMods;
- pWInfo->pExprMods = p->pNext;
- memcpy(p->pExpr, &p->orig, sizeof(p->orig));
- sqlite3DbFree(pWInfo->pParse->db, p);
- }
+ sqlite3DbNNFreeNN(db, pWInfo);
}
/*
@@ -156844,32 +158415,11 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* tag-20191211-001: Do not allow constraints from the WHERE clause to
- ** be used by the right table of a LEFT JOIN nor by the left table of a
- ** RIGHT JOIN. Only constraints in the ON clause are allowed.
- ** See tag-20191211-002 for the vtab equivalent.
- **
- ** 2022-06-06: See https://sqlite.org/forum/forumpost/206d99a16dd9212f
- ** for an example of a WHERE clause constraints that may not be used on
- ** the right table of a RIGHT JOIN because the constraint implies a
- ** not-NULL condition on the left table of the RIGHT JOIN.
- **
- ** 2022-06-10: The same condition applies to termCanDriveIndex() above.
- ** https://sqlite.org/forum/forumpost/51e6959f61
- */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
-
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
}else{
@@ -156880,7 +158430,11 @@ static int whereLoopAddBtreeIndex(
pNew->u.btree.nBtm = saved_nBtm;
pNew->u.btree.nTop = saved_nTop;
pNew->nLTerm = saved_nLTerm;
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ if( pNew->nLTerm>=pNew->nLSlot
+ && whereLoopResize(db, pNew, pNew->nLTerm+1)
+ ){
+ break; /* OOM while trying to enlarge the pNew->aLTerm array */
+ }
pNew->aLTerm[pNew->nLTerm++] = pTerm;
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
@@ -156973,38 +158527,39 @@ static int whereLoopAddBtreeIndex(
if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
- }else if( eOp & (WO_GT|WO_GE) ){
- testcase( eOp & WO_GT );
- testcase( eOp & WO_GE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
- pNew->u.btree.nBtm = whereRangeVectorLen(
- pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
- );
- pBtm = pTerm;
- pTop = 0;
- if( pTerm->wtFlags & TERM_LIKEOPT ){
- /* Range constraints that come from the LIKE optimization are
- ** always used in pairs. */
- pTop = &pTerm[1];
- assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
- assert( pTop->wtFlags & TERM_LIKEOPT );
- assert( pTop->eOperator==WO_LT );
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
- pNew->aLTerm[pNew->nLTerm++] = pTop;
- pNew->wsFlags |= WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = 1;
- }
- }else{
- assert( eOp & (WO_LT|WO_LE) );
- testcase( eOp & WO_LT );
- testcase( eOp & WO_LE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = whereRangeVectorLen(
+ }else{
+ int nVecLen = whereRangeVectorLen(
pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
);
- pTop = pTerm;
- pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
- pNew->aLTerm[pNew->nLTerm-2] : 0;
+ if( eOp & (WO_GT|WO_GE) ){
+ testcase( eOp & WO_GT );
+ testcase( eOp & WO_GE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
+ pNew->u.btree.nBtm = nVecLen;
+ pBtm = pTerm;
+ pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range constraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = 1;
+ }
+ }else{
+ assert( eOp & (WO_LT|WO_LE) );
+ testcase( eOp & WO_LT );
+ testcase( eOp & WO_LE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = nVecLen;
+ pTop = pTerm;
+ pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
+ pNew->aLTerm[pNew->nLTerm-2] : 0;
+ }
}
/* At this point pNew->nOut is set to the number of rows expected to
@@ -157249,6 +158804,94 @@ static int whereUsablePartialIndex(
}
/*
+** Structure passed to the whereIsCoveringIndex Walker callback.
+*/
+struct CoveringIndexCheck {
+ Index *pIdx; /* The index */
+ int iTabCur; /* Cursor number for the corresponding table */
+};
+
+/*
+** Information passed in is pWalk->u.pCovIdxCk. Call is pCk.
+**
+** If the Expr node references the table with cursor pCk->iTabCur, then
+** make sure that column is covered by the index pCk->pIdx. We know that
+** all columns less than 63 (really BMS-1) are covered, so we don't need
+** to check them. But we do need to check any column at 63 or greater.
+**
+** If the index does not cover the column, then set pWalk->eCode to
+** non-zero and return WRC_Abort to stop the search.
+**
+** If this node does not disprove that the index can be a covering index,
+** then just return WRC_Continue, to continue the search.
+*/
+static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){
+ int i; /* Loop counter */
+ const Index *pIdx; /* The index of interest */
+ const i16 *aiColumn; /* Columns contained in the index */
+ u16 nColumn; /* Number of columns in the index */
+ if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_AGG_COLUMN ) return WRC_Continue;
+ if( pExpr->iColumn<(BMS-1) ) return WRC_Continue;
+ if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ) return WRC_Continue;
+ pIdx = pWalk->u.pCovIdxCk->pIdx;
+ aiColumn = pIdx->aiColumn;
+ nColumn = pIdx->nColumn;
+ for(i=0; i<nColumn; i++){
+ if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
+ }
+ pWalk->eCode = 1;
+ return WRC_Abort;
+}
+
+
+/*
+** pIdx is an index that covers all of the low-number columns used by
+** pWInfo->pSelect (columns from 0 through 62). But there are columns
+** in pWInfo->pSelect beyond 62. This routine tries to answer the question
+** of whether pIdx covers *all* columns in the query.
+**
+** Return 0 if pIdx is a covering index. Return non-zero if pIdx is
+** not a covering index or if we are unable to determine if pIdx is a
+** covering index.
+**
+** This routine is an optimization. It is always safe to return non-zero.
+** But returning zero when non-zero should have been returned can lead to
+** incorrect bytecode and assertion faults.
+*/
+static SQLITE_NOINLINE u32 whereIsCoveringIndex(
+ WhereInfo *pWInfo, /* The WHERE clause context */
+ Index *pIdx, /* Index that is being tested */
+ int iTabCur /* Cursor for the table being indexed */
+){
+ int i;
+ struct CoveringIndexCheck ck;
+ Walker w;
+ if( pWInfo->pSelect==0 ){
+ /* We don't have access to the full query, so we cannot check to see
+ ** if pIdx is covering. Assume it is not. */
+ return 1;
+ }
+ for(i=0; i<pIdx->nColumn; i++){
+ if( pIdx->aiColumn[i]>=BMS-1 ) break;
+ }
+ if( i>=pIdx->nColumn ){
+ /* pIdx does not index any columns greater than 62, but we know from
+ ** colMask that columns greater than 62 are used, so this is not a
+ ** covering index */
+ return 1;
+ }
+ ck.pIdx = pIdx;
+ ck.iTabCur = iTabCur;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = whereIsCoveringIndexWalkCallback;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.u.pCovIdxCk = &ck;
+ w.eCode = 0;
+ sqlite3WalkSelect(&w, pWInfo->pSelect);
+ return w.eCode;
+}
+
+/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
@@ -157450,6 +159093,9 @@ static int whereLoopAddBtree(
#else
pNew->rRun = rSize + 16;
#endif
+ if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ pNew->wsFlags |= WHERE_VIEWSCAN;
+ }
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
@@ -157462,6 +159108,9 @@ static int whereLoopAddBtree(
m = 0;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
+ if( m==TOPBIT ){
+ m = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
+ }
pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
}
@@ -158176,7 +159825,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
- whereLoopInit(pNew);
+
+ /* Verify that pNew has already been initialized */
+ assert( pNew->nLTerm==0 );
+ assert( pNew->wsFlags==0 );
+ assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) );
+ assert( pNew->aLTerm!=0 );
+
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
Bitmask mUnusable = 0;
@@ -158681,7 +160336,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
- sqlite3 *db; /* The database connection */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
@@ -158700,7 +160354,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
- db = pParse->db;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
@@ -158723,7 +160376,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
- pSpace = sqlite3DbMallocRawNN(db, nSpace);
+ pSpace = sqlite3StackAllocRawNN(pParse->db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
@@ -158773,9 +160426,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
- i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
+ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
- Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
+ Bitmask revMask; /* Mask of rev-order loops for (..) */
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
@@ -158794,7 +160447,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
+ isOrdered = pFrom->isOrdered;
if( isOrdered<0 ){
+ revMask = 0;
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
@@ -158822,6 +160477,13 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
+ /* TUNING: A full-scan of a VIEW or subquery in the outer loop
+ ** is not so bad. */
+ if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
+ rCost += -10;
+ nOut += -30;
+ }
+
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
@@ -158972,7 +160634,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
- sqlite3DbFreeNN(db, pSpace);
+ sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_ERROR;
}
@@ -159054,7 +160716,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
- sqlite3DbFreeNN(db, pSpace);
+ sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_OK;
}
@@ -159354,6 +161016,77 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
/*
+** This is an sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxExpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
+ Parse *pParse = (Parse*)pObject;
+ while( pParse->pIdxExpr!=0 ){
+ IndexedExpr *p = pParse->pIdxExpr;
+ pParse->pIdxExpr = p->pIENext;
+ sqlite3ExprDelete(db, p->pExpr);
+ sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** The index pIdx is used by a query and contains one or more expressions.
+** In other words pIdx is an index on an expression. iIdxCur is the cursor
+** number for the index and iDataCur is the cursor number for the corresponding
+** table.
+**
+** This routine adds IndexedExpr entries to the Parse->pIdxExpr field for
+** each of the expressions in the index so that the expression code generator
+** will know to replace occurrences of the indexed expression with
+** references to the corresponding column of the index.
+*/
+static SQLITE_NOINLINE void whereAddIndexedExpr(
+ Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxExpr */
+ Index *pIdx, /* The index-on-expression that contains the expressions */
+ int iIdxCur, /* Cursor number for pIdx */
+ SrcItem *pTabItem /* The FROM clause entry for the table */
+){
+ int i;
+ IndexedExpr *p;
+ Table *pTab;
+ assert( pIdx->bHasExpr );
+ pTab = pIdx->pTable;
+ for(i=0; i<pIdx->nColumn; i++){
+ Expr *pExpr;
+ int j = pIdx->aiColumn[i];
+ int bMaybeNullRow;
+ if( j==XN_EXPR ){
+ pExpr = pIdx->aColExpr->a[i].pExpr;
+ testcase( pTabItem->fg.jointype & JT_LEFT );
+ testcase( pTabItem->fg.jointype & JT_RIGHT );
+ testcase( pTabItem->fg.jointype & JT_LTORJ );
+ bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
+ }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
+ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
+ bMaybeNullRow = 0;
+ }else{
+ continue;
+ }
+ if( sqlite3ExprIsConstant(pExpr) ) continue;
+ p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
+ if( p==0 ) break;
+ p->pIENext = pParse->pIdxExpr;
+ p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
+ p->iDataCur = pTabItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = i;
+ p->bMaybeNullRow = bMaybeNullRow;
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ p->zIdxName = pIdx->zName;
+#endif
+ pParse->pIdxExpr = p;
+ if( p->pIENext==0 ){
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
+ }
+ }
+}
+
+/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
@@ -159447,7 +161180,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
- Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */
+ Select *pSelect, /* The entire SELECT statement */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */
@@ -159516,7 +161249,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
+#if WHERETRACE_ENABLED
pWInfo->pWhere = pWhere;
+#endif
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
@@ -159524,9 +161259,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- pWInfo->pLimit = pLimit;
-#endif
+ pWInfo->pSelect = pSelect;
memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
@@ -159595,7 +161328,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
- sqlite3WhereAddLimit(&pWInfo->sWC, pLimit);
+ if( pSelect && pSelect->pLimit ){
+ sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
+ }
if( pParse->nErr ) goto whereBeginError;
/* Special case: WHERE terms that do not refer to any tables in the join
@@ -159898,6 +161633,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
+ if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
+ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -160020,8 +161758,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginError:
if( pWInfo ){
- testcase( pWInfo->pExprMods!=0 );
- whereUndoExprMods(pWInfo);
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
@@ -160240,7 +161976,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
assert( pWInfo->nLevel<=pTabList->nSrc );
- if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
int k, last;
VdbeOp *pOp, *pLastOp;
@@ -160294,6 +162029,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}else{
last = pWInfo->iEndWhere;
}
+ if( pIdx->bHasExpr ){
+ IndexedExpr *p = pParse->pIdxExpr;
+ while( p ){
+ if( p->iIdxCur==pLevel->iIdxCur ){
+ p->iDataCur = -1;
+ p->iIdxCur = -1;
+ }
+ p = p->pIENext;
+ }
+ }
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
@@ -161287,7 +163032,6 @@ static ExprList *exprListAppendList(
for(i=0; i<pAppend->nExpr; i++){
sqlite3 *db = pParse->db;
Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
- assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
break;
@@ -162558,10 +164302,9 @@ static void windowCodeRangeTest(
/* This block runs if reg1 is not NULL, but reg2 is. */
sqlite3VdbeJumpHere(v, addr);
- sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
- if( op==OP_Gt || op==OP_Ge ){
- sqlite3VdbeChangeP2(v, -1, addrDone);
- }
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2,
+ (op==OP_Gt || op==OP_Ge) ? addrDone : lbl);
+ VdbeCoverage(v);
}
/* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
@@ -170138,7 +171881,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
- if( pParse->pVList ) sqlite3DbFreeNN(db, pParse->pVList);
+ if( pParse->pVList ) sqlite3DbNNFreeNN(db, pParse->pVList);
db->pParse = pParentParse;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
@@ -171494,18 +173237,19 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm;
}else{
- db->lookaside.pStart = db;
+ db->lookaside.pStart = 0;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
db->lookaside.pSmallInit = 0;
db->lookaside.pSmallFree = 0;
- db->lookaside.pMiddle = db;
+ db->lookaside.pMiddle = 0;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
- db->lookaside.pEnd = db;
+ db->lookaside.pEnd = 0;
db->lookaside.bDisable = 1;
db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
+ db->lookaside.pTrueEnd = db->lookaside.pEnd;
assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -171584,6 +173328,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
+ sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
@@ -171649,6 +173394,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
}
}
va_end(ap);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -174019,6 +175765,19 @@ static int openDatabase(
goto opendb_out;
}
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+ /* Process magic filenames ":localStorage:" and ":sessionStorage:" */
+ if( zFilename && zFilename[0]==':' ){
+ if( strcmp(zFilename, ":localStorage:")==0 ){
+ zFilename = "file:local?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }else if( strcmp(zFilename, ":sessionStorage:")==0 ){
+ zFilename = "file:session?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }
+ }
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
+
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
@@ -174049,6 +175808,12 @@ static int openDatabase(
sqlite3_free(zErrMsg);
goto opendb_out;
}
+ assert( db->pVfs!=0 );
+#if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL)
+ if( sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){
+ db->temp_store = 2;
+ }
+#endif
/* Open the backend database driver */
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
@@ -175158,7 +176923,7 @@ static char *appendText(char *p, const char *z){
** Memory layout must be compatible with that generated by the pager
** and expected by sqlite3_uri_parameter() and databaseName().
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API const char *sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
@@ -175194,10 +176959,10 @@ SQLITE_API char *sqlite3_create_filename(
** error to call this routine with any parameter other than a pointer
** previously obtained from sqlite3_create_filename() or a NULL pointer.
*/
-SQLITE_API void sqlite3_free_filename(char *p){
+SQLITE_API void sqlite3_free_filename(const char *p){
if( p==0 ) return;
- p = (char*)databaseName(p);
- sqlite3_free(p - 4);
+ p = databaseName(p);
+ sqlite3_free((char*)p - 4);
}
@@ -175448,8 +177213,8 @@ SQLITE_API int sqlite3_snapshot_open(
*/
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR;
- int iDb;
#ifndef SQLITE_OMIT_WAL
+ int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -177004,7 +178769,7 @@ struct Fts3MultiSegReader {
int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */
- int nBuffer; /* Allocated size of aBuffer[] in bytes */
+ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
int iColFilter; /* If >=0, filter for this column */
int bRestart;
@@ -179700,7 +181465,7 @@ static int fts3TermSelectMerge(
**
** Similar padding is added in the fts3DoclistOrMerge() function.
*/
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
+ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@@ -181557,7 +183322,7 @@ static int fts3EvalIncrPhraseNext(
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
+ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
@@ -185793,7 +187558,7 @@ static int porterNext(
if( n>c->nAllocated ){
char *pNew;
c->nAllocated = n+20;
- pNew = sqlite3_realloc(c->zToken, c->nAllocated);
+ pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->zToken = pNew;
}
@@ -186545,7 +188310,7 @@ static int simpleNext(
if( n>c->nTokenAllocated ){
char *pNew;
c->nTokenAllocated = n+20;
- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
+ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew;
}
@@ -187707,7 +189472,7 @@ static int fts3PendingListAppendVarint(
/* Allocate or grow the PendingList as required. */
if( !p ){
- p = sqlite3_malloc(sizeof(*p) + 100);
+ p = sqlite3_malloc64(sizeof(*p) + 100);
if( !p ){
return SQLITE_NOMEM;
}
@@ -187716,14 +189481,14 @@ static int fts3PendingListAppendVarint(
p->nData = 0;
}
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
- int nNew = p->nSpace * 2;
- p = sqlite3_realloc(p, sizeof(*p) + nNew);
+ i64 nNew = p->nSpace * 2;
+ p = sqlite3_realloc64(p, sizeof(*p) + nNew);
if( !p ){
sqlite3_free(*pp);
*pp = 0;
return SQLITE_NOMEM;
}
- p->nSpace = nNew;
+ p->nSpace = (int)nNew;
p->aData = (char *)&p[1];
}
@@ -188280,7 +190045,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte;
if( paBlob ){
- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
+ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
if( !aByte ){
rc = SQLITE_NOMEM;
}else{
@@ -188397,7 +190162,7 @@ static int fts3SegReaderNext(
int nTerm = fts3HashKeysize(pElem);
if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
- pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2);
+ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
if( !pReader->zTerm ) return SQLITE_NOMEM;
pReader->nTermAlloc = (nTerm+1)*2;
}
@@ -188405,7 +190170,7 @@ static int fts3SegReaderNext(
pReader->zTerm[nTerm] = '\0';
pReader->nTerm = nTerm;
- aCopy = (char*)sqlite3_malloc(nCopy);
+ aCopy = (char*)sqlite3_malloc64(nCopy);
if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy;
@@ -188692,7 +190457,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
nExtra = nRoot + FTS3_NODE_PADDING;
}
- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
+ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
@@ -188784,7 +190549,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
if( nElem==nAlloc ){
Fts3HashElem **aElem2;
nAlloc += 16;
- aElem2 = (Fts3HashElem **)sqlite3_realloc(
+ aElem2 = (Fts3HashElem **)sqlite3_realloc64(
aElem, nAlloc*sizeof(Fts3HashElem *)
);
if( !aElem2 ){
@@ -189118,7 +190883,7 @@ static int fts3NodeAddTerm(
** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
- pTree->aData = (char *)sqlite3_malloc(nReq);
+ pTree->aData = (char *)sqlite3_malloc64(nReq);
if( !pTree->aData ){
return SQLITE_NOMEM;
}
@@ -189136,7 +190901,7 @@ static int fts3NodeAddTerm(
if( isCopyTerm ){
if( pTree->nMalloc<nTerm ){
- char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2);
+ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189162,7 +190927,7 @@ static int fts3NodeAddTerm(
** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here.
*/
- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
+ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
if( !pNew ){
return SQLITE_NOMEM;
}
@@ -189300,7 +191065,7 @@ static int fts3SegWriterAdd(
){
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
- int nReq; /* Number of bytes required on leaf page */
+ i64 nReq; /* Number of bytes required on leaf page */
int nData;
SegmentWriter *pWriter = *ppWriter;
@@ -189309,13 +191074,13 @@ static int fts3SegWriterAdd(
sqlite3_stmt *pStmt;
/* Allocate the SegmentWriter structure */
- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter));
+ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
if( !pWriter ) return SQLITE_NOMEM;
memset(pWriter, 0, sizeof(SegmentWriter));
*ppWriter = pWriter;
/* Allocate a buffer in which to accumulate data */
- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
+ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
if( !pWriter->aData ) return SQLITE_NOMEM;
pWriter->nSize = p->nNodeSize;
@@ -189390,7 +191155,7 @@ static int fts3SegWriterAdd(
** the buffer to make it large enough.
*/
if( nReq>pWriter->nSize ){
- char *aNew = sqlite3_realloc(pWriter->aData, nReq);
+ char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
if( !aNew ) return SQLITE_NOMEM;
pWriter->aData = aNew;
pWriter->nSize = nReq;
@@ -189415,7 +191180,7 @@ static int fts3SegWriterAdd(
*/
if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){
- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2);
+ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189723,12 +191488,12 @@ static void fts3ColumnFilter(
static int fts3MsrBufferData(
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
char *pList,
- int nList
+ i64 nList
){
if( nList>pMsr->nBuffer ){
char *pNew;
pMsr->nBuffer = nList*2;
- pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer);
+ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
}
@@ -189784,7 +191549,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
- rc = fts3MsrBufferData(pMsr, pList, nList+1);
+ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
if( rc!=SQLITE_OK ) return rc;
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
pList = pMsr->aBuffer;
@@ -189921,11 +191686,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
-static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
if( nReq>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = nReq*2;
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
+ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
@@ -190016,7 +191781,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
){
pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){
- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
+ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
+ (i64)pCsr->nDoclist);
pCsr->aDoclist = pCsr->aBuffer;
}else{
pCsr->aDoclist = apSegment[0]->aDoclist;
@@ -190069,7 +191835,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
+ rc = fts3GrowSegReaderBuffer(pCsr,
+ (i64)nByte+nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
if( isFirst ){
@@ -190095,7 +191862,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
- rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
+ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
@@ -190808,7 +192575,7 @@ struct NodeReader {
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
+ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
if( a ){
pBlob->nAlloc = nAlloc;
pBlob->a = a;
@@ -191605,7 +193372,7 @@ static int fts3RepackSegdirLevel(
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
+ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
if( !aNew ){
rc = SQLITE_NOMEM;
break;
@@ -191979,7 +193746,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
+ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1];
@@ -192615,7 +194382,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
return SQLITE_OK;
}
- pRet = (char *)sqlite3_malloc(p->pList->nData);
+ pRet = (char *)sqlite3_malloc64(p->pList->nData);
if( !pRet ) return SQLITE_NOMEM;
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
@@ -192635,7 +194402,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
int iCol /* Column that token must appear in (or -1) */
){
Fts3DeferredToken *pDeferred;
- pDeferred = sqlite3_malloc(sizeof(*pDeferred));
+ pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
if( !pDeferred ){
return SQLITE_NOMEM;
}
@@ -201350,7 +203117,7 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
- cell.iRowid = 0; /* Used only to suppress a compiler warning */
+ memset(&cell, 0, sizeof(cell));
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
@@ -204817,8 +206584,9 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
- }else{
- assert(!pExpr);
+ pExpr = sqlite3_get_auxdata(p, 0);
+ }
+ if( !pExpr ){
icuFunctionError(p, "uregex_open", status);
return;
}
@@ -205976,6 +207744,34 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
+** As part of applying an RBU update or performing an RBU vacuum operation,
+** the system must at one point move the *-oal file to the equivalent *-wal
+** path. Normally, it does this by invoking POSIX function rename(2) directly.
+** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
+** function may be used to register a callback that the RBU module will invoke
+** instead of one of these APIs.
+**
+** If a callback is registered with an RBU handle, it invokes it instead
+** of rename(2) when it needs to move a file within the file-system. The
+** first argument passed to the xRename() callback is a copy of the second
+** argument (pArg) passed to this function. The second is the full path
+** to the file to move and the third the full path to which it should be
+** moved. The callback function should return SQLITE_OK to indicate
+** success. If an error occurs, it should return an SQLite error code.
+** In this case the RBU operation will be abandoned and the error returned
+** to the RBU user.
+**
+** Passing a NULL pointer in place of the xRename argument to this function
+** restores the default behaviour.
+*/
+SQLITE_API void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+);
+
+
+/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
** then the new RBU VFS uses the default system VFS to access the file-system.
@@ -206342,6 +208138,8 @@ struct sqlite3rbu {
int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
+ void *pRenameArg;
+ int (*xRename)(void*, const char*, const char*);
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@@ -208730,7 +210528,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){
sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
if( p->zState==0 ){
const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
- p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
+ p->zState = rbuMPrintf(p, "file:///%s-vacuum?modeof=%s", zFile, zFile);
}
}
@@ -209190,32 +210988,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
}
if( p->rc==SQLITE_OK ){
-#if defined(_WIN32_WCE)
- {
- LPWSTR zWideOal;
- LPWSTR zWideWal;
-
- zWideOal = rbuWinUtf8ToUnicode(zOal);
- if( zWideOal ){
- zWideWal = rbuWinUtf8ToUnicode(zWal);
- if( zWideWal ){
- if( MoveFileW(zWideOal, zWideWal) ){
- p->rc = SQLITE_OK;
- }else{
- p->rc = SQLITE_IOERR;
- }
- sqlite3_free(zWideWal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- sqlite3_free(zWideOal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- }
-#else
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
+ p->rc = p->xRename(p->pRenameArg, zOal, zWal);
}
if( p->rc!=SQLITE_OK
@@ -209954,6 +211727,7 @@ static sqlite3rbu *openRbuHandle(
/* Create the custom VFS. */
memset(p, 0, sizeof(sqlite3rbu));
+ sqlite3rbu_rename_handler(p, 0, 0);
rbuCreateVfs(p);
/* Open the target, RBU and state databases */
@@ -210345,6 +212119,54 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
return rc;
}
+/*
+** Default xRename callback for RBU.
+*/
+static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
+ int rc = SQLITE_OK;
+#if defined(_WIN32_WCE)
+ {
+ LPWSTR zWideOld;
+ LPWSTR zWideNew;
+
+ zWideOld = rbuWinUtf8ToUnicode(zOld);
+ if( zWideOld ){
+ zWideNew = rbuWinUtf8ToUnicode(zNew);
+ if( zWideNew ){
+ if( MoveFileW(zWideOld, zWideNew) ){
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_IOERR;
+ }
+ sqlite3_free(zWideNew);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_free(zWideOld);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ }
+#else
+ rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+ return rc;
+}
+
+SQLITE_API void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+){
+ if( xRename ){
+ pRbu->xRename = xRename;
+ pRbu->pRenameArg = pArg;
+ }else{
+ pRbu->xRename = xDefaultRename;
+ pRbu->pRenameArg = 0;
+ }
+}
+
/**************************************************************************
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:
@@ -212475,12 +214297,18 @@ static int dbpageColumn(
}
case 1: { /* data */
DbPage *pDbPage = 0;
- rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
- if( rc==SQLITE_OK ){
- sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
- SQLITE_TRANSIENT);
+ if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
+ /* The pending byte page. Assume it is zeroed out. Attempting to
+ ** request this page from the page is an SQLITE_CORRUPT error. */
+ sqlite3_result_zeroblob(ctx, pCsr->szPage);
+ }else{
+ rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlite3PagerUnref(pDbPage);
}
- sqlite3PagerUnref(pDbPage);
break;
}
default: { /* schema */
@@ -212489,7 +214317,7 @@ static int dbpageColumn(
break;
}
}
- return SQLITE_OK;
+ return rc;
}
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
@@ -212549,11 +214377,12 @@ static int dbpageUpdate(
pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3PagerWrite(pDbPage);
- if( rc==SQLITE_OK ){
- memcpy(sqlite3PagerGetData(pDbPage),
- sqlite3_value_blob(argv[3]),
- szPage);
+ const void *pData = sqlite3_value_blob(argv[3]);
+ assert( pData!=0 || pTab->db->mallocFailed );
+ if( pData
+ && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
+ ){
+ memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
}
}
sqlite3PagerUnref(pDbPage);
@@ -212573,11 +214402,12 @@ static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab;
sqlite3 *db = pTab->db;
int i;
- for(i=0; i<db->nDb; i++){
+ int rc = SQLITE_OK;
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
- if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
+ if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
}
- return SQLITE_OK;
+ return rc;
}
@@ -219301,7 +221131,7 @@ static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
-#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
+#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,(i64)c)
#define fts5BufferFree(a) sqlite3Fts5BufferFree(a)
#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d)
@@ -231178,7 +233008,9 @@ static void fts5WriteAppendRowid(
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
+ fts5BufferAppendVarint(&p->rc, &pPage->buf,
+ (u64)iRowid - (u64)pWriter->iPrevRowid
+ );
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
@@ -231942,7 +233774,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
static void fts5AppendRowid(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pUnused,
Fts5Buffer *pBuf
){
@@ -231952,7 +233784,7 @@ static void fts5AppendRowid(
static void fts5AppendPoslist(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pMulti,
Fts5Buffer *pBuf
){
@@ -232027,10 +233859,10 @@ static void fts5MergeAppendDocid(
}
#endif
-#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
- assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
- fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
- (iLastRowid) = (iRowid); \
+#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
+ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
+ fts5BufferSafeAppendVarint((pBuf), (u64)(iRowid) - (u64)(iLastRowid)); \
+ (iLastRowid) = (iRowid); \
}
/*
@@ -232301,7 +234133,7 @@ static void fts5SetupPrefixIter(
int nMerge = 1;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
xMerge = fts5MergeRowidLists;
xAppend = fts5AppendRowid;
@@ -232340,7 +234172,7 @@ static void fts5SetupPrefixIter(
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
}
@@ -232388,7 +234220,7 @@ static void fts5SetupPrefixIter(
iLastRowid = 0;
}
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
@@ -233367,6 +235199,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum
/* If this is a new term, query for it. Update cksum3 with the results. */
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
+ if( p->rc ) break;
if( eDetail==FTS5_DETAIL_NONE ){
if( 0==fts5MultiIterIsEmpty(p, pIter) ){
@@ -236704,7 +238537,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2022-09-05 11:02:23 4635f4a69c8c2a8df242b384a992aea71224e39a2ccab42d8c0b0602f1e826e8", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318", -1, SQLITE_TRANSIENT);
}
/*
diff --git a/sqlite3.h b/sqlite3.h
index 2868334676f4..2859cc09b4f5 100644
--- a/sqlite3.h
+++ b/sqlite3.h
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.3"
-#define SQLITE_VERSION_NUMBER 3039003
-#define SQLITE_SOURCE_ID "2022-09-05 11:02:23 4635f4a69c8c2a8df242b384a992aea71224e39a2ccab42d8c0b0602f1e826e8"
+#define SQLITE_VERSION "3.40.0"
+#define SQLITE_VERSION_NUMBER 3040000
+#define SQLITE_SOURCE_ID "2022-11-16 12:10:08 89c459e766ea7e9165d0beeb124708b955a4950d0f4792f457465d71b158d318"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -670,13 +670,17 @@ SQLITE_API int sqlite3_exec(
**
** 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.
+** of an [sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#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
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -754,7 +758,14 @@ struct sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+* If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** 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
@@ -859,9 +870,8 @@ struct sqlite3_io_methods {
** 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 is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1254,6 +1264,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlite3_filename_database()
+** <li> sqlite3_filename_journal()
+** <li> sqlite3_filename_wal()
+** <li> sqlite3_uri_parameter()
+** <li> sqlite3_uri_boolean()
+** <li> sqlite3_uri_int64()
+** <li> sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1431,7 +1461,7 @@ struct sqlite3_vfs {
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 (*xOpen)(sqlite3_vfs*, sqlite3_filename 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);
@@ -2309,6 +2339,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -3424,6 +3455,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3439,7 +3473,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
@@ -3698,10 +3732,10 @@ SQLITE_API int sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -3730,9 +3764,9 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -3798,14 +3832,14 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API sqlite3_filename sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlite3_free_filename(char*);
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -5508,6 +5542,16 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** then the conversion is performed. Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
**
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
+** sqlite3_value_text(X), sqlite3_value_text16(X), sqlite3_value_text16be(X),
+** sqlite3_value_text16le(X), sqlite3_value_bytes(X), or
+** sqlite3_value_bytes16(X) might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
+**
** ^Within the [xUpdate] method of a [virtual table], the
** sqlite3_value_nochange(X) interface returns true if and only if
** the column corresponding to X is unchanged by the UPDATE operation
@@ -5572,6 +5616,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -5625,7 +5670,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation 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
@@ -5830,9 +5875,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^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 any of the sqlite3_result_text* interfaces
+** other than sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for 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
@@ -6328,7 +6374,7 @@ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
** <li> [sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6465,7 +6511,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6586,6 +6632,11 @@ SQLITE_API void *sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -6684,7 +6735,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -8979,7 +9030,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** 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.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9407,7 +9458,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
diff --git a/sqlite3ext.h b/sqlite3ext.h
index 2cdd0e429b69..79702d7b21e3 100644
--- a/sqlite3ext.h
+++ b/sqlite3ext.h
@@ -331,9 +331,9 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
- char *(*create_filename)(const char*,const char*,const char*,
+ const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
- void (*free_filename)(char*);
+ void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
@@ -357,6 +357,8 @@ struct sqlite3_api_routines {
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
+ /* Version 3.40.0 and later */
+ int (*value_encoding)(sqlite3_value*);
};
/*
@@ -681,6 +683,8 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
+/* Version 3.40.0 and later */
+#define sqlite3_value_encoding sqlite3_api->value_encoding
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/sqlite3rc.h b/sqlite3rc.h
index cf7de82cf924..713a6c653ab5 100644
--- a/sqlite3rc.h
+++ b/sqlite3rc.h
@@ -1,3 +1,3 @@
#ifndef SQLITE_RESOURCE_VERSION
-#define SQLITE_RESOURCE_VERSION 3,39,3
+#define SQLITE_RESOURCE_VERSION 3,40,0
#endif
diff --git a/tea/Makefile.in b/tea/Makefile.in
index 3e481dadfe84..5264f89f3c55 100644
--- a/tea/Makefile.in
+++ b/tea/Makefile.in
@@ -11,8 +11,6 @@
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-#
-# RCS: @(#) $Id: Makefile.in,v 1.59 2005/07/26 19:17:02 mdejong Exp $
#========================================================================
# Add additional lines to handle any additional AC_SUBST cases that
@@ -60,6 +58,8 @@ PKG_HEADERS = @PKG_HEADERS@
#========================================================================
PKG_LIB_FILE = @PKG_LIB_FILE@
+PKG_LIB_FILE8 = @PKG_LIB_FILE8@
+PKG_LIB_FILE9 = @PKG_LIB_FILE9@
PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@
lib_BINARIES = $(PKG_LIB_FILE)
@@ -73,10 +73,11 @@ exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
+includedir = @includedir@
datarootdir = @datarootdir@
+runstatedir = @runstatedir@
datadir = @datadir@
mandir = @mandir@
-includedir = @includedir@
DESTDIR =
@@ -85,24 +86,25 @@ pkgdatadir = $(datadir)/$(PKG_DIR)
pkglibdir = $(libdir)/$(PKG_DIR)
pkgincludedir = $(includedir)/$(PKG_DIR)
-top_builddir = .
+top_builddir = @abs_top_builddir@
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_OPTIONS =
+INSTALL = @INSTALL@ $(INSTALL_OPTIONS)
+INSTALL_DATA_DIR = @INSTALL_DATA_DIR@
INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_LIBRARY = @INSTALL_LIBRARY@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
CC = @CC@
+CCLD = @CCLD@
CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
CFLAGS_WARNING = @CFLAGS_WARNING@
-CLEANFILES = @CLEANFILES@
EXEEXT = @EXEEXT@
LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
MAKE_LIB = @MAKE_LIB@
-MAKE_SHARED_LIB = @MAKE_SHARED_LIB@
-MAKE_STATIC_LIB = @MAKE_STATIC_LIB@
MAKE_STUB_LIB = @MAKE_STUB_LIB@
OBJEXT = @OBJEXT@
RANLIB = @RANLIB@
@@ -117,8 +119,6 @@ TCL_SRC_DIR = @TCL_SRC_DIR@
#TK_BIN_DIR = @TK_BIN_DIR@
#TK_SRC_DIR = @TK_SRC_DIR@
-# This is no longer necessary even for packages that use private Tcl headers
-#TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@
# Not used, but retained for reference of what libs Tcl required
#TCL_LIBS = @TCL_LIBS@
@@ -132,41 +132,52 @@ TCL_SRC_DIR = @TCL_SRC_DIR@
EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR)
#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
TCLLIBPATH = $(top_builddir)
-TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \
- @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
+TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library`
+PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
PATH="$(EXTRA_PATH):$(PATH)" \
TCLLIBPATH="$(TCLLIBPATH)"
-# TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
TCLSH_PROG = @TCLSH_PROG@
-TCLSH = $(TCLSH_ENV) $(TCLSH_PROG)
+TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG)
+#WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
#WISH_PROG = @WISH_PROG@
-#WISH = $(TCLSH_ENV) $(WISH_PROG)
-
+#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG)
SHARED_BUILD = @SHARED_BUILD@
-INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I$(srcdir)/..
+INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I. -I$(srcdir)/..
#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@
PKG_CFLAGS = @PKG_CFLAGS@
# TCL_DEFS is not strictly need here, but if you remove it, then you
-# must make sure that configure.in checks for the necessary components
+# must make sure that configure.ac checks for the necessary components
# that your library may use. TCL_DEFS can actually be a problem if
# you do not compile with a similar machine setup as the Tcl core was
# compiled with.
#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
DEFS = @DEFS@ $(PKG_CFLAGS)
+# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl
+CLEANFILES = @CLEANFILES@
CPPFLAGS = @CPPFLAGS@
LIBS = @PKG_LIBS@ @LIBS@
AR = @AR@
CFLAGS = @CFLAGS@
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LDFLAGS = @LDFLAGS@
+LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \
+ $(CFLAGS_DEFAULT) $(CFLAGS_WARNING) $(SHLIB_CFLAGS) $(CFLAGS)
+
+GDB = gdb
+VALGRIND = valgrind
+VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \
+ --leak-check=yes --show-reachable=yes -v
+
+.SUFFIXES: .c .$(OBJEXT)
#========================================================================
# Start of user-definable TARGETS section
@@ -174,7 +185,7 @@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(C
#========================================================================
# TEA TARGETS. Please note that the "libraries:" target refers to platform
-# independent files, and the "binaries:" target inclues executable programs and
+# independent files, and the "binaries:" target includes executable programs and
# platform-dependent libraries. Modify these targets so that they install
# the various pieces of your package. The make and install rules
# for the BINARIES that you specified above have already been done.
@@ -193,7 +204,6 @@ binaries: $(BINARIES)
libraries:
-
#========================================================================
# Your doc target should differentiate from doc builds (by the developer)
# and doc installs (see install-doc), which just install the docs on the
@@ -216,11 +226,11 @@ install-binaries: binaries install-lib-binaries install-bin-binaries
#========================================================================
install-libraries: libraries
- @mkdir -p $(DESTDIR)$(includedir)
+ @$(INSTALL_DATA_DIR) "$(DESTDIR)$(includedir)"
@echo "Installing header files in $(DESTDIR)$(includedir)"
@list='$(PKG_HEADERS)'; for i in $$list; do \
echo "Installing $(srcdir)/$$i" ; \
- $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \
+ $(INSTALL_DATA) $(srcdir)/$$i "$(DESTDIR)$(includedir)" ; \
done;
#========================================================================
@@ -229,12 +239,11 @@ install-libraries: libraries
#========================================================================
install-doc: doc
- @mkdir -p $(DESTDIR)$(mandir)/mann
+ @$(INSTALL_DATA_DIR) "$(DESTDIR)$(mandir)/mann"
@echo "Installing documentation in $(DESTDIR)$(mandir)"
@list='$(srcdir)/doc/*.n'; for i in $$list; do \
echo "Installing $$i"; \
- rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \
- $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \
+ $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/mann" ; \
done
test: binaries libraries
@@ -244,7 +253,21 @@ shell: binaries libraries
@$(TCLSH) $(SCRIPT)
gdb:
- $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT)
+ $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT)
+
+gdb-test: binaries libraries
+ $(TCLSH_ENV) $(PKG_ENV) $(GDB) \
+ --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \
+ $(TESTFLAGS) -singleproc 1 \
+ -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \
+ [list load `@CYGPATH@ $(PKG_LIB_FILE)` [string totitle $(PACKAGE_NAME)]]"
+
+valgrind: binaries libraries
+ $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \
+ `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS)
+
+valgrindshell: binaries libraries
+ $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT)
depend:
@@ -283,49 +306,70 @@ $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS)
# As necessary, add $(srcdir):$(srcdir)/compat:....
#========================================================================
-VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win
+VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx
.c.@OBJEXT@:
$(COMPILE) -c `@CYGPATH@ $<` -o $@
+tclsample.@OBJEXT@: sampleUuid.h
+
+$(srcdir)/manifest.uuid:
+ printf "git-" >$(srcdir)/manifest.uuid
+ (cd $(srcdir); git rev-parse HEAD >>$(srcdir)/manifest.uuid || \
+ (printf "svn-r" >$(srcdir)/manifest.uuid ; \
+ svn info --show-item last-changed-revision >>$(srcdir)/manifest.uuid) || \
+ printf "unknown" >$(srcdir)/manifest.uuid)
+
+sampleUuid.h: $(srcdir)/manifest.uuid
+ echo "#define SAMPLE_VERSION_UUID \\" >$@
+ cat $(srcdir)/manifest.uuid >>$@
+ echo "" >>$@
+
#========================================================================
# Distribution creation
# You may need to tweak this target to make it work correctly.
#========================================================================
#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar
-COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR)
+COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR)
DIST_ROOT = /tmp/dist
DIST_DIR = $(DIST_ROOT)/$(PKG_DIR)
+DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644
+DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755
+
dist-clean:
rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*
-dist: dist-clean
- mkdir -p $(DIST_DIR)
- cp -p $(srcdir)/README* $(srcdir)/license* \
- $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \
- $(DIST_DIR)/
- chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4
- chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in
-
- for i in $(srcdir)/*.[ch]; do \
- if [ -f $$i ]; then \
- cp -p $$i $(DIST_DIR)/ ; \
- fi; \
- done;
-
- mkdir $(DIST_DIR)/tclconfig
- cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \
- $(DIST_DIR)/tclconfig/
- chmod 664 $(DIST_DIR)/tclconfig/tcl.m4
- chmod +x $(DIST_DIR)/tclconfig/install-sh
-
- list='demos doc generic library mac tests unix win'; \
+dist: dist-clean $(srcdir)/manifest.uuid
+ $(INSTALL_DATA_DIR) $(DIST_DIR)
+
+ # TEA files
+ $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \
+ $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \
+ $(DIST_DIR)/
+ $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/
+
+ $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig
+ $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \
+ $(srcdir)/manifest.uuid \
+ $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \
+ $(DIST_DIR)/tclconfig/
+
+ # Extension files
+ $(DIST_INSTALL_DATA) \
+ $(srcdir)/ChangeLog \
+ $(srcdir)/README.sha \
+ $(srcdir)/license.terms \
+ $(srcdir)/README \
+ $(srcdir)/pkgIndex.tcl.in \
+ $(DIST_DIR)/
+
+ list='demos doc generic library macosx tests unix win'; \
for p in $$list; do \
if test -d $(srcdir)/$$p ; then \
- mkdir $(DIST_DIR)/$$p; \
- cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \
+ $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \
+ $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \
fi; \
done
@@ -337,10 +381,10 @@ dist: dist-clean
#========================================================================
# Don't modify the file to clean here. Instead, set the "CLEANFILES"
-# variable in configure.in
+# variable in configure.ac
#========================================================================
-clean:
+clean:
-test -z "$(BINARIES)" || rm -f $(BINARIES)
-rm -f *.$(OBJEXT) core *.core
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
@@ -348,7 +392,7 @@ clean:
distclean: clean
-rm -f *.tab.c
-rm -f $(CONFIG_CLEAN_FILES)
- -rm -f config.h config.cache config.log config.status
+ -rm -f config.cache config.log config.status
#========================================================================
# Install binary object libraries. On Windows this includes both .dll and
@@ -362,25 +406,17 @@ distclean: clean
#========================================================================
install-lib-binaries: binaries
- @mkdir -p $(DESTDIR)$(pkglibdir)
+ @$(INSTALL_DATA_DIR) "$(DESTDIR)$(pkglibdir)"
@list='$(lib_BINARIES)'; for p in $$list; do \
if test -f $$p; then \
- echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
- $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \
- stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \
- if test "x$$stub" = "xstub"; then \
- echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \
- $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \
- else \
- echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \
- $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \
- fi; \
+ echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
+ $(INSTALL_LIBRARY) $$p "$(DESTDIR)$(pkglibdir)/$$p"; \
ext=`echo $$p|sed -e "s/.*\.//"`; \
if test "x$$ext" = "xdll"; then \
lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
if test -f $$lib; then \
echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
- $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \
+ $(INSTALL_DATA) $$lib "$(DESTDIR)$(pkglibdir)/$$lib"; \
fi; \
fi; \
fi; \
@@ -389,12 +425,12 @@ install-lib-binaries: binaries
if test -f $(srcdir)/$$p; then \
destp=`basename $$p`; \
echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
- $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \
+ $(INSTALL_DATA) $(srcdir)/$$p "$(DESTDIR)$(pkglibdir)/$$destp"; \
fi; \
done
@if test "x$(SHARED_BUILD)" = "x1"; then \
echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \
- $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \
+ $(INSTALL_DATA) pkgIndex.tcl "$(DESTDIR)$(pkglibdir)"; \
fi
#========================================================================
@@ -407,33 +443,32 @@ install-lib-binaries: binaries
#========================================================================
install-bin-binaries: binaries
- @mkdir -p $(DESTDIR)$(bindir)
+ @$(INSTALL_DATA_DIR) "$(DESTDIR)$(bindir)"
@list='$(bin_BINARIES)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
- $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
+ $(INSTALL_PROGRAM) $$p "$(DESTDIR)$(bindir)/$$p"; \
fi; \
done
-.SUFFIXES: .c .$(OBJEXT)
-
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
uninstall-binaries:
list='$(lib_BINARIES)'; for p in $$list; do \
- rm -f $(DESTDIR)$(pkglibdir)/$$p; \
+ rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
done
list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
p=`basename $$p`; \
- rm -f $(DESTDIR)$(pkglibdir)/$$p; \
+ rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
done
list='$(bin_BINARIES)'; for p in $$list; do \
- rm -f $(DESTDIR)$(bindir)/$$p; \
+ rm -f "$(DESTDIR)$(bindir)/$$p"; \
done
.PHONY: all binaries clean depend distclean doc install libraries test
+.PHONY: gdb gdb-test valgrind valgrindshell
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/tea/configure b/tea/configure
index b651eb52894d..c9cb3764a147 100755
--- a/tea/configure
+++ b/tea/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for sqlite 3.39.3.
+# Generated by GNU Autoconf 2.71 for sqlite 3.40.0.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -608,8 +608,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.39.3'
-PACKAGE_STRING='sqlite 3.39.3'
+PACKAGE_VERSION='3.40.0'
+PACKAGE_STRING='sqlite 3.40.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -646,7 +646,6 @@ ac_includes_default="\
ac_header_c_list=
ac_subst_vars='LTLIBOBJS
-LIBOBJS
TCLSH_PROG
VC_MANIFEST_EMBED_EXE
VC_MANIFEST_EMBED_DLL
@@ -655,7 +654,8 @@ MAKE_STUB_LIB
MAKE_STATIC_LIB
MAKE_SHARED_LIB
MAKE_LIB
-TCL_DBGX
+EGREP
+GREP
LDFLAGS_DEFAULT
CFLAGS_DEFAULT
LD_LIBRARY_PATH_VAR
@@ -663,26 +663,22 @@ SHLIB_CFLAGS
SHLIB_LD_LIBS
SHLIB_LD
STLIB_LD
+LDFLAGS_OPTIMIZE
+LDFLAGS_DEBUG
CFLAGS_WARNING
CFLAGS_OPTIMIZE
CFLAGS_DEBUG
+LIBOBJS
RC
-CELIB_DIR
AR
+STUBS_BUILD
SHARED_BUILD
TCL_THREADS
TCL_INCLUDES
PKG_OBJECTS
PKG_SOURCES
-EGREP
-GREP
-MATH_LIBS
RANLIB
SET_MAKE
-INSTALL_SCRIPT
-INSTALL_PROGRAM
-INSTALL_DATA
-INSTALL
CPP
TCL_SHLIB_LD_LIBS
TCL_LD_FLAGS
@@ -706,6 +702,12 @@ TCL_SRC_DIR
TCL_BIN_DIR
TCL_PATCH_LEVEL
TCL_VERSION
+INSTALL_LIBRARY
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+INSTALL_DATA
+INSTALL_DATA_DIR
+INSTALL
PKG_CFLAGS
PKG_LIBS
PKG_INCLUDES
@@ -714,6 +716,8 @@ PKG_TCL_SOURCES
PKG_STUB_OBJECTS
PKG_STUB_SOURCES
PKG_STUB_LIB_FILE
+PKG_LIB_FILE9
+PKG_LIB_FILE8
PKG_LIB_FILE
EXEEXT
CYGPATH
@@ -764,11 +768,10 @@ with_system_sqlite
with_tclinclude
enable_threads
enable_shared
+enable_stubs
enable_64bit
enable_64bit_vis
enable_rpath
-enable_wince
-with_celib
enable_symbols
'
ac_precious_vars='build_alias
@@ -1328,7 +1331,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures sqlite 3.39.3 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.40.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1390,7 +1393,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of sqlite 3.39.3:";;
+ short | recursive ) echo "Configuration of sqlite 3.40.0:";;
esac
cat <<\_ACEOF
@@ -1398,12 +1401,13 @@ Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --enable-threads build with threads
+ --enable-threads build with threads (default: on)
--enable-shared build and link with shared libraries (default: on)
+ --enable-stubs build and link with stub libraries. Always true for
+ shared builds (default: on)
--enable-64bit enable 64bit support (default: off)
--enable-64bit-vis enable 64bit Sparc VIS support (default: off)
--disable-rpath disable rpath support (default: on)
- --enable-wince enable Win/CE support (where applicable)
--enable-symbols build with debugging symbols (default: off)
Optional Packages:
@@ -1414,7 +1418,6 @@ Optional Packages:
--with-system-sqlite use a system-supplied libsqlite3 instead of the
bundled one
--with-tclinclude directory containing the public Tcl header files
- --with-celib=DIR use Windows/CE support library from DIR
Some influential environment variables:
CC C compiler command
@@ -1493,7 +1496,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-sqlite configure 3.39.3
+sqlite configure 3.40.0
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1768,58 +1771,6 @@ printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_func
-
-# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
-# ------------------------------------------------------------------
-# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
-ac_fn_check_decl ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- as_decl_name=`echo $2|sed 's/ *(.*//'`
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
-printf %s "checking whether $as_decl_name is declared... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
- eval ac_save_FLAGS=\$$6
- as_fn_append $6 " $5"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-#ifndef $as_decl_name
-#ifdef __cplusplus
- (void) $as_decl_use;
-#else
- (void) $as_decl_name;
-#endif
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- eval $6=\$ac_save_FLAGS
-
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_check_decl
ac_configure_args_raw=
for ac_arg
do
@@ -1844,7 +1795,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by sqlite $as_me 3.39.3, which was
+It was created by sqlite $as_me 3.40.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -2509,26 +2460,16 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
#--------------------------------------------------------------------
- # TEA extensions pass this us the version of TEA they think they
- # are compatible with.
- TEA_VERSION="3.9"
+ TEA_VERSION="3.13"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5
-printf %s "checking for correct TEA configuration... " >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking TEA configuration" >&5
+printf %s "checking TEA configuration... " >&6; }
if test x"${PACKAGE_NAME}" = x ; then
as_fn_error $? "
-The PACKAGE_NAME variable must be defined by your TEA configure.in" "$LINENO" 5
+The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5
fi
- if test x"3.9" = x ; then
- as_fn_error $? "
-TEA version not specified." "$LINENO" 5
- elif test "3.9" != "${TEA_VERSION}" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&5
-printf "%s\n" "warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5
printf "%s\n" "ok (TEA ${TEA_VERSION})" >&6; }
- fi
# If the user did not set CFLAGS, set it now to keep macros
# like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
@@ -2537,7 +2478,7 @@ printf "%s\n" "ok (TEA ${TEA_VERSION})" >&6; }
fi
case "`uname -s`" in
- *win32*|*WIN32*|*MINGW32_*)
+ *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*)
# Extract the first word of "cygpath", so it can be a program name with args.
set dummy cygpath; ac_word=$2
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -2560,7 +2501,7 @@ do
esac
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CYGPATH="cygpath -w"
+ ac_cv_prog_CYGPATH="cygpath -m"
printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -2585,9 +2526,8 @@ fi
TEA_PLATFORM="windows"
;;
*CYGWIN_*)
- CYGPATH=echo
EXEEXT=".exe"
- # TEA_PLATFORM is determined later in LOAD_TCLCONFIG
+ # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG
;;
*)
CYGPATH=echo
@@ -2622,6 +2562,8 @@ printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;}
# This package name must be replaced statically for AC_SUBST to work
+
+
# Substitute STUB_LIB_FILE in case package creates a stub library too.
@@ -2635,6 +2577,59 @@ printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;}
+ # Configure the installer.
+
+ INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c'
+ INSTALL_DATA_DIR='${INSTALL} -d -m 755'
+ INSTALL_DATA='${INSTALL} -m 644'
+ INSTALL_PROGRAM='${INSTALL} -m 755'
+ INSTALL_SCRIPT='${INSTALL} -m 755'
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system version" >&5
+printf %s "checking system version... " >&6; }
+if test ${tcl_cv_sys_version+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ # TEA specific:
+ if test "${TEA_PLATFORM}" = "windows" ; then
+ tcl_cv_sys_version=windows
+ else
+ tcl_cv_sys_version=`uname -s`-`uname -r`
+ if test "$?" -ne 0 ; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5
+printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;}
+ tcl_cv_sys_version=unknown
+ else
+ if test "`uname -s`" = "AIX" ; then
+ tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
+ fi
+ if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
+ tcl_cv_sys_version=NetBSD-Debian
+ fi
+ fi
+ fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5
+printf "%s\n" "$tcl_cv_sys_version" >&6; }
+ system=$tcl_cv_sys_version
+
+ case $system in
+ HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;;
+ *) INSTALL_LIBRARY='${INSTALL} -m 644' ;;
+ esac
+
+
+
+
+
+
+
+
+
@@ -2717,7 +2712,9 @@ printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory co
for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
- `ls -d /System/Library/Frameworks 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
; do
if test -f "$i/Tcl.framework/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
@@ -2746,10 +2743,15 @@ printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory co
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
; do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i; pwd)`"
@@ -3800,10 +3802,6 @@ printf "%s\n" "loading" >&6; }
printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; }
fi
- # eval is required to do the TCL_DBGX substitution
- eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
- eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
-
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
@@ -3837,12 +3835,6 @@ printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; }
esac
fi
- # eval is required to do the TCL_DBGX substitution
- eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
- eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
- eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
- eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
-
@@ -3876,9 +3868,57 @@ main (void)
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
- TEA_PLATFORM="unix"
+
+ # first test we've already retrieved platform (cross-compile), fallback to unix otherwise:
+ TEA_PLATFORM="${TEA_PLATFORM-unix}"
+ CYGPATH=echo
+
+else $as_nop
+
+ TEA_PLATFORM="windows"
+ # Extract the first word of "cygpath", so it can be a program name with args.
+set dummy cygpath; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CYGPATH+y}
+then :
+ printf %s "(cached) " >&6
else $as_nop
- TEA_PLATFORM="windows"
+ if test -n "$CYGPATH"; then
+ ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CYGPATH="cygpath -m"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo"
+fi
+fi
+CYGPATH=$ac_cv_prog_CYGPATH
+if test -n "$CYGPATH"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5
+printf "%s\n" "$CYGPATH" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
@@ -3948,8 +3988,8 @@ printf "%s\n" "$as_me: --exec-prefix defaulting to ${prefix}" >&6;}
#-----------------------------------------------------------------------
# Standard compiler checks.
# This sets up CC by using the CC env var, or looks for gcc otherwise.
-# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create
-# the basic setup necessary to compile executables.
+# This also calls AC_PROG_CC and a few others to create the basic setup
+# necessary to compile executables.
#-----------------------------------------------------------------------
@@ -4820,15 +4860,6 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
- INSTALL="\$(SHELL) \$(srcdir)/tclconfig/install-sh -c"
-
- INSTALL_DATA="\${INSTALL} -m 644"
-
- INSTALL_PROGRAM="\${INSTALL}"
-
- INSTALL_SCRIPT="\${INSTALL}"
-
-
#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------
@@ -5010,149 +5041,6 @@ printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-printf %s "checking for grep that handles long lines and -e... " >&6; }
-if test ${ac_cv_path_GREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$GREP"; then
- ac_path_GREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in grep ggrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-printf "%s\n" "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-printf %s "checking for egrep... " >&6; }
-if test ${ac_cv_path_EGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in egrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-printf "%s\n" "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-
# Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here.
@@ -5434,493 +5322,6 @@ printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
esac
- if test "${TEA_PLATFORM}" = "unix" ; then
-
- #--------------------------------------------------------------------
- # On a few very rare systems, all of the libm.a stuff is
- # already in libc.a. Set compiler flags accordingly.
- # Also, Linux requires the "ieee" library for math to work
- # right (and it must appear before "-lm").
- #--------------------------------------------------------------------
-
- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin"
-if test "x$ac_cv_func_sin" = xyes
-then :
- MATH_LIBS=""
-else $as_nop
- MATH_LIBS="-lm"
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5
-printf %s "checking for main in -lieee... " >&6; }
-if test ${ac_cv_lib_ieee_main+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lieee $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
-int
-main (void)
-{
-return main ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_ieee_main=yes
-else $as_nop
- ac_cv_lib_ieee_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5
-printf "%s\n" "$ac_cv_lib_ieee_main" >&6; }
-if test "x$ac_cv_lib_ieee_main" = xyes
-then :
- MATH_LIBS="-lieee $MATH_LIBS"
-fi
-
-
- #--------------------------------------------------------------------
- # Interactive UNIX requires -linet instead of -lsocket, plus it
- # needs net/errno.h to define the socket-related error codes.
- #--------------------------------------------------------------------
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5
-printf %s "checking for main in -linet... " >&6; }
-if test ${ac_cv_lib_inet_main+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-linet $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-
-int
-main (void)
-{
-return main ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_inet_main=yes
-else $as_nop
- ac_cv_lib_inet_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5
-printf "%s\n" "$ac_cv_lib_inet_main" >&6; }
-if test "x$ac_cv_lib_inet_main" = xyes
-then :
- LIBS="$LIBS -linet"
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default"
-if test "x$ac_cv_header_net_errno_h" = xyes
-then :
-
-
-printf "%s\n" "#define HAVE_NET_ERRNO_H 1" >>confdefs.h
-
-fi
-
-
- #--------------------------------------------------------------------
- # Check for the existence of the -lsocket and -lnsl libraries.
- # The order here is important, so that they end up in the right
- # order in the command line generated by make. Here are some
- # special considerations:
- # 1. Use "connect" and "accept" to check for -lsocket, and
- # "gethostbyname" to check for -lnsl.
- # 2. Use each function name only once: can't redo a check because
- # autoconf caches the results of the last check and won't redo it.
- # 3. Use -lnsl and -lsocket only if they supply procedures that
- # aren't already present in the normal libraries. This is because
- # IRIX 5.2 has libraries, but they aren't needed and they're
- # bogus: they goof up name resolution if used.
- # 4. On some SVR4 systems, can't use -lsocket without -lnsl too.
- # To get around this problem, check for both libraries together
- # if -lsocket doesn't work by itself.
- #--------------------------------------------------------------------
-
- tcl_checkBoth=0
- ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
-if test "x$ac_cv_func_connect" = xyes
-then :
- tcl_checkSocket=0
-else $as_nop
- tcl_checkSocket=1
-fi
-
- if test "$tcl_checkSocket" = 1; then
- ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt"
-if test "x$ac_cv_func_setsockopt" = xyes
-then :
-
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5
-printf %s "checking for setsockopt in -lsocket... " >&6; }
-if test ${ac_cv_lib_socket_setsockopt+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsocket $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char setsockopt ();
-int
-main (void)
-{
-return setsockopt ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_socket_setsockopt=yes
-else $as_nop
- ac_cv_lib_socket_setsockopt=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5
-printf "%s\n" "$ac_cv_lib_socket_setsockopt" >&6; }
-if test "x$ac_cv_lib_socket_setsockopt" = xyes
-then :
- LIBS="$LIBS -lsocket"
-else $as_nop
- tcl_checkBoth=1
-fi
-
-fi
-
- fi
- if test "$tcl_checkBoth" = 1; then
- tk_oldLibs=$LIBS
- LIBS="$LIBS -lsocket -lnsl"
- ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept"
-if test "x$ac_cv_func_accept" = xyes
-then :
- tcl_checkNsl=0
-else $as_nop
- LIBS=$tk_oldLibs
-fi
-
- fi
- ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
-if test "x$ac_cv_func_gethostbyname" = xyes
-then :
-
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
-printf %s "checking for gethostbyname in -lnsl... " >&6; }
-if test ${ac_cv_lib_nsl_gethostbyname+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnsl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char gethostbyname ();
-int
-main (void)
-{
-return gethostbyname ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_nsl_gethostbyname=yes
-else $as_nop
- ac_cv_lib_nsl_gethostbyname=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
-printf "%s\n" "$ac_cv_lib_nsl_gethostbyname" >&6; }
-if test "x$ac_cv_lib_nsl_gethostbyname" = xyes
-then :
- LIBS="$LIBS -lnsl"
-fi
-
-fi
-
-
- # TEA specific: Don't perform the eval of the libraries here because
- # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS
-
- TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}'
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5
-printf %s "checking dirent.h... " >&6; }
-if test ${tcl_cv_dirent_h+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <sys/types.h>
-#include <dirent.h>
-int
-main (void)
-{
-
-#ifndef _POSIX_SOURCE
-# ifdef __Lynx__
- /*
- * Generate compilation error to make the test fail: Lynx headers
- * are only valid if really in the POSIX environment.
- */
-
- missing_procedure();
-# endif
-#endif
-DIR *d;
-struct dirent *entryPtr;
-char *p;
-d = opendir("foobar");
-entryPtr = readdir(d);
-p = entryPtr->d_name;
-closedir(d);
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- tcl_cv_dirent_h=yes
-else $as_nop
- tcl_cv_dirent_h=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5
-printf "%s\n" "$tcl_cv_dirent_h" >&6; }
-
- if test $tcl_cv_dirent_h = no; then
-
-printf "%s\n" "#define NO_DIRENT_H 1" >>confdefs.h
-
- fi
-
- # TEA specific:
- ac_fn_c_check_header_compile "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default"
-if test "x$ac_cv_header_errno_h" = xyes
-then :
-
-else $as_nop
-
-printf "%s\n" "#define NO_ERRNO_H 1" >>confdefs.h
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default"
-if test "x$ac_cv_header_float_h" = xyes
-then :
-
-else $as_nop
-
-printf "%s\n" "#define NO_FLOAT_H 1" >>confdefs.h
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default"
-if test "x$ac_cv_header_values_h" = xyes
-then :
-
-else $as_nop
-
-printf "%s\n" "#define NO_VALUES_H 1" >>confdefs.h
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
-if test "x$ac_cv_header_limits_h" = xyes
-then :
-
-printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h
-
-else $as_nop
-
-printf "%s\n" "#define NO_LIMITS_H 1" >>confdefs.h
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes
-then :
- tcl_ok=1
-else $as_nop
- tcl_ok=0
-fi
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "strtol" >/dev/null 2>&1
-then :
-
-else $as_nop
- tcl_ok=0
-fi
-rm -rf conftest*
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "strtoul" >/dev/null 2>&1
-then :
-
-else $as_nop
- tcl_ok=0
-fi
-rm -rf conftest*
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "strtod" >/dev/null 2>&1
-then :
-
-else $as_nop
- tcl_ok=0
-fi
-rm -rf conftest*
-
- if test $tcl_ok = 0; then
-
-printf "%s\n" "#define NO_STDLIB_H 1" >>confdefs.h
-
- fi
- ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
-if test "x$ac_cv_header_string_h" = xyes
-then :
- tcl_ok=1
-else $as_nop
- tcl_ok=0
-fi
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "strstr" >/dev/null 2>&1
-then :
-
-else $as_nop
- tcl_ok=0
-fi
-rm -rf conftest*
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "strerror" >/dev/null 2>&1
-then :
-
-else $as_nop
- tcl_ok=0
-fi
-rm -rf conftest*
-
-
- # See also memmove check below for a place where NO_STRING_H can be
- # set and why.
-
- if test $tcl_ok = 0; then
-
-printf "%s\n" "#define NO_STRING_H 1" >>confdefs.h
-
- fi
-
- ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_wait_h" = xyes
-then :
-
-else $as_nop
-
-printf "%s\n" "#define NO_SYS_WAIT_H 1" >>confdefs.h
-
-fi
-
- ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
-if test "x$ac_cv_header_dlfcn_h" = xyes
-then :
-
-else $as_nop
-
-printf "%s\n" "#define NO_DLFCN_H 1" >>confdefs.h
-
-fi
-
-
- # OS/390 lacks sys/param.h (and doesn't need it, by chance).
- ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_param_h" = xyes
-then :
- printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h
-
-fi
-
-
- # Let the user call this, because if it triggers, they will
- # need a compat/strtod.c that is correct. Users can also
- # use Tcl_GetDouble(FromObj) instead.
- #TEA_BUGGY_STRTOD
- fi
#-----------------------------------------------------------------------
@@ -5980,7 +5381,7 @@ fi
- vars="-I\"`\${CYGPATH} \${srcdir}/generic`\""
+ vars=""
for i in $vars; do
PKG_INCLUDES="$PKG_INCLUDES $i"
done
@@ -5991,7 +5392,7 @@ fi
for i in $vars; do
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
# Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'`
+ i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
fi
PKG_LIBS="$PKG_LIBS $i"
done
@@ -6002,6 +5403,14 @@ fi
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_FTS4=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_FTS5=1"
+
+
+
PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_3_SUFFIX_ONLY=1"
@@ -6010,6 +5419,30 @@ fi
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_GEOPOLY=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DESERIALIZE=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DBPAGE_VTAB=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_BYTECODE_VTAB=1"
+
+
+
+ PKG_CFLAGS="$PKG_CFLAGS -DSQLITE_ENABLE_DBSTAT_VTAB=1"
+
+
+
vars=""
for i in $vars; do
# check for existence - allows for generic/win/unix VPATH
@@ -6113,6 +5546,31 @@ fi
#--------------------------------------------------------------------
# __CHANGE__
+#
+# You can add more files to clean if your extension creates any extra
+# files by extending CLEANFILES.
+# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
+# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
+#
+# A few miscellaneous platform-specific items:
+# TEA_ADD_* any platform specific compiler/build info here.
+#--------------------------------------------------------------------
+
+#CLEANFILES="$CLEANFILES pkgIndex.tcl"
+if test "${TEA_PLATFORM}" = "windows" ; then
+ # Ensure no empty if clauses
+ :
+ #TEA_ADD_SOURCES([win/winFile.c])
+ #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
+else
+ # Ensure no empty else clauses
+ :
+ #TEA_ADD_SOURCES([unix/unixFile.c])
+ #TEA_ADD_LIBS([-lsuperfly])
+fi
+
+#--------------------------------------------------------------------
+# __CHANGE__
# Choose which headers you need. Extension authors should try very
# hard to only rely on the Tcl public header files. Internal headers
# contain private data structures and are subject to change without
@@ -6524,18 +5982,6 @@ printf "%s\n" "$as_me: WARNING:
that IS thread-enabled. It is recommended to use --enable-threads." >&2;}
fi
;;
- *)
- if test "${TCL_THREADS}" = "1"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING:
- --enable-threads requested, but building against a Tcl that is NOT
- thread-enabled. This is an OK configuration that will also run in
- a thread-enabled core." >&5
-printf "%s\n" "$as_me: WARNING:
- --enable-threads requested, but building against a Tcl that is NOT
- thread-enabled. This is an OK configuration that will also run in
- a thread-enabled core." >&2;}
- fi
- ;;
esac
@@ -6550,7 +5996,7 @@ printf "%s\n" "#define SQLITE_THREADSAFE 1" >>confdefs.h
for i in $vars; do
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
# Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'`
+ i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
fi
PKG_LIBS="$PKG_LIBS $i"
done
@@ -6573,23 +6019,41 @@ printf %s "checking how to build libraries... " >&6; }
# Check whether --enable-shared was given.
if test ${enable_shared+y}
then :
- enableval=$enable_shared; tcl_ok=$enableval
+ enableval=$enable_shared; shared_ok=$enableval
else $as_nop
- tcl_ok=yes
+ shared_ok=yes
fi
if test "${enable_shared+set}" = set; then
enableval="$enable_shared"
- tcl_ok=$enableval
+ shared_ok=$enableval
else
- tcl_ok=yes
+ shared_ok=yes
+ fi
+
+ # Check whether --enable-stubs was given.
+if test ${enable_stubs+y}
+then :
+ enableval=$enable_stubs; stubs_ok=$enableval
+else $as_nop
+ stubs_ok=yes
+fi
+
+
+ if test "${enable_stubs+set}" = set; then
+ enableval="$enable_stubs"
+ stubs_ok=$enableval
+ else
+ stubs_ok=yes
fi
- if test "$tcl_ok" = "yes" ; then
+ # Stubs are always enabled for shared builds
+ if test "$shared_ok" = "yes" ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5
printf "%s\n" "shared" >&6; }
SHARED_BUILD=1
+ STUBS_BUILD=1
else
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5
printf "%s\n" "static" >&6; }
@@ -6597,10 +6061,30 @@ printf "%s\n" "static" >&6; }
printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h
+ if test "$stubs_ok" = "yes" ; then
+ STUBS_BUILD=1
+ else
+ STUBS_BUILD=0
+ fi
+ fi
+ if test "${STUBS_BUILD}" = "1" ; then
+
+printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h
+
+
+printf "%s\n" "#define USE_TCLOO_STUBS 1" >>confdefs.h
+
+ if test "${TEA_WINDOWINGSYSTEM}" != ""; then
+
+printf "%s\n" "#define USE_TK_STUBS 1" >>confdefs.h
+
+ fi
fi
+
+
#--------------------------------------------------------------------
# This macro figures out what flags to use with the compiler/linker
# when building shared/static debug/optimized objects. This information
@@ -6810,26 +6294,6 @@ fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5
printf "%s\n" "$doRpath" >&6; }
- # TEA specific: Cross-compiling options for Windows/CE builds?
-
- if test "${TEA_PLATFORM}" = windows
-then :
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5
-printf %s "checking if Windows/CE build is requested... " >&6; }
- # Check whether --enable-wince was given.
-if test ${enable_wince+y}
-then :
- enableval=$enable_wince; doWince=$enableval
-else $as_nop
- doWince=no
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5
-printf "%s\n" "$doWince" >&6; }
-
-fi
-
# Set the variable "system" to hold the name and version number
# for the system.
@@ -6854,6 +6318,9 @@ printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;}
if test "`uname -s`" = "AIX" ; then
tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
fi
+ if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
+ tcl_cv_sys_version=NetBSD-Debian
+ fi
fi
fi
@@ -7002,164 +6469,26 @@ fi
LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
if test "x$SHLIB_VERSION" = x
then :
- SHLIB_VERSION="1.0"
+ SHLIB_VERSION=""
+else $as_nop
+ SHLIB_VERSION=".$SHLIB_VERSION"
fi
case $system in
# TEA specific:
windows)
- # This is a 2-stage check to make sure we have the 64-bit SDK
- # We have to know where the SDK is installed.
- # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs
- # MACHINE is IX86 for LINK, but this is used by the manifest,
- # which requires x86|amd64|ia64.
MACHINE="X86"
if test "$do64bit" != "no" ; then
- if test "x${MSSDK}x" = "xx" ; then
- MSSDK="C:/Progra~1/Microsoft Platform SDK"
- fi
- MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'`
- PATH64=""
case "$do64bit" in
amd64|x64|yes)
MACHINE="AMD64" ; # default to AMD64 64-bit build
- PATH64="${MSSDK}/Bin/Win64/x86/AMD64"
+ ;;
+ arm64|aarch64)
+ MACHINE="ARM64"
;;
ia64)
MACHINE="IA64"
- PATH64="${MSSDK}/Bin/Win64"
;;
esac
- if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5
-printf "%s\n" "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5
-printf "%s\n" "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;}
- do64bit="no"
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5
-printf "%s\n" " Using 64-bit $MACHINE mode" >&6; }
- do64bit_ok="yes"
- fi
- fi
-
- if test "$doWince" != "no" ; then
- if test "$do64bit" != "no" ; then
- as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5
- fi
- if test "$GCC" = "yes" ; then
- as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5
- fi
-
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-celib
-
- if test x"${no_celib}" = x ; then
- # we reset no_celib in case something fails here
- no_celib=true
-
-# Check whether --with-celib was given.
-if test ${with_celib+y}
-then :
- withval=$with_celib; with_celibconfig=${withval}
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5
-printf %s "checking for Windows/CE celib directory... " >&6; }
- if test ${ac_cv_c_celibconfig+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # First check to see if --with-celibconfig was specified.
- if test x"${with_celibconfig}" != x ; then
- if test -d "${with_celibconfig}/inc" ; then
- ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)`
- else
- as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5
- fi
- fi
-
- # then check for a celib library
- if test x"${ac_cv_c_celibconfig}" = x ; then
- for i in \
- ../celib-palm-3.0 \
- ../celib \
- ../../celib-palm-3.0 \
- ../../celib \
- `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \
- ${srcdir}/../celib-palm-3.0 \
- ${srcdir}/../celib \
- `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \
- ; do
- if test -d "$i/inc" ; then
- ac_cv_c_celibconfig=`(cd $i; pwd)`
- break
- fi
- done
- fi
-
-fi
-
- if test x"${ac_cv_c_celibconfig}" = x ; then
- as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5
- else
- no_celib=
- CELIB_DIR=${ac_cv_c_celibconfig}
- CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'`
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5
-printf "%s\n" "found $CELIB_DIR" >&6; }
- fi
- fi
-
- # Set defaults for common evc4/PPC2003 setup
- # Currently Tcl requires 300+, possibly 420+ for sockets
- CEVERSION=420; # could be 211 300 301 400 420 ...
- TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ...
- ARCH=ARM; # could be ARM MIPS X86EM ...
- PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002"
- if test "$doWince" != "yes"; then
- # If !yes then the user specified something
- # Reset ARCH to allow user to skip specifying it
- ARCH=
- eval `echo $doWince | awk -F, '{ \
- if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \
- if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \
- if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \
- if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \
- if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \
- }'`
- if test "x${ARCH}" = "x" ; then
- ARCH=$TARGETCPU;
- fi
- fi
- OSVERSION=WCE$CEVERSION;
- if test "x${WCEROOT}" = "x" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0"
- if test ! -d "${WCEROOT}" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded Tools"
- fi
- fi
- if test "x${SDKROOT}" = "x" ; then
- SDKROOT="C:/Program Files/Windows CE Tools"
- if test ! -d "${SDKROOT}" ; then
- SDKROOT="C:/Windows CE Tools"
- fi
- fi
- WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'`
- SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'`
- if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \
- -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then
- as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5
- doWince="no"
- else
- # We could PATH_NOSPACE these, but that's not important,
- # as long as we quote them when used.
- CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include"
- if test -d "${CEINCLUDE}/${TARGETCPU}" ; then
- CEINCLUDE="${CEINCLUDE}/${TARGETCPU}"
- fi
- CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"
- fi
fi
if test "$GCC" != "yes" ; then
@@ -7168,14 +6497,30 @@ printf "%s\n" "found $CELIB_DIR" >&6; }
else
runtime=-MD
fi
+ case "x`echo \${VisualStudioVersion}`" in
+ x1[4-9]*)
+ lflags="${lflags} -nodefaultlib:libucrt.lib"
+
+ vars="ucrt.lib"
+ for i in $vars; do
+ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
+ # Convert foo.lib to -lfoo for GCC. No-op if not *.lib
+ i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
+ fi
+ PKG_LIBS="$PKG_LIBS $i"
+ done
+
+
+ ;;
+ *)
+ ;;
+ esac
if test "$do64bit" != "no" ; then
- # All this magic is necessary for the Win64 SDK RC1 - hobbs
- CC="\"${PATH64}/cl.exe\""
- CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\""
- RC="\"${MSSDK}/bin/rc.exe\""
- lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
- LINKBIN="\"${PATH64}/link.exe\""
+ CC="cl.exe"
+ RC="rc.exe"
+ lflags="${lflags} -nologo -MACHINE:${MACHINE} "
+ LINKBIN="link.exe"
CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
# Avoid 'unresolved external symbol __security_cookie'
@@ -7185,47 +6530,15 @@ printf "%s\n" "found $CELIB_DIR" >&6; }
for i in $vars; do
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
# Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'`
+ i=`echo "$i" | sed -e 's/^\([^-].*\)\.[lL][iI][bB]$/-l\1/'`
fi
PKG_LIBS="$PKG_LIBS $i"
done
- elif test "$doWince" != "no" ; then
- CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin"
- if test "${TARGETCPU}" = "X86"; then
- CC="\"${CEBINROOT}/cl.exe\""
- else
- CC="\"${CEBINROOT}/cl${ARCH}.exe\""
- fi
- CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\""
- RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\""
- arch=`echo ${ARCH} | awk '{print tolower($0)}'`
- defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS"
- if test "${SHARED_BUILD}" = "1" ; then
- # Static CE builds require static celib as well
- defs="${defs} _DLL"
- fi
- for i in $defs ; do
-
-printf "%s\n" "#define $i 1" >>confdefs.h
-
- done
-
-printf "%s\n" "#define _WIN32_WCE $CEVERSION" >>confdefs.h
-
-
-printf "%s\n" "#define UNDER_CE $CEVERSION" >>confdefs.h
-
- CFLAGS_DEBUG="-nologo -Zi -Od"
- CFLAGS_OPTIMIZE="-nologo -Ox"
- lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'`
- lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo"
- LINKBIN="\"${CEBINROOT}/link.exe\""
-
else
RC="rc"
- lflags="-nologo"
+ lflags="${lflags} -nologo"
LINKBIN="link"
CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
@@ -7378,14 +6691,21 @@ printf "%s\n" "$ac_cv_cross" >&6; }
if test "$ac_cv_cross" = "yes"; then
case "$do64bit" in
amd64|x64|yes)
- CC="x86_64-w64-mingw32-gcc"
+ CC="x86_64-w64-mingw32-${CC}"
LD="x86_64-w64-mingw32-ld"
AR="x86_64-w64-mingw32-ar"
RANLIB="x86_64-w64-mingw32-ranlib"
RC="x86_64-w64-mingw32-windres"
;;
+ arm64|aarch64)
+ CC="aarch64-w64-mingw32-clang"
+ LD="aarch64-w64-mingw32-ld"
+ AR="aarch64-w64-mingw32-ar"
+ RANLIB="aarch64-w64-mingw32-ranlib"
+ RC="aarch64-w64-mingw32-windres"
+ ;;
*)
- CC="i686-w64-mingw32-gcc"
+ CC="i686-w64-mingw32-${CC}"
LD="i686-w64-mingw32-ld"
AR="i686-w64-mingw32-ar"
RANLIB="i686-w64-mingw32-ranlib"
@@ -7407,13 +6727,8 @@ printf "%s\n" "$ac_cv_cross" >&6; }
# This essentially turns it all on.
LDFLAGS_DEBUG="-debug -debugtype:cv"
LDFLAGS_OPTIMIZE="-release"
- if test "$doWince" != "no" ; then
- LDFLAGS_CONSOLE="-link ${lflags}"
- LDFLAGS_WINDOW=${LDFLAGS_CONSOLE}
- else
- LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
- LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
- fi
+ LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
+ LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
fi
SHLIB_SUFFIX=".dll"
@@ -7422,7 +6737,7 @@ printf "%s\n" "$ac_cv_cross" >&6; }
TCL_LIB_VERSIONS_OK=nodots
;;
AIX-*)
- if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"
+ if test "$GCC" != "yes"
then :
# AIX requires the _r compiler when gcc isn't being used
@@ -7476,14 +6791,14 @@ then :
if test "$GCC" = yes
then :
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
else $as_nop
- CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"'
fi
- LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
else $as_nop
@@ -7499,7 +6814,7 @@ else $as_nop
fi
SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}"
- CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
fi
@@ -7555,6 +6870,13 @@ then :
fi
;;
+ BSD/OS-2.1*|BSD/OS-3*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="shlicc -r"
+ SHLIB_SUFFIX=".so"
+ CC_SEARCH_FLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
BSD/OS-4.*)
SHLIB_CFLAGS="-export-dynamic -fPIC"
SHLIB_LD='${CC} -shared'
@@ -7567,16 +6889,25 @@ fi
SHLIB_CFLAGS=""
SHLIB_LD='${CC} -shared'
SHLIB_SUFFIX=".dll"
+ SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$@.a"
EXEEXT=".exe"
do64bit_ok=yes
CC_SEARCH_FLAGS=""
LD_SEARCH_FLAGS=""
;;
+ dgux*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD='${CC} -G'
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ CC_SEARCH_FLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
Haiku*)
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5
printf %s "checking for inet_ntoa in -lnetwork... " >&6; }
if test ${ac_cv_lib_network_inet_ntoa+y}
@@ -7631,10 +6962,6 @@ printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h
then :
SHLIB_SUFFIX=".so"
- # Use newer C++ library for C++ extensions
- #if test "$GCC" != "yes" ; then
- # CPPFLAGS="-AA"
- #fi
else $as_nop
@@ -7686,9 +7013,11 @@ fi
if test "$tcl_ok" = yes
then :
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
- LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.'
+ CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
+ LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
LD_LIBRARY_PATH_VAR="SHLIB_PATH"
fi
@@ -7701,10 +7030,6 @@ then :
else $as_nop
CFLAGS="$CFLAGS -z"
- # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc
- #CFLAGS="$CFLAGS +DAportable"
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
fi
@@ -7723,7 +7048,7 @@ then :
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
;;
@@ -7742,6 +7067,79 @@ else $as_nop
fi
fi ;;
+ HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
+ SHLIB_SUFFIX=".sl"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+printf %s "checking for shl_load in -ldld... " >&6; }
+if test ${ac_cv_lib_dld_shl_load+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main (void)
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_lib_dld_shl_load=yes
+else $as_nop
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes
+then :
+ tcl_ok=yes
+else $as_nop
+ tcl_ok=no
+fi
+
+ if test "$tcl_ok" = yes
+then :
+
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS=""
+ LDFLAGS="$LDFLAGS -Wl,-E"
+ CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
+ LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
+ LD_LIBRARY_PATH_VAR="SHLIB_PATH"
+
+fi ;;
+ IRIX-5.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -shared -rdata_shared"
+ SHLIB_SUFFIX=".so"
+ case " $LIBOBJS " in
+ *" mkstemp.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext"
+ ;;
+esac
+
+ if test $doRpath = yes
+then :
+
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
+fi
+ ;;
IRIX-6.*)
SHLIB_CFLAGS=""
SHLIB_LD="ld -n32 -shared -rdata_shared"
@@ -7749,8 +7147,8 @@ fi ;;
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
fi
if test "$GCC" = yes
then :
@@ -7780,8 +7178,8 @@ fi
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'
fi
# Check to enable 64-bit flags for compiler/linker
@@ -7806,7 +7204,7 @@ fi
fi
;;
- Linux*|GNU*|NetBSD-Debian)
+ Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*)
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
@@ -7814,12 +7212,26 @@ fi
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
# TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared'
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
+
+ case $system in
+ DragonFly-*|FreeBSD-*)
+ if test "${TCL_THREADS}" = "1"
+then :
+
+ # The -pthread needs to go in the LDFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
+fi
+ ;;
+ esac
+
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
if test "`uname -m`" = "alpha"
@@ -7891,49 +7303,35 @@ fi
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi
;;
OpenBSD-*)
arch=`arch -s`
case "$arch" in
- vax)
- SHLIB_SUFFIX=""
- SHARED_LIB_SUFFIX=""
- LDFLAGS=""
- ;;
- *)
+ alpha|sparc64)
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
- SHLIB_SUFFIX=".so"
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
-fi
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
- LDFLAGS="-Wl,-export-dynamic"
- ;;
- esac
- case "$arch" in
- vax)
- CFLAGS_OPTIMIZE="-O1"
;;
*)
- CFLAGS_OPTIMIZE="-O2"
+ SHLIB_CFLAGS="-fpic"
;;
esac
- if test "${TCL_THREADS}" = "1"
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
+ SHLIB_SUFFIX=".so"
+ if test $doRpath = yes
then :
- # On OpenBSD: Compile with -pthread
- # Don't link with -lpthread
- LIBS=`echo $LIBS | sed s/-lpthread//`
- CFLAGS="$CFLAGS -pthread"
-
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi
+ LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
+ LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
+ CFLAGS_OPTIMIZE="-O2"
+ # On OpenBSD: Compile with -pthread
+ # Don't link with -lpthread
+ LIBS=`echo $LIBS | sed s/-lpthread//`
+ CFLAGS="$CFLAGS -pthread"
# OpenBSD doesn't do version numbers with dots.
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
TCL_LIB_VERSIONS_OK=nodots
@@ -7941,56 +7339,19 @@ fi
NetBSD-*)
# NetBSD has ELF and can use 'cc -shared' to build shared libs
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
SHLIB_SUFFIX=".so"
LDFLAGS="$LDFLAGS -export-dynamic"
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- if test "${TCL_THREADS}" = "1"
-then :
-
- # The -pthread needs to go in the CFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
-
-fi
- ;;
- FreeBSD-*)
- # This configuration from FreeBSD Ports.
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD="${CC} -shared"
- TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$@"
- TK_SHLIB_LD_EXTRAS="-Wl,-soname,\$@"
- SHLIB_SUFFIX=".so"
- LDFLAGS=""
- if test $doRpath = yes
-then :
-
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
-fi
- if test "${TCL_THREADS}" = "1"
-then :
-
- # The -pthread needs to go in the LDFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LDFLAGS="$LDFLAGS $PTHREAD_LIBS"
-fi
- case $system in
- FreeBSD-3.*)
- # Version numbers are dot-stripped by system policy.
- TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .`
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- esac
+ # The -pthread needs to go in the CFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ CFLAGS="$CFLAGS -pthread"
+ LDFLAGS="$LDFLAGS -pthread"
;;
Darwin-*)
CFLAGS_OPTIMIZE="-Os"
@@ -8148,13 +7509,6 @@ fi
vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
SHLIB_SUFFIX=".dylib"
- # Don't use -prebind when building for Mac OS X 10.4 or later only:
- if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \
- "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4
-then :
-
- LDFLAGS="$LDFLAGS -prebind"
-fi
LDFLAGS="$LDFLAGS -headerpad_max_install_names"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5
printf %s "checking if ld accepts -search_paths_first flag... " >&6; }
@@ -8332,7 +7686,7 @@ fi
if test $doRpath = yes
then :
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi
if test "$GCC" = yes
@@ -8343,23 +7697,18 @@ else $as_nop
CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"
fi
# see pthread_intro(3) for pthread support on osf1, k.furukawa
- if test "${TCL_THREADS}" = 1
-then :
-
- CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
- CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
- LIBS=`echo $LIBS | sed s/-lpthreads//`
- if test "$GCC" = yes
+ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
+ CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
+ LIBS=`echo $LIBS | sed s/-lpthreads//`
+ if test "$GCC" = yes
then :
- LIBS="$LIBS -lpthread -lmach -lexc"
+ LIBS="$LIBS -lpthread -lmach -lexc"
else $as_nop
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
-
-fi
+ CFLAGS="$CFLAGS -pthread"
+ LDFLAGS="$LDFLAGS -pthread"
fi
;;
@@ -8411,13 +7760,13 @@ printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
then :
SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
else $as_nop
SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
fi
@@ -8525,7 +7874,7 @@ fi
then :
SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
if test "$do64bit_ok" = yes
then :
@@ -8565,8 +7914,8 @@ else $as_nop
*)
SHLIB_LD='/usr/ccs/bin/ld -G -z text';;
esac
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
fi
;;
@@ -8644,9 +7993,9 @@ then :
case $system in
AIX-*) ;;
BSD/OS*) ;;
- CYGWIN_*|MINGW32_*) ;;
+ CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;;
IRIX*) ;;
- NetBSD-*|FreeBSD-*|OpenBSD-*) ;;
+ NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
Darwin-*) ;;
SCO_SV-3.2*) ;;
windows) ;;
@@ -8861,6 +8210,17 @@ printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h
fi
+ ac_fn_c_check_header_compile "$LINENO" "stdbool.h" "ac_cv_header_stdbool_h" "$ac_includes_default"
+if test "x$ac_cv_header_stdbool_h" = xyes
+then :
+
+printf "%s\n" "#define HAVE_STDBOOL_H 1" >>confdefs.h
+
+fi
+
+
+
+
@@ -9065,7 +8425,7 @@ else $as_nop
tcl_type_64bit="long long"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- # See if we should use long anyway Note that we substitute in the
+ # See if we could use long anyway Note that we substitute in the
# type that is our current guess for a 64-bit type inside this check
# program, so it should be modified only carefully...
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -9092,8 +8452,8 @@ fi
printf "%s\n" "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using long" >&5
-printf "%s\n" "using long" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
elif test "${tcl_cv_type_64bit}" = "__int64" \
-a "${TEA_PLATFORM}" = "windows" ; then
# TEA specific: We actually want to use the default tcl.h checks in
@@ -9143,6 +8503,42 @@ printf "%s\n" "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h
fi
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for DIR64" >&5
+printf %s "checking for DIR64... " >&6; }
+if test ${tcl_cv_DIR64+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <dirent.h>
+int
+main (void)
+{
+struct dirent64 *p; DIR64 d = opendir64(".");
+ p = readdir64(d); rewinddir64(d); closedir64(d);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ tcl_cv_DIR64=yes
+else $as_nop
+ tcl_cv_DIR64=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_DIR64" >&5
+printf "%s\n" "$tcl_cv_DIR64" >&6; }
+ if test "x${tcl_cv_DIR64}" = "xyes" ; then
+
+printf "%s\n" "#define HAVE_DIR64 1" >>confdefs.h
+
+ fi
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5
printf %s "checking for struct stat64... " >&6; }
if test ${tcl_cv_struct_stat64+y}
@@ -9251,12 +8647,14 @@ else $as_nop
tcl_ok=no
fi
- DBGX=""
if test "$tcl_ok" = "no"; then
CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG"
LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
+
+printf "%s\n" "#define TCL_CFG_OPTIMIZED 1" >>confdefs.h
+
else
CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
@@ -9265,11 +8663,6 @@ printf "%s\n" "no" >&6; }
printf "%s\n" "yes (standard debugging)" >&6; }
fi
fi
- # TEA specific:
- if test "${TEA_PLATFORM}" != "windows" ; then
- LDFLAGS_DEFAULT="${LDFLAGS}"
- fi
-
@@ -9291,209 +8684,158 @@ printf "%s\n" "enabled $tcl_ok debugging" >&6; }
#--------------------------------------------------------------------
-# Everyone should be linking against the Tcl stub library. If you
-# can't for some reason, remove this definition. If you aren't using
-# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
-# link against the non-stubbed Tcl library. Add Tk too if necessary.
-#--------------------------------------------------------------------
-
-
-printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h
-
-#AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
-
-
-#--------------------------------------------------------------------
-# Redefine fdatasync as fsync on systems that lack fdatasync
+# This macro generates a line to use when building a library. It
+# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
+# and TEA_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------
-#
-#AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync))
-# Check for library functions that SQLite can optionally use.
-ac_fn_c_check_func "$LINENO" "fdatasync" "ac_cv_func_fdatasync"
-if test "x$ac_cv_func_fdatasync" = xyes
-then :
- printf "%s\n" "#define HAVE_FDATASYNC 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep"
-if test "x$ac_cv_func_usleep" = xyes
-then :
- printf "%s\n" "#define HAVE_USLEEP 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "fullfsync" "ac_cv_func_fullfsync"
-if test "x$ac_cv_func_fullfsync" = xyes
-then :
- printf "%s\n" "#define HAVE_FULLFSYNC 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
-if test "x$ac_cv_func_localtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r"
-if test "x$ac_cv_func_gmtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
-printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
-if test ${ac_cv_c_undeclared_builtin_options+y}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+printf %s "checking for grep that handles long lines and -e... " >&6; }
+if test ${ac_cv_path_GREP+y}
then :
printf %s "(cached) " >&6
else $as_nop
- ac_save_CFLAGS=$CFLAGS
- ac_cv_c_undeclared_builtin_options='cannot detect'
- for ac_arg in '' -fno-builtin; do
- CFLAGS="$ac_save_CFLAGS $ac_arg"
- # This test program should *not* compile successfully.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-(void) strchr;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- # This test program should compile successfully.
- # No library function is consistently available on
- # freestanding implementations, so test against a dummy
- # declaration. Include always-available headers on the
- # off chance that they somehow elicit warnings.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <float.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stddef.h>
-extern void ac_decl (int, char *);
-
-int
-main (void)
-{
-(void) ac_decl (0, (char *) 0);
- (void) ac_decl;
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in grep ggrep
+ do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- if test x"$ac_arg" = x
-then :
- ac_cv_c_undeclared_builtin_options='none needed'
-else $as_nop
- ac_cv_c_undeclared_builtin_options=$ac_arg
-fi
- break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ $ac_path_GREP_found && break 3
done
- CFLAGS=$ac_save_CFLAGS
-
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
-printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
- case $ac_cv_c_undeclared_builtin_options in #(
- 'cannot detect') :
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot make $CC report undeclared builtins
-See \`config.log' for more details" "$LINENO" 5; } ;; #(
- 'none needed') :
- ac_c_undeclared_builtin_options='' ;; #(
- *) :
- ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
-esac
-ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS"
-if test "x$ac_cv_have_decl_strerror_r" = xyes
-then :
- ac_have_decl=1
-else $as_nop
- ac_have_decl=0
fi
-printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h
-
-
-if test $ac_cv_have_decl_strerror_r = yes; then
- # For backward compatibility's sake, define HAVE_STRERROR_R.
- # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well
- # as AC_CHECK_DECLS_ONCE.)
-
-printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+printf "%s\n" "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
-printf %s "checking whether strerror_r returns char *... " >&6; }
-if test ${ac_cv_func_strerror_r_char_p+y}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+printf %s "checking for egrep... " >&6; }
+if test ${ac_cv_path_EGREP+y}
then :
printf %s "(cached) " >&6
else $as_nop
-
- ac_cv_func_strerror_r_char_p=no
- if test $ac_cv_have_decl_strerror_r = yes; then
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-int
-main (void)
-{
-
- char buf[100];
- char x = *strerror_r (0, buf, sizeof buf);
- char *p = strerror_r (0, buf, sizeof buf);
- return !p || x;
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_func_strerror_r_char_p=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_prog in egrep
+ do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ printf %s 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ printf "%s\n" 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
-printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; }
-if test $ac_cv_func_strerror_r_char_p = yes; then
-
-printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h
+ fi
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+printf "%s\n" "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
-#--------------------------------------------------------------------
-# This macro generates a line to use when building a library. It
-# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
-# and TEA_LOAD_TCLCONFIG macros above.
-#--------------------------------------------------------------------
-
-
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -9520,7 +8862,7 @@ rm -rf conftest*
MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\$@ \$(PKG_STUB_OBJECTS)"
else
MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)"
fi
@@ -9536,6 +8878,13 @@ rm -rf conftest*
# substituted. (@@@ Might not be necessary anymore)
#--------------------------------------------------------------------
+ PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}"
+ PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9"
+ if test "${TCL_MAJOR_VERSION}" -gt 8 ; then
+ PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}"
+ else
+ PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}"
+ fi
if test "${TEA_PLATFORM}" = "windows" ; then
if test "${SHARED_BUILD}" = "1" ; then
# We force the unresolved linking of symbols that are really in
@@ -9547,15 +8896,19 @@ rm -rf conftest*
if test "$GCC" = "yes"; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
fi
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
else
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
- PKG_LIB_FILE=lib${PKG_LIB_FILE}
+ PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX}
fi
+ eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
fi
@@ -9569,13 +8922,17 @@ rm -rf conftest*
if test x"${TK_BIN_DIR}" != x ; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}"
fi
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
RANLIB=:
else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
fi
# These are escaped so that only CFLAGS is picked up at configure time.
@@ -9608,16 +8965,24 @@ printf %s "checking for tclsh... " >&6; }
if test -f "${TCL_BIN_DIR}/Makefile" ; then
# tclConfig.sh is in Tcl build directory
if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}"
+ if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
+ fi
else
TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
fi
else
# tclConfig.sh is in install location
if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}"
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
else
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}"
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
fi
list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
`ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
@@ -9637,13 +9002,27 @@ printf "%s\n" "${TCLSH_PROG}" >&6; }
#TEA_PROG_WISH
#--------------------------------------------------------------------
-# Finally, substitute all of the various values into the Makefile.
-# You may alternatively have a special pkgIndex.tcl.in or other files
-# which require substituting th AC variables in. Include these here.
+# Setup a *Config.sh.in configuration file.
+#--------------------------------------------------------------------
+
+#TEA_EXPORT_CONFIG([sample])
+#AC_SUBST(SAMPLE_VAR)
+
+#--------------------------------------------------------------------
+# Specify files to substitute AC variables in. You may alternatively
+# have a special pkgIndex.tcl.in or other files which require
+# substituting the AC variables in. Include these here.
#--------------------------------------------------------------------
ac_config_files="$ac_config_files Makefile pkgIndex.tcl"
+#AC_CONFIG_FILES([sampleConfig.sh])
+
+#--------------------------------------------------------------------
+# Finally, substitute all of the various values into the files
+# specified with AC_CONFIG_FILES.
+#--------------------------------------------------------------------
+
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -10181,7 +9560,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by sqlite $as_me 3.39.3, which was
+This file was extended by sqlite $as_me 3.40.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -10236,7 +9615,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-sqlite config.status 3.39.3
+sqlite config.status 3.40.0
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff --git a/tea/configure.ac b/tea/configure.ac
index 551d4cacaba9..3e17b8b0be96 100644
--- a/tea/configure.ac
+++ b/tea/configure.ac
@@ -2,11 +2,9 @@
dnl This file is an input file used by the GNU "autoconf" program to
dnl generate the file "configure", which is run during Tcl installation
dnl to configure the system for the local environment.
-#
-# RCS: @(#) $Id: configure.in,v 1.43 2005/07/26 19:17:05 mdejong Exp $
#-----------------------------------------------------------------------
-# Sample configure.in for Tcl Extensions. The only places you should
+# Sample configure.ac for Tcl Extensions. The only places you should
# need to modify this file are marked by the string __CHANGE__
#-----------------------------------------------------------------------
@@ -17,9 +15,11 @@ dnl to configure the system for the local environment.
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided. These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
+# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
+# so that we create the export library with the dll.
#-----------------------------------------------------------------------
-AC_INIT([sqlite], [3.39.3])
+AC_INIT([sqlite],[3.40.0])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
@@ -27,7 +27,7 @@ AC_INIT([sqlite], [3.39.3])
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------
-TEA_INIT([3.9])
+TEA_INIT()
AC_CONFIG_AUX_DIR(tclconfig)
@@ -55,8 +55,8 @@ TEA_PREFIX
#-----------------------------------------------------------------------
# Standard compiler checks.
# This sets up CC by using the CC env var, or looks for gcc otherwise.
-# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create
-# the basic setup necessary to compile executables.
+# This also calls AC_PROG_CC and a few others to create the basic setup
+# necessary to compile executables.
#-----------------------------------------------------------------------
TEA_SETUP_COMPILER
@@ -73,11 +73,19 @@ TEA_SETUP_COMPILER
TEA_ADD_SOURCES([tclsqlite3.c])
TEA_ADD_HEADERS([])
-TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"])
+TEA_ADD_INCLUDES([])
TEA_ADD_LIBS([])
TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS4=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS5=1])
TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1])
TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_GEOPOLY=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_MATH_FUNCTIONS=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DESERIALIZE=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBPAGE_VTAB=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_BYTECODE_VTAB=1])
+TEA_ADD_CFLAGS([-DSQLITE_ENABLE_DBSTAT_VTAB=1])
TEA_ADD_STUB_SOURCES([])
TEA_ADD_TCL_SOURCES([])
@@ -101,6 +109,31 @@ fi
#--------------------------------------------------------------------
# __CHANGE__
+#
+# You can add more files to clean if your extension creates any extra
+# files by extending CLEANFILES.
+# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
+# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
+#
+# A few miscellaneous platform-specific items:
+# TEA_ADD_* any platform specific compiler/build info here.
+#--------------------------------------------------------------------
+
+#CLEANFILES="$CLEANFILES pkgIndex.tcl"
+if test "${TEA_PLATFORM}" = "windows" ; then
+ # Ensure no empty if clauses
+ :
+ #TEA_ADD_SOURCES([win/winFile.c])
+ #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
+else
+ # Ensure no empty else clauses
+ :
+ #TEA_ADD_SOURCES([unix/unixFile.c])
+ #TEA_ADD_LIBS([-lsuperfly])
+fi
+
+#--------------------------------------------------------------------
+# __CHANGE__
# Choose which headers you need. Extension authors should try very
# hard to only rely on the Tcl public header files. Internal headers
# contain private data structures and are subject to change without
@@ -152,28 +185,6 @@ TEA_CONFIG_CFLAGS
TEA_ENABLE_SYMBOLS
#--------------------------------------------------------------------
-# Everyone should be linking against the Tcl stub library. If you
-# can't for some reason, remove this definition. If you aren't using
-# stubs, you also need to modify the SHLIB_LD_LIBS setting below to
-# link against the non-stubbed Tcl library. Add Tk too if necessary.
-#--------------------------------------------------------------------
-
-AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
-#AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
-
-
-#--------------------------------------------------------------------
-# Redefine fdatasync as fsync on systems that lack fdatasync
-#--------------------------------------------------------------------
-#
-#AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync))
-# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
-
-AC_FUNC_STRERROR_R
-
-
-#--------------------------------------------------------------------
# This macro generates a line to use when building a library. It
# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
# and TEA_LOAD_TCLCONFIG macros above.
@@ -193,9 +204,24 @@ TEA_PROG_TCLSH
#TEA_PROG_WISH
#--------------------------------------------------------------------
-# Finally, substitute all of the various values into the Makefile.
-# You may alternatively have a special pkgIndex.tcl.in or other files
-# which require substituting th AC variables in. Include these here.
+# Setup a *Config.sh.in configuration file.
+#--------------------------------------------------------------------
+
+#TEA_EXPORT_CONFIG([sample])
+#AC_SUBST(SAMPLE_VAR)
+
+#--------------------------------------------------------------------
+# Specify files to substitute AC variables in. You may alternatively
+# have a special pkgIndex.tcl.in or other files which require
+# substituting the AC variables in. Include these here.
+#--------------------------------------------------------------------
+
+AC_CONFIG_FILES([Makefile pkgIndex.tcl])
+#AC_CONFIG_FILES([sampleConfig.sh])
+
+#--------------------------------------------------------------------
+# Finally, substitute all of the various values into the files
+# specified with AC_CONFIG_FILES.
#--------------------------------------------------------------------
-AC_OUTPUT([Makefile pkgIndex.tcl])
+AC_OUTPUT
diff --git a/tea/pkgIndex.tcl.in b/tea/pkgIndex.tcl.in
index bc585f73b300..f95f7d3893dd 100644
--- a/tea/pkgIndex.tcl.in
+++ b/tea/pkgIndex.tcl.in
@@ -1,7 +1,10 @@
+# -*- tcl -*-
+# Tcl package index file, version 1.1
#
-# Tcl package index file
-#
-# Note sqlite*3* init specifically
-#
-package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE@] Sqlite3]
+if {[package vsatisfies [package provide Tcl] 9.0-]} {
+ package ifneeded sqlite3 @PACKAGE_VERSION@ \
+ [list load [file join $dir @PKG_LIB_FILE9@] sqlite3]
+} else {
+ package ifneeded sqlite3 @PACKAGE_VERSION@ \
+ [list load [file join $dir @PKG_LIB_FILE8@] sqlite3]
+}
diff --git a/tea/tclconfig/tcl.m4 b/tea/tclconfig/tcl.m4
index 4b4bd1e88896..c83d660e184a 100644
--- a/tea/tclconfig/tcl.m4
+++ b/tea/tclconfig/tcl.m4
@@ -9,16 +9,13 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-AC_PREREQ(2.57)
-
-dnl TEA extensions pass us the version of TEA they think they
-dnl are compatible with (must be set in TEA_INIT below)
-dnl TEA_VERSION="3.9"
+AC_PREREQ([2.69])
# Possible values for key variables defined:
#
# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem')
# TEA_PLATFORM - windows unix
+# TEA_TK_EXTENSION - True if this is a Tk extension
#
#------------------------------------------------------------------------
@@ -53,9 +50,9 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
# we reset no_tcl in case something fails here
no_tcl=true
AC_ARG_WITH(tcl,
- AC_HELP_STRING([--with-tcl],
+ AS_HELP_STRING([--with-tcl],
[directory containing tcl configuration (tclConfig.sh)]),
- with_tclconfig="${withval}")
+ [with_tclconfig="${withval}"])
AC_MSG_CHECKING([for Tcl configuration])
AC_CACHE_VAL(ac_cv_c_tclconfig,[
@@ -107,7 +104,9 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
- `ls -d /System/Library/Frameworks 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \
+ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \
; do
if test -f "$i/Tcl.framework/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`"
@@ -136,10 +135,15 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
; do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i; pwd)`"
@@ -208,9 +212,9 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
# we reset no_tk in case something fails here
no_tk=true
AC_ARG_WITH(tk,
- AC_HELP_STRING([--with-tk],
+ AS_HELP_STRING([--with-tk],
[directory containing tk configuration (tkConfig.sh)]),
- with_tkconfig="${withval}")
+ [with_tkconfig="${withval}"])
AC_MSG_CHECKING([for Tk configuration])
AC_CACHE_VAL(ac_cv_c_tkconfig,[
@@ -262,7 +266,6 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
for i in `ls -d ~/Library/Frameworks 2>/dev/null` \
`ls -d /Library/Frameworks 2>/dev/null` \
`ls -d /Network/Library/Frameworks 2>/dev/null` \
- `ls -d /System/Library/Frameworks 2>/dev/null` \
; do
if test -f "$i/Tk.framework/tkConfig.sh" ; then
ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`"
@@ -278,8 +281,15 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
+ `ls -d /usr/lib/tk8.6 2>/dev/null` \
+ `ls -d /usr/lib/tk8.5 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
+ `ls -d /usr/local/lib/tk8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tk8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \
; do
if test -f "$i/tkConfig.sh" ; then
ac_cv_c_tkconfig="`(cd $i; pwd)`"
@@ -348,6 +358,8 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
# TCL_BIN_DIR
# TCL_SRC_DIR
# TCL_LIB_FILE
+# TCL_ZIP_FILE
+# TCL_ZIPFS_SUPPORT
#------------------------------------------------------------------------
AC_DEFUN([TEA_LOAD_TCLCONFIG], [
@@ -360,10 +372,6 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh])
fi
- # eval is required to do the TCL_DBGX substitution
- eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
- eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
-
# If the TCL_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TCL_LIB_SPEC will be set to the value
@@ -397,12 +405,6 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
esac
fi
- # eval is required to do the TCL_DBGX substitution
- eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
- eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
- eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
- eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
-
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_PATCH_LEVEL)
AC_SUBST(TCL_BIN_DIR)
@@ -418,13 +420,18 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
AC_MSG_CHECKING([platform])
hold_cc=$CC; CC="$TCL_CC"
- AC_TRY_COMPILE(,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
#ifdef _WIN32
#error win32
#endif
- ], TEA_PLATFORM="unix",
+ ]])],[
+ # first test we've already retrieved platform (cross-compile), fallback to unix otherwise:
+ TEA_PLATFORM="${TEA_PLATFORM-unix}"
+ CYGPATH=echo
+ ],[
TEA_PLATFORM="windows"
- )
+ AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
+ ])
CC=$hold_cc
AC_MSG_RESULT($TEA_PLATFORM)
@@ -473,10 +480,6 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh])
fi
- # eval is required to do the TK_DBGX substitution
- eval "TK_LIB_FILE=\"${TK_LIB_FILE}\""
- eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\""
-
# If the TK_BIN_DIR is the build directory (not the install directory),
# then set the common variable name to the value of the build variables.
# For example, the variable TK_LIB_SPEC will be set to the value
@@ -510,12 +513,6 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
esac
fi
- # eval is required to do the TK_DBGX substitution
- eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\""
- eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\""
- eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\""
- eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\""
-
# TEA specific: Ensure windowingsystem is defined
if test "${TEA_PLATFORM}" = "unix" ; then
case ${TK_DEFS} in
@@ -572,16 +569,24 @@ AC_DEFUN([TEA_PROG_TCLSH], [
if test -f "${TCL_BIN_DIR}/Makefile" ; then
# tclConfig.sh is in Tcl build directory
if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}"
+ if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
+ fi
else
TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
fi
else
# tclConfig.sh is in install location
if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}"
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
else
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}"
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
fi
list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
`ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
@@ -622,16 +627,24 @@ AC_DEFUN([TEA_PROG_WISH], [
if test -f "${TK_BIN_DIR}/Makefile" ; then
# tkConfig.sh is in Tk build directory
if test "${TEA_PLATFORM}" = "windows"; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}"
+ if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}"
+ fi
else
WISH_PROG="${TK_BIN_DIR}/wish"
fi
else
# tkConfig.sh is in install location
if test "${TEA_PLATFORM}" = "windows"; then
- WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}"
+ WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
else
- WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}"
+ WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}"
fi
list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \
`ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \
@@ -660,6 +673,7 @@ AC_DEFUN([TEA_PROG_WISH], [
#
# Adds the following arguments to configure:
# --enable-shared=yes|no
+# --enable-stubs=yes|no
#
# Defines the following vars:
# STATIC_BUILD Used for building import/export libraries
@@ -667,31 +681,63 @@ AC_DEFUN([TEA_PROG_WISH], [
#
# Sets the following vars:
# SHARED_BUILD Value of 1 or 0
+# STUBS_BUILD Value if 1 or 0
+# USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs
+# AND TEA_WINDOWING_SYSTEM != ""
#------------------------------------------------------------------------
-
AC_DEFUN([TEA_ENABLE_SHARED], [
AC_MSG_CHECKING([how to build libraries])
AC_ARG_ENABLE(shared,
- AC_HELP_STRING([--enable-shared],
+ AS_HELP_STRING([--enable-shared],
[build and link with shared libraries (default: on)]),
- [tcl_ok=$enableval], [tcl_ok=yes])
+ [shared_ok=$enableval], [shared_ok=yes])
if test "${enable_shared+set}" = set; then
enableval="$enable_shared"
- tcl_ok=$enableval
+ shared_ok=$enableval
else
- tcl_ok=yes
+ shared_ok=yes
+ fi
+
+ AC_ARG_ENABLE(stubs,
+ AS_HELP_STRING([--enable-stubs],
+ [build and link with stub libraries. Always true for shared builds (default: on)]),
+ [stubs_ok=$enableval], [stubs_ok=yes])
+
+ if test "${enable_stubs+set}" = set; then
+ enableval="$enable_stubs"
+ stubs_ok=$enableval
+ else
+ stubs_ok=yes
fi
- if test "$tcl_ok" = "yes" ; then
+ # Stubs are always enabled for shared builds
+ if test "$shared_ok" = "yes" ; then
AC_MSG_RESULT([shared])
SHARED_BUILD=1
+ STUBS_BUILD=1
else
AC_MSG_RESULT([static])
SHARED_BUILD=0
- AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?])
+ AC_DEFINE(STATIC_BUILD, 1, [This a static build])
+ if test "$stubs_ok" = "yes" ; then
+ STUBS_BUILD=1
+ else
+ STUBS_BUILD=0
+ fi
+ fi
+ if test "${STUBS_BUILD}" = "1" ; then
+ AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
+ AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs])
+ if test "${TEA_WINDOWINGSYSTEM}" != ""; then
+ AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
+ fi
fi
+
AC_SUBST(SHARED_BUILD)
+ AC_SUBST(STUBS_BUILD)
])
#------------------------------------------------------------------------
@@ -728,8 +774,8 @@ AC_DEFUN([TEA_ENABLE_SHARED], [
AC_DEFUN([TEA_ENABLE_THREADS], [
AC_ARG_ENABLE(threads,
- AC_HELP_STRING([--enable-threads],
- [build with threads]),
+ AS_HELP_STRING([--enable-threads],
+ [build with threads (default: on)]),
[tcl_ok=$enableval], [tcl_ok=yes])
if test "${enable_threads+set}" = set; then
@@ -813,14 +859,6 @@ AC_DEFUN([TEA_ENABLE_THREADS], [
that IS thread-enabled. It is recommended to use --enable-threads.])
fi
;;
- *)
- if test "${TCL_THREADS}" = "1"; then
- AC_MSG_WARN([
- --enable-threads requested, but building against a Tcl that is NOT
- thread-enabled. This is an OK configuration that will also run in
- a thread-enabled core.])
- fi
- ;;
esac
AC_SUBST(TCL_THREADS)
])
@@ -850,8 +888,6 @@ AC_DEFUN([TEA_ENABLE_THREADS], [
# Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false
# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true
# Sets to $(LDFLAGS_OPTIMIZE) if false
-# DBGX Formerly used as debug library extension;
-# always blank now.
#------------------------------------------------------------------------
AC_DEFUN([TEA_ENABLE_SYMBOLS], [
@@ -859,14 +895,14 @@ AC_DEFUN([TEA_ENABLE_SYMBOLS], [
AC_REQUIRE([TEA_CONFIG_CFLAGS])
AC_MSG_CHECKING([for build with symbols])
AC_ARG_ENABLE(symbols,
- AC_HELP_STRING([--enable-symbols],
+ AS_HELP_STRING([--enable-symbols],
[build with debugging symbols (default: off)]),
[tcl_ok=$enableval], [tcl_ok=no])
- DBGX=""
if test "$tcl_ok" = "no"; then
CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG"
LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}"
AC_MSG_RESULT([no])
+ AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?])
else
CFLAGS_DEFAULT="${CFLAGS_DEBUG}"
LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}"
@@ -874,13 +910,8 @@ AC_DEFUN([TEA_ENABLE_SYMBOLS], [
AC_MSG_RESULT([yes (standard debugging)])
fi
fi
- # TEA specific:
- if test "${TEA_PLATFORM}" != "windows" ; then
- LDFLAGS_DEFAULT="${LDFLAGS}"
- fi
AC_SUBST(CFLAGS_DEFAULT)
AC_SUBST(LDFLAGS_DEFAULT)
- AC_SUBST(TCL_DBGX)
if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?])
@@ -915,7 +946,7 @@ AC_DEFUN([TEA_ENABLE_SYMBOLS], [
AC_DEFUN([TEA_ENABLE_LANGINFO], [
AC_ARG_ENABLE(langinfo,
- AC_HELP_STRING([--enable-langinfo],
+ AS_HELP_STRING([--enable-langinfo],
[use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]),
[langinfo_ok=$enableval], [langinfo_ok=yes])
@@ -926,7 +957,7 @@ AC_DEFUN([TEA_ENABLE_LANGINFO], [
AC_MSG_CHECKING([whether to use nl_langinfo])
if test "$langinfo_ok" = "yes"; then
AC_CACHE_VAL(tcl_cv_langinfo_h, [
- AC_TRY_COMPILE([#include <langinfo.h>], [nl_langinfo(CODESET);],
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]], [[nl_langinfo(CODESET);]])],
[tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])])
AC_MSG_RESULT([$tcl_cv_langinfo_h])
if test $tcl_cv_langinfo_h = yes; then
@@ -951,6 +982,7 @@ AC_DEFUN([TEA_ENABLE_LANGINFO], [
# Defines the following var:
#
# system - System/platform/version identification code.
+#
#--------------------------------------------------------------------
AC_DEFUN([TEA_CONFIG_SYSTEM], [
@@ -967,6 +999,9 @@ AC_DEFUN([TEA_CONFIG_SYSTEM], [
if test "`uname -s`" = "AIX" ; then
tcl_cv_sys_version=AIX-`uname -v`.`uname -r`
fi
+ if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then
+ tcl_cv_sys_version=NetBSD-Debian
+ fi
fi
fi
])
@@ -1043,7 +1078,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_MSG_CHECKING([if 64bit support is requested])
AC_ARG_ENABLE(64bit,
- AC_HELP_STRING([--enable-64bit],
+ AS_HELP_STRING([--enable-64bit],
[enable 64bit support (default: off)]),
[do64bit=$enableval], [do64bit=no])
AC_MSG_RESULT([$do64bit])
@@ -1052,7 +1087,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_MSG_CHECKING([if 64bit Sparc VIS support is requested])
AC_ARG_ENABLE(64bit-vis,
- AC_HELP_STRING([--enable-64bit-vis],
+ AS_HELP_STRING([--enable-64bit-vis],
[enable 64bit Sparc VIS support (default: off)]),
[do64bitVIS=$enableval], [do64bitVIS=no])
AC_MSG_RESULT([$do64bitVIS])
@@ -1065,10 +1100,10 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CACHE_CHECK([if compiler supports visibility "hidden"],
tcl_cv_cc_visibility_hidden, [
hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror"
- AC_TRY_LINK([
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
extern __attribute__((__visibility__("hidden"))) void f(void);
- void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes,
- tcl_cv_cc_visibility_hidden=no)
+ void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes],
+ [tcl_cv_cc_visibility_hidden=no])
CFLAGS=$hold_cflags])
AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [
AC_DEFINE(MODULE_SCOPE,
@@ -1081,22 +1116,11 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_MSG_CHECKING([if rpath support is requested])
AC_ARG_ENABLE(rpath,
- AC_HELP_STRING([--disable-rpath],
+ AS_HELP_STRING([--disable-rpath],
[disable rpath support (default: on)]),
[doRpath=$enableval], [doRpath=yes])
AC_MSG_RESULT([$doRpath])
- # TEA specific: Cross-compiling options for Windows/CE builds?
-
- AS_IF([test "${TEA_PLATFORM}" = windows], [
- AC_MSG_CHECKING([if Windows/CE build is requested])
- AC_ARG_ENABLE(wince,
- AC_HELP_STRING([--enable-wince],
- [enable Win/CE support (where applicable)]),
- [doWince=$enableval], [doWince=no])
- AC_MSG_RESULT([$doWince])
- ])
-
# Set the variable "system" to hold the name and version number
# for the system.
@@ -1133,99 +1157,23 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CHECK_TOOL(AR, ar)
STLIB_LD='${AR} cr'
LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH"
- AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"])
+ AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"])
case $system in
# TEA specific:
windows)
- # This is a 2-stage check to make sure we have the 64-bit SDK
- # We have to know where the SDK is installed.
- # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs
- # MACHINE is IX86 for LINK, but this is used by the manifest,
- # which requires x86|amd64|ia64.
MACHINE="X86"
if test "$do64bit" != "no" ; then
- if test "x${MSSDK}x" = "xx" ; then
- MSSDK="C:/Progra~1/Microsoft Platform SDK"
- fi
- MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'`
- PATH64=""
case "$do64bit" in
amd64|x64|yes)
MACHINE="AMD64" ; # default to AMD64 64-bit build
- PATH64="${MSSDK}/Bin/Win64/x86/AMD64"
+ ;;
+ arm64|aarch64)
+ MACHINE="ARM64"
;;
ia64)
MACHINE="IA64"
- PATH64="${MSSDK}/Bin/Win64"
;;
esac
- if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then
- AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode])
- AC_MSG_WARN([Ensure latest Platform SDK is installed])
- do64bit="no"
- else
- AC_MSG_RESULT([ Using 64-bit $MACHINE mode])
- do64bit_ok="yes"
- fi
- fi
-
- if test "$doWince" != "no" ; then
- if test "$do64bit" != "no" ; then
- AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible])
- fi
- if test "$GCC" = "yes" ; then
- AC_MSG_ERROR([Windows/CE and GCC builds incompatible])
- fi
- TEA_PATH_CELIB
- # Set defaults for common evc4/PPC2003 setup
- # Currently Tcl requires 300+, possibly 420+ for sockets
- CEVERSION=420; # could be 211 300 301 400 420 ...
- TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ...
- ARCH=ARM; # could be ARM MIPS X86EM ...
- PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002"
- if test "$doWince" != "yes"; then
- # If !yes then the user specified something
- # Reset ARCH to allow user to skip specifying it
- ARCH=
- eval `echo $doWince | awk -F, '{ \
- if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \
- if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \
- if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \
- if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \
- if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \
- }'`
- if test "x${ARCH}" = "x" ; then
- ARCH=$TARGETCPU;
- fi
- fi
- OSVERSION=WCE$CEVERSION;
- if test "x${WCEROOT}" = "x" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0"
- if test ! -d "${WCEROOT}" ; then
- WCEROOT="C:/Program Files/Microsoft eMbedded Tools"
- fi
- fi
- if test "x${SDKROOT}" = "x" ; then
- SDKROOT="C:/Program Files/Windows CE Tools"
- if test ! -d "${SDKROOT}" ; then
- SDKROOT="C:/Windows CE Tools"
- fi
- fi
- WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'`
- SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'`
- if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \
- -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then
- AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]])
- doWince="no"
- else
- # We could PATH_NOSPACE these, but that's not important,
- # as long as we quote them when used.
- CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include"
- if test -d "${CEINCLUDE}/${TARGETCPU}" ; then
- CEINCLUDE="${CEINCLUDE}/${TARGETCPU}"
- fi
- CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"
- fi
fi
if test "$GCC" != "yes" ; then
@@ -1234,48 +1182,28 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
else
runtime=-MD
fi
+ case "x`echo \${VisualStudioVersion}`" in
+ x1[[4-9]]*)
+ lflags="${lflags} -nodefaultlib:libucrt.lib"
+ TEA_ADD_LIBS([ucrt.lib])
+ ;;
+ *)
+ ;;
+ esac
if test "$do64bit" != "no" ; then
- # All this magic is necessary for the Win64 SDK RC1 - hobbs
- CC="\"${PATH64}/cl.exe\""
- CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\""
- RC="\"${MSSDK}/bin/rc.exe\""
- lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\""
- LINKBIN="\"${PATH64}/link.exe\""
+ CC="cl.exe"
+ RC="rc.exe"
+ lflags="${lflags} -nologo -MACHINE:${MACHINE} "
+ LINKBIN="link.exe"
CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
# Avoid 'unresolved external symbol __security_cookie'
# errors, c.f. http://support.microsoft.com/?id=894573
TEA_ADD_LIBS([bufferoverflowU.lib])
- elif test "$doWince" != "no" ; then
- CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin"
- if test "${TARGETCPU}" = "X86"; then
- CC="\"${CEBINROOT}/cl.exe\""
- else
- CC="\"${CEBINROOT}/cl${ARCH}.exe\""
- fi
- CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\""
- RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\""
- arch=`echo ${ARCH} | awk '{print tolower([$]0)}'`
- defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS"
- if test "${SHARED_BUILD}" = "1" ; then
- # Static CE builds require static celib as well
- defs="${defs} _DLL"
- fi
- for i in $defs ; do
- AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i)
- done
- AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version])
- AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version])
- CFLAGS_DEBUG="-nologo -Zi -Od"
- CFLAGS_OPTIMIZE="-nologo -Ox"
- lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'`
- lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo"
- LINKBIN="\"${CEBINROOT}/link.exe\""
- AC_SUBST(CELIB_DIR)
else
RC="rc"
- lflags="-nologo"
+ lflags="${lflags} -nologo"
LINKBIN="link"
CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}"
@@ -1294,25 +1222,32 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CACHE_CHECK(for cross-compile version of gcc,
ac_cv_cross,
- AC_TRY_COMPILE([
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#ifdef _WIN32
#error cross-compiler
#endif
- ], [],
- ac_cv_cross=yes,
- ac_cv_cross=no)
+ ]], [[]])],
+ [ac_cv_cross=yes],
+ [ac_cv_cross=no])
)
if test "$ac_cv_cross" = "yes"; then
case "$do64bit" in
amd64|x64|yes)
- CC="x86_64-w64-mingw32-gcc"
+ CC="x86_64-w64-mingw32-${CC}"
LD="x86_64-w64-mingw32-ld"
AR="x86_64-w64-mingw32-ar"
RANLIB="x86_64-w64-mingw32-ranlib"
RC="x86_64-w64-mingw32-windres"
;;
+ arm64|aarch64)
+ CC="aarch64-w64-mingw32-clang"
+ LD="aarch64-w64-mingw32-ld"
+ AR="aarch64-w64-mingw32-ar"
+ RANLIB="aarch64-w64-mingw32-ranlib"
+ RC="aarch64-w64-mingw32-windres"
+ ;;
*)
- CC="i686-w64-mingw32-gcc"
+ CC="i686-w64-mingw32-${CC}"
LD="i686-w64-mingw32-ld"
AR="i686-w64-mingw32-ar"
RANLIB="i686-w64-mingw32-ranlib"
@@ -1334,13 +1269,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
# This essentially turns it all on.
LDFLAGS_DEBUG="-debug -debugtype:cv"
LDFLAGS_OPTIMIZE="-release"
- if test "$doWince" != "no" ; then
- LDFLAGS_CONSOLE="-link ${lflags}"
- LDFLAGS_WINDOW=${LDFLAGS_CONSOLE}
- else
- LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
- LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
- fi
+ LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
+ LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
fi
SHLIB_SUFFIX=".dll"
@@ -1349,7 +1279,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
TCL_LIB_VERSIONS_OK=nodots
;;
AIX-*)
- AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [
+ AS_IF([test "$GCC" != "yes"], [
# AIX requires the _r compiler when gcc isn't being used
case "${CC}" in
*_r|*_r\ *)
@@ -1386,11 +1316,11 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
# AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
SHLIB_LD="/usr/ccs/bin/ld -G -z text"
AS_IF([test "$GCC" = yes], [
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
], [
- CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"'
])
- LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
], [
AS_IF([test "$GCC" = yes], [
SHLIB_LD='${CC} -shared -Wl,-bexpall'
@@ -1399,7 +1329,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LDFLAGS="$LDFLAGS -brtl"
])
SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}"
- CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
])
;;
@@ -1415,6 +1345,13 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
#-----------------------------------------------------------
AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"])
;;
+ BSD/OS-2.1*|BSD/OS-3*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="shlicc -r"
+ SHLIB_SUFFIX=".so"
+ CC_SEARCH_FLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
BSD/OS-4.*)
SHLIB_CFLAGS="-export-dynamic -fPIC"
SHLIB_LD='${CC} -shared'
@@ -1427,16 +1364,25 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
SHLIB_CFLAGS=""
SHLIB_LD='${CC} -shared'
SHLIB_SUFFIX=".dll"
+ SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a"
EXEEXT=".exe"
do64bit_ok=yes
CC_SEARCH_FLAGS=""
LD_SEARCH_FLAGS=""
;;
+ dgux*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD='${CC} -G'
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ CC_SEARCH_FLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
Haiku*)
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"])
;;
HP-UX-*.11.*)
@@ -1448,18 +1394,16 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AS_IF([test "`uname -m`" = ia64], [
SHLIB_SUFFIX=".so"
- # Use newer C++ library for C++ extensions
- #if test "$GCC" != "yes" ; then
- # CPPFLAGS="-AA"
- #fi
], [
SHLIB_SUFFIX=".sl"
])
AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
AS_IF([test "$tcl_ok" = yes], [
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
LDFLAGS="$LDFLAGS -Wl,-E"
- CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
- LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.'
+ CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
+ LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
LD_LIBRARY_PATH_VAR="SHLIB_PATH"
])
AS_IF([test "$GCC" = yes], [
@@ -1467,10 +1411,6 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
], [
CFLAGS="$CFLAGS -z"
- # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc
- #CFLAGS="$CFLAGS +DAportable"
- SHLIB_CFLAGS="+z"
- SHLIB_LD="ld -b"
])
# Check to enable 64-bit flags for compiler/linker
@@ -1482,7 +1422,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
do64bit_ok=yes
SHLIB_LD='${CC} -shared'
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
;;
*)
@@ -1495,13 +1435,34 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LDFLAGS_ARCH="+DD64"
])
]) ;;
+ HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
+ SHLIB_SUFFIX=".sl"
+ AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
+ AS_IF([test "$tcl_ok" = yes], [
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS=""
+ LDFLAGS="$LDFLAGS -Wl,-E"
+ CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."'
+ LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."'
+ LD_LIBRARY_PATH_VAR="SHLIB_PATH"
+ ]) ;;
+ IRIX-5.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -shared -rdata_shared"
+ SHLIB_SUFFIX=".so"
+ AC_LIBOBJ(mkstemp)
+ AS_IF([test $doRpath = yes], [
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
+ ;;
IRIX-6.*)
SHLIB_CFLAGS=""
SHLIB_LD="ld -n32 -shared -rdata_shared"
SHLIB_SUFFIX=".so"
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
AS_IF([test "$GCC" = yes], [
CFLAGS="$CFLAGS -mabi=n32"
LDFLAGS="$LDFLAGS -mabi=n32"
@@ -1523,8 +1484,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
SHLIB_LD="ld -n32 -shared -rdata_shared"
SHLIB_SUFFIX=".so"
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"'])
# Check to enable 64-bit flags for compiler/linker
@@ -1539,7 +1500,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
])
])
;;
- Linux*|GNU*|NetBSD-Debian)
+ Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*)
SHLIB_CFLAGS="-fPIC"
SHLIB_SUFFIX=".so"
@@ -1547,17 +1508,29 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer"
# TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS
- SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}'
+ SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared'
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
+
+ case $system in
+ DragonFly-*|FreeBSD-*)
+ AS_IF([test "${TCL_THREADS}" = "1"], [
+ # The -pthread needs to go in the LDFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
+ ;;
+ esac
+
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"])
AS_IF([test $do64bit = yes], [
AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [
hold_cflags=$CFLAGS
CFLAGS="$CFLAGS -m64"
- AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+ [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no])
CFLAGS=$hold_cflags])
AS_IF([test $tcl_cv_cc_m64 = yes], [
CFLAGS="$CFLAGS -m64"
@@ -1580,42 +1553,31 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
SHLIB_LD='${CC} -shared'
LD_FLAGS="-Wl,--export-dynamic"
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
;;
OpenBSD-*)
arch=`arch -s`
case "$arch" in
- vax)
- SHLIB_SUFFIX=""
- SHARED_LIB_SUFFIX=""
- LDFLAGS=""
- ;;
- *)
+ alpha|sparc64)
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
- SHLIB_SUFFIX=".so"
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
- LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}'
- LDFLAGS="-Wl,-export-dynamic"
- ;;
- esac
- case "$arch" in
- vax)
- CFLAGS_OPTIMIZE="-O1"
;;
*)
- CFLAGS_OPTIMIZE="-O2"
+ SHLIB_CFLAGS="-fpic"
;;
esac
- AS_IF([test "${TCL_THREADS}" = "1"], [
- # On OpenBSD: Compile with -pthread
- # Don't link with -lpthread
- LIBS=`echo $LIBS | sed s/-lpthread//`
- CFLAGS="$CFLAGS -pthread"
- ])
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
+ SHLIB_SUFFIX=".so"
+ AS_IF([test $doRpath = yes], [
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
+ LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
+ LDFLAGS="$LDFLAGS -Wl,-export-dynamic"
+ CFLAGS_OPTIMIZE="-O2"
+ # On OpenBSD: Compile with -pthread
+ # Don't link with -lpthread
+ LIBS=`echo $LIBS | sed s/-lpthread//`
+ CFLAGS="$CFLAGS -pthread"
# OpenBSD doesn't do version numbers with dots.
UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
TCL_LIB_VERSIONS_OK=nodots
@@ -1623,44 +1585,16 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
NetBSD-*)
# NetBSD has ELF and can use 'cc -shared' to build shared libs
SHLIB_CFLAGS="-fPIC"
- SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}'
+ SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
SHLIB_SUFFIX=".so"
LDFLAGS="$LDFLAGS -export-dynamic"
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
- AS_IF([test "${TCL_THREADS}" = "1"], [
- # The -pthread needs to go in the CFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
- ])
- ;;
- FreeBSD-*)
- # This configuration from FreeBSD Ports.
- SHLIB_CFLAGS="-fPIC"
- SHLIB_LD="${CC} -shared"
- TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]"
- TK_SHLIB_LD_EXTRAS="-Wl,-soname,\$[@]"
- SHLIB_SUFFIX=".so"
- LDFLAGS=""
- AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
- AS_IF([test "${TCL_THREADS}" = "1"], [
- # The -pthread needs to go in the LDFLAGS, not LIBS
- LIBS=`echo $LIBS | sed s/-pthread//`
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
- case $system in
- FreeBSD-3.*)
- # Version numbers are dot-stripped by system policy.
- TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .`
- UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a'
- SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so'
- TCL_LIB_VERSIONS_OK=nodots
- ;;
- esac
+ # The -pthread needs to go in the CFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ CFLAGS="$CFLAGS -pthread"
+ LDFLAGS="$LDFLAGS -pthread"
;;
Darwin-*)
CFLAGS_OPTIMIZE="-Os"
@@ -1681,8 +1615,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
tcl_cv_cc_arch_ppc64, [
hold_cflags=$CFLAGS
CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
- AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes,
- tcl_cv_cc_arch_ppc64=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+ [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no])
CFLAGS=$hold_cflags])
AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [
CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5"
@@ -1693,8 +1627,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
tcl_cv_cc_arch_x86_64, [
hold_cflags=$CFLAGS
CFLAGS="$CFLAGS -arch x86_64"
- AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes,
- tcl_cv_cc_arch_x86_64=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+ [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no])
CFLAGS=$hold_cflags])
AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [
CFLAGS="$CFLAGS -arch x86_64"
@@ -1714,7 +1648,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [
hold_ldflags=$LDFLAGS
LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module"
- AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
+ [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no])
LDFLAGS=$hold_ldflags])
AS_IF([test $tcl_cv_ld_single_module = yes], [
SHLIB_LD="${SHLIB_LD} -Wl,-single_module"
@@ -1723,17 +1658,13 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d`
SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}"
SHLIB_SUFFIX=".dylib"
- # Don't use -prebind when building for Mac OS X 10.4 or later only:
- AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \
- "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [
- LDFLAGS="$LDFLAGS -prebind"])
LDFLAGS="$LDFLAGS -headerpad_max_install_names"
AC_CACHE_CHECK([if ld accepts -search_paths_first flag],
tcl_cv_ld_search_paths_first, [
hold_ldflags=$LDFLAGS
LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
- AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes,
- tcl_cv_ld_search_paths_first=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
+ [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no])
LDFLAGS=$hold_ldflags])
AS_IF([test $tcl_cv_ld_search_paths_first = yes], [
LDFLAGS="$LDFLAGS -Wl,-search_paths_first"
@@ -1756,8 +1687,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
done
CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include"
LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11"
- AC_TRY_LINK([#include <X11/Xlib.h>], [XrmInitialize();],
- tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <X11/Xlib.h>]], [[XrmInitialize();]])],
+ [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no])
for v in CFLAGS CPPFLAGS LDFLAGS; do
eval $v'="$hold_'$v'"'
done])
@@ -1769,8 +1700,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
done
CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}"
LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}"
- AC_TRY_LINK([#include <tk.h>], [Tk_InitStubs(NULL, "", 0);],
- tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <tk.h>]], [[Tk_InitStubs(NULL, "", 0);]])],
+ [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no])
for v in CFLAGS CPPFLAGS LDFLAGS; do
eval $v'="$hold_'$v'"'
done])
@@ -1799,21 +1730,19 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
])
SHLIB_SUFFIX=".so"
AS_IF([test $doRpath = yes], [
- CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [
CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"])
# see pthread_intro(3) for pthread support on osf1, k.furukawa
- AS_IF([test "${TCL_THREADS}" = 1], [
- CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
- CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
- LIBS=`echo $LIBS | sed s/-lpthreads//`
- AS_IF([test "$GCC" = yes], [
- LIBS="$LIBS -lpthread -lmach -lexc"
- ], [
- CFLAGS="$CFLAGS -pthread"
- LDFLAGS="$LDFLAGS -pthread"
- ])
+ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
+ CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"
+ LIBS=`echo $LIBS | sed s/-lpthreads//`
+ AS_IF([test "$GCC" = yes], [
+ LIBS="$LIBS -lpthread -lmach -lexc"
+ ], [
+ CFLAGS="$CFLAGS -pthread"
+ LDFLAGS="$LDFLAGS -pthread"
])
;;
QNX-6*)
@@ -1854,11 +1783,11 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
SHLIB_SUFFIX=".so"
AS_IF([test "$GCC" = yes], [
SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
], [
SHLIB_LD="/usr/ccs/bin/ld -G -z text"
- CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
])
;;
@@ -1924,7 +1853,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
SHLIB_SUFFIX=".so"
AS_IF([test "$GCC" = yes], [
SHLIB_LD='${CC} -shared'
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
AS_IF([test "$do64bit_ok" = yes], [
AS_IF([test "$arch" = "sparcv9 sparc"], [
@@ -1951,8 +1880,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
*)
SHLIB_LD='/usr/ccs/bin/ld -G -z text';;
esac
- CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
- LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"'
+ LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"'
])
;;
UNIX_SV* | UnixWare-5*)
@@ -1965,7 +1894,8 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [
hold_ldflags=$LDFLAGS
LDFLAGS="$LDFLAGS -Wl,-Bexport"
- AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
+ [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no])
LDFLAGS=$hold_ldflags])
AS_IF([test $tcl_cv_ld_Bexport = yes], [
LDFLAGS="$LDFLAGS -Wl,-Bexport"
@@ -1997,9 +1927,9 @@ dnl # preprocessing tests use only CPPFLAGS.
case $system in
AIX-*) ;;
BSD/OS*) ;;
- CYGWIN_*|MINGW32_*) ;;
+ CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;;
IRIX*) ;;
- NetBSD-*|FreeBSD-*|OpenBSD-*) ;;
+ NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
Darwin-*) ;;
SCO_SV-3.2*) ;;
windows) ;;
@@ -2021,7 +1951,7 @@ dnl # preprocessing tests use only CPPFLAGS.
if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then
AC_CACHE_CHECK(for SEH support in compiler,
tcl_cv_seh,
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
@@ -2036,10 +1966,10 @@ dnl # preprocessing tests use only CPPFLAGS.
}
return 1;
}
- ],
- tcl_cv_seh=yes,
- tcl_cv_seh=no,
- tcl_cv_seh=no)
+ ]])],
+ [tcl_cv_seh=yes],
+ [tcl_cv_seh=no],
+ [tcl_cv_seh=no])
)
if test "$tcl_cv_seh" = "no" ; then
AC_DEFINE(HAVE_NO_SEH, 1,
@@ -2054,15 +1984,15 @@ dnl # preprocessing tests use only CPPFLAGS.
#
AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
tcl_cv_eh_disposition,
- AC_TRY_COMPILE([
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
- ],[
+ ]], [[
EXCEPTION_DISPOSITION x;
- ],
- tcl_cv_eh_disposition=yes,
- tcl_cv_eh_disposition=no)
+ ]])],
+ [tcl_cv_eh_disposition=yes],
+ [tcl_cv_eh_disposition=no])
)
if test "$tcl_cv_eh_disposition" = "no" ; then
AC_DEFINE(EXCEPTION_DISPOSITION, int,
@@ -2075,18 +2005,18 @@ dnl # preprocessing tests use only CPPFLAGS.
AC_CACHE_CHECK(for winnt.h that ignores VOID define,
tcl_cv_winnt_ignore_void,
- AC_TRY_COMPILE([
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#define VOID void
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
- ], [
+ ]], [[
CHAR c;
SHORT s;
LONG l;
- ],
- tcl_cv_winnt_ignore_void=yes,
- tcl_cv_winnt_ignore_void=no)
+ ]])],
+ [tcl_cv_winnt_ignore_void=yes],
+ [tcl_cv_winnt_ignore_void=no])
)
if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1,
@@ -2100,22 +2030,25 @@ dnl # preprocessing tests use only CPPFLAGS.
AC_CACHE_CHECK(for cast to union support,
tcl_cv_cast_to_union,
- AC_TRY_COMPILE([],
- [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
union foo { int i; double d; };
union foo f = (union foo) (int) 0;
- ],
- tcl_cv_cast_to_union=yes,
- tcl_cv_cast_to_union=no)
+ ]])],
+ [tcl_cv_cast_to_union=yes],
+ [tcl_cv_cast_to_union=no])
)
if test "$tcl_cv_cast_to_union" = "yes"; then
AC_DEFINE(HAVE_CAST_TO_UNION, 1,
[Defined when compiler supports casting to union type.])
fi
+ AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have <stdbool.h>?])],)
+
AC_SUBST(CFLAGS_DEBUG)
AC_SUBST(CFLAGS_OPTIMIZE)
AC_SUBST(CFLAGS_WARNING)
+ AC_SUBST(LDFLAGS_DEBUG)
+ AC_SUBST(LDFLAGS_OPTIMIZE)
AC_SUBST(STLIB_LD)
AC_SUBST(SHLIB_LD)
@@ -2155,7 +2088,7 @@ dnl # preprocessing tests use only CPPFLAGS.
AC_DEFUN([TEA_SERIAL_PORT], [
AC_CHECK_HEADERS(sys/modem.h)
AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <termios.h>
int main() {
@@ -2166,9 +2099,9 @@ int main() {
return 0;
}
return 1;
-}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no)
+}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
if test $tcl_cv_api_serial = no ; then
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <termio.h>
int main() {
@@ -2178,10 +2111,10 @@ int main() {
return 0;
}
return 1;
-}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no)
+}]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
fi
if test $tcl_cv_api_serial = no ; then
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sgtty.h>
int main() {
@@ -2192,10 +2125,10 @@ int main() {
return 0;
}
return 1;
-}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no)
+}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
fi
if test $tcl_cv_api_serial = no ; then
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <termios.h>
#include <errno.h>
@@ -2208,10 +2141,10 @@ int main() {
return 0;
}
return 1;
-}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no)
+}]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
fi
if test $tcl_cv_api_serial = no; then
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <termio.h>
#include <errno.h>
@@ -2223,10 +2156,10 @@ int main() {
return 0;
}
return 1;
- }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no)
+ }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no])
fi
if test $tcl_cv_api_serial = no; then
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <sgtty.h>
#include <errno.h>
@@ -2239,7 +2172,7 @@ int main() {
return 0;
}
return 1;
-}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none)
+}]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=none],[tcl_cv_api_serial=none])
fi])
case $tcl_cv_api_serial in
termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);;
@@ -2249,97 +2182,6 @@ int main() {
])
#--------------------------------------------------------------------
-# TEA_MISSING_POSIX_HEADERS
-#
-# Supply substitutes for missing POSIX header files. Special
-# notes:
-# - stdlib.h doesn't define strtol, strtoul, or
-# strtod in some versions of SunOS
-# - some versions of string.h don't declare procedures such
-# as strstr
-#
-# Arguments:
-# none
-#
-# Results:
-#
-# Defines some of the following vars:
-# NO_DIRENT_H
-# NO_ERRNO_H
-# NO_VALUES_H
-# HAVE_LIMITS_H or NO_LIMITS_H
-# NO_STDLIB_H
-# NO_STRING_H
-# NO_SYS_WAIT_H
-# NO_DLFCN_H
-# HAVE_SYS_PARAM_H
-#
-# HAVE_STRING_H ?
-#
-# tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and
-# CHECK on limits.h
-#--------------------------------------------------------------------
-
-AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [
- AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [
- AC_TRY_LINK([#include <sys/types.h>
-#include <dirent.h>], [
-#ifndef _POSIX_SOURCE
-# ifdef __Lynx__
- /*
- * Generate compilation error to make the test fail: Lynx headers
- * are only valid if really in the POSIX environment.
- */
-
- missing_procedure();
-# endif
-#endif
-DIR *d;
-struct dirent *entryPtr;
-char *p;
-d = opendir("foobar");
-entryPtr = readdir(d);
-p = entryPtr->d_name;
-closedir(d);
-], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)])
-
- if test $tcl_cv_dirent_h = no; then
- AC_DEFINE(NO_DIRENT_H, 1, [Do we have <dirent.h>?])
- fi
-
- # TEA specific:
- AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have <errno.h>?])])
- AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have <float.h>?])])
- AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have <values.h>?])])
- AC_CHECK_HEADER(limits.h,
- [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have <limits.h>?])],
- [AC_DEFINE(NO_LIMITS_H, 1, [Do we have <limits.h>?])])
- AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0)
- AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0)
- AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0)
- AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0)
- if test $tcl_ok = 0; then
- AC_DEFINE(NO_STDLIB_H, 1, [Do we have <stdlib.h>?])
- fi
- AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0)
- AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0)
- AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0)
-
- # See also memmove check below for a place where NO_STRING_H can be
- # set and why.
-
- if test $tcl_ok = 0; then
- AC_DEFINE(NO_STRING_H, 1, [Do we have <string.h>?])
- fi
-
- AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have <sys/wait.h>?])])
- AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have <dlfcn.h>?])])
-
- # OS/390 lacks sys/param.h (and doesn't need it, by chance).
- AC_HAVE_HEADERS(sys/param.h)
-])
-
-#--------------------------------------------------------------------
# TEA_PATH_X
#
# Locate the X11 header files and the X11 library archive. Try
@@ -2374,7 +2216,7 @@ AC_DEFUN([TEA_PATH_UNIX_X], [
not_really_there=""
if test "$no_x" = ""; then
if test "$x_includes" = ""; then
- AC_TRY_CPP([#include <X11/Xlib.h>], , not_really_there="yes")
+ AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include <X11/Xlib.h>]])],[],[not_really_there="yes"])
else
if test ! -r $x_includes/X11/Xlib.h; then
not_really_there="yes"
@@ -2384,7 +2226,7 @@ AC_DEFUN([TEA_PATH_UNIX_X], [
if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then
AC_MSG_CHECKING([for X11 header files])
found_xincludes="no"
- AC_TRY_CPP([#include <X11/Xlib.h>], found_xincludes="yes", found_xincludes="no")
+ AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include <X11/Xlib.h>]])],[found_xincludes="yes"],[found_xincludes="no"])
if test "$found_xincludes" = "no"; then
dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include"
for i in $dirs ; do
@@ -2490,6 +2332,7 @@ AC_DEFUN([TEA_BLOCKING_STYLE], [
# HAVE_TM_GMTOFF
# HAVE_TM_TZADJ
# HAVE_TIMEZONE_VAR
+#
#--------------------------------------------------------------------
AC_DEFUN([TEA_TIME_HANDLER], [
@@ -2497,18 +2340,20 @@ AC_DEFUN([TEA_TIME_HANDLER], [
AC_HEADER_TIME
AC_STRUCT_TIMEZONE
- AC_CHECK_FUNCS(gmtime_r localtime_r)
+ AC_CHECK_FUNCS(gmtime_r localtime_r mktime)
AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [
- AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;],
- tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[struct tm tm; (void)tm.tm_tzadj;]])],
+ [tcl_cv_member_tm_tzadj=yes],
+ [tcl_cv_member_tm_tzadj=no])])
if test $tcl_cv_member_tm_tzadj = yes ; then
AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?])
fi
AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [
- AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;],
- tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>]], [[struct tm tm; (void)tm.tm_gmtoff;]])],
+ [tcl_cv_member_tm_gmtoff=yes],
+ [tcl_cv_member_tm_gmtoff=no])])
if test $tcl_cv_member_tm_gmtoff = yes ; then
AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?])
fi
@@ -2518,11 +2363,12 @@ AC_DEFUN([TEA_TIME_HANDLER], [
# (like convex) have timezone functions, etc.
#
AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [
- AC_TRY_COMPILE([#include <time.h>],
- [extern long timezone;
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>
+#include <stdlib.h>]],
+ [[extern long timezone;
timezone += 1;
- exit (0);],
- tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)])
+ exit (0);]])],
+ [tcl_cv_timezone_long=yes], [tcl_cv_timezone_long=no])])
if test $tcl_cv_timezone_long = yes ; then
AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?])
else
@@ -2530,11 +2376,12 @@ AC_DEFUN([TEA_TIME_HANDLER], [
# On some systems (eg IRIX 6.2), timezone is a time_t and not a long.
#
AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [
- AC_TRY_COMPILE([#include <time.h>],
- [extern time_t timezone;
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>
+#include <stdlib.h>]],
+ [[extern time_t timezone;
timezone += 1;
- exit (0);],
- tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)])
+ exit (0);]])],
+ [tcl_cv_timezone_time=yes], [tcl_cv_timezone_time=no])])
if test $tcl_cv_timezone_time = yes ; then
AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?])
fi
@@ -2564,7 +2411,8 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0)
if test "$tcl_strtod" = 1; then
AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[
- AC_TRY_RUN([
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <stdlib.h>
extern double strtod();
int main() {
char *infString="Inf", *nanString="NaN", *spaceString=" ";
@@ -2583,8 +2431,8 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
exit(1);
}
exit(0);
- }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy,
- tcl_cv_strtod_buggy=buggy)])
+ }]])], [tcl_cv_strtod_buggy=ok], [tcl_cv_strtod_buggy=buggy],
+ [tcl_cv_strtod_buggy=buggy])])
if test "$tcl_cv_strtod_buggy" = buggy; then
AC_LIBOBJ([fixstrtod])
USE_COMPAT=1
@@ -2597,38 +2445,30 @@ AC_DEFUN([TEA_BUGGY_STRTOD], [
# TEA_TCL_LINK_LIBS
#
# Search for the libraries needed to link the Tcl shell.
-# Things like the math library (-lm) and socket stuff (-lsocket vs.
-# -lnsl) are dealt with here.
+# Things like the math library (-lm), socket stuff (-lsocket vs.
+# -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here.
#
# Arguments:
-# Requires the following vars to be set in the Makefile:
-# DL_LIBS (not in TEA, only needed in core)
-# LIBS
-# MATH_LIBS
+# None.
#
# Results:
#
-# Substitutes the following vars:
-# TCL_LIBS
-# MATH_LIBS
-#
# Might append to the following vars:
# LIBS
+# MATH_LIBS
#
# Might define the following vars:
# HAVE_NET_ERRNO_H
+#
#--------------------------------------------------------------------
AC_DEFUN([TEA_TCL_LINK_LIBS], [
#--------------------------------------------------------------------
# On a few very rare systems, all of the libm.a stuff is
# already in libc.a. Set compiler flags accordingly.
- # Also, Linux requires the "ieee" library for math to work
- # right (and it must appear before "-lm").
#--------------------------------------------------------------------
AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm")
- AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"])
#--------------------------------------------------------------------
# Interactive UNIX requires -linet instead of -lsocket, plus it
@@ -2670,13 +2510,10 @@ AC_DEFUN([TEA_TCL_LINK_LIBS], [
fi
AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname,
[LIBS="$LIBS -lnsl"])])
-
- # TEA specific: Don't perform the eval of the libraries here because
- # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS
-
- TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}'
- AC_SUBST(TCL_LIBS)
- AC_SUBST(MATH_LIBS)
+ AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32,
+ [LIBS="$LIBS -ltommath"])])
+ AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader,
+ [LIBS="$LIBS -lz"])])
])
#--------------------------------------------------------------------
@@ -2694,15 +2531,16 @@ AC_DEFUN([TEA_TCL_LINK_LIBS], [
# _ISOC99_SOURCE
# _LARGEFILE64_SOURCE
# _LARGEFILE_SOURCE64
+#
#--------------------------------------------------------------------
AC_DEFUN([TEA_TCL_EARLY_FLAG],[
AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]),
- AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,
- AC_TRY_COMPILE([[#define ]$1[ 1
-]$2], $3,
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes,
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)))
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])],
+ [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ 1
+]$2]], [[$3]])],
+ [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes,
+ [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)]))
if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then
AC_DEFINE($1, 1, [Add the ]$1[ flag when building])
tcl_flags="$tcl_flags $1"
@@ -2738,9 +2576,10 @@ AC_DEFUN([TEA_TCL_EARLY_FLAGS],[
# Might define the following vars:
# TCL_WIDE_INT_IS_LONG
# TCL_WIDE_INT_TYPE
-# HAVE_STRUCT_DIRENT64
+# HAVE_STRUCT_DIRENT64, HAVE_DIR64
# HAVE_STRUCT_STAT64
# HAVE_TYPE_OFF64_T
+#
#--------------------------------------------------------------------
AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
@@ -2748,17 +2587,17 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
AC_CACHE_VAL(tcl_cv_type_64bit,[
tcl_cv_type_64bit=none
# See if the compiler knows natively about __int64
- AC_TRY_COMPILE(,[__int64 value = (__int64) 0;],
- tcl_type_64bit=__int64, tcl_type_64bit="long long")
- # See if we should use long anyway Note that we substitute in the
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])],
+ [tcl_type_64bit=__int64],[tcl_type_64bit="long long"])
+ # See if we could use long anyway Note that we substitute in the
# type that is our current guess for a 64-bit type inside this check
# program, so it should be modified only carefully...
- AC_TRY_COMPILE(,[switch (0) {
- case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ;
- }],tcl_cv_type_64bit=${tcl_type_64bit})])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) {
+ case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ;
+ }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])])
if test "${tcl_cv_type_64bit}" = none ; then
- AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?])
- AC_MSG_RESULT([using long])
+ AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?])
+ AC_MSG_RESULT([yes])
elif test "${tcl_cv_type_64bit}" = "__int64" \
-a "${TEA_PLATFORM}" = "windows" ; then
# TEA specific: We actually want to use the default tcl.h checks in
@@ -2771,17 +2610,26 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
# Now check for auxiliary declarations
AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[
- AC_TRY_COMPILE([#include <sys/types.h>
-#include <dirent.h>],[struct dirent64 p;],
- tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <dirent.h>]], [[struct dirent64 p;]])],
+ [tcl_cv_struct_dirent64=yes],[tcl_cv_struct_dirent64=no])])
if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?])
fi
+ AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
+#include <dirent.h>]], [[struct dirent64 *p; DIR64 d = opendir64(".");
+ p = readdir64(d); rewinddir64(d); closedir64(d);]])],
+ [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])])
+ if test "x${tcl_cv_DIR64}" = "xyes" ; then
+ AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in <sys/types.h>?])
+ fi
+
AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[
- AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat64 p;
-],
- tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/stat.h>]], [[struct stat64 p;
+]])],
+ [tcl_cv_struct_stat64=yes], [tcl_cv_struct_stat64=no])])
if test "x${tcl_cv_struct_stat64}" = "xyes" ; then
AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in <sys/stat.h>?])
fi
@@ -2789,9 +2637,9 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
AC_CHECK_FUNCS(open64 lseek64)
AC_MSG_CHECKING([for off64_t])
AC_CACHE_VAL(tcl_cv_type_off64_t,[
- AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset;
-],
- tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>]], [[off64_t offset;
+]])],
+ [tcl_cv_type_off64_t=yes], [tcl_cv_type_off64_t=no])])
dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the
dnl functions lseek64 and open64 are defined.
if test "x${tcl_cv_type_off64_t}" = "xyes" && \
@@ -2840,23 +2688,14 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
#------------------------------------------------------------------------
AC_DEFUN([TEA_INIT], [
- # TEA extensions pass this us the version of TEA they think they
- # are compatible with.
- TEA_VERSION="3.9"
+ TEA_VERSION="3.13"
- AC_MSG_CHECKING([for correct TEA configuration])
+ AC_MSG_CHECKING([TEA configuration])
if test x"${PACKAGE_NAME}" = x ; then
AC_MSG_ERROR([
-The PACKAGE_NAME variable must be defined by your TEA configure.in])
- fi
- if test x"$1" = x ; then
- AC_MSG_ERROR([
-TEA version not specified.])
- elif test "$1" != "${TEA_VERSION}" ; then
- AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"])
- else
- AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
+The PACKAGE_NAME variable must be defined by your TEA configure.ac])
fi
+ AC_MSG_RESULT([ok (TEA ${TEA_VERSION})])
# If the user did not set CFLAGS, set it now to keep macros
# like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2".
@@ -2865,15 +2704,14 @@ TEA version not specified.])
fi
case "`uname -s`" in
- *win32*|*WIN32*|*MINGW32_*)
- AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo)
+ *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*)
+ AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo)
EXEEXT=".exe"
TEA_PLATFORM="windows"
;;
*CYGWIN_*)
- CYGPATH=echo
EXEEXT=".exe"
- # TEA_PLATFORM is determined later in LOAD_TCLCONFIG
+ # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG
;;
*)
CYGPATH=echo
@@ -2907,6 +2745,8 @@ TEA version not specified.])
# This package name must be replaced statically for AC_SUBST to work
AC_SUBST(PKG_LIB_FILE)
+ AC_SUBST(PKG_LIB_FILE8)
+ AC_SUBST(PKG_LIB_FILE9)
# Substitute STUB_LIB_FILE in case package creates a stub library too.
AC_SUBST(PKG_STUB_LIB_FILE)
@@ -2919,6 +2759,9 @@ TEA version not specified.])
AC_SUBST(PKG_INCLUDES)
AC_SUBST(PKG_LIBS)
AC_SUBST(PKG_CFLAGS)
+
+ # Configure the installer.
+ TEA_INSTALLER
])
#------------------------------------------------------------------------
@@ -3111,7 +2954,7 @@ AC_DEFUN([TEA_ADD_LIBS], [
for i in $vars; do
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then
# Convert foo.lib to -lfoo for GCC. No-op if not *.lib
- i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'`
+ i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'`
fi
PKG_LIBS="$PKG_LIBS $i"
done
@@ -3194,7 +3037,7 @@ AC_DEFUN([TEA_PREFIX], [
# TEA_SETUP_COMPILER_CC --
#
# Do compiler checks the way we want. This is just a replacement
-# for AC_PROG_CC in TEA configure.in files to make them cleaner.
+# for AC_PROG_CC in TEA configure.ac files to make them cleaner.
#
# Arguments:
# none
@@ -3210,15 +3053,6 @@ AC_DEFUN([TEA_SETUP_COMPILER_CC], [
AC_PROG_CC
AC_PROG_CPP
- INSTALL="\$(SHELL) \$(srcdir)/tclconfig/install-sh -c"
- AC_SUBST(INSTALL)
- INSTALL_DATA="\${INSTALL} -m 644"
- AC_SUBST(INSTALL_DATA)
- INSTALL_PROGRAM="\${INSTALL}"
- AC_SUBST(INSTALL_PROGRAM)
- INSTALL_SCRIPT="\${INSTALL}"
- AC_SUBST(INSTALL_SCRIPT)
-
#--------------------------------------------------------------------
# Checks to see if the make program sets the $MAKE variable.
#--------------------------------------------------------------------
@@ -3265,7 +3099,7 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
AC_CACHE_CHECK([if the compiler understands -pipe],
tcl_cv_cc_pipe, [
hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe"
- AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no)
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_pipe=yes],[tcl_cv_cc_pipe=no])
CFLAGS=$hold_cflags])
if test $tcl_cv_cc_pipe = yes; then
CFLAGS="$CFLAGS -pipe"
@@ -3277,14 +3111,6 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
#--------------------------------------------------------------------
AC_C_BIGENDIAN
- if test "${TEA_PLATFORM}" = "unix" ; then
- TEA_TCL_LINK_LIBS
- TEA_MISSING_POSIX_HEADERS
- # Let the user call this, because if it triggers, they will
- # need a compat/strtod.c that is correct. Users can also
- # use Tcl_GetDouble(FromObj) instead.
- #TEA_BUGGY_STRTOD
- fi
])
#------------------------------------------------------------------------
@@ -3315,7 +3141,7 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
AC_DEFUN([TEA_MAKE_LIB], [
if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
AC_EGREP_CPP([manifest needed], [
#if defined(_MSC_VER) && _MSC_VER >= 1400
print("manifest needed")
@@ -3330,7 +3156,7 @@ print("manifest needed")
MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)"
else
MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)"
- MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}"
MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)"
fi
@@ -3346,6 +3172,13 @@ print("manifest needed")
# substituted. (@@@ Might not be necessary anymore)
#--------------------------------------------------------------------
+ PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}"
+ PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9"
+ if test "${TCL_MAJOR_VERSION}" -gt 8 ; then
+ PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}"
+ else
+ PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}"
+ fi
if test "${TEA_PLATFORM}" = "windows" ; then
if test "${SHARED_BUILD}" = "1" ; then
# We force the unresolved linking of symbols that are really in
@@ -3357,15 +3190,19 @@ print("manifest needed")
if test "$GCC" = "yes"; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc"
fi
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
else
- eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
- PKG_LIB_FILE=lib${PKG_LIB_FILE}
+ PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX}
fi
+ eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
if test "$GCC" = "yes"; then
PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
fi
@@ -3379,13 +3216,17 @@ print("manifest needed")
if test x"${TK_BIN_DIR}" != x ; then
SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}"
fi
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
RANLIB=:
else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
fi
# These are escaped so that only CFLAGS is picked up at configure time.
@@ -3930,6 +3771,7 @@ AC_DEFUN([TEA_PATH_CONFIG], [
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
+ `ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
; do
@@ -4071,18 +3913,18 @@ AC_DEFUN([TEA_EXPORT_CONFIG], [
# pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib)
eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}"
if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then
- eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}"
- eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}"
+ eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}"
+ eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}"
else
- eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}"
- eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}"
+ eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`"
+ eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`"
fi
- $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}"
- $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}"
- $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}"
- $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}"
- $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}"
- $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}"
+ $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}"
+ $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}"
+ $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}"
+ $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}"
+ $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}"
+ $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}"
AC_SUBST($1_BUILD_LIB_SPEC)
AC_SUBST($1_LIB_SPEC)
@@ -4098,71 +3940,128 @@ AC_DEFUN([TEA_EXPORT_CONFIG], [
#------------------------------------------------------------------------
-# TEA_PATH_CELIB --
+# TEA_INSTALLER --
#
-# Locate Keuchel's celib emulation layer for targeting Win/CE
+# Configure the installer.
#
# Arguments:
# none
#
# Results:
-#
-# Adds the following arguments to configure:
-# --with-celib=...
-#
-# Defines the following vars:
-# CELIB_DIR Full path to the directory containing
-# the include and platform lib files
+# Substitutes the following vars:
+# INSTALL
+# INSTALL_DATA_DIR
+# INSTALL_DATA
+# INSTALL_PROGRAM
+# INSTALL_SCRIPT
+# INSTALL_LIBRARY
#------------------------------------------------------------------------
-AC_DEFUN([TEA_PATH_CELIB], [
- # First, look for one uninstalled.
- # the alternative search directory is invoked by --with-celib
-
- if test x"${no_celib}" = x ; then
- # we reset no_celib in case something fails here
- no_celib=true
- AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval})
- AC_MSG_CHECKING([for Windows/CE celib directory])
- AC_CACHE_VAL(ac_cv_c_celibconfig,[
- # First check to see if --with-celibconfig was specified.
- if test x"${with_celibconfig}" != x ; then
- if test -d "${with_celibconfig}/inc" ; then
- ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)`
- else
- AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory])
- fi
- fi
+AC_DEFUN([TEA_INSTALLER], [
+ INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c'
+ INSTALL_DATA_DIR='${INSTALL} -d -m 755'
+ INSTALL_DATA='${INSTALL} -m 644'
+ INSTALL_PROGRAM='${INSTALL} -m 755'
+ INSTALL_SCRIPT='${INSTALL} -m 755'
- # then check for a celib library
- if test x"${ac_cv_c_celibconfig}" = x ; then
- for i in \
- ../celib-palm-3.0 \
- ../celib \
- ../../celib-palm-3.0 \
- ../../celib \
- `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \
- ${srcdir}/../celib-palm-3.0 \
- ${srcdir}/../celib \
- `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \
- ; do
- if test -d "$i/inc" ; then
- ac_cv_c_celibconfig=`(cd $i; pwd)`
- break
- fi
- done
- fi
- ])
- if test x"${ac_cv_c_celibconfig}" = x ; then
- AC_MSG_ERROR([Cannot find celib support library directory])
- else
- no_celib=
- CELIB_DIR=${ac_cv_c_celibconfig}
- CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'`
- AC_MSG_RESULT([found $CELIB_DIR])
- fi
- fi
+ TEA_CONFIG_SYSTEM
+ case $system in
+ HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;;
+ *) INSTALL_LIBRARY='${INSTALL} -m 644' ;;
+ esac
+
+ AC_SUBST(INSTALL)
+ AC_SUBST(INSTALL_DATA_DIR)
+ AC_SUBST(INSTALL_DATA)
+ AC_SUBST(INSTALL_PROGRAM)
+ AC_SUBST(INSTALL_SCRIPT)
+ AC_SUBST(INSTALL_LIBRARY)
])
+
+###
+# Tip 430 - ZipFS Modifications
+###
+#------------------------------------------------------------------------
+# TEA_ZIPFS_SUPPORT
+# Locate a zip encoder installed on the system path, or none.
+#
+# Arguments:
+# none
+#
+# Results:
+# Substitutes the following vars:
+# MACHER_PROG
+# ZIP_PROG
+# ZIP_PROG_OPTIONS
+# ZIP_PROG_VFSSEARCH
+# ZIP_INSTALL_OBJS
+#------------------------------------------------------------------------
+
+AC_DEFUN([TEA_ZIPFS_SUPPORT], [
+ MACHER_PROG=""
+ ZIP_PROG=""
+ ZIP_PROG_OPTIONS=""
+ ZIP_PROG_VFSSEARCH=""
+ ZIP_INSTALL_OBJS=""
+
+ AC_MSG_CHECKING([for macher])
+ AC_CACHE_VAL(ac_cv_path_macher, [
+ search_path=`echo ${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/macher 2> /dev/null` \
+ `ls -r $dir/macher 2> /dev/null` ; do
+ if test x"$ac_cv_path_macher" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_macher=$j
+ break
+ fi
+ fi
+ done
+ done
+ ])
+ if test -f "$ac_cv_path_macher" ; then
+ MACHER_PROG="$ac_cv_path_macher"
+ AC_MSG_RESULT([$MACHER_PROG])
+ AC_MSG_RESULT([Found macher in environment])
+ fi
+ AC_MSG_CHECKING([for zip])
+ AC_CACHE_VAL(ac_cv_path_zip, [
+ search_path=`echo ${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/zip 2> /dev/null` \
+ `ls -r $dir/zip 2> /dev/null` ; do
+ if test x"$ac_cv_path_zip" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_zip=$j
+ break
+ fi
+ fi
+ done
+ done
+ ])
+ if test -f "$ac_cv_path_zip" ; then
+ ZIP_PROG="$ac_cv_path_zip"
+ AC_MSG_RESULT([$ZIP_PROG])
+ ZIP_PROG_OPTIONS="-rq"
+ ZIP_PROG_VFSSEARCH="*"
+ AC_MSG_RESULT([Found INFO Zip in environment])
+ # Use standard arguments for zip
+ else
+ # It is not an error if an installed version of Zip can't be located.
+ # We can use the locally distributed minizip instead
+ ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
+ ZIP_PROG_OPTIONS="-o -r"
+ ZIP_PROG_VFSSEARCH="*"
+ ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
+ AC_MSG_RESULT([No zip found on PATH. Building minizip])
+ fi
+ AC_SUBST(MACHER_PROG)
+ AC_SUBST(ZIP_PROG)
+ AC_SUBST(ZIP_PROG_OPTIONS)
+ AC_SUBST(ZIP_PROG_VFSSEARCH)
+ AC_SUBST(ZIP_INSTALL_OBJS)
+])
+
# Local Variables:
# mode: autoconf
-# End:
+# End: \ No newline at end of file
diff --git a/tea/win/makefile.vc b/tea/win/makefile.vc
index d92a8428bfee..da56e811fcd0 100644
--- a/tea/win/makefile.vc
+++ b/tea/win/makefile.vc
@@ -251,7 +251,18 @@ INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \
-I"$(GENERICDIR)" -I"$(ROOT)\.."
BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \
-DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \
- -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1
+ -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1 \
+ -DSQLITE_ENABLE_FTS4=1 \
+ -DSQLITE_ENABLE_FTS5=1 \
+ -DSQLITE_3_SUFFIX_ONLY=1 \
+ -DSQLITE_ENABLE_RTREE=1 \
+ -DSQLITE_ENABLE_GEOPOLY=1 \
+ -DSQLITE_ENABLE_MATH_FUNCTIONS=1 \
+ -DSQLITE_ENABLE_DESERIALIZE=1 \
+ -DSQLITE_ENABLE_DBPAGE_VTAB=1 \
+ -DSQLITE_ENABLE_BYTECODE_VTAB=1 \
+ -DSQLITE_ENABLE_DBSTAT_VTAB=1
+
CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -DSQLITE_ENABLE_FTS3=1
TCL_CFLAGS = -DBUILD_sqlite -DUSE_TCL_STUBS \
-DPACKAGE_VERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) \