Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8814cc83c | |||
| 0fbee29700 |
+2
-7
@@ -1177,13 +1177,8 @@ LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h
|
||||
wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS)
|
||||
|
||||
speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
$(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS)
|
||||
|
||||
KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
|
||||
kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
|
||||
speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
|
||||
$(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
|
||||
|
||||
@@ -24,13 +24,6 @@ USE_AMALGAMATION = 1
|
||||
USE_FULLWARN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
# compiling.
|
||||
#
|
||||
!IFNDEF USE_FATAL_WARN
|
||||
USE_FATAL_WARN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable full runtime error checks (-RTC1, etc). This
|
||||
# has no effect if (any) optimizations are enabled.
|
||||
#
|
||||
@@ -500,12 +493,6 @@ TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS)
|
||||
TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS)
|
||||
!ENDIF
|
||||
|
||||
# Check if warnings should be treated as errors when compiling.
|
||||
#
|
||||
!IF $(USE_FATAL_WARN)!=0
|
||||
TCC = $(TCC) -WX
|
||||
!ENDIF
|
||||
|
||||
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src -fp:precise
|
||||
RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -I$(TOP)\src $(RCOPTS) $(RCCOPTS)
|
||||
|
||||
|
||||
@@ -24,13 +24,6 @@ TOP = .
|
||||
USE_FULLWARN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable treating warnings as errors (-WX, etc) when
|
||||
# compiling.
|
||||
#
|
||||
!IFNDEF USE_FATAL_WARN
|
||||
USE_FATAL_WARN = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to enable full runtime error checks (-RTC1, etc). This
|
||||
# has no effect if (any) optimizations are enabled.
|
||||
#
|
||||
@@ -461,12 +454,6 @@ TCC = $(CC) -nologo -W4 -DINCLUDE_MSVC_H=1 $(CCOPTS) $(TCCOPTS)
|
||||
TCC = $(CC) -nologo -W3 $(CCOPTS) $(TCCOPTS)
|
||||
!ENDIF
|
||||
|
||||
# Check if warnings should be treated as errors when compiling.
|
||||
#
|
||||
!IF $(USE_FATAL_WARN)!=0
|
||||
TCC = $(TCC) -WX
|
||||
!ENDIF
|
||||
|
||||
TCC = $(TCC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) -fp:precise
|
||||
RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
|
||||
|
||||
|
||||
+4
-4
@@ -1363,9 +1363,9 @@ static int fts3InitVtab(
|
||||
p->pTokenizer = pTokenizer;
|
||||
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
|
||||
p->bHasDocsize = (isFts4 && bNoDocsize==0);
|
||||
p->bHasStat = (u8)isFts4;
|
||||
p->bFts4 = (u8)isFts4;
|
||||
p->bDescIdx = (u8)bDescIdx;
|
||||
p->bHasStat = isFts4;
|
||||
p->bFts4 = isFts4;
|
||||
p->bDescIdx = bDescIdx;
|
||||
p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */
|
||||
p->zContentTbl = zContent;
|
||||
p->zLanguageid = zLanguageid;
|
||||
@@ -3422,7 +3422,7 @@ static int fts3SetHasStat(Fts3Table *p){
|
||||
if( rc==SQLITE_OK ){
|
||||
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
|
||||
rc = sqlite3_finalize(pStmt);
|
||||
if( rc==SQLITE_OK ) p->bHasStat = (u8)bHasStat;
|
||||
if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
|
||||
@@ -1601,7 +1601,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
|
||||
rc = fts5ParseStringFromToken(pToken, &z);
|
||||
if( rc==SQLITE_OK ){
|
||||
int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0);
|
||||
int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
|
||||
int n;
|
||||
sqlite3Fts5Dequote(z);
|
||||
n = (int)strlen(z);
|
||||
|
||||
@@ -152,7 +152,7 @@ foreach {tn expr res} {
|
||||
1 {abc} {"abc"}
|
||||
2 {one} {"one"|"i"|"1"}
|
||||
3 {3} {"3"|"iii"|"three"}
|
||||
4 {3*} {"3" *}
|
||||
4 {3*} {"3"|"iii"|"three" *}
|
||||
} {
|
||||
do_execsql_test 4.1.$tn {
|
||||
SELECT fts5_expr($expr, 'tokenize=tclnum')
|
||||
|
||||
@@ -262,44 +262,5 @@ do_execsql_test 8.3 {
|
||||
brown dog fox jump lazi over quick the
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the FTS5_TOKENIZE_PREFIX flag is passed to the tokenizer
|
||||
# implementation.
|
||||
#
|
||||
reset_db
|
||||
proc tcl_create {args} { return "tcl_tokenize" }
|
||||
sqlite3_fts5_create_tokenizer db tcl tcl_create
|
||||
set ::flags [list]
|
||||
proc tcl_tokenize {tflags text} {
|
||||
lappend ::flags $tflags
|
||||
foreach {w iStart iEnd} [fts5_tokenize_split $text] {
|
||||
sqlite3_fts5_token $w $iStart $iEnd
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 9.1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=tcl);
|
||||
INSERT INTO t1 VALUES('abc');
|
||||
INSERT INTO t1 VALUES('xyz');
|
||||
} {}
|
||||
do_test 9.1.2 { set ::flags } {document document}
|
||||
|
||||
set ::flags [list]
|
||||
do_execsql_test 9.2.1 { SELECT * FROM t1('abc'); } {abc}
|
||||
do_test 9.2.2 { set ::flags } {query}
|
||||
|
||||
set ::flags [list]
|
||||
do_execsql_test 9.3.1 { SELECT * FROM t1('ab*'); } {abc}
|
||||
do_test 9.3.2 { set ::flags } {prefixquery}
|
||||
|
||||
set ::flags [list]
|
||||
do_execsql_test 9.4.1 { SELECT * FROM t1('"abc xyz" *'); } {}
|
||||
do_test 9.4.2 { set ::flags } {prefixquery}
|
||||
|
||||
set ::flags [list]
|
||||
do_execsql_test 9.5.1 { SELECT * FROM t1('"abc xyz*"'); } {}
|
||||
do_test 9.5.2 { set ::flags } {query}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+23
-21
@@ -493,36 +493,38 @@ static void icuLoadCollation(
|
||||
** Register the ICU extension functions with database db.
|
||||
*/
|
||||
int sqlite3IcuInit(sqlite3 *db){
|
||||
static const struct IcuScalar {
|
||||
struct IcuScalar {
|
||||
const char *zName; /* Function name */
|
||||
unsigned char nArg; /* Number of arguments */
|
||||
unsigned short enc; /* Optimal text encoding */
|
||||
unsigned char iContext; /* sqlite3_user_data() context */
|
||||
int nArg; /* Number of arguments */
|
||||
int enc; /* Optimal text encoding */
|
||||
void *pContext; /* sqlite3_user_data() context */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
|
||||
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
|
||||
|
||||
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
|
||||
|
||||
{"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
|
||||
|
||||
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
|
||||
{"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation},
|
||||
};
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
|
||||
|
||||
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
|
||||
const struct IcuScalar *p = &scalars[i];
|
||||
struct IcuScalar *p = &scalars[i];
|
||||
rc = sqlite3_create_function(
|
||||
db, p->zName, p->nArg, p->enc,
|
||||
p->iContext ? (void*)db : (void*)0,
|
||||
p->xFunc, 0, 0
|
||||
db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
** how JSONB might improve on that.)
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
|
||||
#if !defined(SQLITEINT_H)
|
||||
#if !defined(_SQLITEINT_H_)
|
||||
#include "sqlite3ext.h"
|
||||
#endif
|
||||
SQLITE_EXTENSION_INIT1
|
||||
|
||||
-407
@@ -1,407 +0,0 @@
|
||||
/*
|
||||
** 2017-01-27
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements a functions that compute SHA1 hashes.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha1(X)
|
||||
** sha1_query(Y)
|
||||
**
|
||||
** The sha1(X) function computes the SHA1 hash of the input X, or NULL if
|
||||
** X is NULL.
|
||||
**
|
||||
** The sha1_query(Y) function evalutes all queries in the SQL statements of Y
|
||||
** and returns a hash of their results.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/******************************************************************************
|
||||
** The Hash Engine
|
||||
*/
|
||||
/* Context for the SHA1 hash */
|
||||
typedef struct SHA1Context SHA1Context;
|
||||
struct SHA1Context {
|
||||
unsigned int state[5];
|
||||
unsigned int count[2];
|
||||
unsigned char buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
|
||||
#define rol(x,k) SHA_ROT(x,k,32-(k))
|
||||
#define ror(x,k) SHA_ROT(x,32-(k),k)
|
||||
#endif
|
||||
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#define blk0be(i) block[i]
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
|
||||
/*
|
||||
* (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
|
||||
*
|
||||
* Rl0() for little-endian and Rb0() for big-endian. Endianness is
|
||||
* determined at run-time.
|
||||
*/
|
||||
#define Rl0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define Rb0(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R1(v,w,x,y,z,i) \
|
||||
z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=ror(w,2);
|
||||
#define R2(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=ror(w,2);
|
||||
#define R3(v,w,x,y,z,i) \
|
||||
z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2);
|
||||
#define R4(v,w,x,y,z,i) \
|
||||
z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2);
|
||||
|
||||
/*
|
||||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){
|
||||
unsigned int qq[5]; /* a, b, c, d, e; */
|
||||
static int one = 1;
|
||||
unsigned int block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
memcpy(qq,state,5*sizeof(unsigned int));
|
||||
|
||||
#define a qq[0]
|
||||
#define b qq[1]
|
||||
#define c qq[2]
|
||||
#define d qq[3]
|
||||
#define e qq[4]
|
||||
|
||||
/* Copy p->state[] to working vars */
|
||||
/*
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
*/
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
if( 1 == *(unsigned char*)&one ){
|
||||
Rl0(a,b,c,d,e, 0); Rl0(e,a,b,c,d, 1); Rl0(d,e,a,b,c, 2); Rl0(c,d,e,a,b, 3);
|
||||
Rl0(b,c,d,e,a, 4); Rl0(a,b,c,d,e, 5); Rl0(e,a,b,c,d, 6); Rl0(d,e,a,b,c, 7);
|
||||
Rl0(c,d,e,a,b, 8); Rl0(b,c,d,e,a, 9); Rl0(a,b,c,d,e,10); Rl0(e,a,b,c,d,11);
|
||||
Rl0(d,e,a,b,c,12); Rl0(c,d,e,a,b,13); Rl0(b,c,d,e,a,14); Rl0(a,b,c,d,e,15);
|
||||
}else{
|
||||
Rb0(a,b,c,d,e, 0); Rb0(e,a,b,c,d, 1); Rb0(d,e,a,b,c, 2); Rb0(c,d,e,a,b, 3);
|
||||
Rb0(b,c,d,e,a, 4); Rb0(a,b,c,d,e, 5); Rb0(e,a,b,c,d, 6); Rb0(d,e,a,b,c, 7);
|
||||
Rb0(c,d,e,a,b, 8); Rb0(b,c,d,e,a, 9); Rb0(a,b,c,d,e,10); Rb0(e,a,b,c,d,11);
|
||||
Rb0(d,e,a,b,c,12); Rb0(c,d,e,a,b,13); Rb0(b,c,d,e,a,14); Rb0(a,b,c,d,e,15);
|
||||
}
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
#undef a
|
||||
#undef b
|
||||
#undef c
|
||||
#undef d
|
||||
#undef e
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a SHA1 context */
|
||||
static void hash_init(SHA1Context *p){
|
||||
/* SHA1 initialization constants */
|
||||
p->state[0] = 0x67452301;
|
||||
p->state[1] = 0xEFCDAB89;
|
||||
p->state[2] = 0x98BADCFE;
|
||||
p->state[3] = 0x10325476;
|
||||
p->state[4] = 0xC3D2E1F0;
|
||||
p->count[0] = p->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Add new content to the SHA1 hash */
|
||||
static void hash_step(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const unsigned char *data, /* Data to be added */
|
||||
unsigned int len /* Number of bytes in data */
|
||||
){
|
||||
unsigned int i, j;
|
||||
|
||||
j = p->count[0];
|
||||
if( (p->count[0] += len << 3) < j ){
|
||||
p->count[1] += (len>>29)+1;
|
||||
}
|
||||
j = (j >> 3) & 63;
|
||||
if( (j + len) > 63 ){
|
||||
(void)memcpy(&p->buffer[j], data, (i = 64-j));
|
||||
SHA1Transform(p->state, p->buffer);
|
||||
for(; i + 63 < len; i += 64){
|
||||
SHA1Transform(p->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}else{
|
||||
i = 0;
|
||||
}
|
||||
(void)memcpy(&p->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
/* Compute a string using sqlite3_vsnprintf() and hash it */
|
||||
static void hash_step_vformat(
|
||||
SHA1Context *p, /* Add content to this context */
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
int n;
|
||||
char zBuf[50];
|
||||
va_start(ap, zFormat);
|
||||
sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zBuf);
|
||||
hash_step(p, (unsigned char*)zBuf, n);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and compute the message digest. Render the
|
||||
** message digest as lower-case hexadecimal and put it into
|
||||
** zOut[]. zOut[] must be at least 41 bytes long. */
|
||||
static void hash_finish(
|
||||
SHA1Context *p, /* The SHA1 context to finish and render */
|
||||
char *zOut /* Store hexadecimal hash here */
|
||||
){
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
unsigned char digest[20];
|
||||
static const char zEncode[] = "0123456789abcdef";
|
||||
|
||||
for (i = 0; i < 8; i++){
|
||||
finalcount[i] = (unsigned char)((p->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
hash_step(p, (const unsigned char *)"\200", 1);
|
||||
while ((p->count[0] & 504) != 448){
|
||||
hash_step(p, (const unsigned char *)"\0", 1);
|
||||
}
|
||||
hash_step(p, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
for (i = 0; i < 20; i++){
|
||||
digest[i] = (unsigned char)((p->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
for(i=0; i<20; i++){
|
||||
zOut[i*2] = zEncode[(digest[i]>>4)&0xf];
|
||||
zOut[i*2+1] = zEncode[digest[i] & 0xf];
|
||||
}
|
||||
zOut[i*2]= 0;
|
||||
}
|
||||
/* End of the hashing logic
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
** Implementation of the sha1(X) function.
|
||||
**
|
||||
** Return a lower-case hexadecimal rendering of the SHA1 hash of the
|
||||
** argument X. If X is a BLOB, it is hashed as is. For all other
|
||||
** types of input, X is converted into a UTF-8 string and the string
|
||||
** is hash without the trailing 0x00 terminator. The hash of a NULL
|
||||
** value is NULL.
|
||||
*/
|
||||
static void sha1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
SHA1Context cx;
|
||||
int eType = sqlite3_value_type(argv[0]);
|
||||
int nByte = sqlite3_value_bytes(argv[0]);
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( eType==SQLITE_NULL ) return;
|
||||
hash_init(&cx);
|
||||
if( eType==SQLITE_BLOB ){
|
||||
hash_step(&cx, sqlite3_value_blob(argv[0]), nByte);
|
||||
}else{
|
||||
hash_step(&cx, sqlite3_value_text(argv[0]), nByte);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sha1_query(SQL) function.
|
||||
**
|
||||
** This function compiles and runs the SQL statement(s) given in the
|
||||
** argument. The results are hashed using SHA1 and that hash is returned.
|
||||
**
|
||||
** The original SQL text is included as part of the hash.
|
||||
**
|
||||
** The hash is not just a concatenation of the outputs. Each query
|
||||
** is delimited and each row and value within the query is delimited,
|
||||
** with all values being marked with their datatypes.
|
||||
*/
|
||||
static void sha1QueryFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int nCol; /* Number of columns in the result set */
|
||||
int i; /* Loop counter */
|
||||
int rc;
|
||||
int n;
|
||||
const char *z;
|
||||
SHA1Context cx;
|
||||
char zOut[44];
|
||||
|
||||
assert( argc==1 );
|
||||
if( zSql==0 ) return;
|
||||
hash_init(&cx);
|
||||
while( zSql[0] ){
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
|
||||
if( rc ){
|
||||
char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
|
||||
zSql, sqlite3_errmsg(db));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
if( !sqlite3_stmt_readonly(pStmt) ){
|
||||
char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_result_error(context, zMsg, -1);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
z = sqlite3_sql(pStmt);
|
||||
n = (int)strlen(z);
|
||||
hash_step_vformat(&cx,"S%d:",n);
|
||||
hash_step(&cx,(unsigned char*)z,n);
|
||||
|
||||
/* Compute a hash over the result of the query */
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
hash_step(&cx,(const unsigned char*)"R",1);
|
||||
for(i=0; i<nCol; i++){
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL: {
|
||||
hash_step(&cx, (const unsigned char*)"N",1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
|
||||
memcpy(&u, &v, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'I';
|
||||
hash_step(&cx, x, 9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_uint64 u;
|
||||
int j;
|
||||
unsigned char x[9];
|
||||
double r = sqlite3_column_double(pStmt,i);
|
||||
memcpy(&u, &r, 8);
|
||||
for(j=8; j>=1; j--){
|
||||
x[j] = u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
x[0] = 'F';
|
||||
hash_step(&cx,x,9);
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_text(pStmt, i);
|
||||
hash_step_vformat(&cx,"T%d:",n2);
|
||||
hash_step(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n2 = sqlite3_column_bytes(pStmt, i);
|
||||
const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
|
||||
hash_step_vformat(&cx,"B%d:",n2);
|
||||
hash_step(&cx, z2, n2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
hash_finish(&cx, zOut);
|
||||
sqlite3_result_text(context, zOut, 40, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_sha_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+85
-319
@@ -116,16 +116,13 @@ struct Rtree {
|
||||
sqlite3 *db; /* Host database connection */
|
||||
int iNodeSize; /* Size in bytes of each node in the node table */
|
||||
u8 nDim; /* Number of dimensions */
|
||||
u8 nDim2; /* Twice the number of dimensions */
|
||||
u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
|
||||
u8 nBytesPerCell; /* Bytes consumed per cell */
|
||||
u8 inWrTrans; /* True if inside write transaction */
|
||||
int iDepth; /* Current depth of the r-tree structure */
|
||||
char *zDb; /* Name of database containing r-tree table */
|
||||
char *zName; /* Name of r-tree table */
|
||||
u32 nBusy; /* Current number of users of this structure */
|
||||
int nBusy; /* Current number of users of this structure */
|
||||
i64 nRowEst; /* Estimated number of rows in this table */
|
||||
u32 nCursor; /* Number of open cursors */
|
||||
|
||||
/* List of nodes removed during a CondenseTree operation. List is
|
||||
** linked together via the pointer normally used for hash chains -
|
||||
@@ -135,10 +132,8 @@ struct Rtree {
|
||||
RtreeNode *pDeleted;
|
||||
int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
|
||||
|
||||
/* Blob I/O on xxx_node */
|
||||
sqlite3_blob *pNodeBlob;
|
||||
|
||||
/* Statements to read/write/delete a record from xxx_node */
|
||||
sqlite3_stmt *pReadNode;
|
||||
sqlite3_stmt *pWriteNode;
|
||||
sqlite3_stmt *pDeleteNode;
|
||||
|
||||
@@ -367,65 +362,6 @@ struct RtreeMatchArg {
|
||||
# define MIN(x,y) ((x) > (y) ? (y) : (x))
|
||||
#endif
|
||||
|
||||
/* What version of GCC is being used. 0 means GCC is not being used */
|
||||
#ifndef GCC_VERSION
|
||||
#ifdef __GNUC__
|
||||
# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
# define GCC_VERSION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* What version of CLANG is being used. 0 means CLANG is not being used */
|
||||
#ifndef CLANG_VERSION
|
||||
#if defined(__clang__) && !defined(_WIN32)
|
||||
# define CLANG_VERSION \
|
||||
(__clang_major__*1000000+__clang_minor__*1000+__clang_patchlevel__)
|
||||
#else
|
||||
# define CLANG_VERSION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The testcase() macro should already be defined in the amalgamation. If
|
||||
** it is not, make it a no-op.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# define testcase(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros to determine whether the machine is big or little endian,
|
||||
** and whether or not that determination is run-time or compile-time.
|
||||
**
|
||||
** For best performance, an attempt is made to guess at the byte-order
|
||||
** using C-preprocessor macros. If that is unsuccessful, or if
|
||||
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
|
||||
** at run-time.
|
||||
*/
|
||||
#ifndef SQLITE_BYTEORDER
|
||||
#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
|
||||
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
|
||||
defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 1234
|
||||
#endif
|
||||
#if (defined(sparc) || defined(__ppc__)) \
|
||||
&& !defined(SQLITE_RUNTIME_BYTEORDER)
|
||||
# define SQLITE_BYTEORDER 4321
|
||||
#endif
|
||||
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
|
||||
#endif
|
||||
|
||||
|
||||
/* What version of MSVC is being used. 0 means MSVC is not being used */
|
||||
#ifndef MSVC_VERSION
|
||||
#if defined(_MSC_VER)
|
||||
# define MSVC_VERSION _MSC_VER
|
||||
#else
|
||||
# define MSVC_VERSION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Functions to deserialize a 16 bit integer, 32 bit real number and
|
||||
** 64 bit integer. The deserialized value is returned.
|
||||
@@ -434,43 +370,14 @@ static int readInt16(u8 *p){
|
||||
return (p[0]<<8) + p[1];
|
||||
}
|
||||
static void readCoord(u8 *p, RtreeCoord *pCoord){
|
||||
assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
||||
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
pCoord->u = _byteswap_ulong(*(u32*)p);
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
pCoord->u = __builtin_bswap32(*(u32*)p);
|
||||
#elif SQLITE_BYTEORDER==1234
|
||||
pCoord->u = ((pCoord->u>>24)&0xff)|((pCoord->u>>8)&0xff00)|
|
||||
((pCoord->u&0xff)<<24)|((pCoord->u&0xff00)<<8);
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
pCoord->u = *(u32*)p;
|
||||
#else
|
||||
pCoord->u = (
|
||||
(((u32)p[0]) << 24) +
|
||||
(((u32)p[1]) << 16) +
|
||||
(((u32)p[2]) << 8) +
|
||||
(((u32)p[3]) << 0)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
static i64 readInt64(u8 *p){
|
||||
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
u64 x;
|
||||
testcase( ((((char*)p) - (char*)0)&7)!=0 ); /* not always 8-byte aligned */
|
||||
memcpy(&x, p, 8);
|
||||
return (i64)_byteswap_uint64(x);
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
u64 x;
|
||||
testcase( ((((char*)p) - (char*)0)&7)!=0 ); /* not always 8-byte aligned */
|
||||
memcpy(&x, p, 8);
|
||||
return (i64)__builtin_bswap64(x);
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
i64 x;
|
||||
testcase( ((((char*)p) - (char*)0)&7)!=0 ); /* not always 8-byte aligned */
|
||||
memcpy(&x, p, 8);
|
||||
return x;
|
||||
#else
|
||||
testcase( ((((char*)p) - (char*)0)&7)!=0 ); /* not always 8-byte aligned */
|
||||
return (
|
||||
(((i64)p[0]) << 56) +
|
||||
(((i64)p[1]) << 48) +
|
||||
@@ -481,7 +388,6 @@ static i64 readInt64(u8 *p){
|
||||
(((i64)p[6]) << 8) +
|
||||
(((i64)p[7]) << 0)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -496,38 +402,16 @@ static int writeInt16(u8 *p, int i){
|
||||
}
|
||||
static int writeCoord(u8 *p, RtreeCoord *pCoord){
|
||||
u32 i;
|
||||
assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
||||
assert( sizeof(RtreeCoord)==4 );
|
||||
assert( sizeof(u32)==4 );
|
||||
#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
i = __builtin_bswap32(pCoord->u);
|
||||
memcpy(p, &i, 4);
|
||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
i = _byteswap_ulong(pCoord->u);
|
||||
memcpy(p, &i, 4);
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
i = pCoord->u;
|
||||
memcpy(p, &i, 4);
|
||||
#else
|
||||
i = pCoord->u;
|
||||
p[0] = (i>>24)&0xFF;
|
||||
p[1] = (i>>16)&0xFF;
|
||||
p[2] = (i>> 8)&0xFF;
|
||||
p[3] = (i>> 0)&0xFF;
|
||||
#endif
|
||||
return 4;
|
||||
}
|
||||
static int writeInt64(u8 *p, i64 i){
|
||||
testcase( ((((char*)p) - (char*)0)&7)!=0 ); /* Not always 8-byte aligned */
|
||||
#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
i = (i64)__builtin_bswap64((u64)i);
|
||||
memcpy(p, &i, 8);
|
||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
i = (i64)_byteswap_uint64((u64)i);
|
||||
memcpy(p, &i, 8);
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
memcpy(p, &i, 8);
|
||||
#else
|
||||
p[0] = (i>>56)&0xFF;
|
||||
p[1] = (i>>48)&0xFF;
|
||||
p[2] = (i>>40)&0xFF;
|
||||
@@ -536,7 +420,6 @@ static int writeInt64(u8 *p, i64 i){
|
||||
p[5] = (i>>16)&0xFF;
|
||||
p[6] = (i>> 8)&0xFF;
|
||||
p[7] = (i>> 0)&0xFF;
|
||||
#endif
|
||||
return 8;
|
||||
}
|
||||
|
||||
@@ -619,17 +502,6 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
|
||||
return pNode;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the Rtree.pNodeBlob object
|
||||
*/
|
||||
static void nodeBlobReset(Rtree *pRtree){
|
||||
if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
|
||||
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
||||
pRtree->pNodeBlob = 0;
|
||||
sqlite3_blob_close(pBlob);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Obtain a reference to an r-tree node.
|
||||
*/
|
||||
@@ -639,8 +511,9 @@ static int nodeAcquire(
|
||||
RtreeNode *pParent, /* Either the parent node or NULL */
|
||||
RtreeNode **ppNode /* OUT: Acquired node */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
RtreeNode *pNode = 0;
|
||||
int rc;
|
||||
int rc2 = SQLITE_OK;
|
||||
RtreeNode *pNode;
|
||||
|
||||
/* Check if the requested node is already in the hash table. If so,
|
||||
** increase its reference count and return it.
|
||||
@@ -656,45 +529,28 @@ static int nodeAcquire(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( pRtree->pNodeBlob ){
|
||||
sqlite3_blob *pBlob = pRtree->pNodeBlob;
|
||||
pRtree->pNodeBlob = 0;
|
||||
rc = sqlite3_blob_reopen(pBlob, iNode);
|
||||
pRtree->pNodeBlob = pBlob;
|
||||
if( rc ){
|
||||
nodeBlobReset(pRtree);
|
||||
if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
if( pRtree->pNodeBlob==0 ){
|
||||
char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
|
||||
if( zTab==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
|
||||
&pRtree->pNodeBlob);
|
||||
sqlite3_free(zTab);
|
||||
}
|
||||
if( rc ){
|
||||
nodeBlobReset(pRtree);
|
||||
*ppNode = 0;
|
||||
/* If unable to open an sqlite3_blob on the desired row, that can only
|
||||
** be because the shadow tables hold erroneous data. */
|
||||
if( rc==SQLITE_ERROR ) rc = SQLITE_CORRUPT_VTAB;
|
||||
}else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
|
||||
pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
|
||||
if( !pNode ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pNode->pParent = pParent;
|
||||
pNode->zData = (u8 *)&pNode[1];
|
||||
pNode->nRef = 1;
|
||||
pNode->iNode = iNode;
|
||||
pNode->isDirty = 0;
|
||||
pNode->pNext = 0;
|
||||
rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
|
||||
pRtree->iNodeSize, 0);
|
||||
nodeReference(pParent);
|
||||
sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
|
||||
rc = sqlite3_step(pRtree->pReadNode);
|
||||
if( rc==SQLITE_ROW ){
|
||||
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
|
||||
if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
|
||||
pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
|
||||
if( !pNode ){
|
||||
rc2 = SQLITE_NOMEM;
|
||||
}else{
|
||||
pNode->pParent = pParent;
|
||||
pNode->zData = (u8 *)&pNode[1];
|
||||
pNode->nRef = 1;
|
||||
pNode->iNode = iNode;
|
||||
pNode->isDirty = 0;
|
||||
pNode->pNext = 0;
|
||||
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
|
||||
nodeReference(pParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3_reset(pRtree->pReadNode);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
|
||||
/* If the root node was just loaded, set pRtree->iDepth to the height
|
||||
** of the r-tree structure. A height of zero means all data is stored on
|
||||
@@ -746,7 +602,7 @@ static void nodeOverwriteCell(
|
||||
int ii;
|
||||
u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
|
||||
p += writeInt64(p, pCell->iRowid);
|
||||
for(ii=0; ii<pRtree->nDim2; ii++){
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii++){
|
||||
p += writeCoord(p, &pCell->aCoord[ii]);
|
||||
}
|
||||
pNode->isDirty = 1;
|
||||
@@ -880,16 +736,13 @@ static void nodeGetCell(
|
||||
){
|
||||
u8 *pData;
|
||||
RtreeCoord *pCoord;
|
||||
int ii = 0;
|
||||
int ii;
|
||||
pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
|
||||
pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
|
||||
pCoord = pCell->aCoord;
|
||||
do{
|
||||
readCoord(pData, &pCoord[ii]);
|
||||
readCoord(pData+4, &pCoord[ii+1]);
|
||||
pData += 8;
|
||||
ii += 2;
|
||||
}while( ii<pRtree->nDim2 );
|
||||
for(ii=0; ii<pRtree->nDim*2; ii++){
|
||||
readCoord(&pData[ii*4], &pCoord[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -940,9 +793,7 @@ static void rtreeReference(Rtree *pRtree){
|
||||
static void rtreeRelease(Rtree *pRtree){
|
||||
pRtree->nBusy--;
|
||||
if( pRtree->nBusy==0 ){
|
||||
pRtree->inWrTrans = 0;
|
||||
pRtree->nCursor = 0;
|
||||
nodeBlobReset(pRtree);
|
||||
sqlite3_finalize(pRtree->pReadNode);
|
||||
sqlite3_finalize(pRtree->pWriteNode);
|
||||
sqlite3_finalize(pRtree->pDeleteNode);
|
||||
sqlite3_finalize(pRtree->pReadRowid);
|
||||
@@ -980,7 +831,6 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
||||
if( !zCreate ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
nodeBlobReset(pRtree);
|
||||
rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0);
|
||||
sqlite3_free(zCreate);
|
||||
}
|
||||
@@ -996,7 +846,6 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
||||
*/
|
||||
static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
int rc = SQLITE_NOMEM;
|
||||
Rtree *pRtree = (Rtree *)pVTab;
|
||||
RtreeCursor *pCsr;
|
||||
|
||||
pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
|
||||
@@ -1004,7 +853,6 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
memset(pCsr, 0, sizeof(RtreeCursor));
|
||||
pCsr->base.pVtab = pVTab;
|
||||
rc = SQLITE_OK;
|
||||
pRtree->nCursor++;
|
||||
}
|
||||
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
|
||||
|
||||
@@ -1037,13 +885,10 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
|
||||
Rtree *pRtree = (Rtree *)(cur->pVtab);
|
||||
int ii;
|
||||
RtreeCursor *pCsr = (RtreeCursor *)cur;
|
||||
assert( pRtree->nCursor>0 );
|
||||
freeCursorConstraints(pCsr);
|
||||
sqlite3_free(pCsr->aPoint);
|
||||
for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
|
||||
sqlite3_free(pCsr);
|
||||
pRtree->nCursor--;
|
||||
nodeBlobReset(pRtree);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1066,22 +911,15 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
|
||||
** false. a[] is the four bytes of the on-disk record to be decoded.
|
||||
** Store the results in "r".
|
||||
**
|
||||
** There are five versions of this macro. The last one is generic. The
|
||||
** other four are various architectures-specific optimizations.
|
||||
** There are three versions of this macro, one each for little-endian and
|
||||
** big-endian processors and a third generic implementation. The endian-
|
||||
** specific implementations are much faster and are preferred if the
|
||||
** processor endianness is known at compile-time. The SQLITE_BYTEORDER
|
||||
** macro is part of sqliteInt.h and hence the endian-specific
|
||||
** implementation will only be used if this module is compiled as part
|
||||
** of the amalgamation.
|
||||
*/
|
||||
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
#define RTREE_DECODE_COORD(eInt, a, r) { \
|
||||
RtreeCoord c; /* Coordinate decoded */ \
|
||||
c.u = _byteswap_ulong(*(u32*)a); \
|
||||
r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
|
||||
}
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#define RTREE_DECODE_COORD(eInt, a, r) { \
|
||||
RtreeCoord c; /* Coordinate decoded */ \
|
||||
c.u = __builtin_bswap32(*(u32*)a); \
|
||||
r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
|
||||
}
|
||||
#elif SQLITE_BYTEORDER==1234
|
||||
#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234
|
||||
#define RTREE_DECODE_COORD(eInt, a, r) { \
|
||||
RtreeCoord c; /* Coordinate decoded */ \
|
||||
memcpy(&c.u,a,4); \
|
||||
@@ -1089,7 +927,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
|
||||
((c.u&0xff)<<24)|((c.u&0xff00)<<8); \
|
||||
r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
|
||||
}
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321
|
||||
#define RTREE_DECODE_COORD(eInt, a, r) { \
|
||||
RtreeCoord c; /* Coordinate decoded */ \
|
||||
memcpy(&c.u,a,4); \
|
||||
@@ -1116,10 +954,10 @@ static int rtreeCallbackConstraint(
|
||||
sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */
|
||||
int *peWithin /* OUT: visibility of the cell */
|
||||
){
|
||||
int i; /* Loop counter */
|
||||
sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */
|
||||
int nCoord = pInfo->nCoord; /* No. of coordinates */
|
||||
int rc; /* Callback return code */
|
||||
RtreeCoord c; /* Translator union */
|
||||
sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */
|
||||
|
||||
assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY );
|
||||
@@ -1129,41 +967,13 @@ static int rtreeCallbackConstraint(
|
||||
pInfo->iRowid = readInt64(pCellData);
|
||||
}
|
||||
pCellData += 8;
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( eInt==0 ){
|
||||
switch( nCoord ){
|
||||
case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f;
|
||||
readCoord(pCellData+32, &c); aCoord[8] = c.f;
|
||||
case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f;
|
||||
readCoord(pCellData+24, &c); aCoord[6] = c.f;
|
||||
case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f;
|
||||
readCoord(pCellData+16, &c); aCoord[4] = c.f;
|
||||
case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f;
|
||||
readCoord(pCellData+8, &c); aCoord[2] = c.f;
|
||||
default: readCoord(pCellData+4, &c); aCoord[1] = c.f;
|
||||
readCoord(pCellData, &c); aCoord[0] = c.f;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
switch( nCoord ){
|
||||
case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i;
|
||||
readCoord(pCellData+32, &c); aCoord[8] = c.i;
|
||||
case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i;
|
||||
readCoord(pCellData+24, &c); aCoord[6] = c.i;
|
||||
case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i;
|
||||
readCoord(pCellData+16, &c); aCoord[4] = c.i;
|
||||
case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i;
|
||||
readCoord(pCellData+8, &c); aCoord[2] = c.i;
|
||||
default: readCoord(pCellData+4, &c); aCoord[1] = c.i;
|
||||
readCoord(pCellData, &c); aCoord[0] = c.i;
|
||||
}
|
||||
for(i=0; i<nCoord; i++, pCellData += 4){
|
||||
RTREE_DECODE_COORD(eInt, pCellData, aCoord[i]);
|
||||
}
|
||||
if( pConstraint->op==RTREE_MATCH ){
|
||||
int eWithin = 0;
|
||||
rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo,
|
||||
nCoord, aCoord, &eWithin);
|
||||
if( eWithin==0 ) *peWithin = NOT_WITHIN;
|
||||
nCoord, aCoord, &i);
|
||||
if( i==0 ) *peWithin = NOT_WITHIN;
|
||||
*prScore = RTREE_ZERO;
|
||||
}else{
|
||||
pInfo->aCoord = aCoord;
|
||||
@@ -1199,7 +1009,6 @@ static void rtreeNonleafConstraint(
|
||||
|
||||
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ );
|
||||
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
||||
switch( p->op ){
|
||||
case RTREE_LE:
|
||||
case RTREE_LT:
|
||||
@@ -1240,7 +1049,6 @@ static void rtreeLeafConstraint(
|
||||
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ );
|
||||
pCellData += 8 + p->iCoord*4;
|
||||
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
||||
RTREE_DECODE_COORD(eInt, pCellData, xN);
|
||||
switch( p->op ){
|
||||
case RTREE_LE: if( xN <= p->u.rValue ) return; break;
|
||||
@@ -1557,7 +1365,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
|
||||
if( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
|
||||
p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
p->eWithin = (u8)eWithin;
|
||||
p->eWithin = eWithin;
|
||||
p->id = x.id;
|
||||
p->iCell = x.iCell;
|
||||
RTREE_QUEUE_TRACE(pCur, "PUSH-S:");
|
||||
@@ -1745,7 +1553,7 @@ static int rtreeFilter(
|
||||
p->id = iNode;
|
||||
p->eWithin = PARTLY_WITHIN;
|
||||
rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
|
||||
p->iCell = (u8)iCell;
|
||||
p->iCell = iCell;
|
||||
RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
|
||||
}else{
|
||||
pCsr->atEOF = 1;
|
||||
@@ -1778,7 +1586,7 @@ static int rtreeFilter(
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
}
|
||||
p->pInfo->nCoord = pRtree->nDim2;
|
||||
p->pInfo->nCoord = pRtree->nDim*2;
|
||||
p->pInfo->anQueue = pCsr->anQueue;
|
||||
p->pInfo->mxLevel = pRtree->iDepth + 1;
|
||||
}else{
|
||||
@@ -1793,7 +1601,7 @@ static int rtreeFilter(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
RtreeSearchPoint *pNew;
|
||||
pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
|
||||
pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1);
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
pNew->id = 1;
|
||||
pNew->iCell = 0;
|
||||
@@ -1921,7 +1729,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
break;
|
||||
}
|
||||
zIdxStr[iIdx++] = op;
|
||||
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
|
||||
zIdxStr[iIdx++] = p->iColumn - 1 + '0';
|
||||
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
|
||||
pIdxInfo->aConstraintUsage[ii].omit = 1;
|
||||
}
|
||||
@@ -1945,26 +1753,9 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
*/
|
||||
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
|
||||
RtreeDValue area = (RtreeDValue)1;
|
||||
assert( pRtree->nDim>=1 && pRtree->nDim<=5 );
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
switch( pRtree->nDim ){
|
||||
case 5: area = p->aCoord[9].f - p->aCoord[8].f;
|
||||
case 4: area *= p->aCoord[7].f - p->aCoord[6].f;
|
||||
case 3: area *= p->aCoord[5].f - p->aCoord[4].f;
|
||||
case 2: area *= p->aCoord[3].f - p->aCoord[2].f;
|
||||
default: area *= p->aCoord[1].f - p->aCoord[0].f;
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
switch( pRtree->nDim ){
|
||||
case 5: area = p->aCoord[9].i - p->aCoord[8].i;
|
||||
case 4: area *= p->aCoord[7].i - p->aCoord[6].i;
|
||||
case 3: area *= p->aCoord[5].i - p->aCoord[4].i;
|
||||
case 2: area *= p->aCoord[3].i - p->aCoord[2].i;
|
||||
default: area *= p->aCoord[1].i - p->aCoord[0].i;
|
||||
}
|
||||
int ii;
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
|
||||
}
|
||||
return area;
|
||||
}
|
||||
@@ -1974,10 +1765,9 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
|
||||
** of the objects size in each dimension.
|
||||
*/
|
||||
static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
|
||||
RtreeDValue margin;
|
||||
RtreeDValue margin = (RtreeDValue)0;
|
||||
int ii;
|
||||
margin = DCOORD(p->aCoord[1]) - DCOORD(p->aCoord[0]);
|
||||
for(ii=2; ii<pRtree->nDim2; ii+=2){
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
|
||||
}
|
||||
return margin;
|
||||
@@ -1987,19 +1777,17 @@ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
|
||||
** Store the union of cells p1 and p2 in p1.
|
||||
*/
|
||||
static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
|
||||
int ii = 0;
|
||||
int ii;
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
do{
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f);
|
||||
p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f);
|
||||
ii += 2;
|
||||
}while( ii<pRtree->nDim2 );
|
||||
}
|
||||
}else{
|
||||
do{
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i);
|
||||
p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i);
|
||||
ii += 2;
|
||||
}while( ii<pRtree->nDim2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2010,7 +1798,7 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
|
||||
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
|
||||
int ii;
|
||||
int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
|
||||
for(ii=0; ii<pRtree->nDim2; ii+=2){
|
||||
for(ii=0; ii<(pRtree->nDim*2); ii+=2){
|
||||
RtreeCoord *a1 = &p1->aCoord[ii];
|
||||
RtreeCoord *a2 = &p2->aCoord[ii];
|
||||
if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
|
||||
@@ -2045,7 +1833,7 @@ static RtreeDValue cellOverlap(
|
||||
for(ii=0; ii<nCell; ii++){
|
||||
int jj;
|
||||
RtreeDValue o = (RtreeDValue)1;
|
||||
for(jj=0; jj<pRtree->nDim2; jj+=2){
|
||||
for(jj=0; jj<(pRtree->nDim*2); jj+=2){
|
||||
RtreeDValue x1, x2;
|
||||
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
|
||||
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
|
||||
@@ -3101,7 +2889,7 @@ static int rtreeUpdate(
|
||||
** This problem was discovered after years of use, so we silently ignore
|
||||
** these kinds of misdeclared tables to avoid breaking any legacy.
|
||||
*/
|
||||
assert( nData<=(pRtree->nDim2 + 3) );
|
||||
assert( nData<=(pRtree->nDim*2 + 3) );
|
||||
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
|
||||
@@ -3191,27 +2979,6 @@ constraint:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Called when a transaction starts.
|
||||
*/
|
||||
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
assert( pRtree->inWrTrans==0 );
|
||||
pRtree->inWrTrans++;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Called when a transaction completes (either by COMMIT or ROLLBACK).
|
||||
** The sqlite3_blob object should be released at this point.
|
||||
*/
|
||||
static int rtreeEndTransaction(sqlite3_vtab *pVtab){
|
||||
Rtree *pRtree = (Rtree *)pVtab;
|
||||
pRtree->inWrTrans = 0;
|
||||
nodeBlobReset(pRtree);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The xRename method for rtree module virtual tables.
|
||||
*/
|
||||
@@ -3233,7 +3000,6 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function populates the pRtree->nRowEst variable with an estimate
|
||||
** of the number of rows in the virtual table. If possible, this is based
|
||||
@@ -3293,15 +3059,15 @@ static sqlite3_module rtreeModule = {
|
||||
rtreeColumn, /* xColumn - read data */
|
||||
rtreeRowid, /* xRowid - read data */
|
||||
rtreeUpdate, /* xUpdate - write data */
|
||||
rtreeBeginTransaction, /* xBegin - begin transaction */
|
||||
rtreeEndTransaction, /* xSync - sync transaction */
|
||||
rtreeEndTransaction, /* xCommit - commit transaction */
|
||||
rtreeEndTransaction, /* xRollback - rollback transaction */
|
||||
0, /* xBegin - begin transaction */
|
||||
0, /* xSync - sync transaction */
|
||||
0, /* xCommit - commit transaction */
|
||||
0, /* xRollback - rollback transaction */
|
||||
0, /* xFindFunction - function overloading */
|
||||
rtreeRename, /* xRename - rename the table */
|
||||
0, /* xSavepoint */
|
||||
0, /* xRelease */
|
||||
0, /* xRollbackTo */
|
||||
0 /* xRollbackTo */
|
||||
};
|
||||
|
||||
static int rtreeSqlInit(
|
||||
@@ -3313,9 +3079,10 @@ static int rtreeSqlInit(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
#define N_STATEMENT 8
|
||||
#define N_STATEMENT 9
|
||||
static const char *azSql[N_STATEMENT] = {
|
||||
/* Write the xxx_node table */
|
||||
/* Read and write the xxx_node table */
|
||||
"SELECT data FROM '%q'.'%q_node' WHERE nodeno = :1",
|
||||
"INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)",
|
||||
"DELETE FROM '%q'.'%q_node' WHERE nodeno = :1",
|
||||
|
||||
@@ -3353,14 +3120,15 @@ static int rtreeSqlInit(
|
||||
}
|
||||
}
|
||||
|
||||
appStmt[0] = &pRtree->pWriteNode;
|
||||
appStmt[1] = &pRtree->pDeleteNode;
|
||||
appStmt[2] = &pRtree->pReadRowid;
|
||||
appStmt[3] = &pRtree->pWriteRowid;
|
||||
appStmt[4] = &pRtree->pDeleteRowid;
|
||||
appStmt[5] = &pRtree->pReadParent;
|
||||
appStmt[6] = &pRtree->pWriteParent;
|
||||
appStmt[7] = &pRtree->pDeleteParent;
|
||||
appStmt[0] = &pRtree->pReadNode;
|
||||
appStmt[1] = &pRtree->pWriteNode;
|
||||
appStmt[2] = &pRtree->pDeleteNode;
|
||||
appStmt[3] = &pRtree->pReadRowid;
|
||||
appStmt[4] = &pRtree->pWriteRowid;
|
||||
appStmt[5] = &pRtree->pDeleteRowid;
|
||||
appStmt[6] = &pRtree->pReadParent;
|
||||
appStmt[7] = &pRtree->pWriteParent;
|
||||
appStmt[8] = &pRtree->pDeleteParent;
|
||||
|
||||
rc = rtreeQueryStat1(db, pRtree);
|
||||
for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){
|
||||
@@ -3498,10 +3266,9 @@ static int rtreeInit(
|
||||
pRtree->base.pModule = &rtreeModule;
|
||||
pRtree->zDb = (char *)&pRtree[1];
|
||||
pRtree->zName = &pRtree->zDb[nDb+1];
|
||||
pRtree->nDim = (u8)((argc-4)/2);
|
||||
pRtree->nDim2 = pRtree->nDim*2;
|
||||
pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
|
||||
pRtree->eCoordType = (u8)eCoordType;
|
||||
pRtree->nDim = (argc-4)/2;
|
||||
pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2;
|
||||
pRtree->eCoordType = eCoordType;
|
||||
memcpy(pRtree->zDb, argv[1], nDb);
|
||||
memcpy(pRtree->zName, argv[2], nName);
|
||||
|
||||
@@ -3574,8 +3341,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
||||
UNUSED_PARAMETER(nArg);
|
||||
memset(&node, 0, sizeof(RtreeNode));
|
||||
memset(&tree, 0, sizeof(Rtree));
|
||||
tree.nDim = (u8)sqlite3_value_int(apArg[0]);
|
||||
tree.nDim2 = tree.nDim*2;
|
||||
tree.nDim = sqlite3_value_int(apArg[0]);
|
||||
tree.nBytesPerCell = 8 + 8 * tree.nDim;
|
||||
node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
|
||||
|
||||
@@ -3588,7 +3354,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
||||
nodeGetCell(&tree, &node, ii, &cell);
|
||||
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
|
||||
nCell = (int)strlen(zCell);
|
||||
for(jj=0; jj<tree.nDim2; jj++){
|
||||
for(jj=0; jj<tree.nDim*2; jj++){
|
||||
#ifndef SQLITE_RTREE_INT_ONLY
|
||||
sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
|
||||
(double)cell.aCoord[jj].f);
|
||||
|
||||
@@ -109,7 +109,7 @@ do_corruption_tests rtreeA-1.1 {
|
||||
}
|
||||
|
||||
do_execsql_test rtreeA-1.2.0 { DROP TABLE t1_node } {}
|
||||
do_corruption_tests rtreeA-1.2 -error "database disk image is malformed" {
|
||||
do_corruption_tests rtreeA-1.2 -error "SQL logic error or missing database" {
|
||||
1 "SELECT * FROM t1"
|
||||
2 "SELECT * FROM t1 WHERE rowid=5"
|
||||
3 "INSERT INTO t1 VALUES(1000, 1, 2, 3, 4)"
|
||||
|
||||
+111
-147
@@ -20,61 +20,46 @@ ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix session1
|
||||
|
||||
# Run all tests in this file twice. Once with "WITHOUT ROWID", and once
|
||||
# with regular rowid tables.
|
||||
#
|
||||
foreach {tn trailing} {
|
||||
1 ""
|
||||
2 " WITHOUT ROWID "
|
||||
} {
|
||||
eval [string map [list %WR% $trailing] {
|
||||
|
||||
db close
|
||||
forcedelete test.db test.db2
|
||||
reset_db
|
||||
|
||||
do_execsql_test $tn.1.0 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y) %WR%;
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES('abc', 'def');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test creating, attaching tables to and deleting session objects.
|
||||
#
|
||||
do_test $tn.1.1 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.2 { S delete } {}
|
||||
do_test $tn.1.3 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.4 { S attach t1 } {}
|
||||
do_test $tn.1.5 { S delete } {}
|
||||
do_test $tn.1.6 { sqlite3session S db main } {S}
|
||||
do_test $tn.1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test $tn.1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test $tn.1.9 { S delete } {}
|
||||
do_test $tn.1.10 {
|
||||
do_test 1.1 { sqlite3session S db main } {S}
|
||||
do_test 1.2 { S delete } {}
|
||||
do_test 1.3 { sqlite3session S db main } {S}
|
||||
do_test 1.4 { S attach t1 } {}
|
||||
do_test 1.5 { S delete } {}
|
||||
do_test 1.6 { sqlite3session S db main } {S}
|
||||
do_test 1.7 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test 1.8 { S attach t1 ; S attach t2 ; S attach t3 } {}
|
||||
do_test 1.9 { S delete } {}
|
||||
do_test 1.10 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('ghi', 'jkl') }
|
||||
} {}
|
||||
do_test $tn.1.11 { S delete } {}
|
||||
if {$tn==1} {
|
||||
do_test $tn.1.12 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
|
||||
execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 2 }
|
||||
} {}
|
||||
do_test $tn.1.13 {
|
||||
S changeset
|
||||
S delete
|
||||
} {}
|
||||
}
|
||||
do_test 1.11 { S delete } {}
|
||||
do_test 1.12 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES('mno', 'pqr') }
|
||||
execsql { UPDATE t1 SET x = 111 WHERE rowid = 1 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 2 }
|
||||
} {}
|
||||
do_test 1.13 {
|
||||
S changeset
|
||||
S delete
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Simple changeset tests. Also test the sqlite3changeset_invert()
|
||||
# function.
|
||||
#
|
||||
do_test $tn.2.1.1 {
|
||||
do_test 2.1.1 {
|
||||
execsql { DELETE FROM t1 }
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
@@ -82,36 +67,36 @@ do_test $tn.2.1.1 {
|
||||
execsql { INSERT INTO t1 VALUES(2, 'Ayutthaya') }
|
||||
execsql { INSERT INTO t1 VALUES(3, 'Thonburi') }
|
||||
} {}
|
||||
do_changeset_test $tn.2.1.2 S {
|
||||
do_changeset_test 2.1.2 S {
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{INSERT t1 0 X. {} {i 2 t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
}
|
||||
do_changeset_invert_test $tn.2.1.3 S {
|
||||
do_changeset_invert_test 2.1.3 S {
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{DELETE t1 0 X. {i 2 t Ayutthaya} {}}
|
||||
{DELETE t1 0 X. {i 3 t Thonburi} {}}
|
||||
}
|
||||
do_test $tn.2.1.4 { S delete } {}
|
||||
do_test 2.1.4 { S delete } {}
|
||||
|
||||
do_test $tn.2.2.1 {
|
||||
do_test 2.2.1 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { DELETE FROM t1 WHERE 1 }
|
||||
} {}
|
||||
do_changeset_test $tn.2.2.2 S {
|
||||
do_changeset_test 2.2.2 S {
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{DELETE t1 0 X. {i 2 t Ayutthaya} {}}
|
||||
{DELETE t1 0 X. {i 3 t Thonburi} {}}
|
||||
}
|
||||
do_changeset_invert_test $tn.2.2.3 S {
|
||||
do_changeset_invert_test 2.2.3 S {
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{INSERT t1 0 X. {} {i 2 t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
}
|
||||
do_test $tn.2.2.4 { S delete } {}
|
||||
do_test 2.2.4 { S delete } {}
|
||||
|
||||
do_test $tn.2.3.1 {
|
||||
do_test 2.3.1 {
|
||||
execsql { DELETE FROM t1 }
|
||||
sqlite3session S db main
|
||||
execsql { INSERT INTO t1 VALUES(1, 'Sukhothai') }
|
||||
@@ -125,7 +110,7 @@ do_test $tn.2.3.1 {
|
||||
}
|
||||
} {}
|
||||
|
||||
do_changeset_test $tn.2.3.2 S {
|
||||
do_changeset_test 2.3.2 S {
|
||||
{INSERT t1 0 X. {} {i 10 t Sukhothai}}
|
||||
{DELETE t1 0 X. {i 1 t Sukhothai} {}}
|
||||
{UPDATE t1 0 X. {i 2 t Ayutthaya} {{} {} t Surin}}
|
||||
@@ -133,24 +118,24 @@ do_changeset_test $tn.2.3.2 S {
|
||||
{INSERT t1 0 X. {} {i 20 t Thapae}}
|
||||
}
|
||||
|
||||
do_changeset_invert_test $tn.2.3.3 S {
|
||||
do_changeset_invert_test 2.3.3 S {
|
||||
{DELETE t1 0 X. {i 10 t Sukhothai} {}}
|
||||
{INSERT t1 0 X. {} {i 1 t Sukhothai}}
|
||||
{UPDATE t1 0 X. {i 2 t Surin} {{} {} t Ayutthaya}}
|
||||
{INSERT t1 0 X. {} {i 3 t Thonburi}}
|
||||
{DELETE t1 0 X. {i 20 t Thapae} {}}
|
||||
}
|
||||
do_test $tn.2.3.4 { S delete } {}
|
||||
do_test 2.3.4 { S delete } {}
|
||||
|
||||
do_test $tn.2.4.1 {
|
||||
do_test 2.4.1 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql { INSERT INTO t1 VALUES(100, 'Bangkok') }
|
||||
execsql { DELETE FROM t1 WHERE x = 100 }
|
||||
} {}
|
||||
do_changeset_test $tn.2.4.2 S {}
|
||||
do_changeset_invert_test $tn.2.4.3 S {}
|
||||
do_test $tn.2.4.4 { S delete } {}
|
||||
do_changeset_test 2.4.2 S {}
|
||||
do_changeset_invert_test 2.4.3 S {}
|
||||
do_test 2.4.4 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the application of simple changesets. These tests also test that
|
||||
@@ -204,16 +189,16 @@ proc do_db2_test {testname sql {result {}}} {
|
||||
|
||||
# Test INSERT changesets.
|
||||
#
|
||||
do_test $tn.3.1.0 {
|
||||
execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) %WR% } db2
|
||||
do_test 3.1.0 {
|
||||
execsql { CREATE TABLE t1(a PRIMARY KEY, b NOT NULL) } db2
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) %WR%;
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
} db
|
||||
} {}
|
||||
do_db2_test $tn.3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
|
||||
do_conflict_test $tn.3.1.2 -tables t1 -sql {
|
||||
do_db2_test 3.1.1 "INSERT INTO t1 VALUES(6, 'VI')"
|
||||
do_conflict_test 3.1.2 -tables t1 -sql {
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
INSERT INTO t1 VALUES(5, 'five');
|
||||
@@ -225,34 +210,34 @@ do_conflict_test $tn.3.1.2 -tables t1 -sql {
|
||||
{INSERT t1 CONSTRAINT {i 8 n {}}}
|
||||
}
|
||||
|
||||
do_db2_test $tn.3.1.3 "SELECT * FROM t1 ORDER BY a" {
|
||||
3 three 4 four 5 five 6 VI 7 seven
|
||||
do_db2_test 3.1.3 "SELECT * FROM t1" {
|
||||
6 VI 3 three 4 four 5 five 7 seven
|
||||
}
|
||||
do_execsql_test $tn.3.1.4 "SELECT * FROM t1" {
|
||||
do_execsql_test 3.1.4 "SELECT * FROM t1" {
|
||||
1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 {}
|
||||
}
|
||||
|
||||
# Test DELETE changesets.
|
||||
#
|
||||
do_execsql_test $tn.3.2.1 {
|
||||
do_execsql_test 3.2.1 {
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b);
|
||||
CREATE TABLE t3(c, d REFERENCES t2);
|
||||
INSERT INTO t2 VALUES(1, 'one');
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
INSERT INTO t2 VALUES(3, 'three');
|
||||
INSERT INTO t2 VALUES(4, 'four');
|
||||
}
|
||||
do_db2_test $tn.3.2.2 {
|
||||
do_db2_test 3.2.2 {
|
||||
PRAGMA foreign_keys = on;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t2(a PRIMARY KEY, b);
|
||||
CREATE TABLE t3(c, d REFERENCES t2);
|
||||
INSERT INTO t2 VALUES(1, 'one');
|
||||
INSERT INTO t2 VALUES(2, 'two');
|
||||
INSERT INTO t2 VALUES(4, 'five');
|
||||
INSERT INTO t3 VALUES('i', 1);
|
||||
}
|
||||
do_conflict_test $tn.3.2.3 -tables t2 -sql {
|
||||
do_conflict_test 3.2.3 -tables t2 -sql {
|
||||
DELETE FROM t2 WHERE a = 1;
|
||||
DELETE FROM t2 WHERE a = 2;
|
||||
DELETE FROM t2 WHERE a = 3;
|
||||
@@ -262,26 +247,26 @@ do_conflict_test $tn.3.2.3 -tables t2 -sql {
|
||||
{DELETE t2 DATA {i 4 t four} {i 4 t five}}
|
||||
{FOREIGN_KEY 1}
|
||||
}
|
||||
do_execsql_test $tn.3.2.4 "SELECT * FROM t2" {}
|
||||
do_db2_test $tn.3.2.5 "SELECT * FROM t2" {4 five}
|
||||
do_execsql_test 3.2.4 "SELECT * FROM t2" {}
|
||||
do_db2_test 3.2.5 "SELECT * FROM t2" {4 five}
|
||||
|
||||
# Test UPDATE changesets.
|
||||
#
|
||||
do_execsql_test $tn.3.3.1 {
|
||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c))%WR%;
|
||||
do_execsql_test 3.3.1 {
|
||||
CREATE TABLE t4(a, b, c, PRIMARY KEY(b, c));
|
||||
INSERT INTO t4 VALUES(1, 2, 3);
|
||||
INSERT INTO t4 VALUES(4, 5, 6);
|
||||
INSERT INTO t4 VALUES(7, 8, 9);
|
||||
INSERT INTO t4 VALUES(10, 11, 12);
|
||||
}
|
||||
do_db2_test $tn.3.3.2 {
|
||||
CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c))%WR%;
|
||||
do_db2_test 3.3.2 {
|
||||
CREATE TABLE t4(a NOT NULL, b, c, PRIMARY KEY(b, c));
|
||||
INSERT INTO t4 VALUES(0, 2, 3);
|
||||
INSERT INTO t4 VALUES(4, 5, 7);
|
||||
INSERT INTO t4 VALUES(7, 8, 9);
|
||||
INSERT INTO t4 VALUES(10, 11, 12);
|
||||
}
|
||||
do_conflict_test $tn.3.3.3 -tables t4 -sql {
|
||||
do_conflict_test 3.3.3 -tables t4 -sql {
|
||||
UPDATE t4 SET a = -1 WHERE b = 2;
|
||||
UPDATE t4 SET a = -1 WHERE b = 5;
|
||||
UPDATE t4 SET a = NULL WHERE c = 9;
|
||||
@@ -291,8 +276,8 @@ do_conflict_test $tn.3.3.3 -tables t4 -sql {
|
||||
{UPDATE t4 NOTFOUND {i 4 i 5 i 6} {i -1 {} {} {} {}}}
|
||||
{UPDATE t4 CONSTRAINT {i 7 i 8 i 9} {n {} {} {} {} {}}}
|
||||
}
|
||||
do_db2_test $tn.3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
|
||||
do_execsql_test $tn.3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
|
||||
do_db2_test 3.3.4 { SELECT * FROM t4 } {0 2 3 4 5 7 7 8 9 x 11 12}
|
||||
do_execsql_test 3.3.5 { SELECT * FROM t4 } {-1 2 3 -1 5 6 {} 8 9 x 11 12}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This next block of tests verifies that values returned by the conflict
|
||||
@@ -312,16 +297,16 @@ proc xConflict {args} {
|
||||
return $::conflict_return
|
||||
}
|
||||
|
||||
foreach {tn2 conflict_return after} {
|
||||
foreach {tn conflict_return after} {
|
||||
1 OMIT {1 2 value1 4 5 7 10 x x}
|
||||
2 REPLACE {1 2 value1 4 5 value2 10 8 9}
|
||||
} {
|
||||
test_reset
|
||||
|
||||
do_test $tn.4.$tn2.1 {
|
||||
do_test 4.$tn.1 {
|
||||
foreach db {db db2} {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a))%WR%;
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
@@ -333,7 +318,7 @@ foreach {tn2 conflict_return after} {
|
||||
} db2
|
||||
} {}
|
||||
|
||||
do_conflict_test $tn.4.$tn2.2 -tables t1 -sql {
|
||||
do_conflict_test 4.$tn.2 -tables t1 -sql {
|
||||
UPDATE t1 SET c = 'value1' WHERE a = 1; -- no conflict
|
||||
UPDATE t1 SET c = 'value2' WHERE a = 4; -- DATA conflict
|
||||
UPDATE t1 SET a = 10 WHERE a = 7; -- CONFLICT conflict
|
||||
@@ -342,19 +327,19 @@ foreach {tn2 conflict_return after} {
|
||||
{UPDATE t1 DATA {i 4 {} {} i 6} {{} {} {} {} t value2} {i 4 i 5 i 7}}
|
||||
}
|
||||
|
||||
do_db2_test $tn.4.$tn2.3 "SELECT * FROM t1 ORDER BY a" $after
|
||||
do_db2_test 4.$tn.3 "SELECT * FROM t1 ORDER BY a" $after
|
||||
}
|
||||
|
||||
foreach {tn2 conflict_return} {
|
||||
foreach {tn conflict_return} {
|
||||
1 OMIT
|
||||
2 REPLACE
|
||||
} {
|
||||
test_reset
|
||||
|
||||
do_test $tn.5.$tn2.1 {
|
||||
do_test 5.$tn.1 {
|
||||
# Create an identical schema in both databases.
|
||||
set schema {
|
||||
CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y))%WR%;
|
||||
CREATE TABLE "'foolish name'"(x, y, z, PRIMARY KEY(x, y));
|
||||
}
|
||||
execsql $schema db
|
||||
execsql $schema db2
|
||||
@@ -369,7 +354,7 @@ foreach {tn2 conflict_return} {
|
||||
|
||||
} {}
|
||||
|
||||
do_conflict_test $tn.5.$tn2.2 -tables {{'foolish name'}} -sql {
|
||||
do_conflict_test 5.$tn.2 -tables {{'foolish name'}} -sql {
|
||||
INSERT INTO "'foolish name'" VALUES('one', 'two', 2);
|
||||
} -conflicts {
|
||||
{INSERT {'foolish name'} CONFLICT {t one t two i 2} {t one t two t i}}
|
||||
@@ -377,14 +362,14 @@ foreach {tn2 conflict_return} {
|
||||
|
||||
set res(REPLACE) {one one ii one two 2 two two ii}
|
||||
set res(OMIT) {one one ii one two i two two ii}
|
||||
do_db2_test $tn.5.$tn2.3 {
|
||||
do_db2_test 5.$tn.3 {
|
||||
SELECT * FROM "'foolish name'" ORDER BY x, y
|
||||
} $res($conflict_return)
|
||||
|
||||
|
||||
do_test $tn.5.$tn2.1 {
|
||||
do_test 5.$tn.1 {
|
||||
set schema {
|
||||
CREATE TABLE d1("z""z" PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE d1("z""z" PRIMARY KEY, y);
|
||||
INSERT INTO d1 VALUES(1, 'one');
|
||||
INSERT INTO d1 VALUES(2, 'two');
|
||||
}
|
||||
@@ -397,7 +382,7 @@ foreach {tn2 conflict_return} {
|
||||
|
||||
} {}
|
||||
|
||||
do_conflict_test $tn.5.$tn2.2 -tables d1 -sql {
|
||||
do_conflict_test 5.$tn.2 -tables d1 -sql {
|
||||
DELETE FROM d1 WHERE "z""z" = 2;
|
||||
} -conflicts {
|
||||
{DELETE d1 DATA {i 2 t two} {i 2 t TWO}}
|
||||
@@ -405,7 +390,7 @@ foreach {tn2 conflict_return} {
|
||||
|
||||
set res(REPLACE) {1 one}
|
||||
set res(OMIT) {1 one 2 TWO}
|
||||
do_db2_test $tn.5.$tn2.3 "SELECT * FROM d1" $res($conflict_return)
|
||||
do_db2_test 5.$tn.3 "SELECT * FROM d1" $res($conflict_return)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -413,10 +398,10 @@ foreach {tn2 conflict_return} {
|
||||
#
|
||||
test_reset
|
||||
set schema {
|
||||
CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE t2(a, b PRIMARY KEY)%WR%;
|
||||
CREATE TABLE t1(a COLLATE nocase PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a, b PRIMARY KEY);
|
||||
}
|
||||
do_test $tn.6.0 {
|
||||
do_test 6.0 {
|
||||
execsql $schema db
|
||||
execsql $schema db2
|
||||
execsql {
|
||||
@@ -426,7 +411,7 @@ do_test $tn.6.0 {
|
||||
} {}
|
||||
|
||||
set conflict_return ""
|
||||
do_conflict_test $tn.6.1 -tables {t1 t2} -sql {
|
||||
do_conflict_test 6.1 -tables {t1 t2} -sql {
|
||||
INSERT INTO t1 VALUES('1', '2');
|
||||
INSERT INTO t1 VALUES('A', 'B');
|
||||
INSERT INTO t2 VALUES('A', 'B');
|
||||
@@ -434,8 +419,8 @@ do_conflict_test $tn.6.1 -tables {t1 t2} -sql {
|
||||
{INSERT t1 CONFLICT {t A t B} {t a t b}}
|
||||
}
|
||||
|
||||
do_db2_test $tn.6.2 "SELECT * FROM t1 ORDER BY a" {1 2 a b}
|
||||
do_db2_test $tn.6.3 "SELECT * FROM t2 ORDER BY a" {A B a b}
|
||||
do_db2_test 6.2 "SELECT * FROM t1" {a b 1 2}
|
||||
do_db2_test 6.3 "SELECT * FROM t2" {a b A B}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that session objects are not confused by changes to table in
|
||||
@@ -444,10 +429,10 @@ do_db2_test $tn.6.3 "SELECT * FROM t2 ORDER BY a" {A B a b}
|
||||
catch { db2 close }
|
||||
drop_all_tables
|
||||
forcedelete test.db2
|
||||
do_iterator_test $tn.7.1 * {
|
||||
do_iterator_test 7.1 * {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE main.t1(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE aux.t1(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE main.t1(x PRIMARY KEY, y);
|
||||
CREATE TABLE aux.t1(x PRIMARY KEY, y);
|
||||
|
||||
INSERT INTO main.t1 VALUES('one', 1);
|
||||
INSERT INTO main.t1 VALUES('two', 2);
|
||||
@@ -461,10 +446,10 @@ do_iterator_test $tn.7.1 * {
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the sqlite3session_isempty() function.
|
||||
#
|
||||
do_test $tn.8.1 {
|
||||
do_test 8.1 {
|
||||
execsql {
|
||||
CREATE TABLE t5(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE t6(x PRIMARY KEY, y)%WR%;
|
||||
CREATE TABLE t5(x PRIMARY KEY, y);
|
||||
CREATE TABLE t6(x PRIMARY KEY, y);
|
||||
INSERT INTO t5 VALUES('a', 'b');
|
||||
INSERT INTO t6 VALUES('a', 'b');
|
||||
}
|
||||
@@ -473,20 +458,20 @@ do_test $tn.8.1 {
|
||||
|
||||
S isempty
|
||||
} {1}
|
||||
do_test $tn.8.2 {
|
||||
do_test 8.2 {
|
||||
execsql { DELETE FROM t5 }
|
||||
S isempty
|
||||
} {0}
|
||||
do_test $tn.8.3 {
|
||||
do_test 8.3 {
|
||||
S delete
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
execsql { DELETE FROM t5 }
|
||||
S isempty
|
||||
} {1}
|
||||
do_test $tn.8.4 { S delete } {}
|
||||
do_test 8.4 { S delete } {}
|
||||
|
||||
do_test $tn.8.5 {
|
||||
do_test 8.5 {
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
S attach t6
|
||||
@@ -494,7 +479,7 @@ do_test $tn.8.5 {
|
||||
S isempty
|
||||
} {0}
|
||||
|
||||
do_test $tn.8.6 {
|
||||
do_test 8.6 {
|
||||
S delete
|
||||
sqlite3session S db main
|
||||
S attach t5
|
||||
@@ -502,20 +487,20 @@ do_test $tn.8.6 {
|
||||
execsql { INSERT INTO t6 VALUES(1, 2) }
|
||||
S isempty
|
||||
} {0}
|
||||
do_test $tn.8.7 { S delete } {}
|
||||
do_test 8.7 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test $tn.9.1 {
|
||||
CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g)%WR%;
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g);
|
||||
INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1);
|
||||
}
|
||||
do_test $tn.9.2 {
|
||||
do_test 9.2 {
|
||||
sqlite3session S db main
|
||||
S attach *
|
||||
execsql { UPDATE t7 SET b=2, d=2 }
|
||||
} {}
|
||||
do_changeset_test $tn.9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
|
||||
do_changeset_test 9.2 S {{UPDATE t7 0 ....X.. {{} {} i 1 {} {} i 1 i 1 {} {} {} {}} {{} {} i 2 {} {} i 2 {} {} {} {} {} {}}}}
|
||||
S delete
|
||||
catch { db2 close }
|
||||
|
||||
@@ -524,9 +509,9 @@ catch { db2 close }
|
||||
#
|
||||
reset_db
|
||||
set tblname [string repeat tblname123 100]
|
||||
do_test $tn.10.1.1 {
|
||||
do_test 10.1.1 {
|
||||
execsql "
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b);
|
||||
INSERT INTO $tblname VALUES('xyz', 'def');
|
||||
"
|
||||
sqlite3session S db main
|
||||
@@ -537,18 +522,18 @@ do_test $tn.10.1.1 {
|
||||
"
|
||||
} {}
|
||||
breakpoint
|
||||
do_changeset_test $tn.10.1.2 S "
|
||||
do_changeset_test 10.1.2 S "
|
||||
{INSERT $tblname 0 X. {} {t uvw t abc}}
|
||||
{DELETE $tblname 0 X. {t xyz t def} {}}
|
||||
"
|
||||
do_test $tn.10.1.4 { S delete } {}
|
||||
do_test 10.1.4 { S delete } {}
|
||||
|
||||
#---------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test $tn.11.1 {
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
do_test $tn.11.2 {
|
||||
do_test 11.2 {
|
||||
sqlite3session S db main
|
||||
S attach t1
|
||||
execsql {
|
||||
@@ -565,9 +550,9 @@ S delete
|
||||
#
|
||||
reset_db
|
||||
set tblname [string repeat tblname123 100]
|
||||
do_test $tn.10.1.1 {
|
||||
do_test 10.1.1 {
|
||||
execsql "
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b)%WR%;
|
||||
CREATE TABLE $tblname (a PRIMARY KEY, b);
|
||||
INSERT INTO $tblname VALUES('xyz', 'def');
|
||||
"
|
||||
sqlite3session S db main
|
||||
@@ -578,44 +563,23 @@ do_test $tn.10.1.1 {
|
||||
"
|
||||
} {}
|
||||
breakpoint
|
||||
do_changeset_test $tn.10.1.2 S "
|
||||
do_changeset_test 10.1.2 S "
|
||||
{INSERT $tblname 0 X. {} {t uvw t abc}}
|
||||
{DELETE $tblname 0 X. {t xyz t def} {}}
|
||||
"
|
||||
do_test $tn.10.1.4 { S delete } {}
|
||||
do_test 10.1.4 { S delete } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the effect of updating a column from 0.0 to 0.0.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test $tn.11.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL)%WR%;
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b REAL);
|
||||
INSERT INTO t1 VALUES(1, 0.0);
|
||||
}
|
||||
do_iterator_test $tn.11.2 * {
|
||||
do_iterator_test 11.2 * {
|
||||
UPDATE t1 SET b = 0.0;
|
||||
} {
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test $tn.12.1 {
|
||||
CREATE TABLE t1(r INTEGER PRIMARY KEY, a, b)%WR%;
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 1, 2);
|
||||
INSERT INTO t1 VALUES(3, 1, 3);
|
||||
}
|
||||
|
||||
do_iterator_test $tn.12.2 * {
|
||||
UPDATE t1 SET b='one' WHERE a=1;
|
||||
} {
|
||||
{UPDATE t1 0 X.. {i 1 {} {} i 1} {{} {} {} {} t one}}
|
||||
{UPDATE t1 0 X.. {i 2 {} {} i 2} {{} {} {} {} t one}}
|
||||
{UPDATE t1 0 X.. {i 3 {} {} i 3} {{} {} {} {} t one}}
|
||||
}
|
||||
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
** 2017 January 31
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This file contains the source code for a standalone program used to
|
||||
** test the performance of the sessions module. Compile and run:
|
||||
**
|
||||
** ./session_speed_test -help
|
||||
**
|
||||
** for details.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*************************************************************************
|
||||
** Start of generic command line parser.
|
||||
*/
|
||||
#define CMDLINE_BARE 0
|
||||
#define CMDLINE_INTEGER 1
|
||||
#define CMDLINE_STRING 2
|
||||
#define CMDLINE_BOOLEAN 3
|
||||
|
||||
typedef struct CmdLineOption CmdLineOption;
|
||||
struct CmdLineOption {
|
||||
const char *zText; /* Name of command line option */
|
||||
const char *zHelp; /* Help text for option */
|
||||
int eType; /* One of the CMDLINE_* values */
|
||||
int iOff; /* Offset of output variable */
|
||||
};
|
||||
|
||||
#define CMDLINE_INT32(x,y,z) {x, y, CMDLINE_INTEGER, z}
|
||||
#define CMDLINE_BOOL(x,y,z) {x, y, CMDLINE_BOOLEAN, z}
|
||||
#define CMDLINE_TEXT(x,y,z) {x, y, CMDLINE_STRING, z}
|
||||
#define CMDLINE_NONE(x,y,z) {x, y, CMDLINE_BARE, z}
|
||||
|
||||
static void option_requires_argument_error(CmdLineOption *pOpt){
|
||||
fprintf(stderr, "Option requires a%s argument: %s\n",
|
||||
pOpt->eType==CMDLINE_INTEGER ? "n integer" :
|
||||
pOpt->eType==CMDLINE_STRING ? " string" : " boolean",
|
||||
pOpt->zText
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ambiguous_option_error(const char *zArg){
|
||||
fprintf(stderr, "Option is ambiguous: %s\n", zArg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void unknown_option_error(
|
||||
const char *zArg,
|
||||
CmdLineOption *aOpt,
|
||||
const char *zHelp
|
||||
){
|
||||
int i;
|
||||
fprintf(stderr, "Unknown option: %s\n", zArg);
|
||||
fprintf(stderr, "\nOptions are:\n");
|
||||
fprintf(stderr, " % -30sEcho command line options\n", "-cmdline:verbose");
|
||||
for(i=0; aOpt[i].zText; i++){
|
||||
int eType = aOpt[i].eType;
|
||||
char *zOpt = sqlite3_mprintf("%s %s", aOpt[i].zText,
|
||||
eType==CMDLINE_BARE ? "" :
|
||||
eType==CMDLINE_INTEGER ? "N" :
|
||||
eType==CMDLINE_BOOLEAN ? "BOOLEAN" : "TEXT"
|
||||
);
|
||||
fprintf(stderr, " % -30s%s\n", zOpt, aOpt[i].zHelp);
|
||||
sqlite3_free(zOpt);
|
||||
}
|
||||
if( zHelp ){
|
||||
fprintf(stderr, "\n%s\n", zHelp);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int get_integer_option(CmdLineOption *pOpt, const char *zArg){
|
||||
int i = 0;
|
||||
int iRet = 0;
|
||||
int bSign = 1;
|
||||
if( zArg[0]=='-' ){
|
||||
bSign = -1;
|
||||
i = 1;
|
||||
}
|
||||
while( zArg[i] ){
|
||||
if( zArg[i]<'0' || zArg[i]>'9' ) option_requires_argument_error(pOpt);
|
||||
iRet = iRet*10 + (zArg[i] - '0');
|
||||
i++;
|
||||
}
|
||||
return (iRet*bSign);
|
||||
}
|
||||
|
||||
static int get_boolean_option(CmdLineOption *pOpt, const char *zArg){
|
||||
if( 0==sqlite3_stricmp(zArg, "true") ) return 1;
|
||||
if( 0==sqlite3_stricmp(zArg, "1") ) return 1;
|
||||
if( 0==sqlite3_stricmp(zArg, "0") ) return 0;
|
||||
if( 0==sqlite3_stricmp(zArg, "false") ) return 0;
|
||||
option_requires_argument_error(pOpt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_command_line(
|
||||
int argc,
|
||||
char **argv,
|
||||
int iStart,
|
||||
CmdLineOption *aOpt,
|
||||
void *pStruct,
|
||||
const char *zHelp
|
||||
){
|
||||
char *pOut = (char*)pStruct;
|
||||
int bVerbose = 0;
|
||||
int iArg;
|
||||
|
||||
for(iArg=iStart; iArg<argc; iArg++){
|
||||
const char *zArg = argv[iArg];
|
||||
int nArg = strlen(zArg);
|
||||
int nMatch = 0;
|
||||
int iOpt;
|
||||
|
||||
for(iOpt=0; aOpt[iOpt].zText; iOpt++){
|
||||
CmdLineOption *pOpt = &aOpt[iOpt];
|
||||
if( 0==sqlite3_strnicmp(pOpt->zText, zArg, nArg) ){
|
||||
if( nMatch ){
|
||||
ambiguous_option_error(zArg);
|
||||
}
|
||||
nMatch++;
|
||||
if( pOpt->eType==CMDLINE_BARE ){
|
||||
*(int*)(&pOut[pOpt->iOff]) = 1;
|
||||
}else{
|
||||
iArg++;
|
||||
if( iArg==argc ){
|
||||
option_requires_argument_error(pOpt);
|
||||
}
|
||||
switch( pOpt->eType ){
|
||||
case CMDLINE_INTEGER:
|
||||
*(int*)(&pOut[pOpt->iOff]) = get_integer_option(pOpt, argv[iArg]);
|
||||
break;
|
||||
case CMDLINE_STRING:
|
||||
*(const char**)(&pOut[pOpt->iOff]) = argv[iArg];
|
||||
break;
|
||||
case CMDLINE_BOOLEAN:
|
||||
*(int*)(&pOut[pOpt->iOff]) = get_boolean_option(pOpt, argv[iArg]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( nMatch==0 && 0==sqlite3_strnicmp("-cmdline:verbose", zArg, nArg) ){
|
||||
bVerbose = 1;
|
||||
nMatch = 1;
|
||||
}
|
||||
|
||||
if( nMatch==0 ){
|
||||
unknown_option_error(zArg, aOpt, zHelp);
|
||||
}
|
||||
}
|
||||
|
||||
if( bVerbose ){
|
||||
int iOpt;
|
||||
fprintf(stdout, "Options are: ");
|
||||
for(iOpt=0; aOpt[iOpt].zText; iOpt++){
|
||||
CmdLineOption *pOpt = &aOpt[iOpt];
|
||||
if( pOpt->eType!=CMDLINE_BARE || *(int*)(&pOut[pOpt->iOff]) ){
|
||||
fprintf(stdout, "%s ", pOpt->zText);
|
||||
}
|
||||
switch( pOpt->eType ){
|
||||
case CMDLINE_INTEGER:
|
||||
fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
case CMDLINE_BOOLEAN:
|
||||
fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
case CMDLINE_STRING:
|
||||
fprintf(stdout, "%s ", *(const char**)(&pOut[pOpt->iOff]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
/*
|
||||
** End of generic command line parser.
|
||||
*************************************************************************/
|
||||
|
||||
static void abort_due_to_error(int rc){
|
||||
fprintf(stderr, "Error: %d\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void execsql(sqlite3 *db, const char *zSql){
|
||||
int rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
}
|
||||
|
||||
static int xConflict(void *pCtx, int eConflict, sqlite3_changeset_iter *p){
|
||||
return SQLITE_CHANGESET_ABORT;
|
||||
}
|
||||
|
||||
static void run_test(
|
||||
sqlite3 *db,
|
||||
sqlite3 *db2,
|
||||
int nRow,
|
||||
const char *zSql
|
||||
){
|
||||
sqlite3_session *pSession = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc;
|
||||
int i;
|
||||
int nChangeset;
|
||||
void *pChangeset;
|
||||
|
||||
/* Attach a session object to database db */
|
||||
rc = sqlite3session_create(db, "main", &pSession);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Configure the session to capture changes on all tables */
|
||||
rc = sqlite3session_attach(pSession, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Prepare the SQL statement */
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Open a transaction */
|
||||
execsql(db, "BEGIN");
|
||||
|
||||
/* Execute the SQL statement nRow times */
|
||||
for(i=0; i<nRow; i++){
|
||||
sqlite3_bind_int(pStmt, 1, i);
|
||||
sqlite3_step(pStmt);
|
||||
rc = sqlite3_reset(pStmt);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
/* Extract a changeset from the sessions object */
|
||||
rc = sqlite3session_changeset(pSession, &nChangeset, &pChangeset);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
execsql(db, "COMMIT");
|
||||
|
||||
/* Apply the changeset to the second db */
|
||||
rc = sqlite3changeset_apply(db2, nChangeset, pChangeset, 0, xConflict, 0);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Cleanup */
|
||||
sqlite3_free(pChangeset);
|
||||
sqlite3session_delete(pSession);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct Options {
|
||||
int nRow;
|
||||
int bWithoutRowid;
|
||||
int bInteger;
|
||||
int bAll;
|
||||
const char *zDb;
|
||||
};
|
||||
struct Options o = { 2500, 0, 0, 0, "session_speed_test.db" };
|
||||
|
||||
CmdLineOption aOpt[] = {
|
||||
CMDLINE_INT32( "-rows", "number of rows in test",
|
||||
offsetof(struct Options, nRow) ),
|
||||
CMDLINE_BOOL("-without-rowid", "use WITHOUT ROWID tables",
|
||||
offsetof(struct Options, bWithoutRowid) ),
|
||||
CMDLINE_BOOL("-integer", "use integer data (instead of text/blobs)",
|
||||
offsetof(struct Options, bInteger) ),
|
||||
CMDLINE_NONE("-all", "Run all 4 combos of -without-rowid and -integer",
|
||||
offsetof(struct Options, bAll) ),
|
||||
CMDLINE_TEXT("-database", "prefix for database files to use",
|
||||
offsetof(struct Options, zDb) ),
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
const char *azCreate[] = {
|
||||
"CREATE TABLE t1(a PRIMARY KEY, b, c, d)",
|
||||
"CREATE TABLE t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID",
|
||||
};
|
||||
|
||||
const char *azInsert[] = {
|
||||
"INSERT INTO t1 VALUES("
|
||||
"printf('%.8d',?), randomblob(50), randomblob(50), randomblob(50))",
|
||||
"INSERT INTO t1 VALUES(?, random(), random(), random())"
|
||||
};
|
||||
|
||||
const char *azUpdate[] = {
|
||||
"UPDATE t1 SET d = randomblob(50) WHERE a = printf('%.8d',?)",
|
||||
"UPDATE t1 SET d = random() WHERE a = ?"
|
||||
};
|
||||
|
||||
const char *azDelete[] = {
|
||||
"DELETE FROM t1 WHERE a = printf('%.8d',?)",
|
||||
"DELETE FROM t1 WHERE a = ?"
|
||||
};
|
||||
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
sqlite3 *db2;
|
||||
char *zDb2;
|
||||
int bWithoutRowid;
|
||||
int bInteger;
|
||||
|
||||
parse_command_line(argc, argv, 1, aOpt, (void*)&o,
|
||||
"This program creates two new, empty, databases each containing a single\n"
|
||||
"table. It then does the following:\n\n"
|
||||
" 1. Inserts -rows rows into the first database\n"
|
||||
" 2. Updates each row in the first db\n"
|
||||
" 3. Delete each row from the first db\n\n"
|
||||
"The modifications made by each step are captured in a changeset and\n"
|
||||
"applied to the second database.\n"
|
||||
);
|
||||
zDb2 = sqlite3_mprintf("%s2", o.zDb);
|
||||
|
||||
for(bWithoutRowid=0; bWithoutRowid<2; bWithoutRowid++){
|
||||
for(bInteger=0; bInteger<2; bInteger++){
|
||||
if( o.bAll || (o.bWithoutRowid==bWithoutRowid && o.bInteger==bInteger) ){
|
||||
fprintf(stdout, "Testing %s data with %s table\n",
|
||||
bInteger ? "integer" : "blob/text",
|
||||
bWithoutRowid ? "WITHOUT ROWID" : "rowid"
|
||||
);
|
||||
|
||||
/* Open new database handles on two empty databases */
|
||||
unlink(o.zDb);
|
||||
rc = sqlite3_open(o.zDb, &db);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
unlink(zDb2);
|
||||
rc = sqlite3_open(zDb2, &db2);
|
||||
if( rc!=SQLITE_OK ) abort_due_to_error(rc);
|
||||
|
||||
/* Create the schema in both databases. */
|
||||
execsql(db, azCreate[o.bWithoutRowid]);
|
||||
execsql(db2, azCreate[o.bWithoutRowid]);
|
||||
|
||||
/* Run the three tests */
|
||||
run_test(db, db2, o.nRow, azInsert[o.bInteger]);
|
||||
run_test(db, db2, o.nRow, azUpdate[o.bInteger]);
|
||||
run_test(db, db2, o.nRow, azDelete[o.bInteger]);
|
||||
|
||||
/* Close the db handles */
|
||||
sqlite3_close(db);
|
||||
sqlite3_close(db2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# 2017 Jan 31
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# The focus of this file is testing the session module. Specifically,
|
||||
# testing support for WITHOUT ROWID tables.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] session_common.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !session {finish_test; return}
|
||||
|
||||
set testprefix sessionwor
|
||||
|
||||
proc test_reset {} {
|
||||
catch { db close }
|
||||
catch { db2 close }
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db test.db
|
||||
sqlite3 db2 test.db2
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
|
||||
do_iterator_test 1.1 t1 {
|
||||
INSERT INTO t1 VALUES('one', 'two');
|
||||
} {
|
||||
{INSERT t1 0 X. {} {t one t two}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.2 t1 {
|
||||
UPDATE t1 SET b='three'
|
||||
} {
|
||||
{UPDATE t1 0 X. {t one t two} {{} {} t three}}
|
||||
}
|
||||
|
||||
do_iterator_test 1.3 t1 {
|
||||
DELETE FROM t1;
|
||||
} {
|
||||
{DELETE t1 0 X. {t one t three} {}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
** directory as this file for additional information.
|
||||
*/
|
||||
#ifdef SQLITE_USER_AUTHENTICATION
|
||||
#ifndef SQLITEINT_H
|
||||
#ifndef _SQLITEINT_H_
|
||||
# include "sqliteInt.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -478,8 +478,6 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
|
||||
# This is the default Makefile target. The objects listed here
|
||||
# are what get build when you type just "make" with no arguments.
|
||||
@@ -894,11 +892,8 @@ wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o wordcount$(EXE) \
|
||||
$(TOP)/test/wordcount.c sqlite3.c
|
||||
|
||||
speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c
|
||||
$(TCCX) -I. $(ST_OPT) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.c $(THREADLIB)
|
||||
|
||||
kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c
|
||||
$(TCCX) -I. $(KV+OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB)
|
||||
speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.o
|
||||
$(TCCX) -I. $(OTAFLAGS) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.o $(THREADLIB)
|
||||
|
||||
rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o
|
||||
$(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
C Merge\sthe\slatest\strunk\schanges,\sespecially\sthe\sRTREE\senhancement\sto\suse\nsqlite3_blob\sobjects.
|
||||
D 2017-02-04T14:30:57.322
|
||||
F Makefile.in 5f415e7867296d678fed2e6779aea10c1318b4bc
|
||||
C Fix\sproblems\sin\sthe\sprevious\scommit.
|
||||
D 2017-01-21T16:21:24.115
|
||||
F Makefile.in 41bd4cad981487345c4a84081074bcdb876e4b2e
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc ba953c8921fc7e18333f61898007206de7e23964
|
||||
F Makefile.msc b8ca53350ae545e3562403d5da2a69cec79308da
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION cddd8d88dc8202afa0ebc96da61fc4acbd1e96a5
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -11,7 +11,7 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am 1a47d071e3d5435f8f7ebff7eb6703848bbd65d4
|
||||
F autoconf/Makefile.msc 3f29e0fc2a78e113250d79a5da375c1d8d8c06b0
|
||||
F autoconf/Makefile.msc b6d27f735911fd09a589d3c966936c47a5850c17
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac cacf2616abf6e4a569bde2ef365c143caeec40bc
|
||||
@@ -70,7 +70,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 5a8cafedffd101e9946f8909ecf8d34aaa383b4d
|
||||
F ext/fts3/fts3.c e028eb13432f108d2e22cded019fc980700e4e00
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 89d0bd4595a0de384dac78e94b803de12586e8dd
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
@@ -102,7 +102,7 @@ F ext/fts5/fts5Int.h b2eda36e0f224365c8e23dc8f559311834f1c13f
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c 33f0e8063ac7360bcd71c0ff0dcbacdc05fffe50
|
||||
F ext/fts5/fts5_expr.c dc2cee9f56b1818b85df59304b8104a5dfb8ab60
|
||||
F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2
|
||||
F ext/fts5/fts5_index.c f67032a9a529ba52a545e6e3ab970764199c05d4
|
||||
F ext/fts5/fts5_main.c f85281445dcf8be32d18841c93a6f90fe27dbfe2
|
||||
@@ -184,11 +184,11 @@ F ext/fts5/test/fts5rowid.test 16908a99d6efc9ba21081b4f2b86b3fc699839a6
|
||||
F ext/fts5/test/fts5simple.test 5da9b15ed534eb0be9f279d8a2bb2e24d30e4e38
|
||||
F ext/fts5/test/fts5simple2.test 00839031878f52391562594fdab0503e424ee071
|
||||
F ext/fts5/test/fts5simple3.test 25faa8cb8ad470c6f01f670bcc1317c19a89f091
|
||||
F ext/fts5/test/fts5synonym.test f964f9a98580dec06c995d4638ecb36eee60ae4a
|
||||
F ext/fts5/test/fts5synonym.test 6475d189c2e20d60795808f83e36bf9318708d48
|
||||
F ext/fts5/test/fts5synonym2.test aa4c43bd3b691ff80f658cb064f5ab40690e834e
|
||||
F ext/fts5/test/fts5tok1.test beb894c6f3468f10a574302f69ebe4436b0287c7
|
||||
F ext/fts5/test/fts5tok2.test dcacb32d4a2a3f0dd3215d4a3987f78ae4be21a2
|
||||
F ext/fts5/test/fts5tokenizer.test f64ab5fe48fa1317ff6315264bfe26e73cbdefde
|
||||
F ext/fts5/test/fts5tokenizer.test ea4df698b35cc427ebf2ba22829d0e28386d8c89
|
||||
F ext/fts5/test/fts5unicode.test fbef8d8a3b4b88470536cc57604a82ca52e51841
|
||||
F ext/fts5/test/fts5unicode2.test 529ac7e8648c943bc87bfed1e427128a2f3f9e33
|
||||
F ext/fts5/test/fts5unicode3.test 35c3d02aa7acf7d43d8de3bfe32c15ba96e8928e
|
||||
@@ -202,7 +202,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
|
||||
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
|
||||
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c 84900472a088a3a172c6c079f58a1d3a1952c332
|
||||
F ext/icu/icu.c 03ff6f90f3004a7e5a86205b581b2b7035ebf6e1
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
|
||||
F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d
|
||||
@@ -213,7 +213,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c 552a7d730863419e05dc947265b28bd411680e2e
|
||||
F ext/misc/json1.c e0797ef1bfa637429ceab9140ecba620809ee02a
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
@@ -222,7 +222,6 @@ F ext/misc/remember.c 8440f8d0b452c5cdefb62b57135ccd1267aa729d
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/scrub.c 1c5bfb8b0cd18b602fcb55755e84abf0023ac2fb
|
||||
F ext/misc/series.c e11e534ada797d5b816d7e7a93c022306563ca35
|
||||
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c a4723b6aff748a417b5091b68a46443265c40f0d
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
@@ -264,7 +263,7 @@ F ext/rbu/sqlite3rbu.c bb0de6cdbdb14a7d55a097238a434b7e99caf318
|
||||
F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
|
||||
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 0c229d23ce7b9bc69365281689065f3cbbe4561e
|
||||
F ext/rtree/rtree.c 078fc27417b48aaebe988621bf96ef0e1645b201
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 42dadfc7b44a436cd74a1bebc0b9b689e4eaf7ec
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -275,7 +274,7 @@ F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196
|
||||
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
|
||||
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
|
||||
F ext/rtree/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea
|
||||
F ext/rtree/rtreeA.test ac8b503931f2f397cc3c3303354e1e085dcadb86
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
|
||||
F ext/rtree/rtreeC.test c0a9c67f2efa98b6fae12acb8a28348d231a481d
|
||||
F ext/rtree/rtreeD.test bdfaaf26df8b4eea7364039aca9150bc1e1f8825
|
||||
@@ -288,7 +287,7 @@ F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
|
||||
F ext/session/session1.test c8a50e0e8581dc1a00e832aa59bb61f180404d44
|
||||
F ext/session/session1.test e5125b216d1e8c91e0984b361b0b68529e7c5dfb
|
||||
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
|
||||
F ext/session/session3.test a7a9ce59b8d1e49e2cc23d81421ac485be0eea01
|
||||
F ext/session/session4.test 457b02bdc349eb01151e54de014df77abd3c08c8
|
||||
@@ -304,20 +303,18 @@ F ext/session/sessionE.test e60a238c47f0feb3bb707e7f35e22be09c7e8f26
|
||||
F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce
|
||||
F ext/session/sessionG.test 01ef705096a9d3984eebdcca79807a211dee1b60
|
||||
F ext/session/session_common.tcl 9b696a341cf1d3744823715ed92bb19749b6c3d4
|
||||
F ext/session/session_speed_test.c edc1f96fd5e0e4b16eb03e2a73041013d59e8723
|
||||
F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7
|
||||
F ext/session/sessionfault2.test 04aa0bc9aa70ea43d8de82c4f648db4de1e990b0
|
||||
F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc
|
||||
F ext/session/sqlite3session.c c61a43396368ec00dc127f7bc647e9bd6a4ee5fb
|
||||
F ext/session/sqlite3session.h 9345166bd8f80562145586cf817f707de5ecada2
|
||||
F ext/session/test_session.c eb0bd6c1ea791c1d66ee4ef94c16500dad936386
|
||||
F ext/userauth/sqlite3userauth.h 19cb6f0e31316d0ee4afdfb7a85ef9da3333a220
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk afc52937b4e5fe08678e8d5a4fe4487d44e3bc61
|
||||
F main.mk 8f620f3418d7252a3f428f5aacf674b5507807a8
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -330,13 +327,13 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121
|
||||
F src/analyze.c ac7a5d7e3cee07d074697904e00e4a8ab7b2b4f5
|
||||
F src/analyze.c 317dbaf31c16050582b09bf4f323b4e0f1813251
|
||||
F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
|
||||
F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 9fe65ab418d99e80289f024016b5e5e74c3059dd
|
||||
F src/btree.c e6b8f39d7dd1ad65f1747956de36f2595172a23d
|
||||
F src/btree.h e6d352808956ec163a17f832193a3e198b3fb0ac
|
||||
F src/btreeInt.h 10c4b77c2fb399580babbcc7cf652ac10dba796e
|
||||
F src/build.c 9e799f1edd910dfa8a0bc29bd390d35d310596af
|
||||
@@ -345,8 +342,8 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 9f2296a4e5d26ebf0e0d95a0af4628f1ea694e7a
|
||||
F src/date.c dc3f1391d9297f8c748132813aaffcb117090d6e
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c d29114e9b709eaeaaa18553a5bbe60a19302aeef
|
||||
F src/delete.c 8a444fea8340989d6b1be2e122c55bfc61ce69be
|
||||
F src/expr.c f06f41e5e5daca10fb090e70a2502dcc0dbc992b
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae
|
||||
F src/func.c c67273e1ec08abbdcc14c189892a3ff6eeece86b
|
||||
@@ -355,7 +352,7 @@ F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 444354c23d4d140a57d6eb46f34e376a7f8f62e8
|
||||
F src/insert.c 05e47e2de7b712a3a4148cd469e5f60873f5ef13
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c a68d8d1d14cf7488bb29dc5311cb1ce9a4404258
|
||||
F src/main.c e207b81542d13b9f13d61e78ca441f9781f055b0
|
||||
@@ -380,25 +377,25 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
|
||||
F src/os_win.c cf90abd4e50d9f56d2c20ce8e005aff55d7bd8e9
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b
|
||||
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
|
||||
F src/parse.y 591704fce84f814d9a3642774c1f011d38f4149c
|
||||
F src/pager.c 9dc72d23eebbdf992bd69f2ab954d0d3a27c7340
|
||||
F src/pager.h d1e944291030351f362a0a7da9b5c3e34e603e39
|
||||
F src/parse.y 29153738a7322054359320eb00b5a4cd44389f20
|
||||
F src/pcache.c 51070ec9b8251bbf9c6ea3d35fd96a458752929e
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c e3967219b2a92b9edcb9324a4ba75009090d3953
|
||||
F src/pragma.c 7831956012f5d764761fbd023e59b0ffc08f5e8d
|
||||
F src/pragma.c 0e7a7c6f1c6fd8ff50c0fff65b8bb80174bc49c5
|
||||
F src/pragma.h 61aa5389118594bebb28120a6720401aee34ce1a
|
||||
F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a
|
||||
F src/printf.c ff10a9b9902cd2afe5f655f3013c6307d969b1fd
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c f9bc0de45a30a450da47b3766de00be89bf9be79
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f
|
||||
F src/shell.c a84e453c213f3e0d6935a582024da4e242f85a19
|
||||
F src/sqlite.h.in 878b0f81f3f59d1f24c002127dd18740a81ba32a
|
||||
F src/select.c 3856db523b942062bca8722ba03b61c324ff94d6
|
||||
F src/shell.c 0344f71dc008df2433ae10175f59ad432c428810
|
||||
F src/sqlite.h.in e71655293c9bde26939496f3aac9d1821d2c07a2
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
|
||||
F src/sqliteInt.h 3724c48e82605b471bbf7e41109b5850c6e89f31
|
||||
F src/sqliteInt.h 525c061ae9aafc8d4720a018d82f0936d9eee5ab
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@@ -419,7 +416,7 @@ F src/test_bestindex.c d23f80d334c59662af69191854c76b8d3d0c8c96
|
||||
F src/test_blob.c 6a4c7920d1d9c6cc0f7aa50c89c4f80016aeda83
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 83179ea845479b5be9a651d014649e3f2722a1fe
|
||||
F src/test_delete.c af7eab5702f853fb1c62a5f7665e2234cf1ae17b
|
||||
F src/test_delete.c 8499d4d323f2ec8e28301deb3d6ddd8eef8b8139
|
||||
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
|
||||
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
|
||||
F src/test_fs.c e16cbe68d3b107e00a907c20a9a02629870eb69b
|
||||
@@ -453,19 +450,19 @@ F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff
|
||||
F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 25ccc63ae2c4163933221f3181c9982b47cd08d2
|
||||
F src/tokenize.c 5c2f516876fc27fbd7753913f032f49eb89e83b5
|
||||
F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c
|
||||
F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182
|
||||
F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58
|
||||
F src/update.c b356b29d04c71f33c779f2cb557cf953819bdd7a
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c a88b0466fddf445ce752226d4698ca3faada620a
|
||||
F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16
|
||||
F src/vdbe.c e7b1e860140f1d1803c6f4176b1e8f3801f3a290
|
||||
F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c
|
||||
F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f
|
||||
F src/vdbeapi.c 3e4a8893feeb78620f4aac4ac5b85d92255b97e1
|
||||
F src/vdbeaux.c b9a36e530e6525ca9d9a685bc7b1d01fa77b5cf8
|
||||
F src/vdbeblob.c a0e2edbfff53935c5434e2bce031801decd0e6dd
|
||||
F src/vdbe.c 132f552033f72820c27a100861fa83254358cbcd
|
||||
F src/vdbe.h b0866e4191f096f1c987a84b042c3599bdf5423b
|
||||
F src/vdbeInt.h 4cad10b68ed052104a997454540ea71ceb2888e1
|
||||
F src/vdbeapi.c d6ebaa465f070eb1af8ba4e7b34583ece87bdd24
|
||||
F src/vdbeaux.c 35c9a9908174e5a26c96d15e1f98214814a39147
|
||||
F src/vdbeblob.c 824f360105b8cd43c2ec8c4611fd3b162a3a3eed
|
||||
F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd
|
||||
F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face
|
||||
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
|
||||
@@ -476,7 +473,7 @@ F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
||||
F src/where.c bc71775e23d23334e8f449aa31012d692dc09cb2
|
||||
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
|
||||
F src/wherecode.c 99a8ced164c75edf41b3a865a75381c9adb38b28
|
||||
F src/wherecode.c e04ac8f24c3ac8621df6c3be3ac8c7d4fa893745
|
||||
F src/whereexpr.c 35ad025389a632a3987a35617c878be3b3d70dc6
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@@ -652,7 +649,7 @@ F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
|
||||
F test/e_blobclose.test 4b3c8c60c2171164d472059c73e9f3c1844bb66d
|
||||
F test/e_blobopen.test e95e1d40f995056f6f322cd5e1a1b83a27e1a145
|
||||
F test/e_blobwrite.test 98c2f532be5b4e5f7b4d653f716bec06835b7957
|
||||
F test/e_blobwrite.test 650ded42ee5e0c2dbf263583ce01adf280129599
|
||||
F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579
|
||||
F test/e_createtable.test d4c6059d44dcd4b636de9aae322766062b471844
|
||||
F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
|
||||
@@ -682,7 +679,7 @@ F test/eqp.test 3fe051af50921284189d1970eb653f9fcf5117d2
|
||||
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
|
||||
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
|
||||
F test/exclusive.test 9a57bd66e39144b888ca75c309914fcdefb4e3f9
|
||||
F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7
|
||||
F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
|
||||
F test/expr.test 66a2c9ac34f74f036faa4092f5402c7d3162fc93
|
||||
@@ -835,8 +832,7 @@ F test/gcfault.test dd28c228a38976d6336a3fc42d7e5f1ad060cb8c
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
|
||||
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
|
||||
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
|
||||
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/hook.test 3a01b876691f9151d3e44562354f7d663ff90fce
|
||||
F test/icu.test 73956798bace8982909c00476b216714a6d0559a
|
||||
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
@@ -847,7 +843,7 @@ F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 6c006e0bcd7351b69350ef566e65f244023489e9
|
||||
F test/incrblob.test c9b96afc292aeff43d6687bcb09b0280aa599822
|
||||
F test/incrblob2.test a5ce5ed1d0b01e2ed347245a21170372528af0a5
|
||||
F test/incrblob3.test f1b473c65d8bb43b5f4e2bdcc3f7fc3ac83fd19c
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
F test/incrblob4.test 21a52a6843a56cdcce968c6a86b72a7066d0e6ba
|
||||
F test/incrblob_err.test 69f9247fed50278d48ea710d1a8f9cdb09e4c0b8
|
||||
F test/incrblobfault.test 280474078f6da9e732cd2a215d3d854969014b6e
|
||||
@@ -902,7 +898,7 @@ F test/json101.test c0897616f32d95431f37fd291cb78742181980ac
|
||||
F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a
|
||||
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
|
||||
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
|
||||
F test/kvtest.c 7a3c38ee56b9cc45dc5a5edc50fd9bc9425659a9
|
||||
F test/kvtest.c 9e428931f0733b5ba65b6b5abd95b27320e875a3
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 0603f4fa0dad50987f70032c05800cbfa8985302
|
||||
@@ -1155,7 +1151,7 @@ F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012
|
||||
F test/tabfunc01.test 8b2ef53caa37854864c89e1e57e8a10efd4f5e43
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
@@ -1167,7 +1163,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 2a49c1aff731f380ea640106377e19611a1443ae
|
||||
F test/tester.tcl 4ce5afd5e192db4cae178e1a983b060e0f08c5d6
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1358,7 +1354,7 @@ F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
|
||||
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
|
||||
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
|
||||
F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
|
||||
F test/update2.test 81772e5c9b93d1006d66d65e9a1327281bdec4e8
|
||||
F test/update2.test 7f72ef307d58be09a8ef61db23a7ef60e5af019d
|
||||
F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
|
||||
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
|
||||
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
|
||||
@@ -1478,9 +1474,8 @@ F tool/fuzzershell.c dbf6c26eef936ec78cb0707570de3a4308b2507e
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
|
||||
F tool/lemon.c 5ccba178a8e8a4b21e1c9232944d23973da38ad7
|
||||
F tool/lempar.c db1bdb4821f2d8fbd76e577cf3ab18642c8d08d1
|
||||
F tool/lempar.c 320d630b44da693407684c64d9fa91a163419dac
|
||||
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
|
||||
@@ -1512,7 +1507,7 @@ F tool/showstat4.c b14159aa062f661b394ba37b6b7b94bfb8012ab9
|
||||
F tool/showwal.c ec79959834f7b21f1e0a2aa52bb7c056d2203977
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/spaceanal.tcl ab7d9bf68062907282a64b3e12ccbfad47193c5a
|
||||
F tool/speed-check.sh 9630ba0468b609c52f48309243d4eb6e9c34deda
|
||||
F tool/speed-check.sh 65ac2f5b00771b9dcefb95bebae1aab76c537ea3
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
@@ -1552,7 +1547,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 53b77838f05b4805b956b5763c75af434662fb20 97ccf3e4de11ffea46993cb7fb7ab559b9810705
|
||||
R 2f9978803a25617be0ce666b2a1de5c0
|
||||
U drh
|
||||
Z 44ad075deb400520ebcde6cf0102f52f
|
||||
P ffda1d1e1c858abd02f0c07b906cfac5ad075498
|
||||
R c37bc6770e2789d7f8851d61fd232055
|
||||
U dan
|
||||
Z a07b3b8a92ddc391359da9de406f8455
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
61bd2a885da45e7fa4f02ea1c44d6706faa6bf46
|
||||
74ad80eb745c708bdbbbf24cbbbf50971e84182f
|
||||
@@ -797,12 +797,6 @@ static const FuncDef statPushFuncdef = {
|
||||
** The content to returned is determined by the parameter J
|
||||
** which is one of the STAT_GET_xxxx values defined above.
|
||||
**
|
||||
** The stat_get(P,J) function is not available to generic SQL. It is
|
||||
** inserted as part of a manually constructed bytecode program. (See
|
||||
** the callStatGet() routine below.) It is guaranteed that the P
|
||||
** parameter will always be a poiner to a Stat4Accum object, never a
|
||||
** NULL.
|
||||
**
|
||||
** If neither STAT3 nor STAT4 are enabled, then J is always
|
||||
** STAT_GET_STAT1 and is hence omitted and this routine becomes
|
||||
** a one-parameter function, stat_get(P), that always returns the
|
||||
|
||||
+66
-86
@@ -4038,12 +4038,7 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
||||
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
|
||||
assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
|
||||
sqlite3BtreeEnter(p);
|
||||
if( op==SAVEPOINT_ROLLBACK ){
|
||||
rc = saveAllCursors(pBt, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
|
||||
}
|
||||
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
|
||||
pBt->nPage = 0;
|
||||
@@ -4429,6 +4424,7 @@ static int copyPayload(
|
||||
**
|
||||
** 0: The operation is a read. Populate the overflow cache.
|
||||
** 1: The operation is a write. Populate the overflow cache.
|
||||
** 2: The operation is a read. Do not populate the overflow cache.
|
||||
**
|
||||
** A total of "amt" bytes are read or written beginning at "offset".
|
||||
** Data is read to or from the buffer pBuf.
|
||||
@@ -4436,13 +4432,13 @@ static int copyPayload(
|
||||
** The content being read or written might appear on the main page
|
||||
** or be scattered out on multiple overflow pages.
|
||||
**
|
||||
** If the current cursor entry uses one or more overflow pages
|
||||
** this function may allocate space for and lazily populate
|
||||
** the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** If the current cursor entry uses one or more overflow pages and the
|
||||
** eOp argument is not 2, this function may allocate space for and lazily
|
||||
** populates the overflow page-list cache array (BtCursor.aOverflow).
|
||||
** Subsequent calls use this cache to make seeking to the supplied offset
|
||||
** more efficient.
|
||||
**
|
||||
** Once an overflow page-list cache has been allocated, it must be
|
||||
** Once an overflow page-list cache has been allocated, it may be
|
||||
** invalidated if some other cursor writes to the same table, or if
|
||||
** the cursor is moved to a different row. Additionally, in auto-vacuum
|
||||
** mode, the following events may invalidate an overflow page-list cache.
|
||||
@@ -4464,17 +4460,21 @@ static int accessPayload(
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
|
||||
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
unsigned char * const pBufStart = pBuf; /* Start of original out buffer */
|
||||
unsigned char * const pBufStart = pBuf;
|
||||
int bEnd; /* True if reading to end of data */
|
||||
#endif
|
||||
|
||||
assert( pPage );
|
||||
assert( eOp==0 || eOp==1 );
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
|
||||
|
||||
getCellInfo(pCur);
|
||||
aPayload = pCur->info.pPayload;
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
bEnd = offset+amt==pCur->info.nPayload;
|
||||
#endif
|
||||
assert( offset+amt <= pCur->info.nPayload );
|
||||
|
||||
assert( aPayload > pPage->aData );
|
||||
@@ -4493,7 +4493,7 @@ static int accessPayload(
|
||||
if( a+offset>pCur->info.nLocal ){
|
||||
a = pCur->info.nLocal - offset;
|
||||
}
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
|
||||
rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
|
||||
offset = 0;
|
||||
pBuf += a;
|
||||
amt -= a;
|
||||
@@ -4509,13 +4509,14 @@ static int accessPayload(
|
||||
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
|
||||
|
||||
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
|
||||
** Except, do not allocate aOverflow[] for eOp==2.
|
||||
**
|
||||
** The aOverflow[] array is sized at one entry for each overflow page
|
||||
** in the overflow chain. The page number of the first overflow page is
|
||||
** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
|
||||
** means "not yet known" (the cache is lazily populated).
|
||||
*/
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
|
||||
if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
|
||||
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
|
||||
if( nOvfl>pCur->nOvflAlloc ){
|
||||
Pgno *aNew = (Pgno*)sqlite3Realloc(
|
||||
@@ -4530,25 +4531,29 @@ static int accessPayload(
|
||||
}
|
||||
memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
|
||||
pCur->curFlags |= BTCF_ValidOvfl;
|
||||
}else{
|
||||
/* If the overflow page-list cache has been allocated and the
|
||||
** entry for the first required overflow page is valid, skip
|
||||
** directly to it.
|
||||
*/
|
||||
if( pCur->aOverflow[offset/ovflSize] ){
|
||||
iIdx = (offset/ovflSize);
|
||||
nextPage = pCur->aOverflow[iIdx];
|
||||
offset = (offset%ovflSize);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the overflow page-list cache has been allocated and the
|
||||
** entry for the first required overflow page is valid, skip
|
||||
** directly to it.
|
||||
*/
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0
|
||||
&& pCur->aOverflow[offset/ovflSize]
|
||||
){
|
||||
iIdx = (offset/ovflSize);
|
||||
nextPage = pCur->aOverflow[iIdx];
|
||||
offset = (offset%ovflSize);
|
||||
}
|
||||
|
||||
assert( rc==SQLITE_OK && amt>0 );
|
||||
while( nextPage ){
|
||||
/* If required, populate the overflow page-list cache. */
|
||||
assert( pCur->aOverflow[iIdx]==0
|
||||
|| pCur->aOverflow[iIdx]==nextPage
|
||||
|| CORRUPT_DB );
|
||||
pCur->aOverflow[iIdx] = nextPage;
|
||||
if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
|
||||
assert( pCur->aOverflow[iIdx]==0
|
||||
|| pCur->aOverflow[iIdx]==nextPage
|
||||
|| CORRUPT_DB );
|
||||
pCur->aOverflow[iIdx] = nextPage;
|
||||
}
|
||||
|
||||
if( offset>=ovflSize ){
|
||||
/* The only reason to read this page is to obtain the page
|
||||
@@ -4556,7 +4561,11 @@ static int accessPayload(
|
||||
** data is not required. So first try to lookup the overflow
|
||||
** page-list cache, if any, then fall back to the getOverflowPage()
|
||||
** function.
|
||||
**
|
||||
** Note that the aOverflow[] array must be allocated because eOp!=2
|
||||
** here. If eOp==2, then offset==0 and this branch is never taken.
|
||||
*/
|
||||
assert( eOp!=2 );
|
||||
assert( pCur->curFlags & BTCF_ValidOvfl );
|
||||
assert( pCur->pBtree->db==pBt->db );
|
||||
if( pCur->aOverflow[iIdx+1] ){
|
||||
@@ -4570,7 +4579,7 @@ static int accessPayload(
|
||||
** range of data that is being read (eOp==0) or written (eOp!=0).
|
||||
*/
|
||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
sqlite3_file *fd; /* File from which to do direct overflow read */
|
||||
sqlite3_file *fd;
|
||||
#endif
|
||||
int a = amt;
|
||||
if( a + offset > ovflSize ){
|
||||
@@ -4582,25 +4591,27 @@ static int accessPayload(
|
||||
**
|
||||
** 1) this is a read operation, and
|
||||
** 2) data is required from the start of this overflow page, and
|
||||
** 3) there is no open write-transaction, and
|
||||
** 4) the database is file-backed, and
|
||||
** 5) the page is not in the WAL file
|
||||
** 6) at least 4 bytes have already been read into the output buffer
|
||||
** 3) the database is file-backed, and
|
||||
** 4) there is no open write-transaction, and
|
||||
** 5) the database is not a WAL database,
|
||||
** 6) all data from the page is being read.
|
||||
** 7) at least 4 bytes have already been read into the output buffer
|
||||
**
|
||||
** then data can be read directly from the database file into the
|
||||
** output buffer, bypassing the page-cache altogether. This speeds
|
||||
** up loading large records that span many overflow pages.
|
||||
*/
|
||||
if( eOp==0 /* (1) */
|
||||
if( (eOp&0x01)==0 /* (1) */
|
||||
&& offset==0 /* (2) */
|
||||
&& pBt->inTransaction==TRANS_READ /* (3) */
|
||||
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (4) */
|
||||
&& 0==sqlite3PagerUseWal(pBt->pPager, nextPage) /* (5) */
|
||||
&& &pBuf[-4]>=pBufStart /* (6) */
|
||||
&& (bEnd || a==ovflSize) /* (6) */
|
||||
&& pBt->inTransaction==TRANS_READ /* (4) */
|
||||
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
|
||||
&& 0==sqlite3PagerUseWal(pBt->pPager) /* (5) */
|
||||
&& &pBuf[-4]>=pBufStart /* (7) */
|
||||
){
|
||||
u8 aSave[4];
|
||||
u8 *aWrite = &pBuf[-4];
|
||||
assert( aWrite>=pBufStart ); /* due to (6) */
|
||||
assert( aWrite>=pBufStart ); /* hence (7) */
|
||||
memcpy(aSave, aWrite, 4);
|
||||
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
|
||||
nextPage = get4byte(aWrite);
|
||||
@@ -4611,27 +4622,27 @@ static int accessPayload(
|
||||
{
|
||||
DbPage *pDbPage;
|
||||
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
|
||||
(eOp==0 ? PAGER_GET_READONLY : 0)
|
||||
((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
aPayload = sqlite3PagerGetData(pDbPage);
|
||||
nextPage = get4byte(aPayload);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
|
||||
rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
amt -= a;
|
||||
if( amt==0 ) return rc;
|
||||
pBuf += a;
|
||||
}
|
||||
if( amt==0 ) break;
|
||||
if( rc ) break;
|
||||
iIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && amt>0 ){
|
||||
return SQLITE_CORRUPT_BKPT; /* Overflow chain ends prematurely */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -4660,34 +4671,21 @@ int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** This variant of sqlite3BtreePayload() works even if the cursor has not
|
||||
** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read()
|
||||
** interface.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
static SQLITE_NOINLINE int accessPayloadChecked(
|
||||
BtCursor *pCur,
|
||||
u32 offset,
|
||||
u32 amt,
|
||||
void *pBuf
|
||||
){
|
||||
int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
int rc;
|
||||
if ( pCur->eState==CURSOR_INVALID ){
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
rc = btreeRestoreCursorPosition(pCur);
|
||||
return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0);
|
||||
}
|
||||
int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
if( pCur->eState==CURSOR_VALID ){
|
||||
assert( cursorOwnsBtShared(pCur) );
|
||||
return accessPayload(pCur, offset, amt, pBuf, 0);
|
||||
}else{
|
||||
return accessPayloadChecked(pCur, offset, amt, pBuf);
|
||||
rc = restoreCursorPosition(pCur);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
rc = accessPayload(pCur, offset, amt, pBuf, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_INCRBLOB */
|
||||
|
||||
@@ -5093,26 +5091,9 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
*pRes = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->info.nKey<intKey ){
|
||||
if( (pCur->curFlags & BTCF_AtLast)!=0 ){
|
||||
*pRes = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
/* If the requested key is one more than the previous key, then
|
||||
** try to get there using sqlite3BtreeNext() rather than a full
|
||||
** binary search. This is an optimization only. The correct answer
|
||||
** is still obtained without this ase, only a little more slowely */
|
||||
if( pCur->info.nKey+1==intKey && !pCur->skipNext ){
|
||||
*pRes = 0;
|
||||
rc = sqlite3BtreeNext(pCur, pRes);
|
||||
if( rc ) return rc;
|
||||
if( *pRes==0 ){
|
||||
getCellInfo(pCur);
|
||||
if( pCur->info.nKey==intKey ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
|
||||
*pRes = -1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5248,8 +5229,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
pCur->curFlags &= ~BTCF_ValidOvfl;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
goto moveto_finish;
|
||||
|
||||
+1
-3
@@ -715,9 +715,7 @@ void sqlite3GenerateRowDelete(
|
||||
u8 p5 = 0;
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
|
||||
if( pParse->nested==0 ){
|
||||
sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
|
||||
}
|
||||
sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
|
||||
if( eMode!=ONEPASS_OFF ){
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
|
||||
}
|
||||
|
||||
+28
-42
@@ -967,13 +967,8 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
i64 i;
|
||||
int bOk;
|
||||
if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/
|
||||
i = z[1]-'0'; /* The common case of ?N for a single digit N */
|
||||
bOk = 1;
|
||||
}else{
|
||||
bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
|
||||
}
|
||||
int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
|
||||
x = (ynVar)i;
|
||||
testcase( i==0 );
|
||||
testcase( i==1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
|
||||
@@ -983,7 +978,6 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
|
||||
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
|
||||
return;
|
||||
}
|
||||
x = (ynVar)i;
|
||||
if( x>pParse->nVar ){
|
||||
pParse->nVar = (int)x;
|
||||
doAdd = 1;
|
||||
@@ -1418,41 +1412,33 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
||||
Select *pRet = 0;
|
||||
Select *pNext = 0;
|
||||
Select **pp = &pRet;
|
||||
Select *p;
|
||||
|
||||
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
Select *pNew, *pPrior;
|
||||
assert( db!=0 );
|
||||
for(p=pDup; p; p=p->pPrior){
|
||||
Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
|
||||
if( pNew==0 ) break;
|
||||
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
|
||||
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
|
||||
pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
|
||||
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
|
||||
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
|
||||
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
|
||||
pNew->op = p->op;
|
||||
pNew->pNext = pNext;
|
||||
pNew->pPrior = 0;
|
||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
||||
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
|
||||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
sqlite3SelectSetName(pNew, p->zSelName);
|
||||
*pp = pNew;
|
||||
pp = &pNew->pPrior;
|
||||
pNext = pNew;
|
||||
}
|
||||
|
||||
return pRet;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
|
||||
pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
|
||||
pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
|
||||
pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
|
||||
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
|
||||
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
|
||||
pNew->op = p->op;
|
||||
pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = 0;
|
||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
||||
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
|
||||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
sqlite3SelectSetName(pNew, p->zSelName);
|
||||
return pNew;
|
||||
}
|
||||
#else
|
||||
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
|
||||
+5
-32
@@ -1668,25 +1668,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_NULL_TRIM
|
||||
/*
|
||||
** Change the P5 operand on the last opcode (which should be an OP_MakeRecord)
|
||||
** to be the number of columns in table pTab that must not be NULL-trimmed.
|
||||
**
|
||||
** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero.
|
||||
*/
|
||||
void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
|
||||
u16 i;
|
||||
|
||||
/* Records with omitted columns are only allowed for schema format
|
||||
** version 2 and later (SQLite version 3.1.4, 2005-02-20). */
|
||||
if( pTab->pSchema->file_format<2 ) return;
|
||||
|
||||
for(i=pTab->nCol; i>1 && pTab->aCol[i-1].pDflt==0; i--){}
|
||||
sqlite3VdbeChangeP5(v, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine generates code to finish the INSERT or UPDATE operation
|
||||
** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
||||
@@ -1730,30 +1711,22 @@ void sqlite3CompleteInsertion(
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
||||
pik_flags = 0;
|
||||
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
assert( pParse->nested==0 );
|
||||
pik_flags |= OPFLAG_NCHANGE;
|
||||
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( update_flags==0 ){
|
||||
sqlite3VdbeAddOp4(v, OP_InsertInt,
|
||||
iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
|
||||
);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
||||
sqlite3VdbeChangeP5(v, pik_flags);
|
||||
}
|
||||
if( !HasRowid(pTab) ) return;
|
||||
regData = regNewData + 1;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
|
||||
sqlite3SetMakeRecordP5(v, pTab);
|
||||
if( !bAffinityDone ){
|
||||
sqlite3TableAffinity(v, pTab, 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
|
||||
|
||||
+6
-12
@@ -814,20 +814,14 @@ static const unsigned char aJournalMagic[] = {
|
||||
#define isOpen(pFd) ((pFd)->pMethods!=0)
|
||||
|
||||
/*
|
||||
** Return true if this pager uses a write-ahead log to read page pgno.
|
||||
** Return false if the pager reads pgno directly from the database.
|
||||
** Return true if this pager uses a write-ahead log instead of the usual
|
||||
** rollback journal. Otherwise false.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_DIRECT_OVERFLOW_READ)
|
||||
int sqlite3PagerUseWal(Pager *pPager, Pgno pgno){
|
||||
u32 iRead = 0;
|
||||
int rc;
|
||||
if( pPager->pWal==0 ) return 0;
|
||||
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
|
||||
return rc || iRead;
|
||||
}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
# define pagerUseWal(x) ((x)->pWal!=0)
|
||||
int sqlite3PagerUseWal(Pager *pPager){
|
||||
return (pPager->pWal!=0);
|
||||
}
|
||||
# define pagerUseWal(x) sqlite3PagerUseWal(x)
|
||||
#else
|
||||
# define pagerUseWal(x) 0
|
||||
# define pagerRollbackWal(x) 0
|
||||
|
||||
+2
-4
@@ -178,16 +178,14 @@ int sqlite3PagerSharedLock(Pager *pPager);
|
||||
int sqlite3PagerWalCallback(Pager *pPager);
|
||||
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
||||
int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
||||
# ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||
int sqlite3PagerUseWal(Pager *pPager, Pgno);
|
||||
# endif
|
||||
int sqlite3PagerUseWal(Pager *pPager);
|
||||
# ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
|
||||
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
||||
int sqlite3PagerSnapshotRecover(Pager *pPager);
|
||||
# endif
|
||||
#else
|
||||
# define sqlite3PagerUseWal(x,y) 0
|
||||
# define sqlite3PagerUseWal(x) 0
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
|
||||
-13
@@ -65,19 +65,6 @@
|
||||
*/
|
||||
#define YYPARSEFREENEVERNULL 1
|
||||
|
||||
/*
|
||||
** In the amalgamation, the parse.c file generated by lemon and the
|
||||
** tokenize.c file are concatenated. In that case, sqlite3RunParser()
|
||||
** has access to the the size of the yyParser object and so the parser
|
||||
** engine can be allocated from stack. In that case, only the
|
||||
** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked
|
||||
** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be
|
||||
** omitted.
|
||||
*/
|
||||
#ifdef SQLITE_AMALGAMATION
|
||||
# define sqlite3Parser_ENGINEALWAYSONSTACK 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Alternative datatype for the argument to the malloc() routine passed
|
||||
** into sqlite3ParserAlloc(). The default is size_t.
|
||||
|
||||
+1
-1
@@ -279,7 +279,7 @@ const char *sqlite3JournalModename(int eMode){
|
||||
** Locate a pragma in the aPragmaName[] array.
|
||||
*/
|
||||
static const PragmaName *pragmaLocate(const char *zName){
|
||||
int upr, lwr, mid = 0, rc;
|
||||
int upr, lwr, mid, rc;
|
||||
lwr = 0;
|
||||
upr = ArraySize(aPragmaName)-1;
|
||||
while( lwr<=upr ){
|
||||
|
||||
+10
-18
@@ -4186,15 +4186,7 @@ static int withExpand(
|
||||
pCte->zCteErr = "circular reference: %s";
|
||||
pSavedWith = pParse->pWith;
|
||||
pParse->pWith = pWith;
|
||||
if( bMayRecursive ){
|
||||
Select *pPrior = pSel->pPrior;
|
||||
assert( pPrior->pWith==0 );
|
||||
pPrior->pWith = pSel->pWith;
|
||||
sqlite3WalkSelect(pWalker, pPrior);
|
||||
pPrior->pWith = 0;
|
||||
}else{
|
||||
sqlite3WalkSelect(pWalker, pSel);
|
||||
}
|
||||
sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
|
||||
pParse->pWith = pWith;
|
||||
|
||||
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
|
||||
@@ -4238,12 +4230,10 @@ static int withExpand(
|
||||
*/
|
||||
static void selectPopWith(Walker *pWalker, Select *p){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
if( pParse->pWith && p->pPrior==0 ){
|
||||
With *pWith = findRightmost(p)->pWith;
|
||||
if( pWith!=0 ){
|
||||
assert( pParse->pWith==pWith );
|
||||
pParse->pWith = pWith->pOuter;
|
||||
}
|
||||
With *pWith = findRightmost(p)->pWith;
|
||||
if( pWith!=0 ){
|
||||
assert( pParse->pWith==pWith );
|
||||
pParse->pWith = pWith->pOuter;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -4293,8 +4283,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
if( p->pWith ){
|
||||
sqlite3WithPush(pParse, p->pWith, 0);
|
||||
if( pWalker->xSelectCallback2==selectPopWith ){
|
||||
sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
|
||||
}
|
||||
|
||||
/* Make sure cursor numbers have been assigned to all entries in
|
||||
@@ -4581,7 +4571,9 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
||||
sqlite3WalkSelect(&w, pSelect);
|
||||
}
|
||||
w.xSelectCallback = selectExpander;
|
||||
w.xSelectCallback2 = selectPopWith;
|
||||
if( (pSelect->selFlags & SF_MultiValue)==0 ){
|
||||
w.xSelectCallback2 = selectPopWith;
|
||||
}
|
||||
sqlite3WalkSelect(&w, pSelect);
|
||||
}
|
||||
|
||||
|
||||
+18
-6
@@ -614,6 +614,7 @@ struct ShellState {
|
||||
int autoExplain; /* Automatically turn on .explain mode */
|
||||
int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
|
||||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int vmstepsOn; /* Display VM steps before each finalize */
|
||||
int scanstatsOn; /* True to display scan stats before each finalize */
|
||||
int countChanges; /* True to display change counts */
|
||||
int backslashOn; /* Resolve C-style \x escapes in SQL input text */
|
||||
@@ -1997,6 +1998,12 @@ static int shell_exec(
|
||||
display_stats(db, pArg, 0);
|
||||
}
|
||||
|
||||
if( pArg && pArg->vmstepsOn && pStmt ){
|
||||
int iCur = sqlite3_stmt_status(pStmt, SQLITE_STMTSTATUS_VM_STEP, 0);
|
||||
FILE *out = pArg->traceOut ? pArg->traceOut : pArg->out;
|
||||
raw_printf(out, "VM steps: %d\n", iCur);
|
||||
}
|
||||
|
||||
/* print loop-counters if required */
|
||||
if( pArg && pArg->scanstatsOn ){
|
||||
display_scanstats(db, pArg);
|
||||
@@ -4288,20 +4295,15 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int c2 = zMode[0];
|
||||
if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
|
||||
p->mode = MODE_Line;
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
|
||||
p->mode = MODE_Column;
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
|
||||
p->mode = MODE_List;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
|
||||
p->mode = MODE_Html;
|
||||
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
|
||||
p->mode = MODE_Tcl;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
|
||||
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
|
||||
p->mode = MODE_Csv;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
|
||||
@@ -5302,7 +5304,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
|
||||
const char *zDbName = nArg==2 ? azArg[1] : "main";
|
||||
sqlite3_vfs *pVfs = 0;
|
||||
sqlite3_vfs *pVfs;
|
||||
if( p->db ){
|
||||
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
|
||||
if( pVfs ){
|
||||
@@ -5344,6 +5346,16 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "vmsteps", n)==0 ){
|
||||
if( nArg==2 ){
|
||||
p->vmstepsOn = booleanValue(azArg[1]);
|
||||
}else{
|
||||
raw_printf(stderr, "Usage: .vmsteps ?on|off?\n");
|
||||
rc = 1;
|
||||
}
|
||||
}else
|
||||
|
||||
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
|
||||
if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
|
||||
sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
|
||||
|
||||
+66
-103
@@ -576,7 +576,7 @@ int sqlite3_exec(
|
||||
** file that were written at the application level might have changed
|
||||
** and that adjacent bytes, even bytes within the same sector are
|
||||
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
|
||||
** flag indicates that a file cannot be deleted when open. The
|
||||
** flag indicate that a file cannot be deleted when open. The
|
||||
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
|
||||
** read-only media and cannot be changed even by processes with
|
||||
** elevated privileges.
|
||||
@@ -726,9 +726,6 @@ struct sqlite3_file {
|
||||
** <li> [SQLITE_IOCAP_ATOMIC64K]
|
||||
** <li> [SQLITE_IOCAP_SAFE_APPEND]
|
||||
** <li> [SQLITE_IOCAP_SEQUENTIAL]
|
||||
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
|
||||
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
|
||||
** <li> [SQLITE_IOCAP_IMMUTABLE]
|
||||
** </ul>
|
||||
**
|
||||
** The SQLITE_IOCAP_ATOMIC property means that all writes of
|
||||
@@ -5417,7 +5414,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
|
||||
**
|
||||
** ^In the current implementation, the update hook
|
||||
** is not invoked when conflicting rows are deleted because of an
|
||||
** is not invoked when duplication rows are deleted because of an
|
||||
** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook
|
||||
** invoked when rows are deleted using the [truncate optimization].
|
||||
** The exceptions defined in this paragraph might change in a future
|
||||
@@ -6138,27 +6135,15 @@ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: A Handle To An Open BLOB
|
||||
** KEYWORDS: {BLOB handle} {BLOB handles} {sqlite3_blob object}
|
||||
**
|
||||
** An instance of this object represents a connection to a single
|
||||
** column in a single row of a table that holds either a BLOB or string
|
||||
** and on which [sqlite3_blob_open | incremental BLOB I/O] can be performed.
|
||||
** KEYWORDS: {BLOB handle} {BLOB handles}
|
||||
**
|
||||
** An instance of this object represents an open BLOB on which
|
||||
** [sqlite3_blob_open | incremental BLOB I/O] can be performed.
|
||||
** ^Objects of this type are created by [sqlite3_blob_open()]
|
||||
** and destroyed by [sqlite3_blob_close()].
|
||||
** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
|
||||
** can be used to read or write small subsections of the BLOB.
|
||||
** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes.
|
||||
**
|
||||
** An sqlite3_blob object can be in two states: ACTIVE and RESET. When in
|
||||
** the ACTIVE state, the object is pointing to a specific entry and is
|
||||
** ready to do I/O. When RESET, the sqlite3_blob object is in standby mode,
|
||||
** is not associated with any particular row of its table,
|
||||
** and is not available for I/O.
|
||||
**
|
||||
** The sqlite3_blob object does not contain a mutex and so a single
|
||||
** sqlite3_blob object may not be safely used by multiple threads
|
||||
** concurrently.
|
||||
*/
|
||||
typedef struct sqlite3_blob sqlite3_blob;
|
||||
|
||||
@@ -6167,8 +6152,8 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** METHOD: sqlite3
|
||||
** CONSTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^(This interfaces creates an sqlite3_blob object pointing to the string
|
||||
** or BLOB located in row iRow, column zColumn, table zTable in database zDb;
|
||||
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
|
||||
** in row iRow, column zColumn, table zTable in database zDb;
|
||||
** in other words, the same BLOB that would be selected by:
|
||||
**
|
||||
** <pre>
|
||||
@@ -6185,11 +6170,10 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** and write access. ^If the flags parameter is zero, the BLOB is opened for
|
||||
** read-only access.
|
||||
**
|
||||
** ^(On success, [SQLITE_OK] is returned and the new [sqlite3_blob object]
|
||||
** is stored in *ppBlob. Otherwise an [error code] is returned and
|
||||
** *ppBlob is set to NULL.)^ ^Because *ppBlob is always set to either a
|
||||
** valid sqlite3_blob object or NULL
|
||||
** it is always safe to call [sqlite3_blob_close()]
|
||||
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
|
||||
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
||||
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
||||
** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
||||
** on *ppBlob after this function it returns.
|
||||
**
|
||||
** This function fails with SQLITE_ERROR if any of the following are true:
|
||||
@@ -6212,17 +6196,10 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** [database connection] error code and message accessible via
|
||||
** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
||||
**
|
||||
** A BLOB referenced by sqlite3_blob_open() may be read using the
|
||||
** [sqlite3_blob_read()] interface and modified by using
|
||||
** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a
|
||||
** different row of the same table using the [sqlite3_blob_reopen()]
|
||||
** interface. However, the column, table, or database of a [BLOB handle]
|
||||
** cannot be changed after the [BLOB handle] is opened.
|
||||
**
|
||||
** ^(If the row that a BLOB handle points to is modified by an
|
||||
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
|
||||
** then the BLOB handle is marked as "expired" and cannot be used
|
||||
** successfully with first being [sqlite3_blob_reopen|reopened].
|
||||
** then the BLOB handle is marked as "expired".
|
||||
** This is true if any column of the row is changed, even a column
|
||||
** other than the one the BLOB handle is open on.)^
|
||||
** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for
|
||||
@@ -6234,8 +6211,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** ^Use the [sqlite3_blob_bytes()] interface to determine the size of
|
||||
** the opened blob. ^The size of a blob may not be changed by this
|
||||
** interface. Use the [UPDATE] SQL command to change the size of a
|
||||
** blob. The [sqlite3_blob_bytes()] interface returns an arbitrary
|
||||
** number when used on an expired sqlite3_blob object.
|
||||
** blob.
|
||||
**
|
||||
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
|
||||
** and the built-in [zeroblob] SQL function may be used to create a
|
||||
@@ -6243,11 +6219,6 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
**
|
||||
** To avoid a resource leak, every open [BLOB handle] should eventually
|
||||
** be released by a call to [sqlite3_blob_close()].
|
||||
**
|
||||
** See also: [sqlite3_blob_close()],
|
||||
** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
|
||||
** [sqlite3_blob_bytes()], [sqlite3_blob_write()],
|
||||
** [sqlite3_blob_reset()].
|
||||
*/
|
||||
int sqlite3_blob_open(
|
||||
sqlite3*,
|
||||
@@ -6260,23 +6231,24 @@ int sqlite3_blob_open(
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Move an sqlite3_blob object to a New Row
|
||||
** CAPI3REF: Move a BLOB Handle to a New Row
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^This function updates an existing [sqlite3_blob object] so that it points
|
||||
** ^This function is used to move an existing blob handle so that it points
|
||||
** to a different row of the same database table. ^The new row is identified
|
||||
** by the rowid value passed as the second argument. Only the row can be
|
||||
** changed. ^The database, table and column on which the blob handle is open
|
||||
** remain the same. Moving an existing [sqlite3_blob object] to a new row is
|
||||
** remain the same. Moving an existing blob handle to a new row can be
|
||||
** faster than closing the existing handle and opening a new one.
|
||||
**
|
||||
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
|
||||
** it must exist and there must be either a blob or text value stored in
|
||||
** the nominated column.)^ ^If the new row is not present in the table, or if
|
||||
** it does not contain a blob or text value, or if another error occurs, an
|
||||
** SQLite error code is returned and the [sqlite3_blob object] is changed
|
||||
** to the RESET state.
|
||||
** ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
|
||||
** SQLite error code is returned and the blob handle is considered aborted.
|
||||
** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
|
||||
** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
|
||||
** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
|
||||
** always returns zero.
|
||||
**
|
||||
** ^This function sets the database handle error code and message.
|
||||
@@ -6284,52 +6256,38 @@ int sqlite3_blob_open(
|
||||
int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Close an sqlite3_blob object
|
||||
** CAPI3REF: Close A BLOB Handle
|
||||
** DESTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^This function is the destructor for an [sqlite3_blob object].
|
||||
** ^(The [sqlite3_blob object] is closed
|
||||
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
||||
** unconditionally. Even if this routine returns an error code, the
|
||||
** object is still closed.)^
|
||||
** handle is still closed.)^
|
||||
**
|
||||
** ^If the sqlite3_blob object being closed was opened for read-write access,
|
||||
** and is in the ACTIVE state,
|
||||
** and if the database is in auto-commit mode and there are no other open
|
||||
** read-write
|
||||
** ^If the blob handle being closed was opened for read-write access, and if
|
||||
** the database is in auto-commit mode and there are no other open read-write
|
||||
** blob handles or active write statements, the current transaction is
|
||||
** committed. ^If an error occurs while committing the transaction, an error
|
||||
** code is returned and the transaction rolled back.
|
||||
**
|
||||
** Calling this function with an argument that is not a NULL pointer or a
|
||||
** valid sqlite3_blob object pointer results in undefined behaviour.
|
||||
** ^Calling this routine
|
||||
** Calling this function with an argument that is not a NULL pointer or an
|
||||
** open blob handle results in undefined behaviour. ^Calling this routine
|
||||
** with a null pointer (such as would be returned by a failed call to
|
||||
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
|
||||
** is passed a valid sqlite3_blob objecct pointer, the values returned by the
|
||||
** is passed a valid open blob handle, the values returned by the
|
||||
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
|
||||
*/
|
||||
int sqlite3_blob_close(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset an sqlite3_blob object
|
||||
** CAPI3REF: Return The Size Of An Open BLOB
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^This function changes an [sqlite3_blob object] to the RESET state.
|
||||
** ^If the [sqlite3_blob object] was already in the RESET state, then this
|
||||
** routine is a harmless no-op.
|
||||
*/
|
||||
int sqlite3_blob_reset(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Size Of A BLOB
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^Returns the size in bytes of the BLOB or string accessible via the
|
||||
** ACTIVE [sqlite3_blob object] in its only argument. ^The
|
||||
** ^Returns the size in bytes of the BLOB accessible via the
|
||||
** successfully opened [BLOB handle] in its only argument. ^The
|
||||
** incremental blob I/O routines can only read or overwriting existing
|
||||
** content; they cannot change the size of a blob or string.
|
||||
** blob content; they cannot change the size of a blob.
|
||||
**
|
||||
** This routine only works on an [sqlite3_blob object] that has been created
|
||||
** This routine only works on a [BLOB handle] which has been created
|
||||
** by a prior successful call to [sqlite3_blob_open()] and which has not
|
||||
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
|
||||
** to this routine results in undefined and probably undesirable behavior.
|
||||
@@ -6340,9 +6298,9 @@ int sqlite3_blob_bytes(sqlite3_blob *);
|
||||
** CAPI3REF: Read Data From A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to read data from string or BLOB that an
|
||||
** [sqlite3_blob object] is pointing to into a caller-supplied buffer.
|
||||
** N bytes of data are copied into buffer Z starting at offset iOffset.)^
|
||||
** ^(This function is used to read data from an open [BLOB handle] into a
|
||||
** caller-supplied buffer. N bytes of data are copied into buffer Z
|
||||
** from the open BLOB, starting at offset iOffset.)^
|
||||
**
|
||||
** ^If offset iOffset is less than N bytes from the end of the BLOB,
|
||||
** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is
|
||||
@@ -6350,14 +6308,17 @@ int sqlite3_blob_bytes(sqlite3_blob *);
|
||||
** ^The size of the blob (and hence the maximum value of N+iOffset)
|
||||
** can be determined using the [sqlite3_blob_bytes()] interface.
|
||||
**
|
||||
** ^An attempt to read from an [sqlite3_blob object] that is in the RESET
|
||||
** state, or from a database row that has changed since the most recent
|
||||
** call to [sqlite3_blob_open()] or [sqlite3_blob_reopen()] fails with an
|
||||
** ^An attempt to read from an expired [BLOB handle] fails with an
|
||||
** error code of [SQLITE_ABORT].
|
||||
**
|
||||
** ^(On success, sqlite3_blob_read() returns SQLITE_OK.
|
||||
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
||||
**
|
||||
** This routine only works on a [BLOB handle] which has been created
|
||||
** by a prior successful call to [sqlite3_blob_open()] and which has not
|
||||
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
|
||||
** to this routine results in undefined and probably undesirable behavior.
|
||||
**
|
||||
** See also: [sqlite3_blob_write()].
|
||||
*/
|
||||
int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
@@ -6366,10 +6327,9 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
** CAPI3REF: Write Data Into A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to write data from a caller-supplied buffer
|
||||
** into a BLOB or string pointed to by an [sqlite3_blob object].
|
||||
** N bytes of data are copied from the buffer Z
|
||||
** into the BLOB or string, starting at offset iOffset.)^
|
||||
** ^(This function is used to write data into an open [BLOB handle] from a
|
||||
** caller-supplied buffer. N bytes of data are copied from the buffer Z
|
||||
** into the open BLOB, starting at offset iOffset.)^
|
||||
**
|
||||
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
|
||||
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
||||
@@ -6389,10 +6349,17 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
||||
** than zero [SQLITE_ERROR] is returned and no data is written.
|
||||
**
|
||||
** ^An attempt to write into an [sqlite3_blob object] that is in the RESET
|
||||
** state, or into a database row that has changed since the most recent
|
||||
** call to [sqlite3_blob_open()] or [sqlite3_blob_reopen()] fails with an
|
||||
** error code of [SQLITE_ABORT].
|
||||
** ^An attempt to write to an expired [BLOB handle] fails with an
|
||||
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
|
||||
** before the [BLOB handle] expired are not rolled back by the
|
||||
** expiration of the handle, though of course those changes might
|
||||
** have been overwritten by the statement that expired the BLOB handle
|
||||
** or by other independent statements.
|
||||
**
|
||||
** This routine only works on a [BLOB handle] which has been created
|
||||
** by a prior successful call to [sqlite3_blob_open()] and which has not
|
||||
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
|
||||
** to this routine results in undefined and probably undesirable behavior.
|
||||
**
|
||||
** See also: [sqlite3_blob_read()].
|
||||
*/
|
||||
@@ -8200,7 +8167,7 @@ int sqlite3_db_cacheflush(sqlite3*);
|
||||
**
|
||||
** ^The [sqlite3_preupdate_hook()] interface registers a callback function
|
||||
** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
|
||||
** on a database table.
|
||||
** on a [rowid table].
|
||||
** ^At most one preupdate hook may be registered at a time on a single
|
||||
** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
|
||||
** the previous setting.
|
||||
@@ -8209,9 +8176,9 @@ int sqlite3_db_cacheflush(sqlite3*);
|
||||
** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
|
||||
** the first parameter to callbacks.
|
||||
**
|
||||
** ^The preupdate hook only fires for changes to real database tables; the
|
||||
** preupdate hook is not invoked for changes to [virtual tables] or to
|
||||
** system tables like sqlite_master or sqlite_stat1.
|
||||
** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
|
||||
** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
|
||||
** tables.
|
||||
**
|
||||
** ^The second parameter to the preupdate callback is a pointer to
|
||||
** the [database connection] that registered the preupdate hook.
|
||||
@@ -8225,16 +8192,12 @@ int sqlite3_db_cacheflush(sqlite3*);
|
||||
** databases.)^
|
||||
** ^The fifth parameter to the preupdate callback is the name of the
|
||||
** table that is being modified.
|
||||
**
|
||||
** For an UPDATE or DELETE operation on a [rowid table], the sixth
|
||||
** parameter passed to the preupdate callback is the initial [rowid] of the
|
||||
** row being modified or deleted. For an INSERT operation on a rowid table,
|
||||
** or any operation on a WITHOUT ROWID table, the value of the sixth
|
||||
** parameter is undefined. For an INSERT or UPDATE on a rowid table the
|
||||
** seventh parameter is the final rowid value of the row being inserted
|
||||
** or updated. The value of the seventh parameter passed to the callback
|
||||
** function is not defined for operations on WITHOUT ROWID tables, or for
|
||||
** INSERT operations on rowid tables.
|
||||
** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
|
||||
** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
|
||||
** undefined for SQLITE_INSERT changes.
|
||||
** ^The seventh parameter to the preupdate callback is the final [rowid] of
|
||||
** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
|
||||
** undefined for SQLITE_DELETE changes.
|
||||
**
|
||||
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
|
||||
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
|
||||
|
||||
+5
-11
@@ -2592,7 +2592,7 @@ struct SrcList {
|
||||
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
|
||||
#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */
|
||||
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
|
||||
#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */
|
||||
/* 0x1000 not currently used */
|
||||
/* 0x2000 not currently used */
|
||||
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
|
||||
/* 0x8000 not currently used */
|
||||
@@ -3057,7 +3057,9 @@ struct AuthContext {
|
||||
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
|
||||
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
|
||||
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
|
||||
#endif
|
||||
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
|
||||
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
|
||||
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
|
||||
@@ -3788,11 +3790,6 @@ int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
|
||||
void sqlite3ResolvePartIdxLabel(Parse*,int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
|
||||
u8,u8,int,int*,int*);
|
||||
#ifdef SQLITE_ENABLE_NULL_TRIM
|
||||
void sqlite3SetMakeRecordP5(Vdbe*,Table*);
|
||||
#else
|
||||
# define sqlite3SetMakeRecordP5(A,B)
|
||||
#endif
|
||||
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
|
||||
int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
|
||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||
@@ -4071,10 +4068,8 @@ char sqlite3IndexColumnAffinity(sqlite3*, Index*, int);
|
||||
/*
|
||||
** The interface to the LEMON-generated parser
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
void *sqlite3ParserAlloc(void*(*)(u64));
|
||||
void sqlite3ParserFree(void*, void(*)(void*));
|
||||
#endif
|
||||
void *sqlite3ParserAlloc(void*(*)(u64));
|
||||
void sqlite3ParserFree(void*, void(*)(void*));
|
||||
void sqlite3Parser(void*, int, Token, Parse*);
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
int sqlite3ParserStackPeak(void*);
|
||||
@@ -4184,7 +4179,6 @@ const char *sqlite3JournalModename(int);
|
||||
#define sqlite3FkDropTable(a,b,c)
|
||||
#define sqlite3FkOldmask(a,b) 0
|
||||
#define sqlite3FkRequired(a,b,c,d) 0
|
||||
#define sqlite3FkReferences(a) 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
void sqlite3FkDelete(sqlite3 *, Table*);
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){
|
||||
** Delete the database file identified by the string argument passed to this
|
||||
** function. The string must contain a filename, not an SQLite URI.
|
||||
*/
|
||||
SQLITE_API int sqlite3_delete_database(
|
||||
int sqlite3_delete_database(
|
||||
const char *zFile /* File to delete */
|
||||
){
|
||||
char *zBuf; /* Buffer to sprintf() filenames to */
|
||||
|
||||
@@ -481,9 +481,6 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
int lastTokenParsed = -1; /* type of the previous token */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int mxSqlLen; /* Max length of an SQL string */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
unsigned char zSpace[sizeof(yyParser)]; /* Space for parser engine object */
|
||||
#endif
|
||||
|
||||
assert( zSql!=0 );
|
||||
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
||||
@@ -495,16 +492,11 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
i = 0;
|
||||
assert( pzErrMsg!=0 );
|
||||
/* sqlite3ParserTrace(stdout, "parser: "); */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
pEngine = zSpace;
|
||||
sqlite3ParserInit(pEngine);
|
||||
#else
|
||||
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
|
||||
if( pEngine==0 ){
|
||||
sqlite3OomFault(db);
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
#endif
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
assert( pParse->nVar==0 );
|
||||
@@ -556,11 +548,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
);
|
||||
sqlite3_mutex_leave(sqlite3MallocMutex());
|
||||
#endif /* YYDEBUG */
|
||||
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
||||
sqlite3ParserFinalize(pEngine);
|
||||
#else
|
||||
sqlite3ParserFree(pEngine, sqlite3_free);
|
||||
#endif
|
||||
if( db->mallocFailed ){
|
||||
pParse->rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
+1
-1
@@ -392,7 +392,7 @@ void sqlite3Update(
|
||||
** be deleted as a result of REPLACE conflict handling. Any of these
|
||||
** things might disturb a cursor being used to scan through the table
|
||||
** or index, causing a single-pass approach to malfunction. */
|
||||
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
|
||||
flags = WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE;
|
||||
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
|
||||
flags |= WHERE_ONEPASS_MULTIROW;
|
||||
}
|
||||
|
||||
+55
-40
@@ -583,6 +583,8 @@ int sqlite3VdbeExec(
|
||||
Mem *pIn2 = 0; /* 2nd input operand */
|
||||
Mem *pIn3 = 0; /* 3rd input operand */
|
||||
Mem *pOut = 0; /* Output operand */
|
||||
int *aPermute = 0; /* Permutation of columns for OP_Compare */
|
||||
i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */
|
||||
#ifdef VDBE_PROFILE
|
||||
u64 start; /* CPU clock count at start of opcode */
|
||||
#endif
|
||||
@@ -597,6 +599,7 @@ int sqlite3VdbeExec(
|
||||
}
|
||||
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
|
||||
assert( p->bIsReader || p->readOnly!=0 );
|
||||
p->rc = SQLITE_OK;
|
||||
p->iCurrentTime = 0;
|
||||
assert( p->explain==0 );
|
||||
p->pResultSet = 0;
|
||||
@@ -957,6 +960,26 @@ case OP_Halt: {
|
||||
p->nFrame--;
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
pcx = sqlite3VdbeFrameRestore(pFrame);
|
||||
#ifdef SQLITE_TRACE_TRIGGER
|
||||
if( (db->mTrace & SQLITE_TRACE_STMT) && aOp[0].p4.z ){
|
||||
int nTotal = nVmStep - pFrame->nVmStep;
|
||||
char *zTrace;
|
||||
assert( nTotal>=0 );
|
||||
assert( db->xTrace );
|
||||
zTrace = sqlite3_mprintf("%.*s%s completed (VM steps: total=%d self=%d)",
|
||||
p->nFrame, " :",
|
||||
aOp[0].p4.z, nTotal, nVmStep - pFrame->nVmStepAdj
|
||||
);
|
||||
if( zTrace ){
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, 0, zTrace);
|
||||
sqlite3_free(zTrace);
|
||||
}
|
||||
if( p->pFrame ){
|
||||
p->pFrame->nVmStepAdj += nTotal;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
lastRowid = db->lastRowid;
|
||||
if( pOp->p2==OE_Ignore ){
|
||||
/* Instruction pcx is the OP_Program that invoked the sub-program
|
||||
** currently being halted. If the p2 instruction of this OP_Halt
|
||||
@@ -1678,7 +1701,9 @@ case OP_Function: {
|
||||
#endif
|
||||
MemSetTypeFlag(pCtx->pOut, MEM_Null);
|
||||
pCtx->fErrorOrAux = 0;
|
||||
db->lastRowid = lastRowid;
|
||||
(*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
|
||||
lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */
|
||||
|
||||
/* If the function returned an error, throw an exception */
|
||||
if( pCtx->fErrorOrAux ){
|
||||
@@ -2134,8 +2159,8 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
|
||||
|
||||
/* Opcode: Permutation * * * P4 *
|
||||
**
|
||||
** Set the permutation used by the OP_Compare operator in the next
|
||||
** instruction. The permutation is stored in the P4 operand.
|
||||
** Set the permutation used by the OP_Compare operator to be the array
|
||||
** of integers in P4.
|
||||
**
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
@@ -2147,8 +2172,7 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
|
||||
case OP_Permutation: {
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
assert( pOp->p4.ai );
|
||||
assert( pOp[1].opcode==OP_Compare );
|
||||
assert( pOp[1].p5 & OPFLAG_PERMUTE );
|
||||
aPermute = pOp->p4.ai + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2181,17 +2205,8 @@ case OP_Compare: {
|
||||
int idx;
|
||||
CollSeq *pColl; /* Collating sequence to use on this term */
|
||||
int bRev; /* True for DESCENDING sort order */
|
||||
int *aPermute; /* The permutation */
|
||||
|
||||
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
|
||||
aPermute = 0;
|
||||
}else{
|
||||
assert( pOp>aOp );
|
||||
assert( pOp[-1].opcode==OP_Permutation );
|
||||
assert( pOp[-1].p4type==P4_INTARRAY );
|
||||
aPermute = pOp[-1].p4.ai + 1;
|
||||
assert( aPermute!=0 );
|
||||
}
|
||||
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
|
||||
n = pOp->p3;
|
||||
pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( n>0 );
|
||||
@@ -2224,6 +2239,7 @@ case OP_Compare: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
aPermute = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2780,20 +2796,6 @@ case OP_MakeRecord: {
|
||||
}while( zAffinity[0] );
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_NULL_TRIM
|
||||
/* NULLs can be safely trimmed from the end of the record, as long as
|
||||
** as the schema format is 2 or more and none of the omitted columns
|
||||
** have a non-NULL default value. Also, the record must be left with
|
||||
** at least one field. If P5>0 then it will be one more than the
|
||||
** index of the right-most column with a non-NULL default value */
|
||||
if( pOp->p5 ){
|
||||
while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){
|
||||
pLast--;
|
||||
nField--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Loop through the elements that will make up the record to figure
|
||||
** out how much space is required for the new record.
|
||||
*/
|
||||
@@ -4383,7 +4385,7 @@ case OP_InsertInt: {
|
||||
assert( pC!=0 );
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->uc.pCursor!=0 );
|
||||
assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
|
||||
assert( pC->isTable );
|
||||
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
|
||||
REGISTER_TRACE(pOp->p2, pData);
|
||||
|
||||
@@ -4399,13 +4401,14 @@ case OP_InsertInt: {
|
||||
}
|
||||
|
||||
if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
|
||||
assert( pC->isTable );
|
||||
assert( pC->iDb>=0 );
|
||||
zDb = db->aDb[pC->iDb].zDbSName;
|
||||
pTab = pOp->p4.pTab;
|
||||
assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
|
||||
assert( HasRowid(pTab) );
|
||||
op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
|
||||
}else{
|
||||
pTab = 0; /* Not needed. Silence a compiler warning. */
|
||||
pTab = 0; /* Not needed. Silence a comiler warning. */
|
||||
zDb = 0; /* Not needed. Silence a compiler warning. */
|
||||
}
|
||||
|
||||
@@ -4417,11 +4420,10 @@ case OP_InsertInt: {
|
||||
){
|
||||
sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_ISNOOP ) break;
|
||||
#endif
|
||||
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
|
||||
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = x.nKey;
|
||||
if( pData->flags & MEM_Null ){
|
||||
x.pData = 0;
|
||||
x.nData = 0;
|
||||
@@ -4530,11 +4532,8 @@ case OP_Delete: {
|
||||
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
/* Invoke the pre-update-hook if required. */
|
||||
if( db->xPreUpdateCallback && pOp->p4.pTab ){
|
||||
assert( !(opflags & OPFLAG_ISUPDATE)
|
||||
|| HasRowid(pTab)==0
|
||||
|| (aMem[pOp->p3].flags & MEM_Int)
|
||||
);
|
||||
if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
|
||||
assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
|
||||
sqlite3VdbePreUpdateHook(p, pC,
|
||||
(opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
|
||||
zDb, pTab, pC->movetoTarget,
|
||||
@@ -5869,11 +5868,15 @@ case OP_Program: { /* jump */
|
||||
|
||||
p->nFrame++;
|
||||
pFrame->pParent = p->pFrame;
|
||||
pFrame->lastRowid = db->lastRowid;
|
||||
pFrame->lastRowid = lastRowid;
|
||||
pFrame->nChange = p->nChange;
|
||||
pFrame->nDbChange = p->db->nChange;
|
||||
assert( pFrame->pAuxData==0 );
|
||||
pFrame->pAuxData = p->pAuxData;
|
||||
#ifdef SQLITE_TRACE_TRIGGER
|
||||
pFrame->nVmStep = nVmStep;
|
||||
pFrame->nVmStepAdj = nVmStep;
|
||||
#endif
|
||||
p->pAuxData = 0;
|
||||
p->nChange = 0;
|
||||
p->pFrame = pFrame;
|
||||
@@ -6810,7 +6813,7 @@ case OP_VUpdate: {
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK && pOp->p1 ){
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = rowid;
|
||||
db->lastRowid = lastRowid = rowid;
|
||||
}
|
||||
if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
|
||||
if( pOp->p5==OE_Ignore ){
|
||||
@@ -6909,6 +6912,17 @@ case OP_Init: { /* jump */
|
||||
x(db->pTraceArg, z);
|
||||
sqlite3_free(z);
|
||||
}else
|
||||
#endif
|
||||
#ifdef SQLITE_TRACE_TRIGGER
|
||||
if( p->pFrame ){
|
||||
zTrace = sqlite3_mprintf("%.*s%s", p->nFrame-1,
|
||||
" :", zTrace
|
||||
);
|
||||
if( zTrace ){
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
||||
sqlite3_free(zTrace);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
(void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
||||
@@ -7046,6 +7060,7 @@ abort_due_to_error:
|
||||
** release the mutexes on btrees that were acquired at the
|
||||
** top. */
|
||||
vdbe_return:
|
||||
db->lastRowid = lastRowid;
|
||||
testcase( nVmStep>0 );
|
||||
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
|
||||
sqlite3VdbeLeave(p);
|
||||
|
||||
+3
-2
@@ -41,7 +41,8 @@ typedef struct SubProgram SubProgram;
|
||||
struct VdbeOp {
|
||||
u8 opcode; /* What operation to perform */
|
||||
signed char p4type; /* One of the P4_xxx constants for p4 */
|
||||
u16 p5; /* Fifth parameter is an unsigned 16-bit integer */
|
||||
u8 notUsed1;
|
||||
u8 p5; /* Fifth parameter is an unsigned character */
|
||||
int p1; /* First operand */
|
||||
int p2; /* Second parameter (often the jump destination) */
|
||||
int p3; /* The third parameter */
|
||||
@@ -193,7 +194,7 @@ void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
|
||||
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
|
||||
void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
|
||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
|
||||
int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
|
||||
|
||||
+4
-1
@@ -175,6 +175,10 @@ struct VdbeFrame {
|
||||
int nChildCsr; /* Number of cursors for child frame */
|
||||
int nChange; /* Statement changes (Vdbe.nChange) */
|
||||
int nDbChange; /* Value of db->nChange */
|
||||
#ifdef SQLITE_TRACE_TRIGGER
|
||||
int nVmStep; /* Value of nVmStep at start of program */
|
||||
int nVmStepAdj; /* Adjusted for nested programs */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
|
||||
@@ -434,7 +438,6 @@ struct PreUpdate {
|
||||
i64 iKey2; /* Second key value passed to hook */
|
||||
Mem *aNew; /* Array of new.* values */
|
||||
Table *pTab; /* Schema object being upated */
|
||||
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+16
-18
@@ -1660,7 +1660,6 @@ static UnpackedRecord *vdbeUnpackRecord(
|
||||
*/
|
||||
int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
PreUpdate *p = db->pPreUpdate;
|
||||
Mem *pMem;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* Test that this call is being made from within an SQLITE_DELETE or
|
||||
@@ -1669,9 +1668,6 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
goto preupdate_old_out;
|
||||
}
|
||||
if( p->pPk ){
|
||||
iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
|
||||
}
|
||||
if( iIdx>=p->pCsr->nField || iIdx<0 ){
|
||||
rc = SQLITE_RANGE;
|
||||
goto preupdate_old_out;
|
||||
@@ -1697,14 +1693,17 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
p->aRecord = aRec;
|
||||
}
|
||||
|
||||
pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
|
||||
if( iIdx==p->pTab->iPKey ){
|
||||
sqlite3VdbeMemSetInt64(pMem, p->iKey1);
|
||||
}else if( iIdx>=p->pUnpacked->nField ){
|
||||
if( iIdx>=p->pUnpacked->nField ){
|
||||
*ppValue = (sqlite3_value *)columnNullValue();
|
||||
}else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
|
||||
if( pMem->flags & MEM_Int ){
|
||||
sqlite3VdbeMemRealify(pMem);
|
||||
}else{
|
||||
Mem *pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
|
||||
*ppValue = &p->pUnpacked->aMem[iIdx];
|
||||
if( iIdx==p->pTab->iPKey ){
|
||||
sqlite3VdbeMemSetInt64(pMem, p->iKey1);
|
||||
}else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
|
||||
if( pMem->flags & MEM_Int ){
|
||||
sqlite3VdbeMemRealify(pMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1757,9 +1756,6 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
goto preupdate_new_out;
|
||||
}
|
||||
if( p->pPk && p->op!=SQLITE_UPDATE ){
|
||||
iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx);
|
||||
}
|
||||
if( iIdx>=p->pCsr->nField || iIdx<0 ){
|
||||
rc = SQLITE_RANGE;
|
||||
goto preupdate_new_out;
|
||||
@@ -1780,11 +1776,13 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
|
||||
}
|
||||
p->pNewUnpacked = pUnpack;
|
||||
}
|
||||
pMem = &pUnpack->aMem[iIdx];
|
||||
if( iIdx==p->pTab->iPKey ){
|
||||
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
|
||||
}else if( iIdx>=pUnpack->nField ){
|
||||
if( iIdx>=pUnpack->nField ){
|
||||
pMem = (sqlite3_value *)columnNullValue();
|
||||
}else{
|
||||
pMem = &pUnpack->aMem[iIdx];
|
||||
if( iIdx==p->pTab->iPKey ){
|
||||
sqlite3VdbeMemSetInt64(pMem, p->iKey2);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
|
||||
|
||||
+47
-51
@@ -783,7 +783,7 @@ void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
|
||||
void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
|
||||
sqlite3VdbeGetOp(p,addr)->p3 = val;
|
||||
}
|
||||
void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
|
||||
void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
|
||||
assert( p->nOp>0 || p->db->mallocFailed );
|
||||
if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
|
||||
}
|
||||
@@ -2497,59 +2497,60 @@ static void checkActiveVdbeCnt(sqlite3 *db){
|
||||
** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
|
||||
** Otherwise SQLITE_OK.
|
||||
*/
|
||||
static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
|
||||
int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
||||
sqlite3 *const db = p->db;
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
const int iSavepoint = p->iStatement-1;
|
||||
|
||||
assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
|
||||
assert( db->nStatement>0 );
|
||||
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
|
||||
/* If p->iStatement is greater than zero, then this Vdbe opened a
|
||||
** statement transaction that should be closed here. The only exception
|
||||
** is that an IO error may have occurred, causing an emergency rollback.
|
||||
** In this case (db->nStatement==0), and there is nothing to do.
|
||||
*/
|
||||
if( db->nStatement && p->iStatement ){
|
||||
int i;
|
||||
const int iSavepoint = p->iStatement-1;
|
||||
|
||||
for(i=0; i<db->nDb; i++){
|
||||
int rc2 = SQLITE_OK;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
|
||||
assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
|
||||
assert( db->nStatement>0 );
|
||||
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
|
||||
|
||||
for(i=0; i<db->nDb; i++){
|
||||
int rc2 = SQLITE_OK;
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
|
||||
}
|
||||
if( rc2==SQLITE_OK ){
|
||||
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
if( rc2==SQLITE_OK ){
|
||||
rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
|
||||
}
|
||||
db->nStatement--;
|
||||
p->iStatement = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = rc2;
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
db->nStatement--;
|
||||
p->iStatement = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* If the statement transaction is being rolled back, also restore the
|
||||
** database handles deferred constraint counter to the value it had when
|
||||
** the statement transaction was opened. */
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
|
||||
db->nDeferredCons = p->nStmtDefCons;
|
||||
db->nDeferredImmCons = p->nStmtDefImmCons;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the statement transaction is being rolled back, also restore the
|
||||
** database handles deferred constraint counter to the value it had when
|
||||
** the statement transaction was opened. */
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
db->nDeferredCons = p->nStmtDefCons;
|
||||
db->nDeferredImmCons = p->nStmtDefImmCons;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
||||
if( p->db->nStatement && p->iStatement ){
|
||||
return vdbeCloseStatement(p, eOp);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called when a transaction opened by the database
|
||||
@@ -4584,10 +4585,10 @@ void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
|
||||
** This function is used to free UnpackedRecord structures allocated by
|
||||
** the vdbeUnpackRecord() function found in vdbeapi.c.
|
||||
*/
|
||||
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
|
||||
static void vdbeFreeUnpacked(sqlite3 *db, UnpackedRecord *p){
|
||||
if( p ){
|
||||
int i;
|
||||
for(i=0; i<nField; i++){
|
||||
for(i=0; i<p->nField; i++){
|
||||
Mem *pMem = &p->aMem[i];
|
||||
if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
@@ -4620,15 +4621,10 @@ void sqlite3VdbePreUpdateHook(
|
||||
|
||||
assert( db->pPreUpdate==0 );
|
||||
memset(&preupdate, 0, sizeof(PreUpdate));
|
||||
if( HasRowid(pTab)==0 ){
|
||||
iKey1 = iKey2 = 0;
|
||||
preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
if( op==SQLITE_UPDATE ){
|
||||
iKey2 = v->aMem[iReg].u.i;
|
||||
}else{
|
||||
if( op==SQLITE_UPDATE ){
|
||||
iKey2 = v->aMem[iReg].u.i;
|
||||
}else{
|
||||
iKey2 = iKey1;
|
||||
}
|
||||
iKey2 = iKey1;
|
||||
}
|
||||
|
||||
assert( pCsr->nField==pTab->nCol
|
||||
@@ -4651,8 +4647,8 @@ void sqlite3VdbePreUpdateHook(
|
||||
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
|
||||
db->pPreUpdate = 0;
|
||||
sqlite3DbFree(db, preupdate.aRecord);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.keyinfo.nField+1, preupdate.pNewUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.pUnpacked);
|
||||
vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
|
||||
if( preupdate.aNew ){
|
||||
int i;
|
||||
for(i=0; i<pCsr->nField; i++){
|
||||
|
||||
+38
-55
@@ -23,9 +23,10 @@
|
||||
*/
|
||||
typedef struct Incrblob Incrblob;
|
||||
struct Incrblob {
|
||||
int nByte; /* Size of open blob if ACTIVE. -1 if RESET */
|
||||
int nByte; /* Size of open blob, in bytes */
|
||||
int iOffset; /* Byte offset of blob in cursor data */
|
||||
u16 iCol; /* Table column this handle is open on */
|
||||
u8 isPureKV; /* True if pTab is a pure key/value table */
|
||||
BtCursor *pCsr; /* Cursor pointing at blob row */
|
||||
sqlite3_stmt *pStmt; /* Statement holding cursor open */
|
||||
sqlite3 *db; /* The associated database */
|
||||
@@ -33,6 +34,7 @@ struct Incrblob {
|
||||
Table *pTab; /* Table object */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** This function is used by both blob_open() and blob_reopen(). It seeks
|
||||
** the b-tree cursor associated with blob handle p to point to row iRow.
|
||||
@@ -65,24 +67,19 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
** then back it up to the point where it does the OP_SeekRowid. This could
|
||||
** have been down with an extra OP_Goto, but simply setting the program
|
||||
** counter is faster. */
|
||||
if( v->pc>3 ){
|
||||
v->pc = 3;
|
||||
rc = sqlite3VdbeExec(v);
|
||||
}else{
|
||||
rc = sqlite3_step(p->pStmt);
|
||||
}
|
||||
if( v->pc>3 ) v->pc = 3;
|
||||
|
||||
rc = sqlite3_step(p->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
VdbeCursor *pC = v->apCsr[0];
|
||||
u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
|
||||
testcase( pC->nHdrParsed==p->iCol );
|
||||
testcase( pC->nHdrParsed==p->iCol+1 );
|
||||
u32 type = pC->aType[p->iCol];
|
||||
if( type<12 ){
|
||||
zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
|
||||
type==0?"null": type==7?"real": "integer"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3_reset(p->pStmt);
|
||||
p->nByte = -1;
|
||||
sqlite3_finalize(p->pStmt);
|
||||
p->pStmt = 0;
|
||||
}else{
|
||||
p->iOffset = pC->aType[p->iCol + pC->nField];
|
||||
p->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
@@ -93,9 +90,9 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
|
||||
if( rc==SQLITE_ROW ){
|
||||
rc = SQLITE_OK;
|
||||
}else if( p->nByte>=0 ){
|
||||
rc = sqlite3_reset(p->pStmt);
|
||||
p->nByte = -1;
|
||||
}else if( p->pStmt ){
|
||||
rc = sqlite3_finalize(p->pStmt);
|
||||
p->pStmt = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow);
|
||||
rc = SQLITE_ERROR;
|
||||
@@ -156,7 +153,6 @@ int sqlite3_blob_open(
|
||||
pParse->db = db;
|
||||
sqlite3DbFree(db, zErr);
|
||||
zErr = 0;
|
||||
sqlite3_finalize(pBlob->pStmt);
|
||||
|
||||
sqlite3BtreeEnterAll(db);
|
||||
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
|
||||
@@ -322,9 +318,9 @@ int sqlite3_blob_open(
|
||||
}
|
||||
}
|
||||
|
||||
pBlob->isPureKV = (pTab->nCol==2 && pTab->iPKey==0);
|
||||
pBlob->iCol = iCol;
|
||||
pBlob->db = db;
|
||||
pBlob->nByte = 0;
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
if( db->mallocFailed ){
|
||||
goto blob_open_out;
|
||||
@@ -360,7 +356,7 @@ int sqlite3_blob_close(sqlite3_blob *pBlob){
|
||||
if( p ){
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
rc = sqlite3VdbeFinalize((Vdbe*)p->pStmt);
|
||||
rc = sqlite3_finalize(p->pStmt);
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}else{
|
||||
@@ -385,10 +381,6 @@ static int blobReadWrite(
|
||||
sqlite3 *db;
|
||||
|
||||
if( p==0 ) return SQLITE_MISUSE_BKPT;
|
||||
if( p->nByte<0 ){
|
||||
/* The blob handle is in the RESET state. Always return SQLITE_ABORT. */
|
||||
return SQLITE_ABORT;
|
||||
}
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
v = (Vdbe*)p->pStmt;
|
||||
@@ -396,6 +388,11 @@ static int blobReadWrite(
|
||||
if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){
|
||||
/* Request is out of range. Return a transient error. */
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( v==0 ){
|
||||
/* If there is no statement handle, then the blob-handle has
|
||||
** already been invalidated. Return SQLITE_ABORT in this case.
|
||||
*/
|
||||
rc = SQLITE_ABORT;
|
||||
}else{
|
||||
/* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
|
||||
** returned, clean-up the statement handle.
|
||||
@@ -429,8 +426,8 @@ static int blobReadWrite(
|
||||
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
|
||||
sqlite3BtreeLeaveCursor(p->pCsr);
|
||||
if( rc==SQLITE_ABORT ){
|
||||
sqlite3_reset(p->pStmt);
|
||||
p->nByte = -1;
|
||||
sqlite3VdbeFinalize(v);
|
||||
p->pStmt = 0;
|
||||
}else{
|
||||
v->rc = rc;
|
||||
}
|
||||
@@ -458,36 +455,14 @@ int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
|
||||
/*
|
||||
** Query a blob handle for the size of the data.
|
||||
**
|
||||
** The Incrblob.nByte field is fixed for as long as the sqlite3_blob
|
||||
** object is pointing to the same row, so no mutex is required for access.
|
||||
**
|
||||
** When the sqlite3_blob interface was first designed in 2007, we specified
|
||||
** that sqlite3_blob_bytes() returned 0 when in the RESET state. It would
|
||||
** have been better to return -1 in order to distinguish a RESET blob handle
|
||||
** from an ACTIVE blob handle pointing to a zero-length string or blob.
|
||||
** But, sadly, we cannot change that now without breaking compatibility.
|
||||
** So 0 is returned for RESET blob handles and for ACTIVE blob handles
|
||||
** pointing to zero-length blobs.
|
||||
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
|
||||
** so no mutex is required for access.
|
||||
*/
|
||||
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
return (p && p->pStmt && p->nByte>0) ? p->nByte : 0;
|
||||
return (p && p->pStmt) ? p->nByte : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the sqlite3_blob object to the RESET state. This releases
|
||||
** any locks and gets the object out of the way of commits and
|
||||
** rollbacks.
|
||||
*/
|
||||
int sqlite3_blob_reset(sqlite3_blob *pBlob){
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
if( p->nByte>=0 ){
|
||||
sqlite3_reset(p->pStmt);
|
||||
p->nByte = -1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move an existing blob handle to point to a different row of the same
|
||||
** database table.
|
||||
@@ -502,20 +477,28 @@ int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
||||
int rc;
|
||||
Incrblob *p = (Incrblob *)pBlob;
|
||||
sqlite3 *db;
|
||||
char *zErr;
|
||||
|
||||
if( p==0 ) return SQLITE_MISUSE_BKPT;
|
||||
db = p->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
rc = blobSeekToRow(p, iRow, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
if( p->pStmt==0 ){
|
||||
/* If there is no statement handle, then the blob-handle has
|
||||
** already been invalidated. Return SQLITE_ABORT in this case.
|
||||
*/
|
||||
rc = SQLITE_ABORT;
|
||||
}else{
|
||||
char *zErr;
|
||||
rc = blobSeekToRow(p, iRow, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
}
|
||||
assert( rc!=SQLITE_SCHEMA );
|
||||
}
|
||||
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
assert( rc==SQLITE_OK || p->nByte<0 );
|
||||
assert( rc==SQLITE_OK || p->pStmt==0 );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+1
-4
@@ -1591,10 +1591,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( omitTable ){
|
||||
/* pIdx is a covering index. No need to access the main table. */
|
||||
}else if( HasRowid(pIdx->pTable) ){
|
||||
if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) || (
|
||||
(pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)
|
||||
&& (pWInfo->eOnePass==ONEPASS_SINGLE)
|
||||
)){
|
||||
if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){
|
||||
iRowidReg = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
||||
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
||||
|
||||
@@ -141,8 +141,8 @@ do_test 2.3.2 {
|
||||
execsql { SELECT 1, 2, 3 }
|
||||
sqlite3_errcode db
|
||||
} {SQLITE_OK}
|
||||
#blob_write_error_test 2.3.3 $B 5 $blob 5 \
|
||||
# SQLITE_OK {not an error}
|
||||
blob_write_error_test 2.3.3 $B 5 $blob 5 \
|
||||
SQLITE_ABORT {callback requested query abort}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
# EVIDENCE-OF: R-08382-59936 Writes to the BLOB that occurred before the
|
||||
|
||||
@@ -121,13 +121,13 @@ do_test exclusive2-1.1 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);
|
||||
INSERT INTO t1(a, b) VALUES(randstr(10, 400), 0);
|
||||
INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
|
||||
INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
|
||||
INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
|
||||
INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
|
||||
INSERT INTO t1(a, b) SELECT randstr(10, 400), 0 FROM t1;
|
||||
INSERT INTO t1(a) VALUES(randstr(10, 400));
|
||||
INSERT INTO t1(a) VALUES(randstr(10, 400));
|
||||
INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
|
||||
INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
|
||||
INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
|
||||
INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
|
||||
INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
|
||||
COMMIT;
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
@@ -154,7 +154,7 @@ do_test exclusive2-1.4 {
|
||||
} $::sig
|
||||
do_test exclusive2-1.5 {
|
||||
execsql {
|
||||
UPDATE t1 SET b=a, a=0;
|
||||
UPDATE t1 SET b=a, a=NULL;
|
||||
} db2
|
||||
expr {[t1sig db2] eq $::sig}
|
||||
} 0
|
||||
|
||||
+2
-55
@@ -849,62 +849,9 @@ do_preupdate_test 7.6.4 {
|
||||
}
|
||||
|
||||
# No preupdate callbacks for modifying sqlite_master.
|
||||
do_preupdate_test 8.1 { CREATE TABLE x1(x, y); } { }
|
||||
do_preupdate_test 8.2 { ALTER TABLE x1 ADD COLUMN z } { }
|
||||
do_preupdate_test 8.3 { ALTER TABLE x1 RENAME TO y1 } { }
|
||||
do_preupdate_test 8.4 { CREATE INDEX y1x ON y1(x) } { }
|
||||
do_preupdate_test 8.5 { CREATE VIEW v1 AS SELECT * FROM y1 } { }
|
||||
do_preupdate_test 8.6 { DROP TABLE y1 } { }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
db preupdate hook preupdate_hook
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
|
||||
}
|
||||
do_preupdate_test 9.1 {
|
||||
INSERT INTO t1 VALUES(456, NULL, NULL);
|
||||
do_preupdate_test 8.1 {
|
||||
CREATE TABLE x1(x, y);
|
||||
} {
|
||||
INSERT main t1 456 456 0 456 {} {}
|
||||
}
|
||||
do_execsql_test 9.2 {
|
||||
ALTER TABLE t1 ADD COLUMN d;
|
||||
}
|
||||
do_preupdate_test 9.3 {
|
||||
INSERT INTO t1(a, b, c) VALUES(457, NULL, NULL);
|
||||
} {
|
||||
INSERT main t1 457 457 0 457 {} {} {}
|
||||
}
|
||||
do_preupdate_test 9.4 {
|
||||
DELETE FROM t1 WHERE a=456
|
||||
} {
|
||||
DELETE main t1 456 456 0 456 {} {} {}
|
||||
}
|
||||
do_preupdate_test 9.5 {
|
||||
INSERT INTO t2 DEFAULT VALUES;
|
||||
} {
|
||||
INSERT main t2 1 1 0 {} 1
|
||||
}
|
||||
do_preupdate_test 9.6 {
|
||||
INSERT INTO t1 DEFAULT VALUES;
|
||||
} {
|
||||
INSERT main t1 458 458 0 458 {} {} {}
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 10.0 {
|
||||
CREATE TABLE t3(a, b INTEGER PRIMARY KEY);
|
||||
}
|
||||
do_preupdate_test 10.1 {
|
||||
INSERT INTO t3 DEFAULT VALUES
|
||||
} {
|
||||
INSERT main t3 1 1 0 {} 1
|
||||
}
|
||||
do_execsql_test 10.2 { SELECT * FROM t3 } {{} 1}
|
||||
do_preupdate_test 10.3 {
|
||||
DELETE FROM t3 WHERE b=1
|
||||
} {DELETE main t3 1 1 0 {} 1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
-218
@@ -1,218 +0,0 @@
|
||||
# 2017 Jan 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# The tests in this file focus on the pre-update hook.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix hook2
|
||||
|
||||
ifcapable !preupdate {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
proc do_preupdate_test {tn sql x} {
|
||||
set X [list]
|
||||
foreach elem $x {lappend X $elem}
|
||||
uplevel do_test $tn [list "
|
||||
set ::preupdate \[list\]
|
||||
execsql { $sql }
|
||||
set ::preupdate
|
||||
"] [list $X]
|
||||
}
|
||||
|
||||
proc preupdate_hook {args} {
|
||||
set type [lindex $args 0]
|
||||
eval lappend ::preupdate $args
|
||||
if {$type != "INSERT"} {
|
||||
for {set i 0} {$i < [db preupdate count]} {incr i} {
|
||||
lappend ::preupdate [db preupdate old $i]
|
||||
}
|
||||
}
|
||||
if {$type != "DELETE"} {
|
||||
for {set i 0} {$i < [db preupdate count]} {incr i} {
|
||||
set rc [catch { db preupdate new $i } v]
|
||||
lappend ::preupdate $v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Simple tests - INSERT, UPDATE and DELETE on a WITHOUT ROWID table.
|
||||
#
|
||||
db preupdate hook preupdate_hook
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
do_preupdate_test 1.1 {
|
||||
INSERT INTO t1 VALUES('one', 1);
|
||||
} {
|
||||
INSERT main t1 0 0 one 1
|
||||
}
|
||||
do_preupdate_test 1.2 {
|
||||
UPDATE t1 SET b=2 WHERE a='one';
|
||||
} {
|
||||
UPDATE main t1 0 0 one 1 one 2
|
||||
}
|
||||
do_preupdate_test 1.3 {
|
||||
DELETE FROM t1 WHERE a='one';
|
||||
} {
|
||||
DELETE main t1 0 0 one 2
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Some more complex tests for the pre-update callback on WITHOUT ROWID
|
||||
# tables.
|
||||
#
|
||||
# 2.1.1 - INSERT statement.
|
||||
# 2.1.2 - INSERT INTO ... SELECT statement.
|
||||
# 2.1.3 - REPLACE INTO ... (PK conflict)
|
||||
# 2.1.4 - REPLACE INTO ... (other index conflicts)
|
||||
# 2.1.5 - REPLACE INTO ... (both PK and other index conflicts)
|
||||
#
|
||||
# 2.2.1 - DELETE statement.
|
||||
# 2.2.2 - DELETE statement that uses the truncate optimization.
|
||||
#
|
||||
# 2.3.1 - UPDATE statement.
|
||||
# 2.3.2 - UPDATE statement that modifies the PK.
|
||||
# 2.3.3 - UPDATE OR REPLACE ... (PK conflict).
|
||||
# 2.3.4 - UPDATE OR REPLACE ... (other index conflicts)
|
||||
# 2.3.4 - UPDATE OR REPLACE ... (both PK and other index conflicts)
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t2(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX t2a ON t2(a);
|
||||
}
|
||||
|
||||
do_preupdate_test 2.1.1 {
|
||||
INSERT INTO t2(b, c) VALUES(1, 1);
|
||||
} {
|
||||
INSERT main t2 0 0 4 1 1
|
||||
}
|
||||
|
||||
do_execsql_test 2.1.2.0 {
|
||||
CREATE TABLE d1(a DEFAULT 4, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX d1a ON d1(a);
|
||||
INSERT INTO d1 VALUES(1, 2, 3);
|
||||
INSERT INTO d1 VALUES(11, 12, 13);
|
||||
}
|
||||
do_preupdate_test 2.1.2.1 {
|
||||
INSERT INTO t2 SELECT * FROM d1;
|
||||
} {
|
||||
INSERT main t2 0 0 1 2 3
|
||||
INSERT main t2 0 0 11 12 13
|
||||
}
|
||||
do_preupdate_test 2.1.2.2 {
|
||||
INSERT INTO t2 SELECT a+20, b+20, c+20 FROM d1;
|
||||
} {
|
||||
INSERT main t2 0 0 21 22 23
|
||||
INSERT main t2 0 0 31 32 33
|
||||
}
|
||||
do_execsql_test 2.1.2.3 {
|
||||
SELECT * FROM t2 ORDER BY b, c;
|
||||
} {
|
||||
4 1 1
|
||||
1 2 3
|
||||
11 12 13
|
||||
21 22 23
|
||||
31 32 33
|
||||
}
|
||||
do_preupdate_test 2.1.3 {
|
||||
REPLACE INTO t2 VALUES(45, 22, 23);
|
||||
} {
|
||||
DELETE main t2 0 0 21 22 23
|
||||
INSERT main t2 0 0 45 22 23
|
||||
}
|
||||
do_preupdate_test 2.1.4 {
|
||||
REPLACE INTO t2 VALUES(11, 100, 100);
|
||||
} {
|
||||
DELETE main t2 0 0 11 12 13
|
||||
INSERT main t2 0 0 11 100 100
|
||||
}
|
||||
do_preupdate_test 2.1.5 {
|
||||
REPLACE INTO t2(c, b) VALUES(33, 32)
|
||||
} {
|
||||
DELETE main t2 0 0 4 1 1
|
||||
DELETE main t2 0 0 31 32 33
|
||||
INSERT main t2 0 0 4 32 33
|
||||
}
|
||||
|
||||
do_execsql_test 2.2.0 {
|
||||
SELECT * FROM t2 ORDER BY b,c;
|
||||
} {
|
||||
1 2 3
|
||||
45 22 23
|
||||
4 32 33
|
||||
11 100 100
|
||||
}
|
||||
do_preupdate_test 2.2.1 {
|
||||
DELETE FROM t2 WHERE b=22;
|
||||
} {
|
||||
DELETE main t2 0 0 45 22 23
|
||||
}
|
||||
do_preupdate_test 2.2.2 {
|
||||
DELETE FROM t2;
|
||||
} {
|
||||
DELETE main t2 0 0 1 2 3
|
||||
DELETE main t2 0 0 4 32 33
|
||||
DELETE main t2 0 0 11 100 100
|
||||
}
|
||||
|
||||
do_execsql_test 2.3.0 {
|
||||
CREATE TABLE t3(x, y PRIMARY KEY, z UNIQUE) WITHOUT ROWID;
|
||||
INSERT INTO t3 VALUES('a', 'b', 'c');
|
||||
INSERT INTO t3 VALUES('d', 'e', 'f');
|
||||
|
||||
INSERT INTO t3 VALUES(1, 1, 1);
|
||||
INSERT INTO t3 VALUES(2, 2, 2);
|
||||
INSERT INTO t3 VALUES(3, 3, 3);
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.1 {
|
||||
UPDATE t3 SET x=4 WHERE y IN ('b', 'e', 'x');
|
||||
} {
|
||||
UPDATE main t3 0 0 a b c 4 b c
|
||||
UPDATE main t3 0 0 d e f 4 e f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.2 {
|
||||
UPDATE t3 SET y=y||y WHERE z IN('c', 'f');
|
||||
} {
|
||||
UPDATE main t3 0 0 4 b c 4 bb c
|
||||
UPDATE main t3 0 0 4 e f 4 ee f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.3 {
|
||||
UPDATE OR REPLACE t3 SET y='bb' WHERE z='f'
|
||||
} {
|
||||
DELETE main t3 0 0 4 bb c
|
||||
UPDATE main t3 0 0 4 ee f 4 bb f
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.4 {
|
||||
UPDATE OR REPLACE t3 SET z=2 WHERE y=1;
|
||||
} {
|
||||
DELETE main t3 0 0 2 2 2
|
||||
UPDATE main t3 0 0 1 1 1 1 1 2
|
||||
}
|
||||
|
||||
do_preupdate_test 2.3.5 {
|
||||
UPDATE OR REPLACE t3 SET z=2, y='bb' WHERE y=3;
|
||||
} {
|
||||
DELETE main t3 0 0 1 1 2
|
||||
DELETE main t3 0 0 4 bb f
|
||||
UPDATE main t3 0 0 3 3 3 3 bb 2
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+6
-9
@@ -62,7 +62,7 @@ do_test incrblob3-2.1.2 {
|
||||
} {SQLITE_ERROR {no such rowid: 3}}
|
||||
do_test incrblob3-2.1.3 {
|
||||
list [catch {sqlite3_blob_reopen $::blob 1} msg] $msg
|
||||
} {0 {}}
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test incrblob3-2.1.4 { close $::blob } {}
|
||||
|
||||
do_execsql_test incrblob3-2.2.1 {
|
||||
@@ -85,21 +85,18 @@ foreach {tn rowid type} {
|
||||
|
||||
do_test incrblob3-2.2.$tn.3 {
|
||||
list [catch {sqlite3_blob_reopen $::blob 1} msg] $msg
|
||||
} {0 {}}
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test incrblob3-2.2.$tn.4 {
|
||||
list [catch {sqlite3_blob_read $::blob 0 10} msg] $msg
|
||||
} {0 {hello worl}}
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test incrblob3-2.2.$tn.5 {
|
||||
list [catch {sqlite3_blob_write $::blob 0 "abcd"} msg] $msg
|
||||
} {0 {}}
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test incrblob3-2.2.$tn.6 {
|
||||
sqlite3_blob_bytes $::blob
|
||||
} {100}
|
||||
do_test incrblob3-2.2.$tn.7 {
|
||||
list [catch {sqlite3_blob_write $::blob 0 "hello"} msg] $msg
|
||||
} {0 {}}
|
||||
} {0}
|
||||
|
||||
do_test incrblob3-2.2.$tn.8 { close $::blob } {}
|
||||
do_test incrblob3-2.2.$tn.7 { close $::blob } {}
|
||||
}
|
||||
|
||||
# Test that passing NULL to sqlite3_blob_XXX() APIs returns SQLITE_MISUSE.
|
||||
|
||||
+28
-196
@@ -67,35 +67,27 @@ static const char zHelp[] =
|
||||
"\n"
|
||||
" Generate a new test database file named DBFILE containing N\n"
|
||||
" BLOBs each of size M bytes. The page size of the new database\n"
|
||||
" file will be X. Additional options:\n"
|
||||
"\n"
|
||||
" --variance V Randomly vary M by plus or minus V\n"
|
||||
" file will be X\n"
|
||||
"\n"
|
||||
" kvtest export DBFILE DIRECTORY\n"
|
||||
"\n"
|
||||
" Export all the blobs in the kv table of DBFILE into separate\n"
|
||||
" files in DIRECTORY.\n"
|
||||
"\n"
|
||||
" kvtest stat DBFILE\n"
|
||||
"\n"
|
||||
" Display summary information about DBFILE\n"
|
||||
"\n"
|
||||
" kvtest run DBFILE [options]\n"
|
||||
"\n"
|
||||
" Run a performance test. DBFILE can be either the name of a\n"
|
||||
" database or a directory containing sample files. Options:\n"
|
||||
"\n"
|
||||
" --asc Read blobs in ascending order\n"
|
||||
" --blob-api Use the BLOB API\n"
|
||||
" --cache-size N Database cache size\n"
|
||||
" --count N Read N blobs\n"
|
||||
" --desc Read blobs in descending order\n"
|
||||
" --max-id N Maximum blob key to use\n"
|
||||
" --mmap N Mmap as much as N bytes of DBFILE\n"
|
||||
" --jmode MODE Set MODE journal mode prior to starting\n"
|
||||
" --random Read blobs in a random order\n"
|
||||
" --start N Start reading with this blob key\n"
|
||||
" --stats Output operating stats before exiting\n"
|
||||
" --asc Read blobs in ascending order\n"
|
||||
" --blob-api Use the BLOB API\n"
|
||||
" --cache-size N Database cache size\n"
|
||||
" --count N Read N blobs\n"
|
||||
" --desc Read blobs in descending order\n"
|
||||
" --max-id N Maximum blob key to use\n"
|
||||
" --random Read blobs in a random order\n"
|
||||
" --start N Start reading with this blob key\n"
|
||||
" --stats Output operating stats before exiting\n"
|
||||
;
|
||||
|
||||
/* Reference resources used */
|
||||
@@ -140,64 +132,6 @@ static void fatalError(const char *zFormat, ...){
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the value of a hexadecimal digit. Return -1 if the input
|
||||
** is not a hex digit.
|
||||
*/
|
||||
static int hexDigitValue(char c){
|
||||
if( c>='0' && c<='9' ) return c - '0';
|
||||
if( c>='a' && c<='f' ) return c - 'a' + 10;
|
||||
if( c>='A' && c<='F' ) return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Interpret zArg as an integer value, possibly with suffixes.
|
||||
*/
|
||||
static int integerValue(const char *zArg){
|
||||
int v = 0;
|
||||
static const struct { char *zSuffix; int iMult; } aMult[] = {
|
||||
{ "KiB", 1024 },
|
||||
{ "MiB", 1024*1024 },
|
||||
{ "GiB", 1024*1024*1024 },
|
||||
{ "KB", 1000 },
|
||||
{ "MB", 1000000 },
|
||||
{ "GB", 1000000000 },
|
||||
{ "K", 1000 },
|
||||
{ "M", 1000000 },
|
||||
{ "G", 1000000000 },
|
||||
};
|
||||
int i;
|
||||
int isNeg = 0;
|
||||
if( zArg[0]=='-' ){
|
||||
isNeg = 1;
|
||||
zArg++;
|
||||
}else if( zArg[0]=='+' ){
|
||||
zArg++;
|
||||
}
|
||||
if( zArg[0]=='0' && zArg[1]=='x' ){
|
||||
int x;
|
||||
zArg += 2;
|
||||
while( (x = hexDigitValue(zArg[0]))>=0 ){
|
||||
v = (v<<4) + x;
|
||||
zArg++;
|
||||
}
|
||||
}else{
|
||||
while( zArg[0]>='0' && zArg[0]<='9' ){
|
||||
v = v*10 + zArg[0] - '0';
|
||||
zArg++;
|
||||
}
|
||||
}
|
||||
for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
|
||||
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
|
||||
v *= aMult[i].iMult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isNeg? -v : v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check the filesystem object zPath. Determine what it is:
|
||||
**
|
||||
@@ -257,7 +191,6 @@ static int initMain(int argc, char **argv){
|
||||
int i, rc;
|
||||
int nCount = 1000;
|
||||
int sz = 10000;
|
||||
int iVariance = 0;
|
||||
int pgsz = 4096;
|
||||
sqlite3 *db;
|
||||
char *zSql;
|
||||
@@ -272,24 +205,19 @@ static int initMain(int argc, char **argv){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-count")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
nCount = integerValue(argv[++i]);
|
||||
nCount = atoi(argv[++i]);
|
||||
if( nCount<1 ) fatalError("the --count must be positive");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-size")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
sz = integerValue(argv[++i]);
|
||||
sz = atoi(argv[++i]);
|
||||
if( sz<1 ) fatalError("the --size must be positive");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-variance")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
iVariance = integerValue(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-pagesize")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
pgsz = integerValue(argv[++i]);
|
||||
pgsz = atoi(argv[++i]);
|
||||
if( pgsz<512 || pgsz>65536 || ((pgsz-1)&pgsz)!=0 ){
|
||||
fatalError("the --pagesize must be power of 2 between 512 and 65536");
|
||||
}
|
||||
@@ -308,9 +236,9 @@ static int initMain(int argc, char **argv){
|
||||
"BEGIN;\n"
|
||||
"CREATE TABLE kv(k INTEGER PRIMARY KEY, v BLOB);\n"
|
||||
"WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<%d)"
|
||||
" INSERT INTO kv(k,v) SELECT x, randomblob(%d+(random()%%(%d))) FROM c;\n"
|
||||
" INSERT INTO kv(k,v) SELECT x, randomblob(%d) FROM c;\n"
|
||||
"COMMIT;\n",
|
||||
pgsz, nCount, sz, iVariance
|
||||
pgsz, nCount, sz
|
||||
);
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
|
||||
if( rc ) fatalError("database create failed: %s", zErrMsg);
|
||||
@@ -319,65 +247,6 @@ static int initMain(int argc, char **argv){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Analyze an existing database file. Report its content.
|
||||
*/
|
||||
static int statMain(int argc, char **argv){
|
||||
char *zDb;
|
||||
int i, rc;
|
||||
sqlite3 *db;
|
||||
char *zSql;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
assert( strcmp(argv[1],"stat")==0 );
|
||||
assert( argc>=3 );
|
||||
zDb = argv[2];
|
||||
for(i=3; i<argc; i++){
|
||||
char *z = argv[i];
|
||||
if( z[0]!='-' ) fatalError("unknown argument: \"%s\"", z);
|
||||
if( z[1]=='-' ) z++;
|
||||
fatalError("unknown option: \"%s\"", argv[i]);
|
||||
}
|
||||
rc = sqlite3_open(zDb, &db);
|
||||
if( rc ){
|
||||
fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
|
||||
}
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT count(*), min(length(v)), max(length(v)), avg(length(v))"
|
||||
" FROM kv"
|
||||
);
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
|
||||
sqlite3_free(zSql);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
printf("Number of entries: %8d\n", sqlite3_column_int(pStmt, 0));
|
||||
printf("Average value size: %8d\n", sqlite3_column_int(pStmt, 3));
|
||||
printf("Minimum value size: %8d\n", sqlite3_column_int(pStmt, 1));
|
||||
printf("Maximum value size: %8d\n", sqlite3_column_int(pStmt, 2));
|
||||
}else{
|
||||
printf("No rows\n");
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
zSql = sqlite3_mprintf("PRAGMA page_size");
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
|
||||
sqlite3_free(zSql);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
printf("Page-size: %8d\n", sqlite3_column_int(pStmt, 0));
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
zSql = sqlite3_mprintf("PRAGMA page_count");
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc ) fatalError("cannot prepare SQL [%s]: %s", zSql, sqlite3_errmsg(db));
|
||||
sqlite3_free(zSql);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
printf("Page-count: %8d\n", sqlite3_column_int(pStmt, 0));
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the "writefile(X,Y)" SQL function. The argument Y
|
||||
** is written into file X. The number of bytes written is returned. Or
|
||||
@@ -611,6 +480,9 @@ static int display_stats(
|
||||
displayLinuxIoStats(out);
|
||||
#endif
|
||||
|
||||
/* Do not remove this machine readable comment: extra-stats-output-here */
|
||||
|
||||
fprintf(out, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -619,7 +491,6 @@ static int display_stats(
|
||||
#define ORDER_DESC 2
|
||||
#define ORDER_RANDOM 3
|
||||
|
||||
|
||||
/*
|
||||
** Run a performance test
|
||||
*/
|
||||
@@ -631,7 +502,7 @@ static int runMain(int argc, char **argv){
|
||||
int nCount = 1000; /* Number of blob fetch operations */
|
||||
int nExtra = 0; /* Extra cycles */
|
||||
int iKey = 1; /* Next blob key */
|
||||
int iMax = 0; /* Largest allowed key */
|
||||
int iMax = 1000; /* Largest allowed key */
|
||||
int iPagesize = 0; /* Database page size */
|
||||
int iCache = 1000; /* Database cache size in kibibytes */
|
||||
int bBlobApi = 0; /* Use the incremental blob I/O API */
|
||||
@@ -642,12 +513,10 @@ static int runMain(int argc, char **argv){
|
||||
sqlite3_blob *pBlob = 0; /* Handle for incremental Blob I/O */
|
||||
sqlite3_int64 tmStart; /* Start time */
|
||||
sqlite3_int64 tmElapsed; /* Elapsed time */
|
||||
int mmapSize = 0; /* --mmap N argument */
|
||||
int nData = 0; /* Bytes of data */
|
||||
sqlite3_int64 nTotal = 0; /* Total data read */
|
||||
unsigned char *pData = 0; /* Content of the blob */
|
||||
unsigned char *pData; /* Content of the blob */
|
||||
int nAlloc = 0; /* Space allocated for pData[] */
|
||||
const char *zJMode = 0; /* Journal mode */
|
||||
|
||||
|
||||
assert( strcmp(argv[1],"run")==0 );
|
||||
@@ -662,35 +531,25 @@ static int runMain(int argc, char **argv){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z, "-count")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
nCount = integerValue(argv[++i]);
|
||||
nCount = atoi(argv[++i]);
|
||||
if( nCount<1 ) fatalError("the --count must be positive");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-mmap")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
mmapSize = integerValue(argv[++i]);
|
||||
if( nCount<0 ) fatalError("the --mmap must be non-negative");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-max-id")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
iMax = integerValue(argv[++i]);
|
||||
iMax = atoi(argv[++i]);
|
||||
if( iMax<1 ) fatalError("the --max-id must be positive");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-start")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
iKey = integerValue(argv[++i]);
|
||||
iKey = atoi(argv[++i]);
|
||||
if( iKey<1 ) fatalError("the --start must be positive");
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-cache-size")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
iCache = integerValue(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-jmode")==0 ){
|
||||
if( i==argc-1 ) fatalError("missing argument on \"%s\"", argv[i]);
|
||||
zJMode = argv[++i];
|
||||
iCache = atoi(argv[++i]);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(z, "-random")==0 ){
|
||||
@@ -722,8 +581,6 @@ static int runMain(int argc, char **argv){
|
||||
if( rc ){
|
||||
fatalError("cannot open database \"%s\": %s", zDb, sqlite3_errmsg(db));
|
||||
}
|
||||
zSql = sqlite3_mprintf("PRAGMA mmap_size=%d", mmapSize);
|
||||
sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
zSql = sqlite3_mprintf("PRAGMA cache_size=%d", iCache);
|
||||
sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
@@ -741,29 +598,8 @@ static int runMain(int argc, char **argv){
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
pStmt = 0;
|
||||
if( zJMode ){
|
||||
zSql = sqlite3_mprintf("PRAGMA journal_mode=%Q", zJMode);
|
||||
sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
sqlite3_prepare_v2(db, "PRAGMA journal_mode", -1, &pStmt, 0);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
zJMode = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
|
||||
}else{
|
||||
zJMode = "???";
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( iMax<=0 ){
|
||||
sqlite3_prepare_v2(db, "SELECT max(k) FROM kv", -1, &pStmt, 0);
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
iMax = sqlite3_column_int(pStmt, 0);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
pStmt = 0;
|
||||
sqlite3_exec(db, "BEGIN", 0, 0, 0);
|
||||
}
|
||||
if( iMax<=0 ) iMax = 1000;
|
||||
for(i=0; i<nCount; i++){
|
||||
if( eType==PATH_DIR ){
|
||||
/* CASE 1: Reading blobs out of separate files */
|
||||
@@ -844,15 +680,14 @@ static int runMain(int argc, char **argv){
|
||||
printf("SQLite version: %s\n", sqlite3_libversion());
|
||||
}
|
||||
printf("--count %d --max-id %d", nCount-nExtra, iMax);
|
||||
if( eType==PATH_DB ){
|
||||
printf(" --cache-size %d", iCache);
|
||||
}
|
||||
switch( eOrder ){
|
||||
case ORDER_RANDOM: printf(" --random\n"); break;
|
||||
case ORDER_DESC: printf(" --desc\n"); break;
|
||||
default: printf(" --asc\n"); break;
|
||||
}
|
||||
if( eType==PATH_DB ){
|
||||
printf("--cache-size %d --jmode %s\n", iCache, zJMode);
|
||||
printf("--mmap %d%s\n", mmapSize, bBlobApi ? " --blob-api" : "");
|
||||
}
|
||||
if( iPagesize ) printf("Database page size: %d\n", iPagesize);
|
||||
printf("Total elapsed time: %.3f\n", tmElapsed/1000.0);
|
||||
printf("Microseconds per BLOB read: %.3f\n", tmElapsed*1000.0/nCount);
|
||||
@@ -872,9 +707,6 @@ int main(int argc, char **argv){
|
||||
if( strcmp(argv[1],"run")==0 ){
|
||||
return runMain(argc, argv);
|
||||
}
|
||||
if( strcmp(argv[1],"stat")==0 ){
|
||||
return statMain(argc, argv);
|
||||
}
|
||||
showHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+16
-24
@@ -148,68 +148,60 @@ do_execsql_test tabfunc01-600 {
|
||||
|
||||
|
||||
do_test tabfunc01-700 {
|
||||
set PTR1 [intarray_addr 5 7 13 17 23]
|
||||
set PTR [intarray_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR1,5) WHERE a=value;
|
||||
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($PTR1,5,'int32');
|
||||
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($PTR1,4,'int32');
|
||||
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($PTR1,5,'int33');
|
||||
SELECT b FROM t600 WHERE a IN carray($PTR,5,'int33');
|
||||
} {1 {unknown datatype: 'int33'}}
|
||||
|
||||
do_test tabfunc01-720 {
|
||||
set PTR2 [int64array_addr 5 7 13 17 23]
|
||||
set PTR [int64array_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR2,5,'int64') WHERE a=value;
|
||||
SELECT b FROM t600, carray($PTR,5,'int64') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
do_test tabfunc01-721 {
|
||||
db eval {
|
||||
SELECT remember(123,$PTR2);
|
||||
SELECT value FROM carray($PTR2,5,'int64');
|
||||
SELECT remember(123,$PTR);
|
||||
SELECT value FROM carray($PTR,5,'int64');
|
||||
}
|
||||
} {123 123 7 13 17 23}
|
||||
do_test tabfunc01-722 {
|
||||
set PTR3 [expr {$PTR2+16}]
|
||||
set PTR2 [expr {$PTR+16}]
|
||||
db eval {
|
||||
SELECT remember(987,$PTR3);
|
||||
SELECT value FROM carray($PTR2,5,'int64');
|
||||
SELECT remember(987,$PTR2);
|
||||
SELECT value FROM carray($PTR,5,'int64');
|
||||
}
|
||||
} {987 123 7 987 17 23}
|
||||
|
||||
do_test tabfunc01-730 {
|
||||
set PTR4 [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
|
||||
set PTR [doublearray_addr 5.0 7.0 13.0 17.0 23.0]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR4,5,'double') WHERE a=value;
|
||||
SELECT b FROM t600, carray($PTR,5,'double') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
|
||||
do_test tabfunc01-740 {
|
||||
set PTR5 [textarray_addr x5 x7 x13 x17 x23]
|
||||
set PTR [textarray_addr 5 7 13 17 23]
|
||||
db eval {
|
||||
SELECT b FROM t600, carray($PTR5,5,'char*') WHERE a=trim(value,'x');
|
||||
SELECT b FROM t600, carray($PTR,5,'char*') WHERE a=value;
|
||||
}
|
||||
} {(005) (007) (013) (017) (023)}
|
||||
|
||||
do_test tabfunc01-750 {
|
||||
db eval {
|
||||
SELECT aa.value, bb.value, '|'
|
||||
FROM carray($PTR4,5,'double') AS aa
|
||||
JOIN carray($PTR5,5,'char*') AS bb ON aa.rowid=bb.rowid;
|
||||
}
|
||||
} {5.0 x5 | 7.0 x7 | 13.0 x13 | 17.0 x17 | 23.0 x23 |}
|
||||
|
||||
# Free up memory allocations
|
||||
intarray_addr
|
||||
int64array_addr
|
||||
doublearray_addr
|
||||
|
||||
+1
-1
@@ -461,7 +461,7 @@ if {[info exists cmdlinearg]==0} {
|
||||
}
|
||||
{^-+backtrace=.+$} {
|
||||
foreach {dummy cmdlinearg(backtrace)} [split $a =] break
|
||||
sqlite3_memdebug_backtrace $cmdlinearg(backtrace)
|
||||
sqlite3_memdebug_backtrace $value
|
||||
}
|
||||
{^-+binarylog=.+$} {
|
||||
foreach {dummy cmdlinearg(binarylog)} [split $a =] break
|
||||
|
||||
@@ -176,30 +176,5 @@ foreach {tn sql} {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c);
|
||||
CREATE INDEX x1c ON x1(b, c);
|
||||
INSERT INTO x1 VALUES(1, 'a', 1);
|
||||
INSERT INTO x1 VALUES(2, 'a', 2);
|
||||
INSERT INTO x1 VALUES(3, 'a', 3);
|
||||
}
|
||||
|
||||
do_execsql_test 5.1.1 {
|
||||
UPDATE x1 SET c=c+1 WHERE b='a';
|
||||
}
|
||||
|
||||
do_execsql_test 5.1.2 {
|
||||
SELECT * FROM x1;
|
||||
} {1 a 2 2 a 3 3 a 4}
|
||||
|
||||
do_test 5.2 {
|
||||
catch { array unset A }
|
||||
db eval { EXPLAIN UPDATE x1 SET c=c+1 WHERE b='a' } { incr A($opcode) }
|
||||
set A(NotExists)
|
||||
} {1}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# A script for running speed tests using kvtest.
|
||||
#
|
||||
# The test database must be set up first. Recommended
|
||||
# command-line:
|
||||
#
|
||||
# ./kvtest init kvtest.db --count 100K --size 12K --variance 5K
|
||||
|
||||
if test "$1" = ""
|
||||
then
|
||||
echo "Usage: $0 OUTPUTFILE [OPTIONS]"
|
||||
exit
|
||||
fi
|
||||
NAME=$1
|
||||
shift
|
||||
OPTS="-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DIRECT_OVERFLOW_READ -DUSE_PREAD"
|
||||
KVARGS="--count 100K --stats"
|
||||
gcc -g -Os -I. $OPTS $* kvtest.c sqlite3.c -o kvtest
|
||||
|
||||
# First run using SQL
|
||||
rm cachegrind.out.[1-9][0-9]*
|
||||
valgrind --tool=cachegrind ./kvtest run kvtest.db $KVARGS 2>&1 | tee summary-kvtest-$NAME.txt
|
||||
mv cachegrind.out.[1-9][0-9]* cachegrind.out.sql-$NAME
|
||||
cg_anno.tcl cachegrind.out.sql-$NAME >cout-kvtest-sql-$NAME.txt
|
||||
|
||||
# Second run using the sqlite3_blob object
|
||||
valgrind --tool=cachegrind ./kvtest run kvtest.db $KVARGS --blob-api 2>&1 | tee -a summary-kvtest-$NAME.txt
|
||||
mv cachegrind.out.[1-9][0-9]* cachegrind.out.$NAME
|
||||
cg_anno.tcl cachegrind.out.$NAME >cout-kvtest-$NAME.txt
|
||||
|
||||
# Diff the sqlite3_blob API analysis for non-trunk runs.
|
||||
if test "$NAME" != "trunk"; then
|
||||
fossil test-diff --tk cout-kvtest-trunk.txt cout-kvtest-$NAME.txt &
|
||||
fi
|
||||
+27
-44
@@ -316,31 +316,6 @@ static int yyGrowStack(yyParser *p){
|
||||
# define YYMALLOCARGTYPE size_t
|
||||
#endif
|
||||
|
||||
/* Initialize a new parser that has already been allocated.
|
||||
*/
|
||||
void ParseInit(void *yypParser){
|
||||
yyParser *pParser = (yyParser*)yypParser;
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
pParser->yyhwm = 0;
|
||||
#endif
|
||||
#if YYSTACKDEPTH<=0
|
||||
pParser->yytos = NULL;
|
||||
pParser->yystack = NULL;
|
||||
pParser->yystksz = 0;
|
||||
if( yyGrowStack(pParser) ){
|
||||
pParser->yystack = &pParser->yystk0;
|
||||
pParser->yystksz = 1;
|
||||
}
|
||||
#endif
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
pParser->yyerrcnt = -1;
|
||||
#endif
|
||||
pParser->yytos = pParser->yystack;
|
||||
pParser->yystack[0].stateno = 0;
|
||||
pParser->yystack[0].major = 0;
|
||||
}
|
||||
|
||||
#ifndef Parse_ENGINEALWAYSONSTACK
|
||||
/*
|
||||
** This function allocates a new parser.
|
||||
** The only argument is a pointer to a function which works like
|
||||
@@ -356,11 +331,28 @@ void ParseInit(void *yypParser){
|
||||
void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
|
||||
yyParser *pParser;
|
||||
pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
|
||||
if( pParser ) ParseInit(pParser);
|
||||
if( pParser ){
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
pParser->yyhwm = 0;
|
||||
#endif
|
||||
#if YYSTACKDEPTH<=0
|
||||
pParser->yytos = NULL;
|
||||
pParser->yystack = NULL;
|
||||
pParser->yystksz = 0;
|
||||
if( yyGrowStack(pParser) ){
|
||||
pParser->yystack = &pParser->yystk0;
|
||||
pParser->yystksz = 1;
|
||||
}
|
||||
#endif
|
||||
#ifndef YYNOERRORRECOVERY
|
||||
pParser->yyerrcnt = -1;
|
||||
#endif
|
||||
pParser->yytos = pParser->yystack;
|
||||
pParser->yystack[0].stateno = 0;
|
||||
pParser->yystack[0].major = 0;
|
||||
}
|
||||
return pParser;
|
||||
}
|
||||
#endif /* Parse_ENGINEALWAYSONSTACK */
|
||||
|
||||
|
||||
/* The following function deletes the "minor type" or semantic value
|
||||
** associated with a symbol. The symbol can be either a terminal
|
||||
@@ -414,18 +406,6 @@ static void yy_pop_parser_stack(yyParser *pParser){
|
||||
yy_destructor(pParser, yytos->major, &yytos->minor);
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear all secondary memory allocations from the parser
|
||||
*/
|
||||
void ParseFinalize(void *p){
|
||||
yyParser *pParser = (yyParser*)p;
|
||||
while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
|
||||
#if YYSTACKDEPTH<=0
|
||||
if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef Parse_ENGINEALWAYSONSTACK
|
||||
/*
|
||||
** Deallocate and destroy a parser. Destructors are called for
|
||||
** all stack elements before shutting the parser down.
|
||||
@@ -438,13 +418,16 @@ void ParseFree(
|
||||
void *p, /* The parser to be deleted */
|
||||
void (*freeProc)(void*) /* Function used to reclaim memory */
|
||||
){
|
||||
yyParser *pParser = (yyParser*)p;
|
||||
#ifndef YYPARSEFREENEVERNULL
|
||||
if( p==0 ) return;
|
||||
if( pParser==0 ) return;
|
||||
#endif
|
||||
ParseFinalize(p);
|
||||
(*freeProc)(p);
|
||||
while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
|
||||
#if YYSTACKDEPTH<=0
|
||||
if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
|
||||
#endif
|
||||
(*freeProc)((void*)pParser);
|
||||
}
|
||||
#endif /* Parse_ENGINEALWAYSONSTACK */
|
||||
|
||||
/*
|
||||
** Return the peak depth of the stack for a parser.
|
||||
|
||||
@@ -142,6 +142,3 @@ fi
|
||||
if test $doExplain -eq 1; then
|
||||
./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt
|
||||
fi
|
||||
if test "$NAME" != "trunk"; then
|
||||
fossil test-diff --tk cout-trunk.txt cout-$NAME.txt
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user