Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8afffe7244 | |||
| 557341e8fa | |||
| cf1e395acb | |||
| 9a8b9ec51c | |||
| dec8bc0eb4 | |||
| 8d85364261 | |||
| 0e15d921d9 | |||
| eb5a549ecf | |||
| de6fde6af6 | |||
| 283a85ca21 | |||
| 170e998236 | |||
| a8f286a38a | |||
| e2f84b403c | |||
| b52dcd8989 | |||
| b56660f5a4 | |||
| 86396219a3 | |||
| 0129a54a16 | |||
| c0e2203adb | |||
| fca760c841 | |||
| 1637a5171f | |||
| 3d2a529df6 | |||
| ed916ba025 | |||
| a0620acc4a | |||
| ce0442edf3 | |||
| dd703e22a5 | |||
| e234cfd11f | |||
| e39cd91aea | |||
| a912348a19 | |||
| 11499f0ab4 | |||
| 43f58d6a17 | |||
| c2024c4ef2 | |||
| 1e75483cf0 | |||
| d3d4b3c698 | |||
| 5225449e5b | |||
| c8dcdff37e | |||
| 9c10608a26 | |||
| dc7b7385c9 | |||
| 272989b44d | |||
| 50687436f7 | |||
| e0a6e0fda0 | |||
| 240c7faf8b | |||
| 2e993288e6 | |||
| 9697308f44 | |||
| 2e3f87ae84 | |||
| ba637157ca | |||
| 2519b2a3e5 | |||
| 9de4757c9c | |||
| 5fbab882c0 | |||
| 7c95696e5c | |||
| 883486bada | |||
| e336b8914c | |||
| 2d05331444 | |||
| 64131c15ab | |||
| 4841624ab9 | |||
| a2fbe3bec6 | |||
| 05d1bad674 | |||
| 4b37cd49a6 | |||
| f5fe00399f | |||
| be11ade7cf | |||
| b10ab53f3a | |||
| ec5935924d | |||
| 9c987a833c | |||
| ee84b0f690 | |||
| 2b693d63e4 | |||
| e6912fd819 | |||
| c497441406 | |||
| 419b03c1bb | |||
| b324cf756e | |||
| 3480bfdae9 | |||
| 6b92288119 | |||
| c14566aff3 | |||
| 6c0e41b951 | |||
| debaa86c1c | |||
| edc4024b9d | |||
| 4d249e6128 | |||
| 8dc570b6af | |||
| b9f3f6b672 |
+12
-11
@@ -416,6 +416,7 @@ TESTSRC = \
|
||||
#
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/carray.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/csv.c \
|
||||
$(TOP)/ext/misc/eval.c \
|
||||
@@ -588,15 +589,15 @@ sqlite3$(TEXE): $(TOP)/src/shell.c sqlite3.c
|
||||
$(TOP)/src/shell.c sqlite3.c \
|
||||
$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
|
||||
|
||||
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.c $(TLIBS)
|
||||
sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.lo $(TLIBS)
|
||||
|
||||
dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.c $(TLIBS)
|
||||
dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.lo sqlite3.h
|
||||
$(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.lo $(TLIBS)
|
||||
|
||||
scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.o
|
||||
scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.lo
|
||||
$(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \
|
||||
$(TOP)/ext/misc/scrub.c sqlite3.o $(TLIBS)
|
||||
$(TOP)/ext/misc/scrub.c sqlite3.lo $(TLIBS)
|
||||
|
||||
srcck1$(BEXE): $(TOP)/tool/srcck1.c
|
||||
$(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c
|
||||
@@ -611,8 +612,8 @@ fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
|
||||
fuzzcheck$(TEXE): $(TOP)/test/fuzzcheck.c sqlite3.c sqlite3.h
|
||||
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/fuzzcheck.c sqlite3.c $(TLIBS)
|
||||
|
||||
mptester$(TEXE): sqlite3.c $(TOP)/mptest/mptest.c
|
||||
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.c \
|
||||
mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c
|
||||
$(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \
|
||||
$(TLIBS) -rpath "$(libdir)"
|
||||
|
||||
MPTEST1=./mptester$(TEXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20
|
||||
@@ -1156,8 +1157,8 @@ rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo
|
||||
LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h
|
||||
$(LTLINK) -I. -o $@ $(TOP)/tool/logest.c
|
||||
|
||||
wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c
|
||||
$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS)
|
||||
wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS)
|
||||
|
||||
speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS)
|
||||
@@ -1174,7 +1175,7 @@ loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
|
||||
#
|
||||
VALIDIDS=' sqlite3(changeset|changegroup|session)?_'
|
||||
checksymbols: sqlite3.lo
|
||||
nm -g --defined-only sqlite3.o | egrep -v $(VALIDIDS); test $$? -ne 0
|
||||
nm -g --defined-only sqlite3.lo | egrep -v $(VALIDIDS); test $$? -ne 0
|
||||
echo '0 errors out of 1 tests'
|
||||
|
||||
# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
|
||||
|
||||
@@ -1292,6 +1292,7 @@ TESTSRC = \
|
||||
#
|
||||
TESTEXT = \
|
||||
$(TOP)\ext\misc\amatch.c \
|
||||
$(TOP)\ext\misc\carray.c \
|
||||
$(TOP)\ext\misc\closure.c \
|
||||
$(TOP)\ext\misc\csv.c \
|
||||
$(TOP)\ext\misc\eval.c \
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
** 2016-06-29
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file demonstrates how to create a table-valued-function that
|
||||
** returns the values in a C-language array.
|
||||
** Examples:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,5)
|
||||
**
|
||||
** The query above returns 5 integers contained in a C-language array
|
||||
** at the address $ptr. $ptr is a pointer to the array of integers that
|
||||
** has been cast to an integer.
|
||||
**
|
||||
** There is an optional third parameter to determine the datatype of
|
||||
** the C-language array. Allowed values of the third parameter are
|
||||
** 'int32', 'int64', 'double', 'char*'. Example:
|
||||
**
|
||||
** SELECT * FROM carray($ptr,10,'char*');
|
||||
**
|
||||
** HOW IT WORKS
|
||||
**
|
||||
** The carray "function" is really a virtual table with the
|
||||
** following schema:
|
||||
**
|
||||
** CREATE TABLE carray(
|
||||
** value,
|
||||
** pointer HIDDEN,
|
||||
** count HIDDEN,
|
||||
** ctype TEXT HIDDEN
|
||||
** );
|
||||
**
|
||||
** If the hidden columns "pointer" and "count" are unconstrained, then
|
||||
** the virtual table has no rows. Otherwise, the virtual table interprets
|
||||
** the integer value of "pointer" as a pointer to the array and "count"
|
||||
** as the number of elements in the array. The virtual table steps through
|
||||
** the array, element by element.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** Allowed datatypes
|
||||
*/
|
||||
#define CARRAY_INT32 0
|
||||
#define CARRAY_INT64 1
|
||||
#define CARRAY_DOUBLE 2
|
||||
#define CARRAY_TEXT 3
|
||||
|
||||
/*
|
||||
** Names of types
|
||||
*/
|
||||
static const char *azType[] = { "int32", "int64", "double", "char*" };
|
||||
|
||||
|
||||
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||
** serve as the underlying representation of a cursor that scans
|
||||
** over rows of the result
|
||||
*/
|
||||
typedef struct carray_cursor carray_cursor;
|
||||
struct carray_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_int64 iRowid; /* The rowid */
|
||||
sqlite3_int64 iPtr; /* Pointer to array of values */
|
||||
sqlite3_int64 iCnt; /* Number of integers in the array */
|
||||
unsigned char eType; /* One of the CARRAY_type values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The carrayConnect() method is invoked to create a new
|
||||
** carray_vtab that describes the carray virtual table.
|
||||
**
|
||||
** Think of this routine as the constructor for carray_vtab objects.
|
||||
**
|
||||
** All this routine needs to do is:
|
||||
**
|
||||
** (1) Allocate the carray_vtab object and initialize all fields.
|
||||
**
|
||||
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||
** result set of queries against carray will look like.
|
||||
*/
|
||||
static int carrayConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
sqlite3_vtab *pNew;
|
||||
int rc;
|
||||
|
||||
/* Column numbers */
|
||||
#define CARRAY_COLUMN_VALUE 0
|
||||
#define CARRAY_COLUMN_POINTER 1
|
||||
#define CARRAY_COLUMN_COUNT 2
|
||||
#define CARRAY_COLUMN_CTYPE 3
|
||||
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for carray_cursor objects.
|
||||
*/
|
||||
static int carrayDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new carray_cursor object.
|
||||
*/
|
||||
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
carray_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a carray_cursor.
|
||||
*/
|
||||
static int carrayClose(sqlite3_vtab_cursor *cur){
|
||||
sqlite3_free(cur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a carray_cursor to its next row of output.
|
||||
*/
|
||||
static int carrayNext(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
pCur->iRowid++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the carray_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int carrayColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
sqlite3_int64 x = 0;
|
||||
switch( i ){
|
||||
case CARRAY_COLUMN_POINTER: x = pCur->iPtr; break;
|
||||
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||
case CARRAY_COLUMN_CTYPE: {
|
||||
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
default: {
|
||||
switch( pCur->eType ){
|
||||
case CARRAY_INT32: {
|
||||
int *p = (int*)pCur->iPtr;
|
||||
sqlite3_result_int(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_INT64: {
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pCur->iPtr;
|
||||
sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_DOUBLE: {
|
||||
double *p = (double*)pCur->iPtr;
|
||||
sqlite3_result_double(ctx, p[pCur->iRowid-1]);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case CARRAY_TEXT: {
|
||||
const char **p = (const char**)pCur->iPtr;
|
||||
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_result_int64(ctx, x);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int carrayEof(sqlite3_vtab_cursor *cur){
|
||||
carray_cursor *pCur = (carray_cursor*)cur;
|
||||
return pCur->iRowid>pCur->iCnt;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the carray_cursor object back
|
||||
** to the first row of output.
|
||||
*/
|
||||
static int carrayFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||
if( idxNum ){
|
||||
pCur->iPtr = sqlite3_value_int64(argv[0]);
|
||||
pCur->iCnt = sqlite3_value_int64(argv[1]);
|
||||
if( idxNum<3 ){
|
||||
pCur->eType = CARRAY_INT32;
|
||||
}else{
|
||||
int i;
|
||||
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||
}
|
||||
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"unknown datatype: %Q", zType);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
pCur->eType = i;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
pCur->iPtr = 0;
|
||||
pCur->iCnt = 0;
|
||||
}
|
||||
pCur->iRowid = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** SQLite will invoke this method one or more times while planning a query
|
||||
** that uses the carray virtual table. This routine needs to create
|
||||
** a query plan for each invocation and compute an estimated cost for that
|
||||
** plan.
|
||||
**
|
||||
** In this implementation idxNum is used to represent the
|
||||
** query plan. idxStr is unused.
|
||||
**
|
||||
** idxNum is 2 if the pointer= and count= constraints exist,
|
||||
** 3 if the ctype= constraint also exists, and is 0 otherwise.
|
||||
** If idxNum is 0, then carray becomes an empty table.
|
||||
*/
|
||||
static int carrayBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i; /* Loop over constraints */
|
||||
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
|
||||
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
|
||||
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
|
||||
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
switch( pConstraint->iColumn ){
|
||||
case CARRAY_COLUMN_POINTER:
|
||||
ptrIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_COUNT:
|
||||
cntIdx = i;
|
||||
break;
|
||||
case CARRAY_COLUMN_CTYPE:
|
||||
ctypeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ptrIdx>=0 && cntIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 2;
|
||||
if( ctypeIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||
pIdxInfo->idxNum = 3;
|
||||
}
|
||||
}else{
|
||||
pIdxInfo->estimatedCost = (double)2147483647;
|
||||
pIdxInfo->estimatedRows = 2147483647;
|
||||
pIdxInfo->idxNum = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** carray virtual table.
|
||||
*/
|
||||
static sqlite3_module carrayModule = {
|
||||
0, /* iVersion */
|
||||
0, /* xCreate */
|
||||
carrayConnect, /* xConnect */
|
||||
carrayBestIndex, /* xBestIndex */
|
||||
carrayDisconnect, /* xDisconnect */
|
||||
0, /* xDestroy */
|
||||
carrayOpen, /* xOpen - open a cursor */
|
||||
carrayClose, /* xClose - close a cursor */
|
||||
carrayFilter, /* xFilter - configure scan constraints */
|
||||
carrayNext, /* xNext - advance a cursor */
|
||||
carrayEof, /* xEof - check for end of scan */
|
||||
carrayColumn, /* xColumn - read data */
|
||||
carrayRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_carray_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
+10
-3
@@ -48,6 +48,8 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/*
|
||||
** A macro to hint to the compiler that a function should not be
|
||||
** inlined.
|
||||
@@ -375,7 +377,7 @@ static int csv_string_parameter(
|
||||
char **pzVal /* Write the dequoted string value here */
|
||||
){
|
||||
const char *zValue;
|
||||
zValue = csv_parameter(zParam,strlen(zParam),zArg);
|
||||
zValue = csv_parameter(zParam,(int)strlen(zParam),zArg);
|
||||
if( zValue==0 ) return 0;
|
||||
p->zErr[0] = 0;
|
||||
if( *pzVal ){
|
||||
@@ -616,7 +618,7 @@ static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
CsvCursor *pCur;
|
||||
size_t nByte;
|
||||
nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol;
|
||||
pCur = sqlite3_malloc( nByte );
|
||||
pCur = sqlite3_malloc64( nByte );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, nByte);
|
||||
pCur->azVal = (char**)&pCur[1];
|
||||
@@ -647,7 +649,7 @@ static int csvtabNext(sqlite3_vtab_cursor *cur){
|
||||
}
|
||||
if( i<pTab->nCol ){
|
||||
if( pCur->aLen[i] < pCur->rdr.n+1 ){
|
||||
char *zNew = sqlite3_realloc(pCur->azVal[i], pCur->rdr.n+1);
|
||||
char *zNew = sqlite3_realloc64(pCur->azVal[i], pCur->rdr.n+1);
|
||||
if( zNew==0 ){
|
||||
csv_errmsg(&pCur->rdr, "out of memory");
|
||||
csv_xfer_error(pTab, &pCur->rdr);
|
||||
@@ -834,6 +836,7 @@ static sqlite3_module CsvModuleFauxWrite = {
|
||||
};
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -849,6 +852,7 @@ int sqlite3_csv_init(
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
int rc;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_module(db, "csv", &CsvModule, 0);
|
||||
@@ -858,4 +862,7 @@ int sqlite3_csv_init(
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
#else
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
+18
-26
@@ -10,10 +10,7 @@
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set ::testprefix rbu1
|
||||
|
||||
db close
|
||||
@@ -96,26 +93,6 @@ proc create_rbu5 {filename} {
|
||||
return $filename
|
||||
}
|
||||
|
||||
# Run the RBU in file $rbu on target database $target until completion.
|
||||
#
|
||||
proc run_rbu {target rbu} {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
while 1 {
|
||||
set rc [rbu step]
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
}
|
||||
rbu close
|
||||
}
|
||||
|
||||
proc step_rbu {target rbu} {
|
||||
while 1 {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
set rc [rbu step]
|
||||
rbu close
|
||||
if {$rc != "SQLITE_OK"} break
|
||||
}
|
||||
set rc
|
||||
}
|
||||
|
||||
# Same as [step_rbu], except using a URI to open the target db.
|
||||
#
|
||||
@@ -641,10 +618,25 @@ foreach {tn3 create_vfs destroy_vfs} {
|
||||
# correctly.
|
||||
reset_db
|
||||
forcedelete rbu.db
|
||||
do_test $tn3.8 {
|
||||
do_test $tn3.8.1 {
|
||||
list [catch { run_rbu test.db rbu.db } msg] $msg
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
|
||||
# Test that an RBU database containing only empty data_xxx tables is
|
||||
# also handled correctly.
|
||||
reset_db
|
||||
forcedelete rbu.db
|
||||
do_execsql_test $tn3.8.2.1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
ATTACH 'rbu.db' AS rbu;
|
||||
CREATE TABLE data_t1(a, b, rbu_control);
|
||||
DETACH rbu;
|
||||
}
|
||||
do_test $tn3.8.2.1 {
|
||||
list [catch { run_rbu test.db rbu.db } msg] $msg
|
||||
} {0 SQLITE_DONE}
|
||||
|
||||
# Test that RBU can update indexes containing NULL values.
|
||||
#
|
||||
reset_db
|
||||
|
||||
+1
-26
@@ -12,35 +12,10 @@
|
||||
# Test some properties of the pager_rbu_mode and rbu_mode pragmas.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
source [file join [file dirname [info script]] rbu_common.tcl]
|
||||
set ::testprefix rbu5
|
||||
|
||||
|
||||
# Run the RBU in file $rbu on target database $target until completion.
|
||||
#
|
||||
proc run_rbu {target rbu} {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
while { [rbu step]=="SQLITE_OK" } {}
|
||||
rbu close
|
||||
}
|
||||
|
||||
|
||||
# Run the RBU in file $rbu on target database $target one step at a
|
||||
# time until completion.
|
||||
#
|
||||
proc step_rbu {target rbu} {
|
||||
while 1 {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
set rc [rbu step]
|
||||
rbu close
|
||||
if {$rc != "SQLITE_OK"} break
|
||||
}
|
||||
set rc
|
||||
}
|
||||
|
||||
# Return a list of the primary key columns for table $tbl in the database
|
||||
# opened by database handle $db.
|
||||
#
|
||||
|
||||
@@ -15,12 +15,43 @@ if {![info exists testdir]} {
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
|
||||
proc check_prestep_state {target state} {
|
||||
set oal_exists [file exists $target-oal]
|
||||
set wal_exists [file exists $target-wal]
|
||||
set progress [rbu progress]
|
||||
|
||||
if {($progress==0 && $state!="oal" && $state!="done")
|
||||
|| ($oal_exists && $wal_exists)
|
||||
|| ($progress>0 && $state=="oal" && (!$oal_exists || $wal_exists))
|
||||
|| ($state=="move" && (!$oal_exists || $wal_exists))
|
||||
|| ($state=="checkpoint" && ($oal_exists || !$wal_exists))
|
||||
|| ($state=="done" && ($oal_exists && $progress!=0))
|
||||
} {
|
||||
error "B: state=$state progress=$progress oal=$oal_exists wal=$wal_exists"
|
||||
}
|
||||
}
|
||||
|
||||
proc check_poststep_state {rc target state} {
|
||||
if {$rc=="SQLITE_OK" || $rc=="SQLITE_DONE"} {
|
||||
set oal_exists [file exists $target-oal]
|
||||
set wal_exists [file exists $target-wal]
|
||||
if {$state=="move" && ($oal_exists || !$wal_exists)} {
|
||||
error "A: state=$state progress=$progress oal=$oal_exists wal=$wal_exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Run the RBU in file $rbu on target database $target until completion.
|
||||
#
|
||||
proc run_rbu {target rbu} {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
while 1 {
|
||||
set state [rbu state]
|
||||
|
||||
check_prestep_state $target $state
|
||||
set rc [rbu step]
|
||||
check_poststep_state $rc $target $state
|
||||
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
}
|
||||
rbu close
|
||||
@@ -29,7 +60,10 @@ proc run_rbu {target rbu} {
|
||||
proc step_rbu {target rbu} {
|
||||
while 1 {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
set state [rbu state]
|
||||
check_prestep_state $target $state
|
||||
set rc [rbu step]
|
||||
check_poststep_state $rc $target $state
|
||||
rbu close
|
||||
if {$rc != "SQLITE_OK"} break
|
||||
}
|
||||
@@ -41,7 +75,10 @@ proc do_rbu_vacuum_test {tn step} {
|
||||
if {$step==0} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
while 1 {
|
||||
if {$step==1} { sqlite3rbu_vacuum rbu test.db state.db }
|
||||
set state [rbu state]
|
||||
check_prestep_state test.db $state
|
||||
set rc [rbu step]
|
||||
check_poststep_state $rc test.db $state
|
||||
if {$rc!="SQLITE_OK"} break
|
||||
if {$step==1} { rbu close }
|
||||
}
|
||||
|
||||
+66
-3
@@ -25,6 +25,10 @@ proc get_rbudiff_sql {db1 db2} {
|
||||
exec $::PROG --rbu $db1 $db2
|
||||
}
|
||||
|
||||
proc get_vtab_rbudiff_sql {db1 db2} {
|
||||
exec $::PROG --vtab --rbu $db1 $db2
|
||||
}
|
||||
|
||||
proc step_rbu {target rbu} {
|
||||
while 1 {
|
||||
sqlite3rbu rbu $target $rbu
|
||||
@@ -44,6 +48,11 @@ proc apply_rbudiff {sql target} {
|
||||
step_rbu $target rbu.db
|
||||
}
|
||||
|
||||
proc sqlesc {id} {
|
||||
set ret "'[string map {' ''} $id]'"
|
||||
set ret
|
||||
}
|
||||
|
||||
# The only argument is the output of an [sqldiff -rbu] run. This command
|
||||
# tests that the contents of the rbu_count table is correct. An exception
|
||||
# is thrown if it is not.
|
||||
@@ -54,7 +63,7 @@ proc test_rbucount {sql} {
|
||||
tmpdb eval {
|
||||
SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table'
|
||||
} {
|
||||
set a [tmpdb eval "SELECT count(*) FROM $name"]
|
||||
set a [tmpdb eval "SELECT count(*) FROM [sqlesc $name]"]
|
||||
set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}]
|
||||
if {$a != $b} {
|
||||
tmpdb close
|
||||
@@ -71,9 +80,11 @@ proc rbudiff_cksum {db1} {
|
||||
sqlite3 dbtmp $db1
|
||||
foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] {
|
||||
set cols [list]
|
||||
dbtmp eval "PRAGMA table_info = $tbl" { lappend cols "quote( $name )" }
|
||||
dbtmp eval "PRAGMA table_info = [sqlesc $tbl]" {
|
||||
lappend cols "quote( $name )"
|
||||
}
|
||||
append txt [dbtmp eval \
|
||||
"SELECT [join $cols {||'.'||}] FROM $tbl ORDER BY 1"
|
||||
"SELECT [join $cols {||'.'||}] FROM [sqlesc $tbl] ORDER BY 1"
|
||||
]
|
||||
}
|
||||
dbtmp close
|
||||
@@ -159,5 +170,57 @@ foreach {tn init mod} {
|
||||
do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that if the --vtab switch is present, [sqldiff] handles virtual
|
||||
# table types fts[345] and rtree correctly.
|
||||
#
|
||||
ifcapable fts3&&fts5&&rtree {
|
||||
|
||||
foreach {tn init mod} {
|
||||
1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(c);
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
} {
|
||||
DELETE FROM t1 WHERE rowid = 1;
|
||||
INSERT INTO t1 VALUES('a b c');
|
||||
}
|
||||
|
||||
2 {
|
||||
CREATE VIRTUAL TABLE "x y" USING 'rtree'(id, x1, x2);
|
||||
INSERT INTO "x y" VALUES(1, 2, 3);
|
||||
INSERT INTO "x y" VALUES(2, 4, 6);
|
||||
} {
|
||||
DELETE FROM "x y" WHERE rowid = 1;
|
||||
INSERT INTO "x y" VALUES(3, 6, 9);
|
||||
}
|
||||
|
||||
3 {
|
||||
CREATE VIRTUAL TABLE 'x''y' USING fts3;
|
||||
INSERT INTO 'x''y' VALUES('one two three');
|
||||
INSERT INTO 'x''y' VALUES('four five six');
|
||||
} {
|
||||
DELETE FROM 'x''y' WHERE rowid = 1;
|
||||
INSERT INTO 'x''y' VALUES('one two three');
|
||||
}
|
||||
|
||||
} {
|
||||
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db test.db
|
||||
db eval "$init"
|
||||
sqlite3 db test.db2
|
||||
db eval "$init ; $mod"
|
||||
db close
|
||||
|
||||
do_test 2.$tn.1 {
|
||||
set sql [get_vtab_rbudiff_sql test.db test.db2]
|
||||
apply_rbudiff $sql test.db
|
||||
} {SQLITE_DONE}
|
||||
do_test 2.$tn.2 { rbudiff_cksum test.db } [rbudiff_cksum test.db2]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+60
-31
@@ -2507,9 +2507,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){
|
||||
#endif
|
||||
{
|
||||
int i, sz;
|
||||
sz = sqlite3Strlen30(z);
|
||||
sz = (int)strlen(z)&0xffffff;
|
||||
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
|
||||
if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
|
||||
if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -3555,30 +3555,7 @@ static sqlite3rbu *openRbuHandle(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( p->eStage==RBU_STAGE_OAL ){
|
||||
sqlite3 *db = p->dbMain;
|
||||
|
||||
if( pState->eStage==0 && rbuIsVacuum(p) ){
|
||||
rbuCopyPragma(p, "page_size");
|
||||
rbuCopyPragma(p, "auto_vacuum");
|
||||
}
|
||||
|
||||
/* Open transactions both databases. The *-oal file is opened or
|
||||
** created at this point. */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
|
||||
}
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
|
||||
}
|
||||
|
||||
/* Check if the main database is a zipvfs db. If it is, set the upper
|
||||
** level pager to use "journal_mode=off". This prevents it from
|
||||
** generating a large journal using a temp file. */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
|
||||
if( frc==SQLITE_OK ){
|
||||
p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
|
||||
}
|
||||
}
|
||||
p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
|
||||
|
||||
/* Point the object iterator at the first object */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
@@ -3589,12 +3566,34 @@ static sqlite3rbu *openRbuHandle(
|
||||
** update finished. */
|
||||
if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
|
||||
p->rc = SQLITE_DONE;
|
||||
}
|
||||
p->eStage = RBU_STAGE_DONE;
|
||||
}else{
|
||||
if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
|
||||
rbuCopyPragma(p, "page_size");
|
||||
rbuCopyPragma(p, "auto_vacuum");
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
rbuSetupOal(p, pState);
|
||||
}
|
||||
/* Open transactions both databases. The *-oal file is opened or
|
||||
** created at this point. */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
|
||||
}
|
||||
|
||||
/* Check if the main database is a zipvfs db. If it is, set the upper
|
||||
** level pager to use "journal_mode=off". This prevents it from
|
||||
** generating a large journal using a temp file. */
|
||||
if( p->rc==SQLITE_OK ){
|
||||
int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
|
||||
if( frc==SQLITE_OK ){
|
||||
p->rc = sqlite3_exec(
|
||||
db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
|
||||
}
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
rbuSetupOal(p, pState);
|
||||
}
|
||||
}
|
||||
}else if( p->eStage==RBU_STAGE_MOVE ){
|
||||
/* no-op */
|
||||
}else if( p->eStage==RBU_STAGE_CKPT ){
|
||||
@@ -3761,9 +3760,39 @@ void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current state of the RBU vacuum or update operation.
|
||||
*/
|
||||
int sqlite3rbu_state(sqlite3rbu *p){
|
||||
int aRes[] = {
|
||||
0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
|
||||
0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
|
||||
};
|
||||
|
||||
assert( RBU_STAGE_OAL==1 );
|
||||
assert( RBU_STAGE_MOVE==2 );
|
||||
assert( RBU_STAGE_CKPT==4 );
|
||||
assert( RBU_STAGE_DONE==5 );
|
||||
assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
|
||||
assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
|
||||
assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
|
||||
assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
|
||||
|
||||
if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
|
||||
return SQLITE_RBU_STATE_ERROR;
|
||||
}else{
|
||||
assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
|
||||
assert( p->eStage==RBU_STAGE_OAL
|
||||
|| p->eStage==RBU_STAGE_MOVE
|
||||
|| p->eStage==RBU_STAGE_CKPT
|
||||
|| p->eStage==RBU_STAGE_DONE
|
||||
);
|
||||
return aRes[p->eStage];
|
||||
}
|
||||
}
|
||||
|
||||
int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
int rc = p->rc;
|
||||
|
||||
if( rc==SQLITE_DONE ) return SQLITE_OK;
|
||||
|
||||
assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
|
||||
|
||||
@@ -474,6 +474,44 @@ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
||||
*/
|
||||
void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
|
||||
|
||||
/*
|
||||
** Obtain an indication as to the current stage of an RBU update or vacuum.
|
||||
** This function always returns one of the SQLITE_RBU_STATE_XXX constants
|
||||
** defined in this file. Return values should be interpreted as follows:
|
||||
**
|
||||
** SQLITE_RBU_STATE_OAL:
|
||||
** RBU is currently building a *-oal file. The next call to sqlite3rbu_step()
|
||||
** may either add further data to the *-oal file, or compute data that will
|
||||
** be added by a subsequent call.
|
||||
**
|
||||
** SQLITE_RBU_STATE_MOVE:
|
||||
** RBU has finished building the *-oal file. The next call to sqlite3rbu_step()
|
||||
** will move the *-oal file to the equivalent *-wal path. If the current
|
||||
** operation is an RBU update, then the updated version of the database
|
||||
** file will become visible to ordinary SQLite clients following the next
|
||||
** call to sqlite3rbu_step().
|
||||
**
|
||||
** SQLITE_RBU_STATE_CHECKPOINT:
|
||||
** RBU is currently performing an incremental checkpoint. The next call to
|
||||
** sqlite3rbu_step() will copy a page of data from the *-wal file into
|
||||
** the target database file.
|
||||
**
|
||||
** SQLITE_RBU_STATE_DONE:
|
||||
** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step()
|
||||
** will immediately return SQLITE_DONE.
|
||||
**
|
||||
** SQLITE_RBU_STATE_ERROR:
|
||||
** An error has occurred. Any subsequent calls to sqlite3rbu_step() will
|
||||
** immediately return the SQLite error code associated with the error.
|
||||
*/
|
||||
#define SQLITE_RBU_STATE_OAL 1
|
||||
#define SQLITE_RBU_STATE_MOVE 2
|
||||
#define SQLITE_RBU_STATE_CHECKPOINT 3
|
||||
#define SQLITE_RBU_STATE_DONE 4
|
||||
#define SQLITE_RBU_STATE_ERROR 5
|
||||
|
||||
int sqlite3rbu_state(sqlite3rbu *pRbu);
|
||||
|
||||
/*
|
||||
** Create an RBU VFS named zName that accesses the underlying file-system
|
||||
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
|
||||
|
||||
@@ -69,6 +69,8 @@ static int test_sqlite3rbu_cmd(
|
||||
{"dbMain_eval", 3, "SQL"}, /* 4 */
|
||||
{"bp_progress", 2, ""}, /* 5 */
|
||||
{"db", 3, "RBU"}, /* 6 */
|
||||
{"state", 2, ""}, /* 7 */
|
||||
{"progress", 2, ""}, /* 8 */
|
||||
{0,0,0}
|
||||
};
|
||||
int iCmd;
|
||||
@@ -166,6 +168,18 @@ static int test_sqlite3rbu_cmd(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 7: /* state */ {
|
||||
const char *aRes[] = { 0, "oal", "move", "checkpoint", "done", "error" };
|
||||
int eState = sqlite3rbu_state(pRbu);
|
||||
assert( eState>0 && eState<=5 );
|
||||
Tcl_SetResult(interp, (char*)aRes[eState], TCL_STATIC);
|
||||
break;
|
||||
}
|
||||
case 8: /* progress */ {
|
||||
sqlite3_int64 nStep = sqlite3rbu_progress(pRbu);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nStep));
|
||||
break;
|
||||
}
|
||||
|
||||
default: /* seems unlikely */
|
||||
assert( !"cannot happen" );
|
||||
|
||||
@@ -324,6 +324,7 @@ TESTSRC = \
|
||||
#
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/carray.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/csv.c \
|
||||
$(TOP)/ext/misc/eval.c \
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
C Fix\san\sundersized\sbuffer\sin\sthe\sSHA1\simplementation.
|
||||
D 2016-06-08T13:59:35.817
|
||||
F Makefile.in f3f7d2060ce03af4584e711ef3a626ef0b1d6340
|
||||
C Improvements\sto\ssqlite3_trace_v2()\sdocumentation.\s\sFix\sthe\nsqlite3VdbeExpandSql()\sroutine\sto\srespond\sbetter\sto\sOOM\sconditions.
|
||||
D 2016-07-23T04:58:57.202
|
||||
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 50149765ef72f4e652b9a0f1f6462c4784bb9423
|
||||
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION cb29eb11e493dd85b3eeec4053c03949bf98478e
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -204,9 +204,10 @@ F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c 43df9d8ef2fae7a325100ebd713ab089dc829dd7
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
|
||||
F ext/misc/carray.c 214c9e9d909ceaae3b2f5f917cc2204deca85cc6
|
||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||
F ext/misc/csv.c f01126ba170fd4ef7c752b156568a80c912d4441
|
||||
F ext/misc/csv.c f51b0566ea15e24cce871037e30a4db99ea6cf77
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
@@ -226,14 +227,14 @@ F ext/misc/vfsstat.c 6110aeeaab2f1df17a923c8a8acef3c74f6dc515
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
|
||||
F ext/rbu/rbu.c b2c0b5e6ae1a89affc0edfc127ebfa5f637a0ce4
|
||||
F ext/rbu/rbu1.test 42bd835e019eff789ec241017965277baeb658b1
|
||||
F ext/rbu/rbu1.test 43836fac8c7179a358eaf38a8a1ef3d6e6285842
|
||||
F ext/rbu/rbu10.test 046b0980041d30700464a800bbf6733ed2df515d
|
||||
F ext/rbu/rbu11.test 9bc68c2d3dbeb1720153626e3bd0466dcc017702
|
||||
F ext/rbu/rbu12.test bde22ed0004dd5d1888c72a84ae407e574aeae16
|
||||
F ext/rbu/rbu13.test 462ff799c4afedc3ef8a47ff818c0ffbf14ae4f2
|
||||
F ext/rbu/rbu14.test 01f5dcba904aecadbaea69d4ccdc2ea43dd30560
|
||||
F ext/rbu/rbu3.test 8bd4c6b87367c358981b6a47dc3d654fa60bff90
|
||||
F ext/rbu/rbu5.test 2e24fee3e615aecd99bbdd46967935a641e866f7
|
||||
F ext/rbu/rbu5.test cf1fa84d6107efd73e292a7be8e1fb31953ca45c
|
||||
F ext/rbu/rbu6.test 32e8ed60631b6facdb6366bd2b5f5f25245e7edb
|
||||
F ext/rbu/rbu7.test fd025d5ba440fcfe151fbb0e3835e1e7fe964fa1
|
||||
F ext/rbu/rbu8.test 3bbf2c35d71a843c463efe93946f14ad10c3ede0
|
||||
@@ -241,9 +242,9 @@ F ext/rbu/rbu9.test 0806d1772c9f4981774ff028de6656e4183082af
|
||||
F ext/rbu/rbuA.test c1a7b3e2d926b8f8448bb3b4ae787e314ee4b2b3
|
||||
F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
|
||||
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
|
||||
F ext/rbu/rbu_common.tcl 3a4b916b6f5dca9c9da9a30863e272fe5ea4414f
|
||||
F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
|
||||
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
|
||||
F ext/rbu/rbudiff.test 2df0a8a7d998ecf81764c21eeda3cde5611c5091
|
||||
F ext/rbu/rbudiff.test 4c9f8df6f723f553781d3d117501b7e9d170a145
|
||||
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
|
||||
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
|
||||
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
|
||||
@@ -252,9 +253,9 @@ F ext/rbu/rbuprogress.test 2023a7df2c523e3df1cb532eff811cda385a789a
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
|
||||
F ext/rbu/rbuvacuum2.test 45009e127c3fb385e5c0fd5a8a63fb922a79d0ab
|
||||
F ext/rbu/sqlite3rbu.c a37a7dfb225c497171aa60120e81b884954361c7
|
||||
F ext/rbu/sqlite3rbu.h 2acd0a6344a6079de15c8dc9d84d3df83a665930
|
||||
F ext/rbu/test_rbu.c 9bbdf6bd8efd58fbc4f192698df50569598fbb9e
|
||||
F ext/rbu/sqlite3rbu.c 948677ee0ec57da51148e6c5f64ac68afcf36ab2
|
||||
F ext/rbu/sqlite3rbu.h db8858120c9be14b60c9225f9da28221f5f6b945
|
||||
F ext/rbu/test_rbu.c 9f043b74c46c45b231f4313aed1fccb379a76fe6
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c d26a815b0df1c412a6881dae8d7fd3c9c08cce68
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
@@ -307,7 +308,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 3f669c06db5c4a53ff21dda639247c6310497180
|
||||
F main.mk e9d66f1b1c4874221d12d940be3ce5f397c10741
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -319,35 +320,35 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 1bb0709b3048e24217b80ec6bd78a3e99a47c01b
|
||||
F src/alter.c cc28ab933ae615b22add0d609794ffb6596b42ea
|
||||
F src/analyze.c 37fedc80ac966ce1745811746e68e4d8fa64c7fe
|
||||
F src/attach.c 771153bd1f4ab0b97a44a13dde2c7e5e1efeba22
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 6df65fdd569c901a418887a1a76f82ec35044556
|
||||
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 2781fb1db1e46390a9c27a2162395f371577ac66
|
||||
F src/btree.h 2107a2630e02c8cba58bb12ce14e731e734ea29c
|
||||
F src/btree.c dc4e5f3e95fd57b610422e36e0913662ecd6814c
|
||||
F src/btree.h 075c45707c0f8f8af118f739f36df8098a08b7da
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c e827e57e4a29c00e8429c5fd4d9d4572cb1b32a4
|
||||
F src/build.c d1fdfd7ab8f5447e494ef15825973bf0719527c6
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 999a828425b35b8092a8cde25690e71c20906344
|
||||
F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
|
||||
F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
|
||||
F src/dbstat.c c845548d4346e606e2f2b7d2e714ace2b8a7dd1b
|
||||
F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
|
||||
F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
|
||||
F src/expr.c 798146ea4c87d723e8a157d88450ac9c43256998
|
||||
F src/expr.c 21b153e1046c624e9387a17d3261f69b461e700c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
|
||||
F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
|
||||
F src/global.c c45ea22aff29334f6a9ec549235ac3357c970015
|
||||
F src/hash.c 55b5fb474100cee0b901edaf203e26c970940f36
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/insert.c 8f4e9fcbd8e95e85f15647ba8b413b18d556ec2b
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c 4237fd37ca589f1d90b3ea925dd9df20da8e0c84
|
||||
F src/main.c 405d13e3a4f7c5add9fb27702ae70ed0a6e32cca
|
||||
F src/main.c 2d3e62a971e7f169a74448e81af9ebde95b07381
|
||||
F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
|
||||
@@ -355,27 +356,27 @@ F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
|
||||
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
|
||||
F src/memjournal.c 95752936c11dc6995672d1dd783cd633eea0cc95
|
||||
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
|
||||
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
|
||||
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
|
||||
F src/mutex_w32.c 5e6fe1c298fb5a8a15aaed4161d5759311431c17
|
||||
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
|
||||
F src/os.c 4d83917f072ad958fba9235136fa2ed43df47905
|
||||
F src/os.c add02933b1dce7a39a005b00a2f5364b763e9a24
|
||||
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c a9443cdab41d7f3cdf0df3a5aab62fd6e1c9b234
|
||||
F src/os_win.c d4b8faf8896b65818e67070711fdd00d8e620bd6
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/os_win.c 520f23475f1de530c435d30b67b7b15fe90874b0
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c c368634b888b1c8740aea83b36bfd266f2443e60
|
||||
F src/pager.h 8ab6b6feeee4bc0439bfde7ee59ba99df98b9bc3
|
||||
F src/parse.y 01b9f37c4c7009ab56fda98bc7db4c42643cecfe
|
||||
F src/pager.h 031a87445e5e0afc85312d1c380e123ad6c7aeaf
|
||||
F src/parse.y f374ab20106362eb3f5c01b3e6a002f0bbead7ff
|
||||
F src/pcache.c 5583c8ade4b05075a60ba953ef471d1c1a9c05df
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c 7f51d2b541aab57596adf62db2c4bb025d34f04d
|
||||
F src/pragma.c d98039af2deb5a4990f6635462b3f61f325a6c75
|
||||
F src/pragma.c c8b499756658cb8b82cfdbb5845c22cf11f297aa
|
||||
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
|
||||
F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e
|
||||
F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
|
||||
@@ -383,16 +384,16 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c cca3aa77b95706df5d635a2141a4d1de60ae6598
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c f3c6e9065fb34f6a23af27ec7f1f717ffbfc2ee4
|
||||
F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6
|
||||
F src/sqlite.h.in 5f8113dbec74c6c093ead9930afb8c9fbd9f643d
|
||||
F src/shell.c a8a9e392a6a2777fabf5feb536931cb190f235e5
|
||||
F src/sqlite.h.in 3dc7317ded4bf66facd845705f45f21d03517940
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
|
||||
F src/sqliteInt.h 801e2a569ea79b09b87d045cd6f00ec88205f1f6
|
||||
F src/sqlite3ext.h 46f300b6e300e0fa916d7d58c44b53415b8471a9
|
||||
F src/sqliteInt.h 48cd97eb134665348393dfe277b4c14d1085bfc7
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
F src/tclsqlite.c 9c4c4589d078de37813ded708d8838b338ffb060
|
||||
F src/test1.c 43b37ab2b7338fd3313e74902f0d6c821eae843b
|
||||
F src/tclsqlite.c 573e63c959b314d77486f3565fa79c60cda3df7e
|
||||
F src/test1.c 186e3b53c402b7a73bcb4ade2b77709675c39fe3
|
||||
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
||||
F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59
|
||||
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
|
||||
@@ -404,7 +405,7 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
|
||||
F src/test_bestindex.c 29af3cc3b963ffe5760c85d142b9b3e5302c1e3d
|
||||
F src/test_bestindex.c f9e6807c52aa532e4775321ce3ed8e47c907ed45
|
||||
F src/test_blob.c b2551a9b5573232db5f66f292307c37067937239
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c 7003f6f35134de6f19c6588f44783e43390ea277
|
||||
@@ -415,12 +416,12 @@ F src/test_func.c 37453d346cfcf118774efd5bf6187f7e6a7e3254
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
|
||||
F src/test_intarray.c 870124b95ec4c645d4eb84f15efb7133528fb1a5
|
||||
F src/test_intarray.h 9dc57417fb65bc7835cc18548852cc08cc062202
|
||||
F src/test_intarray.h f3b7672f5d1056eac563c0d6ea8480a660b1475c
|
||||
F src/test_journal.c d3b83f2bcb7792c709e57abddc456a2b1818643a
|
||||
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
|
||||
F src/test_malloc.c 94c18e88d6df6d471a0d04ddb809f833d1739950
|
||||
F src/test_malloc.c 6b27e947eeeb70d11aa65406ed28d749e39b6356
|
||||
F src/test_multiplex.c eafc567ebe162e36f17b5062285dfe90461cf8e9
|
||||
F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
|
||||
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
|
||||
F src/test_mutex.c dbdfaff8580071f2212a0deae3325a93a737819c
|
||||
F src/test_onefile.c 416f87a28d6d673352d33fc4b1c7d39db878e50f
|
||||
F src/test_osinst.c ad0233b1dabb0390e25edded4ebd79a2a61538c6
|
||||
@@ -447,25 +448,25 @@ F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
|
||||
F src/update.c 4f05ea8cddfa367d045e03589756c02199e8f9bd
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d
|
||||
F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
|
||||
F src/vdbe.c e23a15d352e63b51cf08af8052e678e67c54ec09
|
||||
F src/vdbe.h 5591b5add447096e31288b5a0a78ec5d7b5c5170
|
||||
F src/vdbeInt.h ddb157974436d87652de7dc641f7191496d9a8cd
|
||||
F src/vdbeapi.c 02bcbc2ca5d2004b029088b05b468b394881e103
|
||||
F src/vdbeaux.c c90275b0e55a2b32c03dc09314194fe46f2429d8
|
||||
F src/vacuum.c 544ec90a66a4b0460b7c1baeadbc21b45e6ca0b6
|
||||
F src/vdbe.c 7b5570f77e32766949fd8f9478e4a9bb06e6ab24
|
||||
F src/vdbe.h 67bc551f7faf04c33493892e4b378aada823ed10
|
||||
F src/vdbeInt.h c59381049af5c7751a83456c39b80d1a6fde1f9d
|
||||
F src/vdbeapi.c c3f6715a99995c11748ecad91d25e93fd9fc390b
|
||||
F src/vdbeaux.c a32d79aeaa88dc2b97c261172d952d395254a055
|
||||
F src/vdbeblob.c 83d2d266383157b02e2b809350bb197e89d7895b
|
||||
F src/vdbemem.c 1ecaa5ee0caff07255f25d04e8dc88befb6f88d1
|
||||
F src/vdbesort.c 91fda3909326860382b0ca8aa251e609c6a9d62c
|
||||
F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
F src/vtab.c 948d2d4984219eee37a7bf427d6667e21e6eb92e
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/wal.h 6dd221ed384afdc204bc61e25c23ef7fd5a511f2
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c b9f5b0ddb14c3827e70b5379e659cf4cfd524c4d
|
||||
F src/where.c 48eed8ebe319c6cbc7bf7682018f32af0f5189f5
|
||||
F src/whereInt.h e5b939701a7ceffc5a3a8188a37f9746416ebcd0
|
||||
F src/wherecode.c ba71a4e4bada29aa9842200e6299714bf18c812c
|
||||
F src/whereexpr.c c32d47085dbaca0b8fd013210f56693c7d220d48
|
||||
F src/wherecode.c 11e38f5e2dc5c007143fbf7fdb14bca40a6b74ad
|
||||
F src/whereexpr.c d7dcbf14ce1b5876c1f76496162c30fcba669563
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -474,8 +475,8 @@ F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||
F test/alter.test 2facdddf08d0d48e75dc6cc312cd2b030f4835dd
|
||||
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test b3568d11c38c4599c92f24242eda34144d78dc10
|
||||
F test/alter4.test c461150723ac957f3b2214aa0b11552cd72023ec
|
||||
F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3
|
||||
F test/alter4.test 0c33c542247ba5aee4f4a0133ac44bcf8f97e5e0
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
|
||||
F test/analyze.test 3eb35a4af972f98422e5dc0586501b17d103d321
|
||||
@@ -528,7 +529,7 @@ F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
|
||||
F test/bestindex1.test 0cf1bd2d7b97d3a3a8c10736125274f64765c4ee
|
||||
F test/bestindex2.test 4a06b8922ab2fd09434870da8d1cdf525aaf7060
|
||||
F test/bestindex3.test b80da904d23581d233a7ceee7d6bbad2b23a8133
|
||||
F test/bestindex3.test dd5fa4f483cd0356549203c4522f8c9e21cb1fc0
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
@@ -574,6 +575,7 @@ F test/collate7.test 8ec29d98f3ee4ccebce6e16ce3863fb6b8c7b868
|
||||
F test/collate8.test cd9b3d3f999b8520ffaa7cc1647061fc5bab1334
|
||||
F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
|
||||
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/collateB.test 8ec2accd2d7166c1eff0d2a39bc90262c6f89632
|
||||
F test/colmeta.test 2c765ea61ee37bc43bbe6d6047f89004e6508eb1
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 029faa2d81a0d1cafb5f88614beb663d972c01db
|
||||
@@ -615,10 +617,11 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/csv01.test 0929a9ce47021519512be92861f29e32d2538e5f
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/ctime.test 0b995accd44a52914bd4744d5c1b6e1a56c7897c
|
||||
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 2b45341d32d1aae9991a00ef31ebca339b274255
|
||||
F test/date.test 984ac1e3e5e031386866f034006148d3972b4a65
|
||||
F test/dbstatus.test 8de104bb5606f19537d23cd553b41349b5ab1204
|
||||
F test/dbstatus.test 85833ba5bc95262749d080dcd40af87072ea8d5b
|
||||
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
|
||||
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
|
||||
F test/delete.test e1bcdf8926234e27aac24b346ad83d3329ec8b6f
|
||||
@@ -840,7 +843,7 @@ F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
|
||||
F test/index3.test 81bc47890b8abfb181bc35f8d10b56c069803386
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
|
||||
F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a
|
||||
F test/index6.test 43b4e29258b978fcdab84fc61df4f5212119dd09
|
||||
F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
|
||||
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
|
||||
F test/indexexpr1.test cb71b6586177b840e28110dd952178bb2bdfedc2
|
||||
@@ -1040,7 +1043,7 @@ F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
||||
F test/select7.test 95e370c42d47c3c52377d05e9ffc01ccff7c1f61
|
||||
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7
|
||||
F test/selectA.test 101e722370ac6e84978c2958b8931c78b10a1709
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
@@ -1100,7 +1103,7 @@ F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
|
||||
F test/sqllimits1.test a74ee2a3740b9f9c2437c246d8fb77354862a142
|
||||
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
|
||||
F test/stat.test 66e95f97b9f724f9ab921d054ee0db3c2689f1ee
|
||||
F test/stat.test ab95d28503d0f6d98ffd8ce204643c9da090ebf1
|
||||
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
|
||||
F test/stmt.test 64844332db69cf1a735fcb3e11548557fc95392f
|
||||
F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
|
||||
@@ -1113,11 +1116,11 @@ F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test f977868fa8bb7beb4b2072883190411653473906
|
||||
F test/tabfunc01.test 50a9fb379f9747fd0d40ea6d8fa3a101361bb537
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test e1306001a0ca92250b691ea6d3cecaca5b6342aa
|
||||
F test/tclsqlite.test 1d73b9203b1ca8798d7d7310742b8d3febc0d56e
|
||||
F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
|
||||
F test/tempdb2.test 4fc92055f2a3f7626c0f2eabbb637dc021b311d5
|
||||
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
|
||||
@@ -1125,7 +1128,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 3ace46dee55f07e28a1e3ab03258b929fefcee5b
|
||||
F test/tester.tcl a52b5be1bb586afa1c8bcdcd4b86588645e1ae52
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1282,6 +1285,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
|
||||
F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
|
||||
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
|
||||
F test/trace3.test 01e4111d582c7b20ab1c63156169157d256bc3d5
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
|
||||
@@ -1375,7 +1379,7 @@ F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test f0c325563acde44f2c4ea6ba348e9e29f7121757
|
||||
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
|
||||
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
|
||||
F test/where3.test 54cdeb02157acc979de41530b804ae7b09552bf1
|
||||
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -1399,6 +1403,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/with1.test cef099a491eac9874f2c28bd2dc86394fb3e47b3
|
||||
F test/with2.test 2b40da883658eb74ad8ad06afabe11a408e7fb87
|
||||
F test/with3.test 511bacdbe41c49cf34f9fd1bd3245fe1575bca98
|
||||
@@ -1429,7 +1434,7 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c 09a96bed19955697a5e20c49ad863ec2005815a2
|
||||
F tool/lempar.c 8c4e9d8517e50da391f1d89a519e743dd4afbc09
|
||||
F tool/lempar.c 57ffa9852901f6abc45981f0d882f31d1ccb06c0
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
@@ -1468,7 +1473,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/sqldiff.c ca315aca4e2d24233e8f2000edea5880c53d1875
|
||||
F tool/sqldiff.c af5d80cdc88a91a0f3cccfaa316b5a27b213568a
|
||||
F tool/srcck1.c 4c39bdfa9a92edd20233ee720df84dbeb2417602
|
||||
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
|
||||
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
|
||||
@@ -1501,7 +1506,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 44f157e0f0d5a76ef9002b2592164c4fdae89e34
|
||||
R 654981991ade95156b7aa25e1b0590de
|
||||
P ebd388e94da4a2b29c2a546f832d359619803ec5
|
||||
R 19a6abe5f5ce376943dab16457333fb2
|
||||
U drh
|
||||
Z 0f8b86024c43c03c854a2dd32c154497
|
||||
Z 006f9291eaaf608f3169b0980f613014
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
fb2768154c513881886e89801e906bea959197b3
|
||||
0400f642d542e62bb428e0bf263964c65691368e
|
||||
+12
-9
@@ -601,6 +601,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
Expr *pDflt; /* Default value for the new column */
|
||||
sqlite3 *db; /* The database connection; */
|
||||
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
|
||||
int r1; /* Temporary registers */
|
||||
|
||||
db = pParse->db;
|
||||
if( pParse->nErr || db->mallocFailed ) return;
|
||||
@@ -695,16 +696,18 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
db->flags = savedDbFlags;
|
||||
}
|
||||
|
||||
/* If the default value of the new column is NULL, then the file
|
||||
** format to 2. If the default value of the new column is not NULL,
|
||||
** the file format be 3. Back when this feature was first added
|
||||
** in 2006, we went to the trouble to upgrade the file format to the
|
||||
** minimum support values. But 10-years on, we can assume that all
|
||||
** extent versions of SQLite support file-format 4, so we always and
|
||||
** unconditionally upgrade to 4.
|
||||
/* Make sure the schema version is at least 3. But do not upgrade
|
||||
** from less than 3 to 4, as that will corrupt any preexisting DESC
|
||||
** index.
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT,
|
||||
SQLITE_MAX_FILE_FORMAT);
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
|
||||
/* Reload the schema of the modified table. */
|
||||
reloadTableSchema(pParse, pTab, pTab->zName);
|
||||
|
||||
+13
-2
@@ -2337,9 +2337,9 @@ int sqlite3BtreeOpen(
|
||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
|
||||
/* Add the new BtShared object to the linked list sharable BtShareds.
|
||||
*/
|
||||
pBt->nRef = 1;
|
||||
if( p->sharable ){
|
||||
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
|
||||
pBt->nRef = 1;
|
||||
MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
|
||||
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
|
||||
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
|
||||
@@ -2410,6 +2410,7 @@ btree_open_out:
|
||||
assert( sqlite3_mutex_held(mutexOpen) );
|
||||
sqlite3_mutex_leave(mutexOpen);
|
||||
}
|
||||
assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -5070,7 +5071,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( pRes );
|
||||
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
|
||||
assert( (pIdxKey==0)==(pCur->curIntKey!=0) || pCur->eState!=CURSOR_VALID );
|
||||
assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
|
||||
|
||||
/* If the cursor is already positioned at the point we are trying
|
||||
** to move to, then just return without doing any work */
|
||||
@@ -9698,4 +9699,14 @@ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
|
||||
int sqlite3BtreeSharable(Btree *p){
|
||||
return p->sharable;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of connections to the BtShared object accessed by
|
||||
** the Btree handle passed as the only argument. For private caches
|
||||
** this is always 1. For shared caches it may be 1 or greater.
|
||||
*/
|
||||
int sqlite3BtreeConnectionCount(Btree *p){
|
||||
testcase( p->sharable );
|
||||
return p->pBt->nRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
+5
-3
@@ -13,8 +13,8 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
#ifndef SQLITE_BTREE_H
|
||||
#define SQLITE_BTREE_H
|
||||
|
||||
/* TODO: This definition is just included so other modules compile. It
|
||||
** needs to be revisited.
|
||||
@@ -328,11 +328,13 @@ void sqlite3BtreeCursorList(Btree*);
|
||||
void sqlite3BtreeEnterAll(sqlite3*);
|
||||
int sqlite3BtreeSharable(Btree*);
|
||||
void sqlite3BtreeEnterCursor(BtCursor*);
|
||||
int sqlite3BtreeConnectionCount(Btree*);
|
||||
#else
|
||||
# define sqlite3BtreeEnter(X)
|
||||
# define sqlite3BtreeEnterAll(X)
|
||||
# define sqlite3BtreeSharable(X) 0
|
||||
# define sqlite3BtreeEnterCursor(X)
|
||||
# define sqlite3BtreeConnectionCount(X) 1
|
||||
#endif
|
||||
|
||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
|
||||
@@ -357,4 +359,4 @@ void sqlite3BtreeCursorList(Btree*);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _BTREE_H_ */
|
||||
#endif /* SQLITE_BTREE_H */
|
||||
|
||||
+16
-12
@@ -338,7 +338,7 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
*/
|
||||
Table *sqlite3LocateTable(
|
||||
Parse *pParse, /* context in which to report errors */
|
||||
int isView, /* True if looking for a VIEW rather than a TABLE */
|
||||
u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */
|
||||
const char *zName, /* Name of the table we are looking for */
|
||||
const char *zDbase /* Name of the database. Might be NULL */
|
||||
){
|
||||
@@ -352,7 +352,7 @@ Table *sqlite3LocateTable(
|
||||
|
||||
p = sqlite3FindTable(pParse->db, zName, zDbase);
|
||||
if( p==0 ){
|
||||
const char *zMsg = isView ? "no such view" : "no such table";
|
||||
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
|
||||
/* If zName is the not the name of a table in the schema created using
|
||||
@@ -364,12 +364,14 @@ Table *sqlite3LocateTable(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
if( (flags & LOCATE_NOERR)==0 ){
|
||||
if( zDbase ){
|
||||
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
}
|
||||
pParse->checkSchema = 1;
|
||||
}
|
||||
|
||||
return p;
|
||||
@@ -386,7 +388,7 @@ Table *sqlite3LocateTable(
|
||||
*/
|
||||
Table *sqlite3LocateTableItem(
|
||||
Parse *pParse,
|
||||
int isView,
|
||||
u32 flags,
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
@@ -397,7 +399,7 @@ Table *sqlite3LocateTableItem(
|
||||
}else{
|
||||
zDb = p->zDatabase;
|
||||
}
|
||||
return sqlite3LocateTable(pParse, isView, p->zName, zDb);
|
||||
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2504,6 +2506,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
assert( pName->nSrc==1 );
|
||||
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
|
||||
if( noErr ) db->suppressErr++;
|
||||
assert( isView==0 || isView==LOCATE_VIEW );
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
@@ -3434,10 +3437,11 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
int i;
|
||||
|
||||
/* Set the first entry (number of rows in the index) to the estimated
|
||||
** number of rows in the table. Or 10, if the estimated number of rows
|
||||
** in the table is less than that. */
|
||||
** number of rows in the table, or half the number of rows in the table
|
||||
** for a partial index. But do not let the estimate drop below 10. */
|
||||
a[0] = pIdx->pTable->nRowLogEst;
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
|
||||
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
||||
|
||||
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
||||
** 6 and each subsequent value (if any) is 5. */
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ static const char * const azCompileOpt[] = {
|
||||
"DISABLE_LFS",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_8_3_NAMES
|
||||
"ENABLE_8_3_NAMES",
|
||||
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
|
||||
#endif
|
||||
#if SQLITE_ENABLE_API_ARMOR
|
||||
"ENABLE_API_ARMOR",
|
||||
|
||||
+3
-3
@@ -58,10 +58,10 @@
|
||||
*/
|
||||
#define VTAB_SCHEMA \
|
||||
"CREATE TABLE xx( " \
|
||||
" name STRING, /* Name of table or index */" \
|
||||
" path INTEGER, /* Path to page from root */" \
|
||||
" name TEXT, /* Name of table or index */" \
|
||||
" path TEXT, /* Path to page from root */" \
|
||||
" pageno INTEGER, /* Page number */" \
|
||||
" pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
|
||||
" payload INTEGER, /* Bytes of payload on this page */" \
|
||||
" unused INTEGER, /* Bytes of unused space on this page */" \
|
||||
|
||||
+6
-1
@@ -1818,6 +1818,11 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
||||
|
||||
if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
const i64 sOne = 1;
|
||||
sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
||||
iTab, 0, 0, (u8*)&sOne, P4_INT64);
|
||||
#endif
|
||||
*prRhsHasNull = ++pParse->nMem;
|
||||
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
|
||||
}
|
||||
@@ -1830,7 +1835,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
/* If no preexisting index is available for the IN clause
|
||||
** and IN_INDEX_NOOP is an allowed reply
|
||||
** and the RHS of the IN operator is a list, not a subquery
|
||||
** and the RHS is not contant or has two or fewer terms,
|
||||
** and the RHS is not constant or has two or fewer terms,
|
||||
** then it is not worth creating an ephemeral table to evaluate
|
||||
** the IN operator so return IN_INDEX_NOOP.
|
||||
*/
|
||||
|
||||
+3
-3
@@ -12,8 +12,8 @@
|
||||
** This is the header file for the generic hash-table implementation
|
||||
** used in SQLite.
|
||||
*/
|
||||
#ifndef _SQLITE_HASH_H_
|
||||
#define _SQLITE_HASH_H_
|
||||
#ifndef SQLITE_HASH_H
|
||||
#define SQLITE_HASH_H
|
||||
|
||||
/* Forward declarations of structures. */
|
||||
typedef struct Hash Hash;
|
||||
@@ -93,4 +93,4 @@ void sqlite3HashClear(Hash*);
|
||||
*/
|
||||
/* #define sqliteHashCount(H) ((H)->count) // NOT USED */
|
||||
|
||||
#endif /* _SQLITE_HASH_H_ */
|
||||
#endif /* SQLITE_HASH_H */
|
||||
|
||||
+3
-3
@@ -13,8 +13,8 @@
|
||||
** This file contains inline asm code for retrieving "high-performance"
|
||||
** counters for x86 class CPUs.
|
||||
*/
|
||||
#ifndef _HWTIME_H_
|
||||
#define _HWTIME_H_
|
||||
#ifndef SQLITE_HWTIME_H
|
||||
#define SQLITE_HWTIME_H
|
||||
|
||||
/*
|
||||
** The following routine only works on pentium-class (or newer) processors.
|
||||
@@ -82,4 +82,4 @@
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_HWTIME_H_) */
|
||||
#endif /* !defined(SQLITE_HWTIME_H) */
|
||||
|
||||
+30
-2
@@ -1033,6 +1033,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( db->mTrace & SQLITE_TRACE_CLOSE ){
|
||||
db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
||||
}
|
||||
|
||||
/* Force xDisconnect calls on all virtual tables */
|
||||
disconnectAllVtab(db);
|
||||
@@ -1801,7 +1804,8 @@ int sqlite3_overload_function(
|
||||
** trace is a pointer to a function that is invoked at the start of each
|
||||
** SQL statement.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
|
||||
void *pOld;
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
@@ -1812,11 +1816,35 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pOld = db->pTraceArg;
|
||||
db->xTrace = xTrace;
|
||||
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
|
||||
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return pOld;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_DEPRECATED */
|
||||
|
||||
/* Register a trace callback using the version-2 interface.
|
||||
*/
|
||||
int sqlite3_trace_v2(
|
||||
sqlite3 *db, /* Trace this connection */
|
||||
unsigned mTrace, /* Mask of events to be traced */
|
||||
int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */
|
||||
void *pArg /* Context */
|
||||
){
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
db->mTrace = mTrace;
|
||||
db->xTrace = xTrace;
|
||||
db->pTraceArg = pArg;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register a profile function. The pArg from the previously registered
|
||||
** profile function is returned.
|
||||
|
||||
+3
-3
@@ -12,8 +12,8 @@
|
||||
**
|
||||
** This file contains code that is specific to MSVC.
|
||||
*/
|
||||
#ifndef _MSVC_H_
|
||||
#define _MSVC_H_
|
||||
#ifndef SQLITE_MSVC_H
|
||||
#define SQLITE_MSVC_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4054)
|
||||
@@ -33,4 +33,4 @@
|
||||
#pragma warning(disable : 4706)
|
||||
#endif /* defined(_MSC_VER) */
|
||||
|
||||
#endif /* _MSVC_H_ */
|
||||
#endif /* SQLITE_MSVC_H */
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
** This file contains OS interface code that is common to all
|
||||
** architectures.
|
||||
*/
|
||||
#define _SQLITE_OS_C_ 1
|
||||
#include "sqliteInt.h"
|
||||
#undef _SQLITE_OS_C_
|
||||
|
||||
/*
|
||||
** If we compile with the SQLITE_TEST macro set, then the following block
|
||||
|
||||
+3
-3
@@ -13,8 +13,8 @@
|
||||
** This file contains pre-processor directives related to operating system
|
||||
** detection and/or setup.
|
||||
*/
|
||||
#ifndef _OS_SETUP_H_
|
||||
#define _OS_SETUP_H_
|
||||
#ifndef SQLITE_OS_SETUP_H
|
||||
#define SQLITE_OS_SETUP_H
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other operating
|
||||
@@ -54,4 +54,4 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _OS_SETUP_H_ */
|
||||
#endif /* SQLITE_OS_SETUP_H */
|
||||
|
||||
+221
-67
@@ -290,6 +290,17 @@ struct winFile {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** The winVfsAppData structure is used for the pAppData member for all of the
|
||||
** Win32 VFS variants.
|
||||
*/
|
||||
typedef struct winVfsAppData winVfsAppData;
|
||||
struct winVfsAppData {
|
||||
const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
|
||||
void *pAppData; /* The extra pAppData, if any. */
|
||||
BOOL bNoLock; /* Non-zero if locking is disabled. */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values for winFile.ctrlFlags
|
||||
*/
|
||||
@@ -2611,7 +2622,12 @@ static int winClose(sqlite3_file *id){
|
||||
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
|
||||
#if SQLITE_OS_WINCE
|
||||
#define WINCE_DELETION_ATTEMPTS 3
|
||||
winceDestroyLock(pFile);
|
||||
{
|
||||
winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData;
|
||||
if( pAppData==NULL || !pAppData->bNoLock ){
|
||||
winceDestroyLock(pFile);
|
||||
}
|
||||
}
|
||||
if( pFile->zDeleteOnClose ){
|
||||
int cnt = 0;
|
||||
while(
|
||||
@@ -3343,6 +3359,44 @@ static int winUnlock(sqlite3_file *id, int locktype){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
****************************** No-op Locking **********************************
|
||||
**
|
||||
** Of the various locking implementations available, this is by far the
|
||||
** simplest: locking is ignored. No attempt is made to lock the database
|
||||
** file for reading or writing.
|
||||
**
|
||||
** This locking mode is appropriate for use on read-only databases
|
||||
** (ex: databases that are burned into CD-ROM, for example.) It can
|
||||
** also be used if the application employs some external mechanism to
|
||||
** prevent simultaneous access of the same database by two or more
|
||||
** database connections. But there is a serious risk of database
|
||||
** corruption if this locking mode is used in situations where multiple
|
||||
** database connections are accessing the same database file at the same
|
||||
** time and one or more of those connections are writing.
|
||||
*/
|
||||
|
||||
static int winNolockLock(sqlite3_file *id, int locktype){
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(locktype);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(pResOut);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int winNolockUnlock(sqlite3_file *id, int locktype){
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(locktype);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/******************* End of the no-op lock implementation *********************
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
** If *pArg is initially negative then this is a query. Set *pArg to
|
||||
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
|
||||
@@ -3621,12 +3675,12 @@ struct winShm {
|
||||
/*
|
||||
** Apply advisory locks for all n bytes beginning at ofst.
|
||||
*/
|
||||
#define _SHM_UNLCK 1
|
||||
#define _SHM_RDLCK 2
|
||||
#define _SHM_WRLCK 3
|
||||
#define WINSHM_UNLCK 1
|
||||
#define WINSHM_RDLCK 2
|
||||
#define WINSHM_WRLCK 3
|
||||
static int winShmSystemLock(
|
||||
winShmNode *pFile, /* Apply locks to this open shared-memory segment */
|
||||
int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
|
||||
int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
|
||||
int ofst, /* Offset to first byte to be locked/unlocked */
|
||||
int nByte /* Number of bytes to lock or unlock */
|
||||
){
|
||||
@@ -3639,12 +3693,12 @@ static int winShmSystemLock(
|
||||
pFile->hFile.h, lockType, ofst, nByte));
|
||||
|
||||
/* Release/Acquire the system-level lock */
|
||||
if( lockType==_SHM_UNLCK ){
|
||||
if( lockType==WINSHM_UNLCK ){
|
||||
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
|
||||
}else{
|
||||
/* Initialize the locking parameters */
|
||||
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
|
||||
if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
|
||||
}
|
||||
|
||||
@@ -3656,7 +3710,7 @@ static int winShmSystemLock(
|
||||
}
|
||||
|
||||
OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
|
||||
pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
|
||||
pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
|
||||
"winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
|
||||
|
||||
return rc;
|
||||
@@ -3784,7 +3838,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
/* Check to see if another process is holding the dead-man switch.
|
||||
** If not, truncate the file to zero length.
|
||||
*/
|
||||
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
|
||||
if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
|
||||
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
|
||||
@@ -3792,8 +3846,8 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
|
||||
rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
|
||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
||||
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
|
||||
}
|
||||
if( rc ) goto shm_open_err;
|
||||
}
|
||||
@@ -3822,7 +3876,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
|
||||
/* Jump here on any error */
|
||||
shm_open_err:
|
||||
winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
|
||||
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
|
||||
winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
|
||||
sqlite3_free(p);
|
||||
sqlite3_free(pNew);
|
||||
@@ -3911,7 +3965,7 @@ static int winShmLock(
|
||||
|
||||
/* Unlock the system-level locks */
|
||||
if( (mask & allMask)==0 ){
|
||||
rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
|
||||
rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
@@ -3939,7 +3993,7 @@ static int winShmLock(
|
||||
/* Get shared locks at the system level, if necessary */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( (allShared & mask)==0 ){
|
||||
rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
|
||||
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
@@ -3964,7 +4018,7 @@ static int winShmLock(
|
||||
** also mark the local connection as being locked.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
|
||||
rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( (p->sharedMask & mask)==0 );
|
||||
p->exclMask |= mask;
|
||||
@@ -4407,6 +4461,44 @@ static const sqlite3_io_methods winIoMethod = {
|
||||
winUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
/*
|
||||
** This vector defines all the methods that can operate on an
|
||||
** sqlite3_file for win32 without performing any locking.
|
||||
*/
|
||||
static const sqlite3_io_methods winIoNolockMethod = {
|
||||
3, /* iVersion */
|
||||
winClose, /* xClose */
|
||||
winRead, /* xRead */
|
||||
winWrite, /* xWrite */
|
||||
winTruncate, /* xTruncate */
|
||||
winSync, /* xSync */
|
||||
winFileSize, /* xFileSize */
|
||||
winNolockLock, /* xLock */
|
||||
winNolockUnlock, /* xUnlock */
|
||||
winNolockCheckReservedLock, /* xCheckReservedLock */
|
||||
winFileControl, /* xFileControl */
|
||||
winSectorSize, /* xSectorSize */
|
||||
winDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
winShmMap, /* xShmMap */
|
||||
winShmLock, /* xShmLock */
|
||||
winShmBarrier, /* xShmBarrier */
|
||||
winShmUnmap, /* xShmUnmap */
|
||||
winFetch, /* xFetch */
|
||||
winUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
static winVfsAppData winAppData = {
|
||||
&winIoMethod, /* pMethod */
|
||||
0, /* pAppData */
|
||||
0 /* bNoLock */
|
||||
};
|
||||
|
||||
static winVfsAppData winNolockAppData = {
|
||||
&winIoNolockMethod, /* pMethod */
|
||||
0, /* pAppData */
|
||||
1 /* bNoLock */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
**************************** sqlite3_vfs methods ****************************
|
||||
**
|
||||
@@ -4739,7 +4831,7 @@ static int winIsDir(const void *zConverted){
|
||||
** Open a file.
|
||||
*/
|
||||
static int winOpen(
|
||||
sqlite3_vfs *pVfs, /* Used to get maximum path name length */
|
||||
sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */
|
||||
const char *zName, /* Name of the file (UTF-8) */
|
||||
sqlite3_file *id, /* Write the SQLite file handle here */
|
||||
int flags, /* Open mode flags */
|
||||
@@ -4754,6 +4846,7 @@ static int winOpen(
|
||||
#if SQLITE_OS_WINCE
|
||||
int isTemp = 0;
|
||||
#endif
|
||||
winVfsAppData *pAppData;
|
||||
winFile *pFile = (winFile*)id;
|
||||
void *zConverted; /* Filename in OS encoding */
|
||||
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
|
||||
@@ -4975,15 +5068,20 @@ static int winOpen(
|
||||
"rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
|
||||
*pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
|
||||
|
||||
pAppData = (winVfsAppData*)pVfs->pAppData;
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
|
||||
&& (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
|
||||
){
|
||||
osCloseHandle(h);
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zTmpname);
|
||||
OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
{
|
||||
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
|
||||
&& ((pAppData==NULL) || !pAppData->bNoLock)
|
||||
&& (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
|
||||
){
|
||||
osCloseHandle(h);
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zTmpname);
|
||||
OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( isTemp ){
|
||||
pFile->zDeleteOnClose = zConverted;
|
||||
@@ -4994,7 +5092,7 @@ static int winOpen(
|
||||
}
|
||||
|
||||
sqlite3_free(zTmpname);
|
||||
pFile->pMethod = &winIoMethod;
|
||||
pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
|
||||
pFile->pVfs = pVfs;
|
||||
pFile->h = h;
|
||||
if( isReadonly ){
|
||||
@@ -5717,53 +5815,103 @@ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
*/
|
||||
int sqlite3_os_init(void){
|
||||
static sqlite3_vfs winVfs = {
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"win32", /* zName */
|
||||
0, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
0, /* pNext */
|
||||
"win32", /* zName */
|
||||
&winAppData, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
};
|
||||
#if defined(SQLITE_WIN32_HAS_WIDE)
|
||||
static sqlite3_vfs winLongPathVfs = {
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"win32-longpath", /* zName */
|
||||
0, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
0, /* pNext */
|
||||
"win32-longpath", /* zName */
|
||||
&winAppData, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
};
|
||||
#endif
|
||||
static sqlite3_vfs winNolockVfs = {
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"win32-none", /* zName */
|
||||
&winNolockAppData, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
};
|
||||
#if defined(SQLITE_WIN32_HAS_WIDE)
|
||||
static sqlite3_vfs winLongPathNolockVfs = {
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"win32-longpath-none", /* zName */
|
||||
&winNolockAppData, /* pAppData */
|
||||
winOpen, /* xOpen */
|
||||
winDelete, /* xDelete */
|
||||
winAccess, /* xAccess */
|
||||
winFullPathname, /* xFullPathname */
|
||||
winDlOpen, /* xDlOpen */
|
||||
winDlError, /* xDlError */
|
||||
winDlSym, /* xDlSym */
|
||||
winDlClose, /* xDlClose */
|
||||
winRandomness, /* xRandomness */
|
||||
winSleep, /* xSleep */
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
winSetSystemCall, /* xSetSystemCall */
|
||||
winGetSystemCall, /* xGetSystemCall */
|
||||
winNextSystemCall, /* xNextSystemCall */
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -5787,6 +5935,12 @@ int sqlite3_os_init(void){
|
||||
sqlite3_vfs_register(&winLongPathVfs, 0);
|
||||
#endif
|
||||
|
||||
sqlite3_vfs_register(&winNolockVfs, 0);
|
||||
|
||||
#if defined(SQLITE_WIN32_HAS_WIDE)
|
||||
sqlite3_vfs_register(&winLongPathNolockVfs, 0);
|
||||
#endif
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -12,8 +12,8 @@
|
||||
**
|
||||
** This file contains code that is specific to Windows.
|
||||
*/
|
||||
#ifndef _OS_WIN_H_
|
||||
#define _OS_WIN_H_
|
||||
#ifndef SQLITE_OS_WIN_H
|
||||
#define SQLITE_OS_WIN_H
|
||||
|
||||
/*
|
||||
** Include the primary Windows SDK header file.
|
||||
@@ -85,4 +85,4 @@
|
||||
# define SQLITE_OS_WIN_THREADS 0
|
||||
#endif
|
||||
|
||||
#endif /* _OS_WIN_H_ */
|
||||
#endif /* SQLITE_OS_WIN_H */
|
||||
|
||||
+3
-3
@@ -14,8 +14,8 @@
|
||||
** at a time and provides a journal for rollback.
|
||||
*/
|
||||
|
||||
#ifndef _PAGER_H_
|
||||
#define _PAGER_H_
|
||||
#ifndef SQLITE_PAGER_H
|
||||
#define SQLITE_PAGER_H
|
||||
|
||||
/*
|
||||
** Default maximum size for persistent journal files. A negative
|
||||
@@ -229,4 +229,4 @@ void *sqlite3PagerCodec(DbPage *);
|
||||
# define enable_simulated_io_errors()
|
||||
#endif
|
||||
|
||||
#endif /* _PAGER_H_ */
|
||||
#endif /* SQLITE_PAGER_H */
|
||||
|
||||
+10
-1
@@ -1134,9 +1134,10 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||
exprNot(pParse, N, &A);
|
||||
A.zEnd = &E.z[E.n];
|
||||
}
|
||||
expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z). [IN] {
|
||||
expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] {
|
||||
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
|
||||
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
|
||||
if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E);
|
||||
A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
|
||||
sqlite3PExprAddSelect(pParse, A.pExpr, pSelect);
|
||||
exprNot(pParse, N, &A);
|
||||
@@ -1193,6 +1194,14 @@ nexprlist(A) ::= nexprlist(A) COMMA expr(Y).
|
||||
nexprlist(A) ::= expr(Y).
|
||||
{A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/}
|
||||
|
||||
/* A paren_exprlist is an optional expression list contained inside
|
||||
** of parenthesis */
|
||||
%type paren_exprlist {ExprList*}
|
||||
%destructor paren_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
|
||||
paren_exprlist(A) ::= . {A = 0;}
|
||||
paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;}
|
||||
|
||||
|
||||
|
||||
///////////////////////////// The CREATE INDEX command ///////////////////////
|
||||
//
|
||||
|
||||
+1
-1
@@ -1052,7 +1052,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
case PragTyp_TABLE_INFO: if( zRight ){
|
||||
Table *pTab;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
|
||||
if( pTab ){
|
||||
static const char *azCol[] = {
|
||||
"cid", "name", "type", "notnull", "dflt_value", "pk"
|
||||
|
||||
+2
-2
@@ -2946,10 +2946,10 @@ static int db_int(ShellState *p, const char *zSql){
|
||||
/*
|
||||
** Convert a 2-byte or 4-byte big-endian integer into a native integer
|
||||
*/
|
||||
unsigned int get2byteInt(unsigned char *a){
|
||||
static unsigned int get2byteInt(unsigned char *a){
|
||||
return (a[0]<<8) + a[1];
|
||||
}
|
||||
unsigned int get4byteInt(unsigned char *a){
|
||||
static unsigned int get4byteInt(unsigned char *a){
|
||||
return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
|
||||
}
|
||||
|
||||
|
||||
+140
-9
@@ -30,8 +30,8 @@
|
||||
** the version number) and changes its name to "sqlite3.h" as
|
||||
** part of the build process.
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
#ifndef SQLITE3_H
|
||||
#define SQLITE3_H
|
||||
#include <stdarg.h> /* Needed for the definition of va_list */
|
||||
|
||||
/*
|
||||
@@ -2755,6 +2755,9 @@ int sqlite3_set_authorizer(
|
||||
** CAPI3REF: Tracing And Profiling Functions
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
|
||||
** instead of the routines described here.
|
||||
**
|
||||
** These routines register callback functions that can be used for
|
||||
** tracing and profiling the execution of SQL statements.
|
||||
**
|
||||
@@ -2780,10 +2783,101 @@ int sqlite3_set_authorizer(
|
||||
** sqlite3_profile() function is considered experimental and is
|
||||
** subject to change in future versions of SQLite.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||
SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
|
||||
void(*xTrace)(void*,const char*), void*);
|
||||
SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
||||
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Trace Event Codes
|
||||
** KEYWORDS: SQLITE_TRACE
|
||||
**
|
||||
** These constants identify classes of events that can be monitored
|
||||
** using the [sqlite3_trace_v2()] tracing logic. The third argument
|
||||
** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
|
||||
** the following constants. ^The first argument to the trace callback
|
||||
** is one of the following constants.
|
||||
**
|
||||
** New tracing constants may be added in future releases.
|
||||
**
|
||||
** ^A trace callback has four arguments: xCallback(T,C,P,X).
|
||||
** ^The T argument is one of the integer type codes above.
|
||||
** ^The C argument is a copy of the context pointer passed in as the
|
||||
** fourth argument to [sqlite3_trace_v2()].
|
||||
** The P and X arguments are pointers whose meanings depend on T.
|
||||
**
|
||||
** <dl>
|
||||
** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
|
||||
** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
|
||||
** first begins running and possibly at other times during the
|
||||
** execution of the prepared statement, such as at the start of each
|
||||
** trigger subprogram. ^The P argument is a pointer to the
|
||||
** [prepared statement]. ^The X argument is a pointer to a string which
|
||||
** is the expanded SQL text of the prepared statement or a comment that
|
||||
** indicates the invocation of a trigger.
|
||||
**
|
||||
** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
|
||||
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
|
||||
** information as is provided by the [sqlite3_profile()] callback.
|
||||
** ^The P argument is a pointer to the [prepared statement] and the
|
||||
** X argument points to a 64-bit integer which is the estimated of
|
||||
** the number of nanosecond that the prepared statement took to run.
|
||||
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
|
||||
**
|
||||
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
|
||||
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
|
||||
** statement generates a single row of result.
|
||||
** ^The P argument is a pointer to the [prepared statement] and the
|
||||
** X argument is unused.
|
||||
**
|
||||
** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
|
||||
** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
|
||||
** connection closes.
|
||||
** ^The P argument is a pointer to the [database connection] object
|
||||
** and the X argument is unused.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_TRACE_STMT 0x01
|
||||
#define SQLITE_TRACE_PROFILE 0x02
|
||||
#define SQLITE_TRACE_ROW 0x04
|
||||
#define SQLITE_TRACE_CLOSE 0x08
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Trace Hook
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
|
||||
** function X against [database connection] D, using property mask M
|
||||
** and context pointer P. ^If the X callback is
|
||||
** NULL or if the M mask is zero, then tracing is disabled. The
|
||||
** M argument should be the bitwise OR-ed combination of
|
||||
** zero or more [SQLITE_TRACE] constants.
|
||||
**
|
||||
** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
|
||||
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
|
||||
**
|
||||
** ^The X callback is invoked whenever any of the events identified by
|
||||
** mask M occur. ^The integer return value from the callback is currently
|
||||
** ignored, though this may change in future releases. Callback
|
||||
** implementations should return zero to ensure future compatibility.
|
||||
**
|
||||
** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
|
||||
** ^The T argument is one of the [SQLITE_TRACE]
|
||||
** constants to indicate why the callback was invoked.
|
||||
** ^The C argument is a copy of the context pointer.
|
||||
** The P and X arguments are pointers whose meanings depend on T.
|
||||
**
|
||||
** The sqlite3_trace_v2() interface is intended to replace the legacy
|
||||
** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
|
||||
** are deprecated.
|
||||
*/
|
||||
int sqlite3_trace_v2(
|
||||
sqlite3*,
|
||||
unsigned uMask,
|
||||
int(*xCallback)(unsigned,void*,void*,void*),
|
||||
void *pCtx
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Query Progress Callbacks
|
||||
** METHOD: sqlite3
|
||||
@@ -3402,11 +3496,35 @@ int sqlite3_prepare16_v2(
|
||||
** CAPI3REF: Retrieving Statement SQL
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^This interface can be used to retrieve a saved copy of the original
|
||||
** SQL text used to create a [prepared statement] if that statement was
|
||||
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
|
||||
** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
|
||||
** SQL text used to create [prepared statement] P if P was
|
||||
** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
|
||||
** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
|
||||
** string containing the SQL text of prepared statement P with
|
||||
** [bound parameters] expanded.
|
||||
**
|
||||
** ^(For example, if a prepared statement is created using the SQL
|
||||
** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
|
||||
** and parameter :xyz is unbound, then sqlite3_sql() will return
|
||||
** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
|
||||
** will return "SELECT 2345,NULL".)^
|
||||
**
|
||||
** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
|
||||
** is available to hold the result, or if the result would exceed the
|
||||
** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
|
||||
**
|
||||
** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
|
||||
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
|
||||
** option causes sqlite3_expanded_sql() to always return NULL.
|
||||
**
|
||||
** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
|
||||
** automatically freed when the prepared statement is finalized.
|
||||
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
||||
** is obtained from [sqlite3_malloc()] and must be free by the application
|
||||
** by passing it to [sqlite3_free()].
|
||||
*/
|
||||
const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||
@@ -6765,6 +6883,18 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** memory used by all pager caches associated with the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
||||
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
|
||||
** pager cache is shared between two or more connections the bytes of heap
|
||||
** memory used by that pager cache is divided evenly between the attached
|
||||
** connections.)^ In other words, if none of the pager caches associated
|
||||
** with the database connection are shared, this request returns the same
|
||||
** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
|
||||
** shared, the value returned by this call will be smaller than that returned
|
||||
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
|
||||
** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of bytes of heap
|
||||
** memory used to store the schema for all databases associated
|
||||
@@ -6822,7 +6952,8 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
#define SQLITE_DBSTATUS_CACHE_MISS 8
|
||||
#define SQLITE_DBSTATUS_CACHE_WRITE 9
|
||||
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
|
||||
#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
|
||||
#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
|
||||
#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
@@ -8205,4 +8336,4 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
#endif /* _SQLITE3_H_ */
|
||||
#endif /* SQLITE3_H */
|
||||
|
||||
+9
-3
@@ -15,8 +15,8 @@
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef _SQLITE3EXT_H_
|
||||
#define _SQLITE3EXT_H_
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||
@@ -281,6 +281,9 @@ struct sqlite3_api_routines {
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -526,6 +529,9 @@ struct sqlite3_api_routines {
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
@@ -543,4 +549,4 @@ struct sqlite3_api_routines {
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITE3EXT_H_ */
|
||||
#endif /* SQLITE3EXT_H */
|
||||
|
||||
+19
-7
@@ -12,8 +12,8 @@
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
#ifndef SQLITEINT_H
|
||||
#define SQLITEINT_H
|
||||
|
||||
/* Special Comments:
|
||||
**
|
||||
@@ -1241,6 +1241,15 @@ void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
|
||||
const char*);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
|
||||
** in the style of sqlite3_trace()
|
||||
*/
|
||||
#define SQLITE_TRACE_LEGACY 0x80
|
||||
#else
|
||||
#define SQLITE_TRACE_LEGACY 0
|
||||
#endif /* SQLITE_OMIT_DEPRECATED */
|
||||
|
||||
|
||||
/*
|
||||
** Each database connection is an instance of the following structure.
|
||||
@@ -1270,6 +1279,7 @@ struct sqlite3 {
|
||||
u8 suppressErr; /* Do not issue error messages if true */
|
||||
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
|
||||
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
|
||||
u8 mTrace; /* zero or more SQLITE_TRACE flags */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
u32 magic; /* Magic number for detect library misuse */
|
||||
int nChange; /* Value returned by sqlite3_changes() */
|
||||
@@ -1290,7 +1300,7 @@ struct sqlite3 {
|
||||
int nVDestroy; /* Number of active OP_VDestroy operations */
|
||||
int nExtension; /* Number of loaded extensions */
|
||||
void **aExtension; /* Array of shared library handles */
|
||||
void (*xTrace)(void*,const char*); /* Trace function */
|
||||
int (*xTrace)(u32,void*,void*,void*); /* Trace function */
|
||||
void *pTraceArg; /* Argument to the trace function */
|
||||
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
||||
void *pProfileArg; /* Argument to profile function */
|
||||
@@ -2485,7 +2495,7 @@ struct SrcList {
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
struct {
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
u8 jointype; /* Type of join between this table and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
||||
unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
||||
@@ -3671,8 +3681,10 @@ void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
|
||||
#define LOCATE_VIEW 0x01
|
||||
#define LOCATE_NOERR 0x02
|
||||
Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
@@ -4235,4 +4247,4 @@ int sqlite3ThreadJoin(SQLiteThread*, void**);
|
||||
int sqlite3DbstatRegister(sqlite3*);
|
||||
#endif
|
||||
|
||||
#endif /* _SQLITEINT_H_ */
|
||||
#endif /* SQLITEINT_H */
|
||||
|
||||
+6
-1
@@ -219,6 +219,7 @@ int sqlite3_db_status(
|
||||
** by all pagers associated with the given database connection. The
|
||||
** highwater mark is meaningless and is returned as zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_CACHE_USED_SHARED:
|
||||
case SQLITE_DBSTATUS_CACHE_USED: {
|
||||
int totalUsed = 0;
|
||||
int i;
|
||||
@@ -227,7 +228,11 @@ int sqlite3_db_status(
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
totalUsed += sqlite3PagerMemUsed(pPager);
|
||||
int nByte = sqlite3PagerMemUsed(pPager);
|
||||
if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
|
||||
nByte = nByte / sqlite3BtreeConnectionCount(pBt);
|
||||
}
|
||||
totalUsed += nByte;
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
|
||||
+255
-89
@@ -133,6 +133,7 @@ struct SqliteDb {
|
||||
char *zBusy; /* The busy callback routine */
|
||||
char *zCommit; /* The commit hook callback routine */
|
||||
char *zTrace; /* The trace callback routine */
|
||||
char *zTraceV2; /* The trace_v2 callback routine */
|
||||
char *zProfile; /* The profile callback routine */
|
||||
char *zProgress; /* The progress callback routine */
|
||||
char *zAuth; /* The authorization callback routine */
|
||||
@@ -192,7 +193,7 @@ static void closeIncrblobChannels(SqliteDb *pDb){
|
||||
for(p=pDb->pIncrblob; p; p=pNext){
|
||||
pNext = p->pNext;
|
||||
|
||||
/* Note: Calling unregister here call Tcl_Close on the incrblob channel,
|
||||
/* Note: Calling unregister here call Tcl_Close on the incrblob channel,
|
||||
** which deletes the IncrblobChannel structure at *p. So do not
|
||||
** call Tcl_Free() here.
|
||||
*/
|
||||
@@ -233,8 +234,8 @@ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
|
||||
** Read data from an incremental blob channel.
|
||||
*/
|
||||
static int incrblobInput(
|
||||
ClientData instanceData,
|
||||
char *buf,
|
||||
ClientData instanceData,
|
||||
char *buf,
|
||||
int bufSize,
|
||||
int *errorCodePtr
|
||||
){
|
||||
@@ -265,8 +266,8 @@ static int incrblobInput(
|
||||
** Write data to an incremental blob channel.
|
||||
*/
|
||||
static int incrblobOutput(
|
||||
ClientData instanceData,
|
||||
CONST char *buf,
|
||||
ClientData instanceData,
|
||||
CONST char *buf,
|
||||
int toWrite,
|
||||
int *errorCodePtr
|
||||
){
|
||||
@@ -298,7 +299,7 @@ static int incrblobOutput(
|
||||
** Seek an incremental blob channel.
|
||||
*/
|
||||
static int incrblobSeek(
|
||||
ClientData instanceData,
|
||||
ClientData instanceData,
|
||||
long offset,
|
||||
int seekMode,
|
||||
int *errorCodePtr
|
||||
@@ -323,8 +324,8 @@ static int incrblobSeek(
|
||||
}
|
||||
|
||||
|
||||
static void incrblobWatch(ClientData instanceData, int mode){
|
||||
/* NO-OP */
|
||||
static void incrblobWatch(ClientData instanceData, int mode){
|
||||
/* NO-OP */
|
||||
}
|
||||
static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
|
||||
return TCL_ERROR;
|
||||
@@ -352,11 +353,11 @@ static Tcl_ChannelType IncrblobChannelType = {
|
||||
** Create a new incrblob channel.
|
||||
*/
|
||||
static int createIncrblobChannel(
|
||||
Tcl_Interp *interp,
|
||||
SqliteDb *pDb,
|
||||
Tcl_Interp *interp,
|
||||
SqliteDb *pDb,
|
||||
const char *zDb,
|
||||
const char *zTable,
|
||||
const char *zColumn,
|
||||
const char *zTable,
|
||||
const char *zColumn,
|
||||
sqlite_int64 iRow,
|
||||
int isReadonly
|
||||
){
|
||||
@@ -438,7 +439,7 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
|
||||
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
|
||||
pNew->zName = (char*)&pNew[1];
|
||||
memcpy(pNew->zName, zName, nName+1);
|
||||
for(p=pDb->pFunc; p; p=p->pNext){
|
||||
for(p=pDb->pFunc; p; p=p->pNext){
|
||||
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
|
||||
Tcl_Free((char*)pNew);
|
||||
return p;
|
||||
@@ -508,6 +509,9 @@ static void DbDeleteCmd(void *db){
|
||||
if( pDb->zTrace ){
|
||||
Tcl_Free(pDb->zTrace);
|
||||
}
|
||||
if( pDb->zTraceV2 ){
|
||||
Tcl_Free(pDb->zTraceV2);
|
||||
}
|
||||
if( pDb->zProfile ){
|
||||
Tcl_Free(pDb->zProfile);
|
||||
}
|
||||
@@ -587,6 +591,82 @@ static void DbTraceHandler(void *cd, const char *zSql){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** This routine is called by the SQLite trace_v2 handler whenever a new
|
||||
** supported event is generated. Unsupported event types are ignored.
|
||||
** The TCL script in pDb->zTraceV2 is executed, with the arguments for
|
||||
** the event appended to it (as list elements).
|
||||
*/
|
||||
static int DbTraceV2Handler(
|
||||
unsigned type, /* One of the SQLITE_TRACE_* event types. */
|
||||
void *cd, /* The original context data pointer. */
|
||||
void *pd, /* Primary event data, depends on event type. */
|
||||
void *xd /* Extra event data, depends on event type. */
|
||||
){
|
||||
SqliteDb *pDb = (SqliteDb*)cd;
|
||||
Tcl_Obj *pCmd;
|
||||
|
||||
switch( type ){
|
||||
case SQLITE_TRACE_STMT: {
|
||||
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||
char *zSql = (char *)xd;
|
||||
|
||||
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewStringObj(zSql, -1));
|
||||
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||
Tcl_DecrRefCount(pCmd);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TRACE_PROFILE: {
|
||||
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||
sqlite3_int64 ns = (sqlite3_int64)xd;
|
||||
|
||||
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)ns));
|
||||
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||
Tcl_DecrRefCount(pCmd);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TRACE_ROW: {
|
||||
sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
|
||||
|
||||
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
|
||||
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||
Tcl_DecrRefCount(pCmd);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TRACE_CLOSE: {
|
||||
sqlite3 *db = (sqlite3 *)pd;
|
||||
|
||||
pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
Tcl_ListObjAppendElement(pDb->interp, pCmd,
|
||||
Tcl_NewWideIntObj((Tcl_WideInt)db));
|
||||
Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
|
||||
Tcl_DecrRefCount(pCmd);
|
||||
Tcl_ResetResult(pDb->interp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** This routine is called by the SQLite profile handler after a statement
|
||||
@@ -637,9 +717,9 @@ static void DbRollbackHandler(void *clientData){
|
||||
** This procedure handles wal_hook callbacks.
|
||||
*/
|
||||
static int DbWalHandler(
|
||||
void *clientData,
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
void *clientData,
|
||||
sqlite3 *db,
|
||||
const char *zDb,
|
||||
int nEntry
|
||||
){
|
||||
int ret = SQLITE_OK;
|
||||
@@ -653,7 +733,7 @@ static int DbWalHandler(
|
||||
Tcl_IncrRefCount(p);
|
||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
|
||||
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
|
||||
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|
||||
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|
||||
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
|
||||
){
|
||||
Tcl_BackgroundError(interp);
|
||||
@@ -695,11 +775,11 @@ static void DbUnlockNotify(void **apArg, int nArg){
|
||||
** Pre-update hook callback.
|
||||
*/
|
||||
static void DbPreUpdateHandler(
|
||||
void *p,
|
||||
void *p,
|
||||
sqlite3 *db,
|
||||
int op,
|
||||
const char *zDb,
|
||||
const char *zTbl,
|
||||
const char *zDb,
|
||||
const char *zTbl,
|
||||
sqlite_int64 iKey1,
|
||||
sqlite_int64 iKey2
|
||||
){
|
||||
@@ -727,10 +807,10 @@ static void DbPreUpdateHandler(
|
||||
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
||||
|
||||
static void DbUpdateHandler(
|
||||
void *p,
|
||||
void *p,
|
||||
int op,
|
||||
const char *zDb,
|
||||
const char *zTbl,
|
||||
const char *zDb,
|
||||
const char *zTbl,
|
||||
sqlite_int64 rowid
|
||||
){
|
||||
SqliteDb *pDb = (SqliteDb *)p;
|
||||
@@ -815,7 +895,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
** script object, lappend the arguments, then evaluate the copy.
|
||||
**
|
||||
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
|
||||
** The new Tcl_Obj contains pointers to the original list elements.
|
||||
** The new Tcl_Obj contains pointers to the original list elements.
|
||||
** That way, when Tcl_EvalObjv() is run and shimmers the first element
|
||||
** of the list to tclCmdNameType, that alternate representation will
|
||||
** be preserved and reused on the next invocation.
|
||||
@@ -823,15 +903,15 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
Tcl_Obj **aArg;
|
||||
int nArg;
|
||||
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pCmd = Tcl_NewListObj(nArg, aArg);
|
||||
Tcl_IncrRefCount(pCmd);
|
||||
for(i=0; i<argc; i++){
|
||||
sqlite3_value *pIn = argv[i];
|
||||
Tcl_Obj *pVal;
|
||||
|
||||
|
||||
/* Set pVal to contain the i'th column of this row. */
|
||||
switch( sqlite3_value_type(pIn) ){
|
||||
case SQLITE_BLOB: {
|
||||
@@ -866,7 +946,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
|
||||
if( rc ){
|
||||
Tcl_DecrRefCount(pCmd);
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -881,7 +961,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
}
|
||||
|
||||
if( rc && rc!=TCL_RETURN ){
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
|
||||
}else{
|
||||
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
|
||||
int n;
|
||||
@@ -983,7 +1063,7 @@ static int auth_callback(
|
||||
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
|
||||
#endif
|
||||
#endif
|
||||
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
|
||||
Tcl_DStringFree(&str);
|
||||
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
|
||||
@@ -1075,12 +1155,12 @@ static int DbTransPostCmd(
|
||||
pDb->disableAuth++;
|
||||
if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
|
||||
/* This is a tricky scenario to handle. The most likely cause of an
|
||||
** error is that the exec() above was an attempt to commit the
|
||||
** error is that the exec() above was an attempt to commit the
|
||||
** top-level transaction that returned SQLITE_BUSY. Or, less likely,
|
||||
** that an IO-error has occurred. In either case, throw a Tcl exception
|
||||
** and try to rollback the transaction.
|
||||
**
|
||||
** But it could also be that the user executed one or more BEGIN,
|
||||
** But it could also be that the user executed one or more BEGIN,
|
||||
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
|
||||
** this method's logic. Not clear how this would be best handled.
|
||||
*/
|
||||
@@ -1099,7 +1179,7 @@ static int DbTransPostCmd(
|
||||
** Unless SQLITE_TEST is defined, this function is a simple wrapper around
|
||||
** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
|
||||
** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
|
||||
** on whether or not the [db_use_legacy_prepare] command has been used to
|
||||
** on whether or not the [db_use_legacy_prepare] command has been used to
|
||||
** configure the connection.
|
||||
*/
|
||||
static int dbPrepare(
|
||||
@@ -1155,7 +1235,7 @@ static int dbPrepareAndBind(
|
||||
|
||||
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
|
||||
int n = pPreStmt->nSql;
|
||||
if( nSql>=n
|
||||
if( nSql>=n
|
||||
&& memcmp(pPreStmt->zSql, zSql, n)==0
|
||||
&& (zSql[n]==0 || zSql[n-1]==';')
|
||||
){
|
||||
@@ -1181,7 +1261,7 @@ static int dbPrepareAndBind(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* If no prepared statement was found. Compile the SQL text. Also allocate
|
||||
** a new SqlPreparedStmt structure. */
|
||||
if( pPreStmt==0 ){
|
||||
@@ -1227,7 +1307,7 @@ static int dbPrepareAndBind(
|
||||
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
|
||||
assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
|
||||
|
||||
/* Bind values to parameters that begin with $ or : */
|
||||
/* Bind values to parameters that begin with $ or : */
|
||||
for(i=1; i<=nVar; i++){
|
||||
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
|
||||
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
|
||||
@@ -1315,8 +1395,8 @@ static void dbReleaseStmt(
|
||||
assert( pDb->nStmt>0 );
|
||||
}
|
||||
pDb->nStmt++;
|
||||
|
||||
/* If we have too many statement in cache, remove the surplus from
|
||||
|
||||
/* If we have too many statement in cache, remove the surplus from
|
||||
** the end of the cache list. */
|
||||
while( pDb->nStmt>pDb->maxStmt ){
|
||||
SqlPreparedStmt *pLast = pDb->stmtLast;
|
||||
@@ -1370,8 +1450,8 @@ static void dbReleaseColumnNames(DbEvalContext *p){
|
||||
** If pArray is not NULL, then it contains the name of a Tcl array
|
||||
** variable. The "*" member of this array is set to a list containing
|
||||
** the names of the columns returned by the statement as part of each
|
||||
** call to dbEvalStep(), in order from left to right. e.g. if the names
|
||||
** of the returned columns are a, b and c, it does the equivalent of the
|
||||
** call to dbEvalStep(), in order from left to right. e.g. if the names
|
||||
** of the returned columns are a, b and c, it does the equivalent of the
|
||||
** tcl command:
|
||||
**
|
||||
** set ${pArray}(*) {a b c}
|
||||
@@ -1492,7 +1572,7 @@ static int dbEvalStep(DbEvalContext *p){
|
||||
#if SQLITE_TEST
|
||||
if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
|
||||
/* If the runtime error was an SQLITE_SCHEMA, and the database
|
||||
** handle is configured to use the legacy sqlite3_prepare()
|
||||
** handle is configured to use the legacy sqlite3_prepare()
|
||||
** interface, retry prepare()/step() on the same SQL statement.
|
||||
** This only happens once. If there is a second SQLITE_SCHEMA
|
||||
** error, the error will be returned to the caller. */
|
||||
@@ -1580,11 +1660,11 @@ static int DbUseNre(void){
|
||||
return( (major==8 && minor>=6) || major>8 );
|
||||
}
|
||||
#else
|
||||
/*
|
||||
/*
|
||||
** Compiling using headers earlier than 8.6. In this case NR cannot be
|
||||
** used, so DbUseNre() to always return zero. Add #defines for the other
|
||||
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
|
||||
** even though the only invocations of them are within conditional blocks
|
||||
** even though the only invocations of them are within conditional blocks
|
||||
** of the form:
|
||||
**
|
||||
** if( DbUseNre() ) { ... }
|
||||
@@ -1630,11 +1710,11 @@ static int DbEvalNextCmd(
|
||||
}
|
||||
}
|
||||
|
||||
/* The required interpreter variables are now populated with the data
|
||||
/* The required interpreter variables are now populated with the data
|
||||
** from the current row. If using NRE, schedule callbacks to evaluate
|
||||
** script pScript, then to invoke this function again to fetch the next
|
||||
** row (or clean up if there is no next row or the script throws an
|
||||
** exception). After scheduling the callbacks, return control to the
|
||||
** exception). After scheduling the callbacks, return control to the
|
||||
** caller.
|
||||
**
|
||||
** If not using NRE, evaluate pScript directly and continue with the
|
||||
@@ -1659,7 +1739,7 @@ static int DbEvalNextCmd(
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used by the implementations of the following database
|
||||
** This function is used by the implementations of the following database
|
||||
** handle sub-commands:
|
||||
**
|
||||
** $db update_hook ?SCRIPT?
|
||||
@@ -1726,9 +1806,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
"preupdate", "profile", "progress",
|
||||
"rekey", "restore", "rollback_hook",
|
||||
"status", "timeout", "total_changes",
|
||||
"trace", "transaction", "unlock_notify",
|
||||
"update_hook", "version", "wal_hook",
|
||||
0
|
||||
"trace", "trace_v2", "transaction",
|
||||
"unlock_notify", "update_hook", "version",
|
||||
"wal_hook",
|
||||
0
|
||||
};
|
||||
enum DB_enum {
|
||||
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
|
||||
@@ -1741,8 +1822,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
|
||||
DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
|
||||
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||
DB_TRACE, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
|
||||
DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
|
||||
DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
|
||||
DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
|
||||
DB_WAL_HOOK,
|
||||
};
|
||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||
|
||||
@@ -1928,7 +2010,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
||||
Tcl_AppendResult( interp, "cannot convert \"",
|
||||
Tcl_AppendResult( interp, "cannot convert \"",
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
@@ -1942,7 +2024,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
}
|
||||
}else{
|
||||
Tcl_AppendResult( interp, "bad option \"",
|
||||
Tcl_AppendResult( interp, "bad option \"",
|
||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
@@ -1953,7 +2035,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
/* $db changes
|
||||
**
|
||||
** Return the number of rows that were modified, inserted, or deleted by
|
||||
** the most recent INSERT, UPDATE or DELETE statement, not including
|
||||
** the most recent INSERT, UPDATE or DELETE statement, not including
|
||||
** any changes made by trigger programs.
|
||||
*/
|
||||
case DB_CHANGES: {
|
||||
@@ -2000,7 +2082,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
pCollate->zScript = (char*)&pCollate[1];
|
||||
pDb->pCollate = pCollate;
|
||||
memcpy(pCollate->zScript, zScript, nScript+1);
|
||||
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
|
||||
if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
|
||||
pCollate, tclSqlCollate) ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
@@ -2126,7 +2208,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
const char *zSep;
|
||||
const char *zNull;
|
||||
if( objc<5 || objc>7 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -2155,7 +2237,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
strcmp(zConflict, "fail" ) != 0 &&
|
||||
strcmp(zConflict, "ignore" ) != 0 &&
|
||||
strcmp(zConflict, "replace" ) != 0 ) {
|
||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||
"\", conflict-algorithm must be one of: rollback, "
|
||||
"abort, fail, ignore, or replace", (char*)0);
|
||||
return TCL_ERROR;
|
||||
@@ -2244,7 +2326,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
for(i=0; i<nCol; i++){
|
||||
/* check for null data, if so, bind as null */
|
||||
if( (nNull>0 && strcmp(azCol[i], zNull)==0)
|
||||
|| strlen30(azCol[i])==0
|
||||
|| strlen30(azCol[i])==0
|
||||
){
|
||||
sqlite3_bind_null(pStmt, i+1);
|
||||
}else{
|
||||
@@ -2323,8 +2405,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** The onecolumn method is the equivalent of:
|
||||
** lindex [$db eval $sql] 0
|
||||
*/
|
||||
case DB_EXISTS:
|
||||
case DB_EXISTS:
|
||||
case DB_ONECOLUMN: {
|
||||
Tcl_Obj *pResult = 0;
|
||||
DbEvalContext sEval;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SQL");
|
||||
@@ -2335,21 +2418,22 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
rc = dbEvalStep(&sEval);
|
||||
if( choice==DB_ONECOLUMN ){
|
||||
if( rc==TCL_OK ){
|
||||
Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0));
|
||||
pResult = dbEvalColumnValue(&sEval, 0);
|
||||
}else if( rc==TCL_BREAK ){
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
}else if( rc==TCL_BREAK || rc==TCL_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK));
|
||||
pResult = Tcl_NewBooleanObj(rc==TCL_OK);
|
||||
}
|
||||
dbEvalFinalize(&sEval);
|
||||
if( pResult ) Tcl_SetObjResult(interp, pResult);
|
||||
|
||||
if( rc==TCL_BREAK ){
|
||||
rc = TCL_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $db eval $sql ?array? ?{ ...code... }?
|
||||
**
|
||||
@@ -2395,7 +2479,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
pScript = objv[objc-1];
|
||||
Tcl_IncrRefCount(pScript);
|
||||
|
||||
|
||||
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
|
||||
dbEvalInit(p, pDb, objv[2], pArray);
|
||||
|
||||
@@ -2442,7 +2526,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( n>2 && strncmp(z, "-deterministic",n)==0 ){
|
||||
flags |= SQLITE_DETERMINISTIC;
|
||||
}else{
|
||||
Tcl_AppendResult(interp, "bad option \"", z,
|
||||
Tcl_AppendResult(interp, "bad option \"", z,
|
||||
"\": must be -argcount or -deterministic", 0
|
||||
);
|
||||
return TCL_ERROR;
|
||||
@@ -2551,7 +2635,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
|
||||
/*
|
||||
** $db last_insert_rowid
|
||||
** $db last_insert_rowid
|
||||
**
|
||||
** Return an integer which is the ROWID for the most recent insert.
|
||||
*/
|
||||
@@ -2573,7 +2657,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
*/
|
||||
|
||||
/* $db progress ?N CALLBACK?
|
||||
**
|
||||
**
|
||||
** Invoke the given callback every N virtual machine opcodes while executing
|
||||
** queries.
|
||||
*/
|
||||
@@ -2680,7 +2764,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
|
||||
/* $db restore ?DATABASE? FILENAME
|
||||
**
|
||||
** Open a database file named FILENAME. Transfer the content
|
||||
** Open a database file named FILENAME. Transfer the content
|
||||
** of FILENAME into the local database DATABASE (default: "main").
|
||||
*/
|
||||
case DB_RESTORE: {
|
||||
@@ -2741,7 +2825,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
/*
|
||||
** $db status (step|sort|autoindex)
|
||||
**
|
||||
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
|
||||
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
|
||||
** SQLITE_STMTSTATUS_SORT for the most recent eval.
|
||||
*/
|
||||
case DB_STATUS: {
|
||||
@@ -2759,15 +2843,15 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}else if( strcmp(zOp, "autoindex")==0 ){
|
||||
v = pDb->nIndex;
|
||||
}else{
|
||||
Tcl_AppendResult(interp,
|
||||
"bad argument: should be autoindex, step, or sort",
|
||||
Tcl_AppendResult(interp,
|
||||
"bad argument: should be autoindex, step, or sort",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $db timeout MILLESECONDS
|
||||
**
|
||||
@@ -2783,11 +2867,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
sqlite3_busy_timeout(pDb->db, ms);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** $db total_changes
|
||||
**
|
||||
** Return the number of rows that were modified, inserted, or deleted
|
||||
** Return the number of rows that were modified, inserted, or deleted
|
||||
** since the database handle was created.
|
||||
*/
|
||||
case DB_TOTAL_CHANGES: {
|
||||
@@ -2840,6 +2924,88 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db trace_v2 ?CALLBACK? ?MASK?
|
||||
**
|
||||
** Make arrangements to invoke the CALLBACK routine for each trace event
|
||||
** matching the mask that is generated. The parameters are appended to
|
||||
** CALLBACK before it is executed.
|
||||
*/
|
||||
case DB_TRACE_V2: {
|
||||
if( objc>4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?");
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zTraceV2 ){
|
||||
Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zTraceV2;
|
||||
int len;
|
||||
Tcl_WideInt wMask = 0;
|
||||
if( objc==4 ){
|
||||
static const char *TTYPE_strs[] = {
|
||||
"statement", "profile", "row", "close", 0
|
||||
};
|
||||
enum TTYPE_enum {
|
||||
TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE
|
||||
};
|
||||
int i;
|
||||
if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
for(i=0; i<len; i++){
|
||||
Tcl_Obj *pObj;
|
||||
int ttype;
|
||||
if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type",
|
||||
0, &ttype)!=TCL_OK ){
|
||||
Tcl_WideInt wType;
|
||||
Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
|
||||
Tcl_IncrRefCount(pError);
|
||||
if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){
|
||||
Tcl_DecrRefCount(pError);
|
||||
wMask |= wType;
|
||||
}else{
|
||||
Tcl_SetObjResult(interp, pError);
|
||||
Tcl_DecrRefCount(pError);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}else{
|
||||
switch( (enum TTYPE_enum)ttype ){
|
||||
case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break;
|
||||
case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break;
|
||||
case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break;
|
||||
case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */
|
||||
}
|
||||
if( pDb->zTraceV2 ){
|
||||
Tcl_Free(pDb->zTraceV2);
|
||||
}
|
||||
zTraceV2 = Tcl_GetStringFromObj(objv[2], &len);
|
||||
if( zTraceV2 && len>0 ){
|
||||
pDb->zTraceV2 = Tcl_Alloc( len + 1 );
|
||||
memcpy(pDb->zTraceV2, zTraceV2, len+1);
|
||||
}else{
|
||||
pDb->zTraceV2 = 0;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
if( pDb->zTraceV2 ){
|
||||
pDb->interp = interp;
|
||||
sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb);
|
||||
}else{
|
||||
sqlite3_trace_v2(pDb->db, 0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
|
||||
**
|
||||
** Start a new transaction (if we are not already in the midst of a
|
||||
@@ -2892,7 +3058,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
/* If using NRE, schedule a callback to invoke the script pScript, then
|
||||
** a second callback to commit (or rollback) the transaction or savepoint
|
||||
** opened above. If not using NRE, evaluate the script directly, then
|
||||
** call function DbTransPostCmd() to commit (or rollback) the transaction
|
||||
** call function DbTransPostCmd() to commit (or rollback) the transaction
|
||||
** or savepoint. */
|
||||
if( DbUseNre() ){
|
||||
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
|
||||
@@ -2923,14 +3089,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_DecrRefCount(pDb->pUnlockNotify);
|
||||
pDb->pUnlockNotify = 0;
|
||||
}
|
||||
|
||||
|
||||
if( objc==3 ){
|
||||
xNotify = DbUnlockNotify;
|
||||
pNotifyArg = (void *)pDb;
|
||||
pDb->pUnlockNotify = objv[2];
|
||||
Tcl_IncrRefCount(pDb->pUnlockNotify);
|
||||
}
|
||||
|
||||
|
||||
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
@@ -3029,13 +3195,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** $db update_hook ?script?
|
||||
** $db rollback_hook ?script?
|
||||
*/
|
||||
case DB_WAL_HOOK:
|
||||
case DB_UPDATE_HOOK:
|
||||
case DB_WAL_HOOK:
|
||||
case DB_UPDATE_HOOK:
|
||||
case DB_ROLLBACK_HOOK: {
|
||||
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
|
||||
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
|
||||
** whether [$db update_hook] or [$db rollback_hook] was invoked.
|
||||
*/
|
||||
Tcl_Obj **ppHook = 0;
|
||||
Tcl_Obj **ppHook = 0;
|
||||
if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook;
|
||||
if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook;
|
||||
if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook;
|
||||
@@ -3196,7 +3362,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
}
|
||||
if( objc<3 || (objc&1)!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
Tcl_WrongNumArgs(interp, 1, objv,
|
||||
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
|
||||
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
|
||||
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
|
||||
@@ -3488,7 +3654,7 @@ static void MD5Init(MD5Context *ctx){
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
static
|
||||
static
|
||||
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
uint32 t;
|
||||
|
||||
@@ -3534,7 +3700,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
|
||||
@@ -3610,7 +3776,7 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
|
||||
|
||||
/*
|
||||
** A TCL command for md5. The argument is the text to be hashed. The
|
||||
** Result is the hash in base64.
|
||||
** Result is the hash in base64.
|
||||
*/
|
||||
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||
MD5Context ctx;
|
||||
@@ -3619,7 +3785,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||
void (*converter)(unsigned char*, char*);
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -3644,13 +3810,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
||||
char zBuf[10240];
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -3717,7 +3883,7 @@ static void md5finalize(sqlite3_context *context){
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
int Md5_Register(sqlite3 *db){
|
||||
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
|
||||
md5step, md5finalize);
|
||||
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
|
||||
return rc;
|
||||
@@ -3868,7 +4034,7 @@ static int db_last_stmt_ptr(
|
||||
** Configure the interpreter passed as the first argument to have access
|
||||
** to the commands and linked variables that make up:
|
||||
**
|
||||
** * the [sqlite3] extension itself,
|
||||
** * the [sqlite3] extension itself,
|
||||
**
|
||||
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
|
||||
**
|
||||
|
||||
+177
-2
@@ -3241,6 +3241,145 @@ static int test_bind_int(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: intarray_addr INT ...
|
||||
**
|
||||
** Return the address of a C-language array of 32-bit integers.
|
||||
**
|
||||
** Space to hold the array is obtained from malloc(). Call this procedure once
|
||||
** with no arguments in order to release memory. Each call to this procedure
|
||||
** overwrites the previous array.
|
||||
*/
|
||||
static int test_intarray_addr(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int i;
|
||||
static int *p = 0;
|
||||
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
if( objc>1 ){
|
||||
p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
|
||||
if( p==0 ) return TCL_ERROR;
|
||||
for(i=0; i<objc-1; i++){
|
||||
if( Tcl_GetIntFromObj(interp, objv[1+i], &p[i]) ){
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
|
||||
return TCL_OK;
|
||||
}
|
||||
/*
|
||||
** Usage: intarray_addr INT ...
|
||||
**
|
||||
** Return the address of a C-language array of 32-bit integers.
|
||||
**
|
||||
** Space to hold the array is obtained from malloc(). Call this procedure once
|
||||
** with no arguments in order to release memory. Each call to this procedure
|
||||
** overwrites the previous array.
|
||||
*/
|
||||
static int test_int64array_addr(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int i;
|
||||
static sqlite3_int64 *p = 0;
|
||||
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
if( objc>1 ){
|
||||
p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
|
||||
if( p==0 ) return TCL_ERROR;
|
||||
for(i=0; i<objc-1; i++){
|
||||
Tcl_WideInt v;
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[1+i], &v) ){
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p[i] = v;
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
|
||||
return TCL_OK;
|
||||
}
|
||||
/*
|
||||
** Usage: doublearray_addr INT ...
|
||||
**
|
||||
** Return the address of a C-language array of doubles.
|
||||
**
|
||||
** Space to hold the array is obtained from malloc(). Call this procedure once
|
||||
** with no arguments in order to release memory. Each call to this procedure
|
||||
** overwrites the previous array.
|
||||
*/
|
||||
static int test_doublearray_addr(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int i;
|
||||
static double *p = 0;
|
||||
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
if( objc>1 ){
|
||||
p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
|
||||
if( p==0 ) return TCL_ERROR;
|
||||
for(i=0; i<objc-1; i++){
|
||||
if( Tcl_GetDoubleFromObj(interp, objv[1+i], &p[i]) ){
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
|
||||
return TCL_OK;
|
||||
}
|
||||
/*
|
||||
** Usage: textarray_addr TEXT ...
|
||||
**
|
||||
** Return the address of a C-language array of strings.
|
||||
**
|
||||
** Space to hold the array is obtained from malloc(). Call this procedure once
|
||||
** with no arguments in order to release memory. Each call to this procedure
|
||||
** overwrites the previous array.
|
||||
*/
|
||||
static int test_textarray_addr(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int i;
|
||||
static int n = 0;
|
||||
static char **p = 0;
|
||||
|
||||
for(i=0; i<n; i++) sqlite3_free(p[i]);
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
if( objc>1 ){
|
||||
p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
|
||||
if( p==0 ) return TCL_ERROR;
|
||||
for(i=0; i<objc-1; i++){
|
||||
p[i] = sqlite3_mprintf("%s", Tcl_GetString(objv[1+i]));
|
||||
}
|
||||
}
|
||||
n = objc-1;
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_bind_int64 STMT N VALUE
|
||||
**
|
||||
@@ -3494,7 +3633,7 @@ static int test_bind_blob(
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int idx;
|
||||
int len, idx;
|
||||
int bytes;
|
||||
char *value;
|
||||
int rc;
|
||||
@@ -3513,9 +3652,18 @@ static int test_bind_blob(
|
||||
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
|
||||
value = Tcl_GetString(objv[3]);
|
||||
|
||||
value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
|
||||
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
|
||||
|
||||
if( bytes>len ){
|
||||
char zBuf[200];
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf,
|
||||
"cannot use %d blob bytes, have %d", bytes, len);
|
||||
Tcl_AppendResult(interp, zBuf, -1);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
|
||||
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -4247,6 +4395,26 @@ static int test_sql(
|
||||
Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
static int test_ex_sql(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
char *z;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "STMT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
z = sqlite3_expanded_sql(pStmt);
|
||||
Tcl_SetResult(interp, z, TCL_VOLATILE);
|
||||
sqlite3_free(z);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_column_count STMT
|
||||
@@ -6583,6 +6751,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -6601,6 +6770,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
} aExtension[] = {
|
||||
{ "amatch", sqlite3_amatch_init },
|
||||
{ "carray", sqlite3_carray_init },
|
||||
{ "closure", sqlite3_closure_init },
|
||||
{ "csv", sqlite3_csv_init },
|
||||
{ "eval", sqlite3_eval_init },
|
||||
@@ -7095,6 +7265,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "bad_behavior", test_bad_behavior, (void*)&iZero },
|
||||
{ "register_dbstat_vtab", test_register_dbstat_vtab },
|
||||
{ "sqlite3_connection_pointer", get_sqlite_pointer, 0 },
|
||||
{ "intarray_addr", test_intarray_addr, 0 },
|
||||
{ "int64array_addr", test_int64array_addr, 0 },
|
||||
{ "doublearray_addr", test_doublearray_addr, 0 },
|
||||
{ "textarray_addr", test_textarray_addr, 0 },
|
||||
{ "sqlite3_bind_int", test_bind_int, 0 },
|
||||
{ "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 },
|
||||
{ "sqlite3_bind_zeroblob64", test_bind_zeroblob64, 0 },
|
||||
@@ -7131,6 +7305,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_changes", test_changes ,0 },
|
||||
{ "sqlite3_step", test_step ,0 },
|
||||
{ "sqlite3_sql", test_sql ,0 },
|
||||
{ "sqlite3_expanded_sql", test_ex_sql ,0 },
|
||||
{ "sqlite3_next_stmt", test_next_stmt ,0 },
|
||||
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
|
||||
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
|
||||
|
||||
@@ -179,8 +179,8 @@ static int tclConnect(
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
zCmd = sqlite3_malloc(strlen(argv[3])+1);
|
||||
pTab = (tcl_vtab*)sqlite3_malloc(sizeof(tcl_vtab));
|
||||
zCmd = sqlite3_malloc64(strlen(argv[3])+1);
|
||||
pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab));
|
||||
if( zCmd && pTab ){
|
||||
memcpy(zCmd, argv[3], strlen(argv[3])+1);
|
||||
tclDequote(zCmd);
|
||||
|
||||
+3
-3
@@ -75,8 +75,8 @@
|
||||
** action to free the intarray objects.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#ifndef _INTARRAY_H_
|
||||
#define _INTARRAY_H_
|
||||
#ifndef SQLITE_INTARRAY_H
|
||||
#define SQLITE_INTARRAY_H
|
||||
|
||||
/*
|
||||
** Make sure we can call this stuff from C++.
|
||||
@@ -125,4 +125,4 @@ SQLITE_API int sqlite3_intarray_bind(
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
#endif /* _INTARRAY_H_ */
|
||||
#endif /* SQLITE_INTARRAY_H */
|
||||
|
||||
+2
-1
@@ -1417,7 +1417,8 @@ static int test_db_status(
|
||||
{ "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
|
||||
{ "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },
|
||||
{ "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },
|
||||
{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS }
|
||||
{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },
|
||||
{ "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=4 ){
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef _TEST_MULTIPLEX_H
|
||||
#define _TEST_MULTIPLEX_H
|
||||
#ifndef SQLITE_TEST_MULTIPLEX_H
|
||||
#define SQLITE_TEST_MULTIPLEX_H
|
||||
|
||||
/*
|
||||
** CAPI: File-control Operations Supported by Multiplex VFS
|
||||
@@ -96,4 +96,4 @@ extern int sqlite3_multiplex_shutdown(int eForce);
|
||||
} /* End of the 'extern "C"' block */
|
||||
#endif
|
||||
|
||||
#endif /* _TEST_MULTIPLEX_H */
|
||||
#endif /* SQLITE_TEST_MULTIPLEX_H */
|
||||
|
||||
+4
-4
@@ -121,7 +121,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
int saved_nChange; /* Saved value of db->nChange */
|
||||
int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
||||
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
|
||||
u8 saved_mTrace; /* Saved trace settings */
|
||||
Db *pDb = 0; /* Database to detach at end of vacuum */
|
||||
int isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nRes; /* Bytes of reserved space at the end of each page */
|
||||
@@ -142,10 +142,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
saved_flags = db->flags;
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
saved_xTrace = db->xTrace;
|
||||
saved_mTrace = db->mTrace;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
|
||||
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
|
||||
db->xTrace = 0;
|
||||
db->mTrace = 0;
|
||||
|
||||
pMain = db->aDb[0].pBt;
|
||||
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
|
||||
@@ -345,7 +345,7 @@ end_of_vacuum:
|
||||
db->flags = saved_flags;
|
||||
db->nChange = saved_nChange;
|
||||
db->nTotalChange = saved_nTotalChange;
|
||||
db->xTrace = saved_xTrace;
|
||||
db->mTrace = saved_mTrace;
|
||||
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
|
||||
|
||||
/* Currently there is an SQL level transaction open on the vacuum
|
||||
|
||||
+17
-3
@@ -1383,6 +1383,10 @@ case OP_ResultRow: {
|
||||
}
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
|
||||
if( db->mTrace & SQLITE_TRACE_ROW ){
|
||||
db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
||||
}
|
||||
|
||||
/* Return SQLITE_ROW
|
||||
*/
|
||||
p->pc = (int)(pOp - aOp) + 1;
|
||||
@@ -2016,6 +2020,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
if( (flags1 | flags3)&MEM_Str ){
|
||||
if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn1,0);
|
||||
flags3 = pIn3->flags;
|
||||
}
|
||||
if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
|
||||
applyNumericAffinity(pIn3,0);
|
||||
@@ -2028,6 +2033,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
sqlite3VdbeMemStringify(pIn1, encoding, 1);
|
||||
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
|
||||
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
|
||||
flags3 = pIn3->flags;
|
||||
}
|
||||
if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
|
||||
testcase( pIn3->flags & MEM_Int );
|
||||
@@ -6779,13 +6785,21 @@ case OP_Init: { /* jump */
|
||||
char *z;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xTrace
|
||||
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
|
||||
&& !p->doingRerun
|
||||
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
||||
){
|
||||
z = sqlite3VdbeExpandSql(p, zTrace);
|
||||
db->xTrace(db->pTraceArg, z);
|
||||
sqlite3DbFree(db, z);
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
if( db->mTrace & SQLITE_TRACE_LEGACY ){
|
||||
void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
|
||||
x(db->pTraceArg, z);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT,db->pTraceArg,p,z);
|
||||
}
|
||||
sqlite3_free(z);
|
||||
}
|
||||
#ifdef SQLITE_USE_FCNTL_TRACE
|
||||
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
|
||||
|
||||
+3
-3
@@ -15,8 +15,8 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
#ifndef SQLITE_VDBE_H
|
||||
#define SQLITE_VDBE_H
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
@@ -309,4 +309,4 @@ void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
|
||||
# define sqlite3VdbeScanStatus(a,b,c,d,e)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* SQLITE_VDBE_H */
|
||||
|
||||
+3
-3
@@ -15,8 +15,8 @@
|
||||
** 6000 lines long) it was split up into several smaller files and
|
||||
** this header information was factored out.
|
||||
*/
|
||||
#ifndef _VDBEINT_H_
|
||||
#define _VDBEINT_H_
|
||||
#ifndef SQLITE_VDBEINT_H
|
||||
#define SQLITE_VDBEINT_H
|
||||
|
||||
/*
|
||||
** The maximum number of times that a statement will try to reparse
|
||||
@@ -558,4 +558,4 @@ int sqlite3VdbeMemHandleBom(Mem *pMem);
|
||||
#define ExpandBlob(P) SQLITE_OK
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_VDBEINT_H_) */
|
||||
#endif /* !defined(SQLITE_VDBEINT_H) */
|
||||
|
||||
+44
-3
@@ -60,12 +60,19 @@ static int vdbeSafetyNotNull(Vdbe *p){
|
||||
*/
|
||||
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
|
||||
sqlite3_int64 iNow;
|
||||
sqlite3_int64 iElapse;
|
||||
assert( p->startTime>0 );
|
||||
assert( db->xProfile!=0 );
|
||||
assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
|
||||
assert( db->init.busy==0 );
|
||||
assert( p->zSql!=0 );
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
|
||||
db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
|
||||
iElapse = (iNow - p->startTime)*1000000;
|
||||
if( db->xProfile ){
|
||||
db->xProfile(db->pProfileArg, p->zSql, iElapse);
|
||||
}
|
||||
if( db->mTrace & SQLITE_TRACE_PROFILE ){
|
||||
db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
|
||||
}
|
||||
p->startTime = 0;
|
||||
}
|
||||
/*
|
||||
@@ -569,7 +576,8 @@ static int sqlite3Step(Vdbe *p){
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xProfile && !db->init.busy && p->zSql ){
|
||||
if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
|
||||
&& !db->init.busy && p->zSql ){
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
||||
}else{
|
||||
assert( p->startTime==0 );
|
||||
@@ -1604,6 +1612,39 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
||||
return (int)v;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SQL associated with a prepared statement
|
||||
*/
|
||||
const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
return p ? p->zSql : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SQL associated with a prepared statement with
|
||||
** bound parameters expanded. Space to hold the returned string is
|
||||
** obtained from sqlite3_malloc(). The caller is responsible for
|
||||
** freeing the returned string by passing it to sqlite3_free().
|
||||
**
|
||||
** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of
|
||||
** expanded bound parameters.
|
||||
*/
|
||||
char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
return 0;
|
||||
#else
|
||||
char *z = 0;
|
||||
const char *zSql = sqlite3_sql(pStmt);
|
||||
if( zSql ){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
sqlite3_mutex_enter(p->db->mutex);
|
||||
z = sqlite3VdbeExpandSql(p, zSql);
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
}
|
||||
return z;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/*
|
||||
** Allocate and populate an UnpackedRecord structure based on the serialized
|
||||
|
||||
@@ -64,14 +64,6 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
||||
p->isPrepareV2 = (u8)isPrepareV2;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SQL associated with a prepared statement
|
||||
*/
|
||||
const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
||||
Vdbe *p = (Vdbe *)pStmt;
|
||||
return p ? p->zSql : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Swap all content between two VDBE structures.
|
||||
*/
|
||||
|
||||
+9
-3
@@ -81,10 +81,13 @@ char *sqlite3VdbeExpandSql(
|
||||
int i; /* Loop counter */
|
||||
Mem *pVar; /* Value of a host parameter */
|
||||
StrAccum out; /* Accumulate the output here */
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
|
||||
#endif
|
||||
char zBase[100]; /* Initial working space */
|
||||
|
||||
db = p->db;
|
||||
sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase),
|
||||
sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
|
||||
db->aLimit[SQLITE_LIMIT_LENGTH]);
|
||||
if( db->nVdbeExec>1 ){
|
||||
while( *zRawSql ){
|
||||
@@ -135,12 +138,14 @@ char *sqlite3VdbeExpandSql(
|
||||
int nOut; /* Number of bytes of the string text to include in output */
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
u8 enc = ENC(db);
|
||||
Mem utf8;
|
||||
if( enc!=SQLITE_UTF8 ){
|
||||
memset(&utf8, 0, sizeof(utf8));
|
||||
utf8.db = db;
|
||||
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
|
||||
sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
|
||||
if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
|
||||
out.accError = STRACCUM_NOMEM;
|
||||
out.nAlloc = 0;
|
||||
}
|
||||
pVar = &utf8;
|
||||
}
|
||||
#endif
|
||||
@@ -182,6 +187,7 @@ char *sqlite3VdbeExpandSql(
|
||||
}
|
||||
}
|
||||
}
|
||||
if( out.accError ) sqlite3StrAccumReset(&out);
|
||||
return sqlite3StrAccumFinish(&out);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
** the implementation of each function in log.c for further details.
|
||||
*/
|
||||
|
||||
#ifndef _WAL_H_
|
||||
#define _WAL_H_
|
||||
#ifndef SQLITE_WAL_H
|
||||
#define SQLITE_WAL_H
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -143,4 +143,4 @@ int sqlite3WalFramesize(Wal *pWal);
|
||||
sqlite3_file *sqlite3WalFile(Wal *pWal);
|
||||
|
||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||
#endif /* _WAL_H_ */
|
||||
#endif /* SQLITE_WAL_H */
|
||||
|
||||
+6
-1
@@ -2701,6 +2701,7 @@ static int whereLoopAddBtree(
|
||||
pNew->rSetup += 24;
|
||||
}
|
||||
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
|
||||
if( pNew->rSetup<0 ) pNew->rSetup = 0;
|
||||
/* TUNING: Each index lookup yields 20 rows in the table. This
|
||||
** is more than the usual guess of 10 rows, since we have no way
|
||||
** of knowing how selective the index will ultimately be. It would
|
||||
@@ -2761,6 +2762,7 @@ static int whereLoopAddBtree(
|
||||
/* Full scan via index */
|
||||
if( b
|
||||
|| !HasRowid(pTab)
|
||||
|| pProbe->pPartIdxWhere!=0
|
||||
|| ( m==0
|
||||
&& pProbe->bUnordered==0
|
||||
&& (pProbe->szIdxRow<pTab->szTabRow)
|
||||
@@ -3239,6 +3241,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
mPrereq = mPrior;
|
||||
}
|
||||
priorJointype = pItem->fg.jointype;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
struct SrcList_item *p;
|
||||
for(p=&pItem[1]; p<pEnd; p++){
|
||||
@@ -3247,7 +3250,9 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
||||
}
|
||||
}
|
||||
rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable);
|
||||
}else{
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
{
|
||||
rc = whereLoopAddBtree(pBuilder, mPrereq);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+74
-6
@@ -569,7 +569,7 @@ static int codeAllEqualityTerms(
|
||||
** expression: "x>='ABC' AND x<'abd'". But this requires that the range
|
||||
** scan loop run twice, once for strings and a second time for BLOBs.
|
||||
** The OP_String opcodes on the second pass convert the upper and lower
|
||||
** bound string contants to blobs. This routine makes the necessary changes
|
||||
** bound string constants to blobs. This routine makes the necessary changes
|
||||
** to the OP_String opcodes for that to happen.
|
||||
**
|
||||
** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then
|
||||
@@ -626,6 +626,38 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Test whether or not expression pExpr, which was part of a WHERE clause,
|
||||
** should be included in the cursor-hint for a table that is on the rhs
|
||||
** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
|
||||
** expression is not suitable.
|
||||
**
|
||||
** An expression is unsuitable if it might evaluate to non NULL even if
|
||||
** a TK_COLUMN node that does affect the value of the expression is set
|
||||
** to NULL. For example:
|
||||
**
|
||||
** col IS NULL
|
||||
** col IS NOT NULL
|
||||
** coalesce(col, 1)
|
||||
** CASE WHEN col THEN 0 ELSE 1 END
|
||||
*/
|
||||
static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_IS
|
||||
|| pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
|
||||
|| pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
|
||||
){
|
||||
pWalker->eCode = 1;
|
||||
}else if( pExpr->op==TK_FUNCTION ){
|
||||
int d1;
|
||||
char d2[3];
|
||||
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
|
||||
pWalker->eCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called on every node of an expression tree used as an
|
||||
@@ -678,6 +710,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
** Insert an OP_CursorHint instruction if it is appropriate to do so.
|
||||
*/
|
||||
static void codeCursorHint(
|
||||
struct SrcList_item *pTabItem, /* FROM clause item */
|
||||
WhereInfo *pWInfo, /* The where clause */
|
||||
WhereLevel *pLevel, /* Which loop to provide hints for */
|
||||
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
|
||||
@@ -708,7 +741,42 @@ static void codeCursorHint(
|
||||
pTerm = &pWC->a[i];
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( pTerm->prereqAll & pLevel->notReady ) continue;
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
||||
|
||||
/* Any terms specified as part of the ON(...) clause for any LEFT
|
||||
** JOIN for which the current table is not the rhs are omitted
|
||||
** from the cursor-hint.
|
||||
**
|
||||
** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
|
||||
** that were specified as part of the WHERE clause must be excluded.
|
||||
** This is to address the following:
|
||||
**
|
||||
** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
|
||||
**
|
||||
** Say there is a single row in t2 that matches (t1.a=t2.b), but its
|
||||
** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
|
||||
** pushed down to the cursor, this row is filtered out, causing
|
||||
** SQLite to synthesize a row of NULL values. Which does match the
|
||||
** WHERE clause, and so the query returns a row. Which is incorrect.
|
||||
**
|
||||
** For the same reason, WHERE terms such as:
|
||||
**
|
||||
** WHERE 1 = (t2.c IS NULL)
|
||||
**
|
||||
** are also excluded. See codeCursorHintIsOrFunction() for details.
|
||||
*/
|
||||
if( pTabItem->fg.jointype & JT_LEFT ){
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
if( !ExprHasProperty(pExpr, EP_FromJoin)
|
||||
|| pExpr->iRightJoinTable!=pTabItem->iCursor
|
||||
){
|
||||
sWalker.eCode = 0;
|
||||
sWalker.xExprCallback = codeCursorHintIsOrFunction;
|
||||
sqlite3WalkExpr(&sWalker, pTerm->pExpr);
|
||||
if( sWalker.eCode ) continue;
|
||||
}
|
||||
}else{
|
||||
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
||||
}
|
||||
|
||||
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
|
||||
** the cursor. These terms are not needed as hints for a pure range
|
||||
@@ -742,7 +810,7 @@ static void codeCursorHint(
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define codeCursorHint(A,B,C) /* No-op */
|
||||
# define codeCursorHint(A,B,C,D) /* No-op */
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
|
||||
|
||||
/*
|
||||
@@ -998,7 +1066,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pStart = pEnd;
|
||||
pEnd = pTerm;
|
||||
}
|
||||
codeCursorHint(pWInfo, pLevel, pEnd);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
|
||||
if( pStart ){
|
||||
Expr *pX; /* The expression that defines the start bound */
|
||||
int r1, rTemp; /* Registers for holding the start boundary */
|
||||
@@ -1212,7 +1280,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** and store the values of those terms in an array of registers
|
||||
** starting at regBase.
|
||||
*/
|
||||
codeCursorHint(pWInfo, pLevel, pRangeEnd);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
|
||||
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
|
||||
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
|
||||
if( zStartAff ) cEndAff = zStartAff[nEq];
|
||||
@@ -1660,7 +1728,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** a pseudo-cursor. No need to Rewind or Next such cursors. */
|
||||
pLevel->op = OP_Noop;
|
||||
}else{
|
||||
codeCursorHint(pWInfo, pLevel, 0);
|
||||
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
|
||||
pLevel->op = aStep[bRev];
|
||||
pLevel->p1 = iCur;
|
||||
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
|
||||
|
||||
+3
-5
@@ -785,12 +785,10 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
|
||||
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
||||
/* Since pLeft and pRight are both a column references, their collating
|
||||
** sequence should always be defined. */
|
||||
zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
|
||||
zColl1 = pColl ? pColl->zName : 0;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
|
||||
zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
|
||||
return sqlite3StrICmp(zColl1, zColl2)==0;
|
||||
zColl2 = pColl ? pColl->zName : 0;
|
||||
return sqlite3_stricmp(zColl1, zColl2)==0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+6
-6
@@ -184,7 +184,7 @@ do_test alter3-3.2 {
|
||||
if {!$has_codec} {
|
||||
do_test alter3-3.3 {
|
||||
get_file_format
|
||||
} {4}
|
||||
} {3}
|
||||
}
|
||||
ifcapable schema_version {
|
||||
do_test alter3-3.4 {
|
||||
@@ -220,7 +220,7 @@ do_test alter3-4.2 {
|
||||
if {!$has_codec} {
|
||||
do_test alter3-4.3 {
|
||||
get_file_format
|
||||
} {4}
|
||||
} {3}
|
||||
}
|
||||
ifcapable schema_version {
|
||||
do_test alter3-4.4 {
|
||||
@@ -270,7 +270,7 @@ ifcapable attach {
|
||||
if {!$has_codec} {
|
||||
do_test alter3-5.5 {
|
||||
list [get_file_format test2.db] [get_file_format]
|
||||
} {4 4}
|
||||
} {3 3}
|
||||
}
|
||||
do_test alter3-5.6 {
|
||||
execsql {
|
||||
@@ -347,19 +347,19 @@ if {!$has_codec} {
|
||||
ALTER TABLE abc ADD d DEFAULT NULL;
|
||||
}
|
||||
get_file_format
|
||||
} {4}
|
||||
} {3}
|
||||
do_test alter3-7.3 {
|
||||
execsql {
|
||||
ALTER TABLE abc ADD e DEFAULT 10;
|
||||
}
|
||||
get_file_format
|
||||
} {4}
|
||||
} {3}
|
||||
do_test alter3-7.4 {
|
||||
execsql {
|
||||
ALTER TABLE abc ADD f DEFAULT NULL;
|
||||
}
|
||||
get_file_format
|
||||
} {4}
|
||||
} {3}
|
||||
do_test alter3-7.5 {
|
||||
execsql {
|
||||
VACUUM;
|
||||
|
||||
@@ -355,4 +355,23 @@ do_execsql_test alter4-9.3 {
|
||||
SELECT typeof(c), c FROM t5;
|
||||
} {real 9.22337203685478e+18}
|
||||
|
||||
# Confirm that doing an ALTER TABLE on a legacy format database
|
||||
# does not corrupt DESC indexes.
|
||||
#
|
||||
# Ticket https://www.sqlite.org/src/tktview/f68bf68513a1c
|
||||
#
|
||||
do_test alter4-10.1 {
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
db eval {
|
||||
PRAGMA legacy_file_format=on;
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE INDEX t1a ON t1(a DESC);
|
||||
INSERT INTO t1 VALUES(1,2,3);
|
||||
INSERT INTO t1 VALUES(2,3,4);
|
||||
ALTER TABLE t1 ADD COLUMN d;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
|
||||
finish_test
|
||||
|
||||
+15
-10
@@ -135,17 +135,22 @@ foreach omit {0 1} {
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the same pattern works with ordinary tables.
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT);
|
||||
CREATE INDEX t2x ON t2(x COLLATE nocase);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
}
|
||||
# This test does not work if the ICU extension is enabled. ICU overrides
|
||||
# LIKE - and this optimization only works with the built-in LIKE function.
|
||||
#
|
||||
ifcapable !icu {
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT);
|
||||
CREATE INDEX t2x ON t2(x COLLATE nocase);
|
||||
CREATE INDEX t2y ON t2(y);
|
||||
}
|
||||
|
||||
do_eqp_test 2.2 {
|
||||
SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)}
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)}
|
||||
do_eqp_test 2.2 {
|
||||
SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def'
|
||||
} {
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)}
|
||||
0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# 2016-07-01
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Test cases for a crash bug.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test collateB-1.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY);
|
||||
CREATE TABLE t2(b INTEGER PRIMARY KEY, x1 INT COLLATE NOCASE);
|
||||
CREATE TABLE t3(x2 INT);
|
||||
SELECT * FROM t3, t2, t1 WHERE x2=b AND x1=a AND a=1;
|
||||
} {}
|
||||
do_execsql_test collateB-1.2 {
|
||||
INSERT INTO t1(a) VALUES(1),(2),(3);
|
||||
INSERT INTO t2(b,x1) VALUES(11,1),(22,2),(33,3);
|
||||
INSERT INTO t3(x2) VALUES(11),(22),(33);
|
||||
SELECT *,'|' FROM t3, t2, t1 WHERE x2=b AND x1=a AND a=1;
|
||||
} {11 11 1 1 |}
|
||||
do_execsql_test collateB-1.3 {
|
||||
SELECT *,'|' FROM t3, t1, t2 WHERE x2=b AND x1=a AND a=1;
|
||||
} {11 1 11 1 |}
|
||||
do_execsql_test collateB-1.4 {
|
||||
SELECT *,'|' FROM t2, t3, t1 WHERE x2=b AND x1=a AND a=1;
|
||||
} {11 1 11 1 |}
|
||||
do_execsql_test collateB-1.5 {
|
||||
SELECT *,'|' FROM t2, t1, t3 WHERE x2=b AND x1=a AND a=1;
|
||||
} {11 1 1 11 |}
|
||||
do_execsql_test collateB-1.6 {
|
||||
SELECT *,'|' FROM t1, t2, t3 WHERE x2=b AND x1=a AND a=1;
|
||||
} {1 11 1 11 |}
|
||||
do_execsql_test collateB-1.7 {
|
||||
SELECT *,'|' FROM t1, t2, t3 WHERE x2=b AND x1=a AND a=1;
|
||||
} {1 11 1 11 |}
|
||||
do_execsql_test collateB-1.12 {
|
||||
SELECT *,'|' FROM t3, t2, t1 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {11 11 1 1 |}
|
||||
do_execsql_test collateB-1.13 {
|
||||
SELECT *,'|' FROM t3, t1, t2 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {11 1 11 1 |}
|
||||
do_execsql_test collateB-1.14 {
|
||||
SELECT *,'|' FROM t2, t3, t1 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {11 1 11 1 |}
|
||||
do_execsql_test collateB-1.15 {
|
||||
SELECT *,'|' FROM t2, t1, t3 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {11 1 1 11 |}
|
||||
do_execsql_test collateB-1.16 {
|
||||
SELECT *,'|' FROM t1, t2, t3 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {1 11 1 11 |}
|
||||
do_execsql_test collateB-1.17 {
|
||||
SELECT *,'|' FROM t1, t2, t3 WHERE b=x2 AND a=x1 AND 1=a;
|
||||
} {1 11 1 11 |}
|
||||
|
||||
finish_test
|
||||
+3
-2
@@ -196,9 +196,10 @@ set tc 1
|
||||
foreach opt $opts {
|
||||
do_test ctime-2.5.$tc {
|
||||
set N [ expr {$tc-1} ]
|
||||
set ans1 [ catchsql {
|
||||
set ans1 [catch {db one {
|
||||
SELECT sqlite_compileoption_get($N);
|
||||
} ]
|
||||
}} msg]
|
||||
lappend ans1 $msg
|
||||
set ans2 [ catchsql {
|
||||
SELECT sqlite_compileoption_used($opt);
|
||||
} ]
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
# 2016 June 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus is on testing that cursor-hints are correct for queries
|
||||
# involving LEFT JOIN.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix cursorhint2
|
||||
|
||||
ifcapable !cursorhints {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc extract_hints {sql} {
|
||||
|
||||
db eval "SELECT tbl_name, rootpage FROM sqlite_master where rootpage" {
|
||||
set lookup($rootpage) $tbl_name
|
||||
}
|
||||
|
||||
set ret [list]
|
||||
db eval "EXPLAIN $sql" a {
|
||||
switch -- $a(opcode) {
|
||||
OpenRead {
|
||||
set csr($a(p1)) $lookup($a(p2))
|
||||
}
|
||||
CursorHint {
|
||||
lappend ret $csr($a(p1)) $a(p4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set ret
|
||||
}
|
||||
|
||||
proc do_extract_hints_test {tn sql ret} {
|
||||
uplevel [list do_test $tn [list extract_hints $sql] [list {*}$ret]]
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA automatic_index = 0;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE TABLE t3(e, f);
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.1 {
|
||||
SELECT * FROM t1 WHERE a=1;
|
||||
} {
|
||||
t1 EQ(c0,1)
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.2 {
|
||||
SELECT * FROM t1 CROSS JOIN t2 ON (a=c) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {AND(ISNULL(c1),EQ(r[1],c0))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.3 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {EQ(r[2],c0)}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.4 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND a=10) WHERE d IS NULL;
|
||||
} {
|
||||
t2 {AND(EQ(r[2],c0),EQ(r[3],10))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.5 {
|
||||
SELECT * FROM t1 CROSS JOIN t2 ON (a=c AND a=10) WHERE d IS NULL;
|
||||
} {
|
||||
t1 EQ(c0,10) t2 {AND(ISNULL(c1),EQ(r[3],c0))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.6 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c) LEFT JOIN t3 ON (d=f);
|
||||
} {
|
||||
t2 {EQ(r[2],c0)} t3 {EQ(r[6],c1)}
|
||||
}
|
||||
|
||||
do_extract_hints_test 1.7 {
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (a=c AND d=e) LEFT JOIN t3 ON (d=f);
|
||||
} {
|
||||
t2 {EQ(r[2],c0)} t3 {AND(EQ(r[6],c0),EQ(r[7],c1))}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(x, y);
|
||||
CREATE TABLE x2(a, b);
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.1 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NULL;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.2 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS +NULL;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.3 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = (b IS NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.4 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.5 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 1 = coalesce(b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.6 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.7 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE 0 = (b IS NOT +NULL)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.8 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE b IS NOT +NULL
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.9 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE CASE b WHEN 0 THEN 0 ELSE 1 END;
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.10 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b = 32+32
|
||||
} {
|
||||
x2 {AND(EQ(c1,ADD(32,32)),EQ(c0,r[2]))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.11 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE x2.b LIKE 'abc%'
|
||||
} {
|
||||
x2 {AND(expr,EQ(c0,r[2]))}
|
||||
}
|
||||
|
||||
do_extract_hints_test 2.11 {
|
||||
SELECT * FROM x1 LEFT JOIN x2 ON (a=x) WHERE coalesce(x2.b, 1)
|
||||
} {
|
||||
x2 {EQ(c0,r[2])}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+38
-5
@@ -14,6 +14,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix dbstatus
|
||||
|
||||
ifcapable !compound {
|
||||
finish_test
|
||||
@@ -24,6 +25,7 @@ ifcapable !compound {
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_memstatus 1
|
||||
sqlite3_config_uri 1
|
||||
sqlite3_initialize
|
||||
sqlite3 db test.db
|
||||
|
||||
@@ -67,16 +69,12 @@ ifcapable stat4||stat3 {
|
||||
set STAT3 0
|
||||
}
|
||||
|
||||
ifcapable malloc_usable_size {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Run the dbstatus-2 and dbstatus-3 tests with several of different
|
||||
# lookaside buffer sizes.
|
||||
#
|
||||
foreach ::lookaside_buffer_size {0 64 120} {
|
||||
ifcapable malloc_usable_size break
|
||||
|
||||
# Do not run any of these tests if there is SQL configured to run
|
||||
# as part of the [sqlite3] command. This prevents the script from
|
||||
@@ -377,4 +375,39 @@ foreach ::lookaside_buffer_size {0 64 120} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests focus on DBSTATUS_CACHE_USED_SHARED
|
||||
#
|
||||
ifcapable shared_cache {
|
||||
proc do_cacheused_test {tn db res} {
|
||||
set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0]
|
||||
set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0]
|
||||
set cu [lindex $cu 1]
|
||||
set pcu [lindex $pcu 1]
|
||||
uplevel [list do_test $tn [list list $cu $pcu] "#/$res/"]
|
||||
}
|
||||
reset_db
|
||||
sqlite3 db file:test.db?cache=shared
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
}
|
||||
do_cacheused_test 4.0.1 db { 4568 4568 }
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TEMP TABLE tt(a, b, c);
|
||||
INSERT INTO tt VALUES(1, 2, 3);
|
||||
}
|
||||
do_cacheused_test 4.1.1 db { 9000 9000 }
|
||||
|
||||
sqlite3 db2 file:test.db?cache=shared
|
||||
do_cacheused_test 4.2.1 db2 { 4568 2284 }
|
||||
do_cacheused_test 4.2.2 db { 9000 6716 }
|
||||
db close
|
||||
do_cacheused_test 4.2.3 db2 { 4568 4568 }
|
||||
sqlite3 db file:test.db?cache=shared
|
||||
do_cacheused_test 4.2.4 db2 { 4568 2284 }
|
||||
db2 close
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -376,4 +376,15 @@ do_execsql_test index6-10.3eqp {
|
||||
SELECT e FROM t10 WHERE a=1 AND b=2 ORDER BY d DESC;
|
||||
} {~/USING INDEX t10x/}
|
||||
|
||||
# A partial index will be used for a full table scan, where possible
|
||||
do_execsql_test index6-11.1 {
|
||||
CREATE TABLE t11(a,b,c);
|
||||
CREATE INDEX t11x ON t11(a) WHERE b<>99;
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99;
|
||||
} {/USING INDEX t11x/}
|
||||
do_execsql_test index6-11.2 {
|
||||
EXPLAIN QUERY PLAN SELECT a FROM t11 WHERE b<>99 AND c<>98;
|
||||
} {/USING INDEX t11x/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1434,5 +1434,14 @@ do_catchsql_test 5.4 {
|
||||
SELECT * FROM t8 UNION SELECT * FROM t9 ORDER BY a+b COLLATE NOCASE
|
||||
} {1 {1st ORDER BY term does not match any column in the result set}}
|
||||
|
||||
do_execsql_test 6.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1(a INTEGER);
|
||||
CREATE TABLE t2(b TEXT);
|
||||
INSERT INTO t2(b) VALUES('12345');
|
||||
SELECT * FROM (SELECT a FROM t1 UNION SELECT b FROM t2) WHERE a=a;
|
||||
} {12345}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -32,6 +32,9 @@ db func a_string a_string
|
||||
|
||||
register_dbstat_vtab db
|
||||
do_execsql_test stat-0.0 {
|
||||
PRAGMA table_info(dbstat);
|
||||
} {/0 name TEXT .* 1 path TEXT .* 9 pgsize INTEGER/}
|
||||
do_execsql_test stat-0.1 {
|
||||
PRAGMA auto_vacuum = OFF;
|
||||
CREATE VIRTUAL TABLE temp.stat USING dbstat;
|
||||
SELECT * FROM stat;
|
||||
|
||||
@@ -22,6 +22,7 @@ ifcapable !vtab {
|
||||
return
|
||||
}
|
||||
load_static_extension db series
|
||||
load_static_extension db carray
|
||||
|
||||
do_execsql_test tabfunc01-1.1 {
|
||||
SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2;
|
||||
@@ -135,4 +136,61 @@ do_execsql_test tabfunc01-500 {
|
||||
ORDER BY +1;
|
||||
} {1 7 11 17}
|
||||
|
||||
# Table-valued functions on the RHS of an IN operator
|
||||
#
|
||||
do_execsql_test tabfunc01-600 {
|
||||
CREATE TABLE t600(a INTEGER PRIMARY KEY, b TEXT);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
|
||||
INSERT INTO t600(a,b) SELECT x, printf('(%03d)',x) FROM c;
|
||||
SELECT b FROM t600 WHERE a IN generate_series(2,52,10);
|
||||
} {(002) (012) (022) (032) (042) (052)}
|
||||
|
||||
|
||||
do_test tabfunc01-700 {
|
||||
set PTR [intarray_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR,5) WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
do_test tabfunc01-701 {
|
||||
db eval {
|
||||
SELECT b FROM t600 WHERE a IN carray($PTR,5,'int32');
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
do_test tabfunc01-702 {
|
||||
db eval {
|
||||
SELECT b FROM t600 WHERE a IN carray($PTR,4,'int32');
|
||||
}
|
||||
} {(005) (007) (013) (017)}
|
||||
do_catchsql_test tabfunc01-710 {
|
||||
SELECT b FROM t600 WHERE a IN carray($PTR,5,'int33');
|
||||
} {1 {unknown datatype: 'int33'}}
|
||||
|
||||
do_test tabfunc01-720 {
|
||||
set PTR [int64array_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR,5,'int64') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
|
||||
do_test tabfunc01-730 {
|
||||
set PTR [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR,5,'double') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
|
||||
do_test tabfunc01-740 {
|
||||
set PTR [textarray_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR,5,'char*') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
|
||||
|
||||
intarray_addr
|
||||
int64array_addr
|
||||
doublearray_addr
|
||||
textarray_addr
|
||||
|
||||
finish_test
|
||||
|
||||
+34
-1
@@ -34,7 +34,7 @@ do_test tcl-1.1 {
|
||||
do_test tcl-1.2 {
|
||||
set v [catch {db bogus} msg]
|
||||
lappend v $msg
|
||||
} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, transaction, unlock_notify, update_hook, version, or wal_hook}}
|
||||
} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
|
||||
do_test tcl-1.2.1 {
|
||||
set v [catch {db cache bogus} msg]
|
||||
lappend v $msg
|
||||
@@ -635,6 +635,39 @@ do_test tcl-14.2 {
|
||||
db one {SELECT x FROM t6 WHERE xCall()!='value'}
|
||||
} {}
|
||||
|
||||
# Verify that the "exists" and "onecolumn" methods work when
|
||||
# a "profile" is registered.
|
||||
#
|
||||
catch {db close}
|
||||
sqlite3 db :memory:
|
||||
proc noop-profile {args} {
|
||||
return
|
||||
}
|
||||
do_test tcl-15.0 {
|
||||
db eval {CREATE TABLE t1(a); INSERT INTO t1 VALUES(1),(2),(3);}
|
||||
db onecolumn {SELECT a FROM t1 WHERE a>2}
|
||||
} {3}
|
||||
do_test tcl-15.1 {
|
||||
db exists {SELECT a FROM t1 WHERE a>2}
|
||||
} {1}
|
||||
do_test tcl-15.2 {
|
||||
db exists {SELECT a FROM t1 WHERE a>3}
|
||||
} {0}
|
||||
db profile noop-profile
|
||||
do_test tcl-15.3 {
|
||||
db onecolumn {SELECT a FROM t1 WHERE a>2}
|
||||
} {3}
|
||||
do_test tcl-15.4 {
|
||||
db exists {SELECT a FROM t1 WHERE a>2}
|
||||
} {1}
|
||||
do_test tcl-15.5 {
|
||||
db exists {SELECT a FROM t1 WHERE a>3}
|
||||
} {0}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+27
-1
@@ -720,6 +720,17 @@ proc puts {args} { uplevel puts_override $args }
|
||||
|
||||
# Invoke the do_test procedure to run a single test
|
||||
#
|
||||
# The $expected parameter is the expected result. The result is the return
|
||||
# value from the last TCL command in $cmd.
|
||||
#
|
||||
# Normally, $expected must match exactly. But if $expected is of the form
|
||||
# "/regexp/" then regular expression matching is used. If $expected is
|
||||
# "~/regexp/" then the regular expression must NOT match. If $expected is
|
||||
# of the form "#/value-list/" then each term in value-list must be numeric
|
||||
# and must approximately match the corresponding numeric term in $result.
|
||||
# Values must match within 10%. Or if the $expected term is A..B then the
|
||||
# $result term must be in between A and B.
|
||||
#
|
||||
proc do_test {name cmd expected} {
|
||||
global argv cmdlinearg
|
||||
|
||||
@@ -753,7 +764,7 @@ proc do_test {name cmd expected} {
|
||||
output2 "\nError: $result"
|
||||
fail_test $name
|
||||
} else {
|
||||
if {[regexp {^~?/.*/$} $expected]} {
|
||||
if {[regexp {^[~#]?/.*/$} $expected]} {
|
||||
# "expected" is of the form "/PATTERN/" then the result if correct if
|
||||
# regular expression PATTERN matches the result. "~/PATTERN/" means
|
||||
# the regular expression must not match.
|
||||
@@ -767,6 +778,21 @@ proc do_test {name cmd expected} {
|
||||
set ok [regexp $re $result]
|
||||
}
|
||||
set ok [expr {!$ok}]
|
||||
} elseif {[string index $expected 0]=="#"} {
|
||||
# Numeric range value comparison. Each term of the $result is matched
|
||||
# against one term of $expect. Both $result and $expected terms must be
|
||||
# numeric. The values must match within 10%. Or if $expected is of the
|
||||
# form A..B then the $result term must be between A and B.
|
||||
set e2 [string range $expected 2 end-1]
|
||||
foreach i $result j $e2 {
|
||||
if {[regexp {^(-?\d+)\.\.(-?\d)$} $j all A B]} {
|
||||
set ok [expr {$i+0>=$A && $i+0<=$B}]
|
||||
} else {
|
||||
set ok [expr {$i+0>=0.9*$j && $i+0<=1.1*$j}]
|
||||
}
|
||||
if {!$ok} break
|
||||
}
|
||||
if {$ok && [llength $result]!=[llength $e2]} {set ok 0}
|
||||
} else {
|
||||
set re [string range $expected 1 end-1]
|
||||
if {[string index $re 0]=="*"} {
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
# 2016 July 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The focus of
|
||||
# this test file is the "sqlite3_trace_v2()" and "sqlite3_expanded_sql()"
|
||||
# APIs.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !trace { finish_test ; return }
|
||||
set ::testprefix trace3
|
||||
|
||||
proc trace_v2_error { args } {
|
||||
lappend ::stmtlist(error) [string trim $args]
|
||||
error "trace error"; # this will be ignored.
|
||||
}
|
||||
proc trace_v2_record { args } {
|
||||
lappend ::stmtlist(record) [string trim $args]
|
||||
}
|
||||
proc trace_v2_nop { args } {}; # do nothing.
|
||||
|
||||
do_test trace3-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b);
|
||||
INSERT INTO t1 VALUES(1,NULL);
|
||||
INSERT INTO t1 VALUES(2,-1);
|
||||
INSERT INTO t1 VALUES(3,0);
|
||||
INSERT INTO t1 VALUES(4,1);
|
||||
INSERT INTO t1 VALUES(5,-2147483648);
|
||||
INSERT INTO t1 VALUES(6,2147483647);
|
||||
INSERT INTO t1 VALUES(7,-9223372036854775808);
|
||||
INSERT INTO t1 VALUES(8,9223372036854775807);
|
||||
INSERT INTO t1 VALUES(9,-1.0);
|
||||
INSERT INTO t1 VALUES(10,0.0);
|
||||
INSERT INTO t1 VALUES(11,1.0);
|
||||
INSERT INTO t1 VALUES(12,'');
|
||||
INSERT INTO t1 VALUES(13,'1');
|
||||
INSERT INTO t1 VALUES(14,'one');
|
||||
INSERT INTO t1 VALUES(15,x'abcd0123');
|
||||
INSERT INTO t1 VALUES(16,x'4567cdef');
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test trace3-1.1 {
|
||||
set rc [catch {db trace_v2 1 2 3} msg]
|
||||
lappend rc $msg
|
||||
} {1 {wrong # args: should be "db trace_v2 ?CALLBACK? ?MASK?"}}
|
||||
do_test trace3-1.2 {
|
||||
set rc [catch {db trace_v2 1 bad} msg]
|
||||
lappend rc $msg
|
||||
} {1 {bad trace type "bad": must be statement, profile, row, or close}}
|
||||
|
||||
do_test trace3-2.1 {
|
||||
db trace_v2 trace_v2_nop
|
||||
db trace_v2
|
||||
} {trace_v2_nop}
|
||||
|
||||
do_test trace3-3.1 {
|
||||
unset -nocomplain ::stmtlist
|
||||
db trace_v2 trace_v2_nop
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
array get ::stmtlist
|
||||
} {}
|
||||
do_test trace3-3.2 {
|
||||
set ::stmtlist(error) {}
|
||||
db trace_v2 trace_v2_error
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(error)
|
||||
} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
|
||||
do_test trace3-3.3 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
|
||||
do_test trace3-3.4 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record statement
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
|
||||
do_test trace3-3.5 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record 1
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
|
||||
|
||||
do_test trace3-4.1 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record profile
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} {/^\{-?\d+ -?\d+\}$/}
|
||||
do_test trace3-4.2 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record 2
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} {/^\{-?\d+ -?\d+\}$/}
|
||||
|
||||
do_test trace3-5.1 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record row
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} "/^[string trim [string repeat {\d+ } 16]]\$/"
|
||||
do_test trace3-5.2 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record 4
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} "/^[string trim [string repeat {\d+ } 16]]\$/"
|
||||
|
||||
do_test trace3-6.1 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record {profile row}
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} "/^[string trim [string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/"
|
||||
do_test trace3-6.2 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record {statement profile row}
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
set ::stmtlist(record)
|
||||
} "/^\\\{-?\\d+ \\\{SELECT a, b FROM t1 ORDER BY a;\\\}\\\} [string trim \
|
||||
[string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/"
|
||||
|
||||
do_test trace3-7.1 {
|
||||
set DB [sqlite3_connection_pointer db]
|
||||
|
||||
set STMT [sqlite3_prepare_v2 $DB \
|
||||
"SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 TAIL]
|
||||
} {/^[0-9A-Fa-f]+$/}
|
||||
|
||||
do_test trace3-8.1 {
|
||||
list [sqlite3_bind_null $STMT 1] [sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = NULL ORDER BY a;}}
|
||||
do_test trace3-8.2 {
|
||||
list [sqlite3_bind_int $STMT 1 123] [sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}}
|
||||
do_test trace3-8.3 {
|
||||
list [sqlite3_bind_int64 $STMT 1 123] [sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}}
|
||||
do_test trace3-8.4 {
|
||||
list [sqlite3_bind_text $STMT 1 "some string" 11] \
|
||||
[sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 'some string' ORDER BY a;}}
|
||||
do_test trace3-8.5 {
|
||||
list [sqlite3_bind_text $STMT 1 "some 'bad' string" 17] \
|
||||
[sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 'some ''bad'' string' ORDER BY a;}}
|
||||
do_test trace3-8.6 {
|
||||
list [sqlite3_bind_double $STMT 1 123] [sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 123.0 ORDER BY a;}}
|
||||
do_test trace3-8.7 {
|
||||
list [sqlite3_bind_text16 $STMT 1 \
|
||||
[encoding convertto unicode hi\000yall\000] 16] \
|
||||
[sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = 'hi' ORDER BY a;}}
|
||||
do_test trace3-8.8 {
|
||||
list [sqlite3_bind_blob $STMT 1 "\x12\x34\x56" 3] \
|
||||
[sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = x'123456' ORDER BY a;}}
|
||||
do_test trace3-8.9 {
|
||||
list [sqlite3_bind_blob $STMT 1 "\xAB\xCD\xEF" 3] \
|
||||
[sqlite3_expanded_sql $STMT]
|
||||
} {{} {SELECT a, b FROM t1 WHERE b = x'abcdef' ORDER BY a;}}
|
||||
|
||||
do_test trace3-9.1 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test trace3-10.1 {
|
||||
db trace_v2 ""
|
||||
db trace_v2
|
||||
} {}
|
||||
do_test trace3-10.2 {
|
||||
unset -nocomplain ::stmtlist
|
||||
db trace_v2 "" {statement profile row}
|
||||
execsql {
|
||||
SELECT a, b FROM t1 ORDER BY a;
|
||||
}
|
||||
array get ::stmtlist
|
||||
} {}
|
||||
|
||||
do_test trace3-11.1 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record close
|
||||
db close
|
||||
set ::stmtlist(record)
|
||||
} {/^-?\d+$/}
|
||||
|
||||
reset_db
|
||||
|
||||
do_test trace3-11.2 {
|
||||
set ::stmtlist(record) {}
|
||||
db trace_v2 trace_v2_record 8
|
||||
db close
|
||||
set ::stmtlist(record)
|
||||
} {/^-?\d+$/}
|
||||
|
||||
finish_test
|
||||
+2
-2
@@ -45,7 +45,7 @@ do_test where3-1.1 {
|
||||
}
|
||||
} {222 two 2 222 {} {}}
|
||||
|
||||
ifcapable explain {
|
||||
ifcapable explain&&!cursorhints {
|
||||
do_test where3-1.1.1 {
|
||||
explain_no_trace {SELECT * FROM t1, t2 LEFT JOIN t3 ON q=x
|
||||
WHERE p=2 AND a=q}
|
||||
@@ -86,7 +86,7 @@ do_test where3-1.2 {
|
||||
}
|
||||
} {1 {Value for C1.1} {Value for C2.1} 2 {} {Value for C2.2} 3 {Value for C1.3} {Value for C2.3}}
|
||||
|
||||
ifcapable explain {
|
||||
ifcapable explain&&!cursorhints {
|
||||
do_test where3-1.2.1 {
|
||||
explain_no_trace {
|
||||
SELECT parent1.parent1key, child1.value, child2.value
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# 2016 July 8
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
if {$tcl_platform(platform)!="windows"} return
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix win32nolock
|
||||
|
||||
do_test win32nolock-1.0 {
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.1 {
|
||||
execsql COMMIT
|
||||
catchsql { SELECT * FROM t1 }
|
||||
} {0 {1 2}}
|
||||
|
||||
db close
|
||||
|
||||
do_test win32nolock-1.2 {
|
||||
sqlite3 db test.db -vfs win32-none
|
||||
sqlite3 db2 test.db -vfs win32-none
|
||||
execsql { PRAGMA mmap_size = 0 } db2
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.3 {
|
||||
execsql { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test win32nolock-1.4 {
|
||||
execsql { SELECT * FROM t1; } db2
|
||||
} {1 2}
|
||||
|
||||
do_test win32nolock-1.5 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
} db2
|
||||
} {1 2}
|
||||
|
||||
do_test win32nolock-1.6 {
|
||||
execsql COMMIT
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2}
|
||||
|
||||
ifcapable memorymanage {
|
||||
do_test win32nolock-1.7 {
|
||||
sqlite3_release_memory 1000000
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2 3 4}
|
||||
}
|
||||
|
||||
do_test win32nolock-1.8 {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.9.1 {
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db
|
||||
list [catchsql { BEGIN EXCLUSIVE; } db] \
|
||||
[catchsql { BEGIN EXCLUSIVE; } db2]
|
||||
} {{0 {}} {1 {database is locked}}}
|
||||
|
||||
do_test win32nolock-1.9.2 {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.10.1 {
|
||||
sqlite3 db test.db -vfs win32-none
|
||||
sqlite3 db2 test.db
|
||||
list [catchsql { BEGIN EXCLUSIVE; } db] \
|
||||
[catchsql { BEGIN EXCLUSIVE; } db2]
|
||||
} {{0 {}} {0 {}}}
|
||||
|
||||
do_test win32nolock-1.10.2 {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.11.1 {
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db -vfs win32-none
|
||||
list [catchsql { BEGIN EXCLUSIVE; } db] \
|
||||
[catchsql { BEGIN EXCLUSIVE; } db2]
|
||||
} {{0 {}} {0 {}}}
|
||||
|
||||
do_test win32nolock-1.11.2 {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
do_test win32nolock-1.12.1 {
|
||||
sqlite3 db test.db -vfs win32-none
|
||||
sqlite3 db2 test.db -vfs win32-none
|
||||
list [catchsql { BEGIN EXCLUSIVE; } db] \
|
||||
[catchsql { BEGIN EXCLUSIVE; } db2]
|
||||
} {{0 {}} {0 {}}}
|
||||
|
||||
do_test win32nolock-1.12.2 {
|
||||
db close
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
+10
-1
@@ -390,6 +390,7 @@ static void yy_destructor(
|
||||
static void yy_pop_parser_stack(yyParser *pParser){
|
||||
yyStackEntry *yytos;
|
||||
assert( pParser->yytos!=0 );
|
||||
assert( pParser->yytos > pParser->yystack );
|
||||
yytos = pParser->yytos--;
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
@@ -754,6 +755,9 @@ static void yy_accept(
|
||||
if( yyTraceFILE ){
|
||||
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
|
||||
}
|
||||
#endif
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
yypParser->yyerrcnt = -1;
|
||||
#endif
|
||||
assert( yypParser->yytos==yypParser->yystack );
|
||||
/* Here code is inserted which will be executed whenever the
|
||||
@@ -799,7 +803,6 @@ void Parse(
|
||||
#endif
|
||||
yyParser *yypParser; /* The parser */
|
||||
|
||||
/* (re)initialize the parser, if necessary */
|
||||
yypParser = (yyParser*)yyp;
|
||||
assert( yypParser->yytos!=0 );
|
||||
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
|
||||
@@ -879,6 +882,9 @@ void Parse(
|
||||
if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
|
||||
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
|
||||
yy_parse_failed(yypParser);
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
yypParser->yyerrcnt = -1;
|
||||
#endif
|
||||
yymajor = YYNOCODE;
|
||||
}else if( yymx!=YYERRORSYMBOL ){
|
||||
yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
|
||||
@@ -915,6 +921,9 @@ void Parse(
|
||||
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
|
||||
if( yyendofinput ){
|
||||
yy_parse_failed(yypParser);
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
yypParser->yyerrcnt = -1;
|
||||
#endif
|
||||
}
|
||||
yymajor = YYNOCODE;
|
||||
#endif
|
||||
|
||||
+146
-10
@@ -33,6 +33,7 @@ struct GlobalVars {
|
||||
const char *zArgv0; /* Name of program */
|
||||
int bSchemaOnly; /* Only show schema differences */
|
||||
int bSchemaPK; /* Use the schema-defined PK, not the true PK */
|
||||
int bHandleVtab; /* Handle fts3, fts4, fts5 and rtree vtabs */
|
||||
unsigned fDebug; /* Debug flags */
|
||||
sqlite3 *db; /* The database connection */
|
||||
} g;
|
||||
@@ -683,7 +684,7 @@ static void diff_one_table(const char *zTab, FILE *out){
|
||||
|
||||
/* Run the query and output differences */
|
||||
if( !g.bSchemaOnly ){
|
||||
pStmt = db_prepare(sql.z);
|
||||
pStmt = db_prepare("%s", sql.z);
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
int iType = sqlite3_column_int(pStmt, nPk);
|
||||
if( iType==1 || iType==2 ){
|
||||
@@ -1460,7 +1461,7 @@ static void summarize_one_table(const char *zTab, FILE *out){
|
||||
}
|
||||
|
||||
/* Run the query and output difference summary */
|
||||
pStmt = db_prepare(sql.z);
|
||||
pStmt = db_prepare("%s", sql.z);
|
||||
nUpdate = 0;
|
||||
nInsert = 0;
|
||||
nDelete = 0;
|
||||
@@ -1735,6 +1736,144 @@ end_changeset_one_table:
|
||||
sqlite3_free(zId);
|
||||
}
|
||||
|
||||
/*
|
||||
** Extract the next SQL keyword or quoted string from buffer zIn and copy it
|
||||
** (or a prefix of it if it will not fit) into buffer zBuf, size nBuf bytes.
|
||||
** Return a pointer to the character within zIn immediately following
|
||||
** the token or quoted string just extracted.
|
||||
*/
|
||||
const char *gobble_token(const char *zIn, char *zBuf, int nBuf){
|
||||
const char *p = zIn;
|
||||
char *pOut = zBuf;
|
||||
char *pEnd = &pOut[nBuf-1];
|
||||
char q = 0; /* quote character, if any */
|
||||
|
||||
if( p==0 ) return 0;
|
||||
while( *p==' ' ) p++;
|
||||
switch( *p ){
|
||||
case '"': q = '"'; break;
|
||||
case '\'': q = '\''; break;
|
||||
case '`': q = '`'; break;
|
||||
case '[': q = ']'; break;
|
||||
}
|
||||
|
||||
if( q ){
|
||||
p++;
|
||||
while( *p && pOut<pEnd ){
|
||||
if( *p==q ){
|
||||
p++;
|
||||
if( *p!=q ) break;
|
||||
}
|
||||
if( pOut<pEnd ) *pOut++ = *p;
|
||||
p++;
|
||||
}
|
||||
}else{
|
||||
while( *p && *p!=' ' && *p!='(' ){
|
||||
if( pOut<pEnd ) *pOut++ = *p;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
*pOut = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is the implementation of SQL scalar function "module_name":
|
||||
**
|
||||
** module_name(SQL)
|
||||
**
|
||||
** The only argument should be an SQL statement of the type that may appear
|
||||
** in the sqlite_master table. If the statement is a "CREATE VIRTUAL TABLE"
|
||||
** statement, then the value returned is the name of the module that it
|
||||
** uses. Otherwise, if the statement is not a CVT, NULL is returned.
|
||||
*/
|
||||
static void module_name_func(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal, sqlite3_value **apVal
|
||||
){
|
||||
const char *zSql;
|
||||
char zToken[32];
|
||||
|
||||
assert( nVal==1 );
|
||||
zSql = (const char*)sqlite3_value_text(apVal[0]);
|
||||
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
if( zSql==0 || sqlite3_stricmp(zToken, "create") ) return;
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
if( zSql==0 || sqlite3_stricmp(zToken, "virtual") ) return;
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
if( zSql==0 || sqlite3_stricmp(zToken, "table") ) return;
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
if( zSql==0 ) return;
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
if( zSql==0 || sqlite3_stricmp(zToken, "using") ) return;
|
||||
zSql = gobble_token(zSql, zToken, sizeof(zToken));
|
||||
|
||||
sqlite3_result_text(pCtx, zToken, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the text of an SQL statement that itself returns the list of
|
||||
** tables to process within the database.
|
||||
*/
|
||||
const char *all_tables_sql(){
|
||||
if( g.bHandleVtab ){
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_exec(g.db,
|
||||
"CREATE TEMP TABLE tblmap(module, postfix);"
|
||||
"INSERT INTO temp.tblmap VALUES"
|
||||
"('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir'),"
|
||||
|
||||
"('fts4', '_content'), ('fts4', '_segments'), ('fts4', '_segdir'),"
|
||||
"('fts4', '_docsize'), ('fts4', '_stat'),"
|
||||
|
||||
"('fts5', '_data'), ('fts5', '_idx'), ('fts5', '_content'),"
|
||||
"('fts5', '_docsize'), ('fts5', '_config'),"
|
||||
|
||||
"('rtree', '_node'), ('rtree', '_rowid'), ('rtree', '_parent');"
|
||||
, 0, 0, 0
|
||||
);
|
||||
assert( rc==SQLITE_OK );
|
||||
|
||||
rc = sqlite3_create_function(
|
||||
g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0
|
||||
);
|
||||
assert( rc==SQLITE_OK );
|
||||
|
||||
return
|
||||
"SELECT name FROM main.sqlite_master\n"
|
||||
" WHERE type='table' AND (\n"
|
||||
" module_name(sql) IS NULL OR \n"
|
||||
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
|
||||
" ) AND name NOT IN (\n"
|
||||
" SELECT a.name || b.postfix \n"
|
||||
"FROM main.sqlite_master AS a, temp.tblmap AS b \n"
|
||||
"WHERE module_name(a.sql) = b.module\n"
|
||||
" )\n"
|
||||
"UNION \n"
|
||||
"SELECT name FROM aux.sqlite_master\n"
|
||||
" WHERE type='table' AND (\n"
|
||||
" module_name(sql) IS NULL OR \n"
|
||||
" module_name(sql) IN (SELECT module FROM temp.tblmap)\n"
|
||||
" ) AND name NOT IN (\n"
|
||||
" SELECT a.name || b.postfix \n"
|
||||
"FROM aux.sqlite_master AS a, temp.tblmap AS b \n"
|
||||
"WHERE module_name(a.sql) = b.module\n"
|
||||
" )\n"
|
||||
" ORDER BY name";
|
||||
}else{
|
||||
return
|
||||
"SELECT name FROM main.sqlite_master\n"
|
||||
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
|
||||
" UNION\n"
|
||||
"SELECT name FROM aux.sqlite_master\n"
|
||||
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
|
||||
" ORDER BY name";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Print sketchy documentation for this utility program
|
||||
*/
|
||||
@@ -1751,6 +1890,7 @@ static void showHelp(void){
|
||||
" --summary Show only a summary of the differences\n"
|
||||
" --table TAB Show only differences in table TAB\n"
|
||||
" --transaction Show SQL output inside a transaction\n"
|
||||
" --vtab Handle fts3, fts4, fts5 and rtree tables\n"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1821,6 +1961,9 @@ int main(int argc, char **argv){
|
||||
if( strcmp(z,"transaction")==0 ){
|
||||
useTransaction = 1;
|
||||
}else
|
||||
if( strcmp(z,"vtab")==0 ){
|
||||
g.bHandleVtab = 1;
|
||||
}else
|
||||
{
|
||||
cmdlineError("unknown option: %s", argv[i]);
|
||||
}
|
||||
@@ -1875,14 +2018,7 @@ int main(int argc, char **argv){
|
||||
xDiff(zTab, out);
|
||||
}else{
|
||||
/* Handle tables one by one */
|
||||
pStmt = db_prepare(
|
||||
"SELECT name FROM main.sqlite_master\n"
|
||||
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
|
||||
" UNION\n"
|
||||
"SELECT name FROM aux.sqlite_master\n"
|
||||
" WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n"
|
||||
" ORDER BY name"
|
||||
);
|
||||
pStmt = db_prepare("%s", all_tables_sql() );
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
xDiff((const char*)sqlite3_column_text(pStmt,0), out);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user