Add some tests of subsecond modifier for date/time functions. Sync with trunk.

FossilOrigin-Name: 6499ebff545e663198bd0534be205a4e9ca68c7fb20fdcfa54fae4d9b79bfe3a
This commit is contained in:
larrybr 2023-05-04 20:19:33 +00:00
commit 88813681c2
71 changed files with 3583 additions and 597 deletions

View File

@ -543,7 +543,7 @@ int sqlite3Fts5GetVarintLen(u32 iVal);
u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \

View File

@ -550,6 +550,7 @@ int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && i<nArg; i++){
const char *zOrig = azArg[i];
const char *z;

View File

@ -407,7 +407,7 @@ int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
if( *pp1 ){
if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@ -432,7 +432,7 @@ int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
sqlite3_free(p2->apExprPhrase);
sqlite3_free(p2);
}else{
}else if( p2 ){
*pp1 = p2;
}

View File

@ -954,6 +954,7 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
@ -984,6 +985,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@ -4634,6 +4636,9 @@ static void fts5SecureDeleteOverflow(
pLeaf = 0;
}else if( bDetailNone ){
break;
}else if( iNext>=pLeaf->szLeaf || iNext<4 ){
p->rc = FTS5_CORRUPT;
break;
}else{
int nShift = iNext - 4;
int nPg;
@ -4688,7 +4693,6 @@ static void fts5SecureDeleteOverflow(
*/
static void fts5DoSecureDelete(
Fts5Index *p,
Fts5Structure *pStruct,
Fts5SegIter *pSeg
){
const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
@ -4806,7 +4810,7 @@ static void fts5DoSecureDelete(
for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
u32 iVal = 0;
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
if( (iKeyOff+iVal)>iStart ) break;
if( (iKeyOff+iVal)>(u32)iStart ) break;
iKeyOff += iVal;
}
@ -4846,11 +4850,11 @@ static void fts5DoSecureDelete(
}
}
}else if( iStart==4 ){
int iPgno;
assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
/* The entry being removed may be the only position list in
** its doclist. */
int iPgno = pSeg->iLeafPgno-1;
for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
int bEmpty = (pPg && pPg->nn==4);
@ -4934,7 +4938,7 @@ static void fts5FlushSecureDelete(
i64 iRowid
){
const int f = FTS5INDEX_QUERY_SKIPHASH;
int nTerm = strlen(zTerm);
int nTerm = (int)strlen(zTerm);
Fts5Iter *pIter = 0; /* Used to find term instance */
fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
@ -4949,7 +4953,7 @@ static void fts5FlushSecureDelete(
&& iRowid==fts5MultiIterRowid(pIter)
){
Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
fts5DoSecureDelete(p, pStruct, pSeg);
fts5DoSecureDelete(p, pSeg);
}
}

View File

@ -0,0 +1,99 @@
# 2023 April 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.
#
#***********************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt7
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
sqlite3_fts5_may_be_corrupt 1
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
set doc [string repeat "a b " 30]
do_execsql_test 1.1 {
BEGIN;
INSERT INTO t1(rowid, x) VALUES(123, $doc);
INSERT INTO t1(rowid, x) VALUES(124, $doc);
COMMIT;
}
execsql_pp {
SELECT id, fts5_decode(id, block), quote(block) FROM t1_data
}
set rows [db eval { SELECT rowid FROM t1_data }]
db_save_and_close
foreach r $rows {
db_restore_and_reopen
proc edit_block {b} {
binary scan $b c* in
set out [lreplace $in 0 1 255 255]
binary format c* $out
}
db func edit_block edit_block
do_execsql_test 1.2.$r.1 {
UPDATE t1_data SET block = edit_block(block) WHERE rowid=$r;
}
do_execsql_test 1.2.$r.2 {
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
}
do_test 1.2.$r.3 {
catchsql { DELETE FROM t1 WHERE rowid=123; }
catchsql { DELETE FROM t1 WHERE rowid=124; }
set {} {}
} {}
db close
}
foreach r $rows {
set r 137438953475
db_restore_and_reopen
proc edit_block {b} {
binary scan $b c* in
set out [lreplace $in end end 127]
binary format c* $out
}
db func edit_block edit_block
do_execsql_test 1.2.$r.1 {
UPDATE t1_data SET block = edit_block(block) WHERE rowid=$r;
}
do_execsql_test 1.2.$r.2 {
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
}
do_test 1.2.$r.3 {
catchsql { DELETE FROM t1 WHERE rowid=124; }
catchsql { DELETE FROM t1 WHERE rowid=123; }
set {} {}
} {}
db close
}
finish_test

View File

@ -443,5 +443,33 @@ do_execsql_test -db db2 16.6 {
SELECT * FROM x1
} {abc def}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 17.1 {
CREATE VIRTUAL TABLE ft USING fts5(x, tokenize="unicode61 separators 'X'");
}
do_execsql_test 17.2 {
SELECT 0 FROM ft WHERE ft MATCH 'X' AND ft MATCH 'X'
}
do_execsql_test 17.3 {
SELECT 0 FROM ft('X')
}
do_execsql_test 17.4 {
CREATE VIRTUAL TABLE t0 USING fts5(c0, t="trigram");
INSERT INTO t0 VALUES('assertionfaultproblem');
}
do_execsql_test 17.5 {
SELECT 0 FROM t0(0) WHERE c0 GLOB 0;
} {}
do_execsql_test 17.5 {
SELECT c0 FROM t0 WHERE c0 GLOB '*f*';
} {assertionfaultproblem}
do_execsql_test 17.5 {
SELECT c0 FROM t0 WHERE c0 GLOB '*faul*';
} {assertionfaultproblem}
finish_test

View File

@ -148,9 +148,9 @@ static char* toBase64( u8 *pIn, int nbIn, char *pOut ){
}
/* Skip over text which is not base64 numeral(s). */
static char * skipNonB64( char *s ){
static char * skipNonB64( char *s, int nc ){
char c;
while( (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
return s;
}
@ -159,7 +159,7 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn;
while( ncIn>0 && *pIn!=PAD_CHAR ){
static signed char nboi[] = { 0, 0, 1, 2, 3 };
char *pUse = skipNonB64(pIn);
char *pUse = skipNonB64(pIn, ncIn);
unsigned long qv = 0L;
int nti, nbo, nac;
ncIn -= (pUse - pIn);
@ -219,9 +219,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_error(context, "blob expanded to base64 too big", -1);
return;
}
bBuf = (u8*)sqlite3_value_blob(av[0]);
if( !bBuf ){
if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
goto memFail;
}
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
bBuf = (u8*)sqlite3_value_blob(av[0]);
nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
break;
@ -234,9 +241,16 @@ static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
}else if( nb<1 ){
nb = 1;
}
cBuf = (char *)sqlite3_value_text(av[0]);
if( !cBuf ){
if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
goto memFail;
}
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
cBuf = (char *)sqlite3_value_text(av[0]);
nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
break;

View File

@ -140,9 +140,9 @@ static u8 base85DigitValue( char c ){
#define B85_DARK_MAX 80
static char * skipNonB85( char *s ){
static char * skipNonB85( char *s, int nc ){
char c;
while( (c = *s) && !IS_B85(c) ) ++s;
while( nc-- > 0 && (c = *s) && !IS_B85(c) ) ++s;
return s;
}
@ -212,7 +212,7 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){
if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn;
while( ncIn>0 ){
static signed char nboi[] = { 0, 0, 1, 2, 3, 4 };
char *pUse = skipNonB85(pIn);
char *pUse = skipNonB85(pIn, ncIn);
unsigned long qv = 0L;
int nti, nbo;
ncIn -= (pUse - pIn);
@ -297,9 +297,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
sqlite3_result_error(context, "blob expanded to base85 too big", -1);
return;
}
bBuf = (u8*)sqlite3_value_blob(av[0]);
if( !bBuf ){
if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
goto memFail;
}
sqlite3_result_text(context,"",-1,SQLITE_STATIC);
break;
}
cBuf = sqlite3_malloc(nc);
if( !cBuf ) goto memFail;
bBuf = (u8*)sqlite3_value_blob(av[0]);
nc = (int)(toBase85(bBuf, nb, cBuf, "\n") - cBuf);
sqlite3_result_text(context, cBuf, nc, sqlite3_free);
break;
@ -312,9 +319,16 @@ static void base85(sqlite3_context *context, int na, sqlite3_value *av[]){
}else if( nb<1 ){
nb = 1;
}
cBuf = (char *)sqlite3_value_text(av[0]);
if( !cBuf ){
if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
goto memFail;
}
sqlite3_result_zeroblob(context, 0);
break;
}
bBuf = sqlite3_malloc(nb);
if( !bBuf ) goto memFail;
cBuf = (char *)sqlite3_value_text(av[0]);
nb = (int)(fromBase85(cBuf, nc, bBuf) - bBuf);
sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
break;

202
ext/misc/randomjson.c Normal file
View File

@ -0,0 +1,202 @@
/*
** 2023-04-28
**
** 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 the random_json(SEED) and
** random_json5(SEED) functions. Given a numeric SEED value, these
** routines generate pseudo-random JSON or JSON5, respectively. The
** same value is always generated for the same seed.
**
** These SQL functions are intended for testing. They do not have any
** practical real-world use, that we know of.
**
** COMPILE:
**
** gcc --shared -fPIC -o randomjson.so -I. ext/misc/randomjson.c
**
** USING FROM THE CLI:
**
** .load ./randomjson
** SELECT random_json(1);
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <stdlib.h>
/* Pseudo-random number generator */
typedef struct Prng {
unsigned int x, y;
} Prng;
/* Reseed the PRNG */
static void prngSeed(Prng *p, unsigned int iSeed){
p->x = iSeed | 1;
p->y = iSeed;
}
/* Extract a random number */
static unsigned int prngInt(Prng *p){
p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001);
p->y = p->y*1103515245 + 12345;
return p->x ^ p->y;
}
static const char *azJsonAtoms[] = {
/* JSON /* JSON-5 */
"0", "0",
"1", "1",
"-1", "-1",
"2", "+2",
"3", "3",
"2.5", "2.5",
"0.75", ".75",
"-4.0e2", "-4.e2",
"5.0e-3", "+5e-3",
"0", "0x0",
"512", "0x200",
"256", "+0x100",
"-2748", "-0xabc",
"true", "true",
"false", "false",
"null", "null",
"9.0e999", "Infinity",
"-9.0e999", "-Infinity",
"9.0e999", "+Infinity",
"null", "NaN",
"-0.0005123", "-0.0005123",
"4.35e-3", "+4.35e-3",
"\"gem\\\"hay\"", "\"gem\\\"hay\"",
"\"icy'joy\"", "'icy\\'joy\'",
"\"keylog\"", "\"key\\\nlog\"",
"\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"",
"{}", "{}",
"[]", "[]",
"[]", "[/*empty*/]",
"{}", "{//empty\n}",
"\"ask\"", "\"ask\"",
"\"bag\"", "\"bag\"",
"\"can\"", "\"can\"",
"\"day\"", "\"day\"",
"\"end\"", "'end'",
"\"fly\"", "\"fly\"",
"\"\"", "\"\"",
};
static const char *azJsonTemplate[] = {
/* JSON JSON-5 */
"{\"a\":%,\"b\":%,\"c\":%}", "{a:%,b:%,c:%}",
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}",
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,\"\":%}",
"{\"d\":%}", "{d:%}",
"{\"eeee\":%, \"ffff\":%}", "{eeee:% /*and*/, ffff:%}",
"{\"$g\":%,\"_h_\":%}", "{$g:%,_h_:%,}",
"{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}",
"{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}",
"{\"a b c d\":%,e:%,f:%,x:%,y:%}",
"{\"Z\":%}", "{Z:%,}",
"[%]", "[%,]",
"[%,%]", "[%,%]",
"[%,%,%]", "[%,%,%,]",
"[%,%,%,%]", "[%,%,%,%]",
"[%,%,%,%,%]", "[%,%,%,%,%]",
};
#define count(X) (sizeof(X)/sizeof(X[0]))
#define STRSZ 10000
static void jsonExpand(
const char *zSrc,
char *zDest,
Prng *p,
int eType, /* 0 for JSON, 1 for JSON5 */
unsigned int r /* Growth probability 0..1000. 0 means no growth */
){
unsigned int i, j, k;
const char *z;
size_t n;
j = 0;
if( zSrc==0 ){
k = prngInt(p)%(count(azJsonTemplate)/2);
k = k*2 + eType;
zSrc = azJsonTemplate[k];
}
if( strlen(zSrc)>=STRSZ/10 ) r = 0;
for(i=0; zSrc[i]; i++){
if( zSrc[i]!='%' ){
if( j<STRSZ ) zDest[j++] = zSrc[i];
continue;
}
if( r==0 || (r<1000 && (prngInt(p)%1000)<=r) ){
/* Fill in without values without any new % */
k = prngInt(p)%(count(azJsonAtoms)/2);
k = k*2 + eType;
z = azJsonAtoms[k];
}else{
/* Add new % terms */
k = prngInt(p)%(count(azJsonTemplate)/2);
k = k*2 + eType;
z = azJsonTemplate[k];
}
n = strlen(z);
if( j+n<STRSZ ){
memcpy(&zDest[j], z, n);
j += n;
}
}
zDest[STRSZ-1] = 0;
if( j<STRSZ ) zDest[j] = 0;
}
static void randJsonFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
unsigned int iSeed;
int eType = *(int*)sqlite3_user_data(context);
Prng prng;
char z1[STRSZ+1], z2[STRSZ+1];
iSeed = (unsigned int)sqlite3_value_int(argv[0]);
prngSeed(&prng, iSeed);
jsonExpand(0, z2, &prng, eType, 1000);
jsonExpand(z2, z1, &prng, eType, 1000);
jsonExpand(z1, z2, &prng, eType, 100);
jsonExpand(z2, z1, &prng, eType, 0);
sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT);
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_randomjson_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
static int cOne = 1;
static int cZero = 0;
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "random_json", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
&cZero, randJsonFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "random_json5", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
&cOne, randJsonFunc, 0, 0);
}
return rc;
}

View File

@ -1,5 +1,5 @@
/*
** 2015-08-18
** 2015-08-18, 2023-04-28
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@ -12,7 +12,19 @@
**
** This file demonstrates how to create a table-valued-function using
** a virtual table. This demo implements the generate_series() function
** which gives similar results to the eponymous function in PostgreSQL.
** which gives the same results as the eponymous function in PostgreSQL,
** within the limitation that its arguments are signed 64-bit integers.
**
** Considering its equivalents to generate_series(start,stop,step): A
** value V[n] sequence is produced for integer n ascending from 0 where
** ( V[n] == start + n * step && sgn(V[n] - stop) * sgn(step) >= 0 )
** for each produced value (independent of production time ordering.)
**
** All parameters must be either integer or convertable to integer.
** The start parameter is required.
** The stop parameter defaults to (1<<32)-1 (aka 4294967295 or 0xffffffff)
** The step parameter defaults to 1 and 0 is treated as 1.
**
** Examples:
**
** SELECT * FROM generate_series(0,100,5);
@ -28,6 +40,14 @@
**
** Integers 20 through 29.
**
** SELECT * FROM generate_series(0,-100,-5);
**
** Integers 0 -5 -10 ... -100.
**
** SELECT * FROM generate_series(0,-1);
**
** Empty sequence.
**
** HOW IT WORKS
**
** The generate_series "function" is really a virtual table with the
@ -40,6 +60,9 @@
** step HIDDEN
** );
**
** The virtual table also has a rowid, logically equivalent to n+1 where
** "n" is the ascending integer in the aforesaid production definition.
**
** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other
** words, the following pairs of queries are equivalent to each other:
@ -72,9 +95,96 @@
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <limits.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Return that member of a generate_series(...) sequence whose 0-based
** index is ix. The 0th member is given by smBase. The sequence members
** progress per ix increment by smStep.
*/
static sqlite3_int64 genSeqMember(sqlite3_int64 smBase,
sqlite3_int64 smStep,
sqlite3_uint64 ix){
if( ix>=(sqlite3_uint64)LLONG_MAX ){
/* Get ix into signed i64 range. */
ix -= (sqlite3_uint64)LLONG_MAX;
smBase += LLONG_MAX * smStep;
}
return smBase + ((sqlite3_int64)ix)*smStep;
}
typedef unsigned char u8;
typedef struct SequenceSpec {
sqlite3_int64 iBase; /* Starting value ("start") */
sqlite3_int64 iTerm; /* Given terminal value ("stop") */
sqlite3_int64 iStep; /* Increment ("step") */
sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
sqlite3_int64 iValueNow; /* Current value during generation */
u8 isNotEOF; /* Sequence generation not exhausted */
u8 isReversing; /* Sequence is being reverse generated */
} SequenceSpec;
/*
** Prepare a SequenceSpec for use in generating an integer series
** given initialized iBase, iTerm and iStep values. Sequence is
** initialized per given isReversing. Other members are computed.
*/
void setupSequence( SequenceSpec *pss ){
pss->uSeqIndexMax = 0;
pss->isNotEOF = 0;
if( pss->iTerm < pss->iBase ){
sqlite3_uint64 nuspan = (sqlite3_uint64)(pss->iBase-pss->iTerm);
if( pss->iStep<0 ){
pss->isNotEOF = 1;
if( nuspan==ULONG_MAX ){
pss->uSeqIndexMax = ( pss->iStep>LLONG_MIN )? nuspan/-pss->iStep : 1;
}else if( pss->iStep>LLONG_MIN ){
pss->uSeqIndexMax = nuspan/-pss->iStep;
}
}
}else if( pss->iTerm > pss->iBase ){
sqlite3_uint64 puspan = (sqlite3_uint64)(pss->iTerm-pss->iBase);
if( pss->iStep>0 ){
pss->isNotEOF = 1;
pss->uSeqIndexMax = puspan/pss->iStep;
}
}else if( pss->iTerm == pss->iBase ){
pss->isNotEOF = 1;
pss->uSeqIndexMax = 0;
}
pss->uSeqIndexNow = (pss->isReversing)? pss->uSeqIndexMax : 0;
pss->iValueNow = (pss->isReversing)
? genSeqMember(pss->iBase, pss->iStep, pss->uSeqIndexMax)
: pss->iBase;
}
/*
** Progress sequence generator to yield next value, if any.
** Leave its state to either yield next value or be at EOF.
** Return whether there is a next value, or 0 at EOF.
*/
int progressSequence( SequenceSpec *pss ){
if( !pss->isNotEOF ) return 0;
if( pss->isReversing ){
if( pss->uSeqIndexNow > 0 ){
pss->uSeqIndexNow--;
pss->iValueNow -= pss->iStep;
}else{
pss->isNotEOF = 0;
}
}else{
if( pss->uSeqIndexNow < pss->uSeqIndexMax ){
pss->uSeqIndexNow++;
pss->iValueNow += pss->iStep;
}else{
pss->isNotEOF = 0;
}
}
return pss->isNotEOF;
}
/* series_cursor is a subclass of sqlite3_vtab_cursor which will
** serve as the underlying representation of a cursor that scans
@ -83,12 +193,7 @@ SQLITE_EXTENSION_INIT1
typedef struct series_cursor series_cursor;
struct series_cursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
int isDesc; /* True to count down rather than up */
sqlite3_int64 iRowid; /* The rowid */
sqlite3_int64 iValue; /* Current value ("value") */
sqlite3_int64 mnValue; /* Mimimum value ("start") */
sqlite3_int64 mxValue; /* Maximum value ("stop") */
sqlite3_int64 iStep; /* Increment ("step") */
SequenceSpec ss; /* (this) Derived class data */
};
/*
@ -170,12 +275,7 @@ static int seriesClose(sqlite3_vtab_cursor *cur){
*/
static int seriesNext(sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
if( pCur->isDesc ){
pCur->iValue -= pCur->iStep;
}else{
pCur->iValue += pCur->iStep;
}
pCur->iRowid++;
progressSequence( & pCur->ss );
return SQLITE_OK;
}
@ -191,10 +291,10 @@ static int seriesColumn(
series_cursor *pCur = (series_cursor*)cur;
sqlite3_int64 x = 0;
switch( i ){
case SERIES_COLUMN_START: x = pCur->mnValue; break;
case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
case SERIES_COLUMN_STEP: x = pCur->iStep; break;
default: x = pCur->iValue; break;
case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
default: x = pCur->ss.iValueNow; break;
}
sqlite3_result_int64(ctx, x);
return SQLITE_OK;
@ -207,7 +307,7 @@ static int seriesColumn(
*/
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur;
*pRowid = pCur->iRowid;
*pRowid = ((sqlite3_int64)pCur->ss.uSeqIndexNow + 1);
return SQLITE_OK;
}
@ -217,14 +317,10 @@ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
*/
static int seriesEof(sqlite3_vtab_cursor *cur){
series_cursor *pCur = (series_cursor*)cur;
if( pCur->isDesc ){
return pCur->iValue < pCur->mnValue;
}else{
return pCur->iValue > pCur->mxValue;
}
return !pCur->ss.isNotEOF;
}
/* True to cause run-time checking of the start=, stop=, and/or step=
/* True to cause run-time checking of the start=, stop=, and/or step=
** parameters. The only reason to do this is for testing the
** constraint checking logic for virtual tables in the SQLite core.
*/
@ -235,7 +331,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
** once prior to any call to seriesColumn() or seriesRowid() or
** once prior to any call to seriesColumn() or seriesRowid() or
** seriesEof().
**
** The query plan selected by seriesBestIndex is passed in the idxNum
@ -255,7 +351,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
** (so that seriesEof() will return true) if the table is empty.
*/
static int seriesFilter(
sqlite3_vtab_cursor *pVtabCursor,
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStrUnused,
int argc, sqlite3_value **argv
){
@ -263,46 +359,41 @@ static int seriesFilter(
int i = 0;
(void)idxStrUnused;
if( idxNum & 1 ){
pCur->mnValue = sqlite3_value_int64(argv[i++]);
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
}else{
pCur->mnValue = 0;
pCur->ss.iBase = 0;
}
if( idxNum & 2 ){
pCur->mxValue = sqlite3_value_int64(argv[i++]);
pCur->ss.iTerm = sqlite3_value_int64(argv[i++]);
}else{
pCur->mxValue = 0xffffffff;
pCur->ss.iTerm = 0xffffffff;
}
if( idxNum & 4 ){
pCur->iStep = sqlite3_value_int64(argv[i++]);
if( pCur->iStep==0 ){
pCur->iStep = 1;
}else if( pCur->iStep<0 ){
pCur->iStep = -pCur->iStep;
pCur->ss.iStep = sqlite3_value_int64(argv[i++]);
if( pCur->ss.iStep==0 ){
pCur->ss.iStep = 1;
}else if( pCur->ss.iStep<0 ){
if( (idxNum & 16)==0 ) idxNum |= 8;
}
}else{
pCur->iStep = 1;
pCur->ss.iStep = 1;
}
for(i=0; i<argc; i++){
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
/* If any of the constraints have a NULL value, then return no rows.
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
pCur->mnValue = 1;
pCur->mxValue = 0;
pCur->ss.iBase = 1;
pCur->ss.iTerm = 0;
pCur->ss.iStep = 1;
break;
}
}
if( idxNum & 8 ){
pCur->isDesc = 1;
pCur->iValue = pCur->mxValue;
if( pCur->iStep>0 ){
pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
}
pCur->ss.isReversing = pCur->ss.iStep > 0;
}else{
pCur->isDesc = 0;
pCur->iValue = pCur->mnValue;
pCur->ss.isReversing = pCur->ss.iStep < 0;
}
pCur->iRowid = 1;
setupSequence( &pCur->ss );
return SQLITE_OK;
}

View File

@ -1537,9 +1537,19 @@ static u32 zipfileGetTime(sqlite3_value *pVal){
*/
static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
if( pOld ){
ZipfileEntry **pp;
for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext));
*pp = (*pp)->pNext;
if( pTab->pFirstEntry==pOld ){
pTab->pFirstEntry = pOld->pNext;
if( pTab->pLastEntry==pOld ) pTab->pLastEntry = 0;
}else{
ZipfileEntry *p;
for(p=pTab->pFirstEntry; p; p=p->pNext){
if( p->pNext==pOld ){
p->pNext = pOld->pNext;
if( pTab->pLastEntry==pOld ) pTab->pLastEntry = p;
break;
}
}
}
zipfileEntryFree(pOld);
}
}

View File

@ -471,16 +471,17 @@ struct RtreeMatchArg {
** 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__)
# define SQLITE_BYTEORDER 1234
#elif defined(sparc) || defined(__ppc__)
# define SQLITE_BYTEORDER 4321
#else
# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
#endif
# 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(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
# define SQLITE_BYTEORDER 1234
# elif defined(sparc) || defined(__ppc__) || \
defined(__ARMEB__) || defined(__AARCH64EB__)
# define SQLITE_BYTEORDER 4321
# else
# define SQLITE_BYTEORDER 0
# endif
#endif

View File

@ -41,30 +41,6 @@ proc scksum {db dbname} {
return [md5 $txt]
}
proc do_diff_test {tn setup} {
reset_db
forcedelete test.db2
execsql { ATTACH 'test.db2' AS aux }
execsql $setup
sqlite3session S db main
foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
S attach $tbl
S diff aux $tbl
}
set C [S changeset]
S delete
sqlite3 db2 test.db2
sqlite3changeset_apply db2 $C ""
uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok
db2 close
set cksum [scksum db main]
uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum]
}
# Ensure that the diff produced by comparing the current contents of [db]
# with itself is empty.
proc do_empty_diff_test {tn} {

View File

@ -52,6 +52,7 @@ proc do_conflict_test {tn args} {
proc bgerror {args} { set ::background_error $args }
sqlite3session S db main
S object_config rowid 1
foreach t $O(-tables) { S attach $t }
execsql $O(-sql)
@ -81,6 +82,7 @@ proc changeset_from_sql {sql {dbname main}} {
}
set rc [catch {
sqlite3session S db $dbname
S object_config rowid 1
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
S attach $name
}
@ -138,6 +140,7 @@ proc do_then_apply_sql {args} {
proc xConflict args { incr ::n_conflict ; return "OMIT" }
set rc [catch {
sqlite3session S db $dbname
S object_config rowid 1
db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
S attach $name
}
@ -162,6 +165,8 @@ proc do_then_apply_sql {args} {
proc do_iterator_test {tn tbl_list sql res} {
sqlite3session S db main
S object_config rowid 1
if {[llength $tbl_list]==0} { S attach * }
foreach t $tbl_list {S attach $t}
@ -171,6 +176,7 @@ proc do_iterator_test {tn tbl_list sql res} {
foreach v $res { lappend r $v }
set x [list]
# set ::c [S changeset] ; execsql_pp { SELECT quote($::c) }
sqlite3session_foreach c [S changeset] { lappend x $c }
uplevel do_test $tn [list [list set {} $x]] [list $r]
@ -245,3 +251,49 @@ proc number_name {n} {
if {$txt==""} {set txt zero}
return $txt
}
proc scksum {db dbname} {
if {$dbname=="temp"} {
set master sqlite_temp_master
} else {
set master $dbname.sqlite_master
}
set alltab [$db eval "SELECT name FROM $master WHERE type='table'"]
set txt [$db eval "SELECT * FROM $master ORDER BY type,name,sql"]
foreach tab $alltab {
set cols [list]
db eval "PRAGMA $dbname.table_info = $tab" x {
lappend cols "quote($x(name))"
}
set cols [join $cols ,]
append txt [db eval "SELECT $cols FROM $dbname.$tab ORDER BY $cols"]
}
return [md5 $txt]
}
proc do_diff_test {tn setup} {
reset_db
forcedelete test.db2
execsql { ATTACH 'test.db2' AS aux }
execsql $setup
sqlite3session S db main
S object_config rowid 1
foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
S attach $tbl
S diff aux $tbl
}
set C [S changeset]
S delete
sqlite3 db2 test.db2
sqlite3changeset_apply db2 $C ""
uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok
db2 close
set cksum [scksum db main]
uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum]
}

View File

@ -84,6 +84,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
db eval BEGIN
sqlite3session S1 db main
S1 object_config rowid 1
S1 attach *
execsql $sql1 db
set c1 [S1 changeset]
@ -91,6 +92,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
if {$i==1} {
sqlite3session S2 db2 main
S2 object_config rowid 1
S2 attach *
execsql $sql2 db2
set c2 [S2 changeset]
@ -100,6 +102,7 @@ proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
foreach sql [split $sql2 ";"] {
if {[string is space $sql]} continue
sqlite3session S2 db2 main
S2 object_config rowid 1
S2 attach *
execsql $sql db2
lappend c2 [S2 changeset]
@ -341,6 +344,79 @@ do_rebase_test 2.2.3 {
OMIT
} { SELECT * FROM t2 WHERE z='B' } { 1 one B }
reset_db
do_execsql_test 2.3.0 {
CREATE TABLE t1 (b TEXT);
INSERT INTO t1(rowid, b) VALUES(1, 'one');
INSERT INTO t1(rowid, b) VALUES(2, 'two');
INSERT INTO t1(rowid, b) VALUES(3, 'three');
}
do_rebase_test 2.3.1 {
UPDATE t1 SET b = 'two.1' WHERE rowid=2
} {
UPDATE t1 SET b = 'two.2' WHERE rowid=2;
} {
OMIT
} { SELECT rowid, * FROM t1 } {1 one 2 two.1 3 three}
do_rebase_test 2.3.2 {
UPDATE t1 SET b = 'two.1' WHERE rowid=2
} {
UPDATE t1 SET b = 'two.2' WHERE rowid=2;
} {
REPLACE
} { SELECT rowid, * FROM t1 } {1 one 2 two.2 3 three}
do_rebase_test 2.3.3 {
DELETE FROM t1 WHERE rowid=3
} {
DELETE FROM t1 WHERE rowid=3;
} {
OMIT
} { SELECT rowid, * FROM t1 } {1 one 2 two}
do_rebase_test 2.3.4 {
DELETE FROM t1 WHERE rowid=1
} {
UPDATE t1 SET b='one.2' WHERE rowid=1
} {
OMIT
} { SELECT rowid, * FROM t1 } {2 two 3 three}
do_rebase_test 2.3.6 {
UPDATE t1 SET b='three.1' WHERE rowid=3
} {
DELETE FROM t1 WHERE rowid=3;
} {
OMIT
} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three.1}
do_rebase_test 2.3.7 {
UPDATE t1 SET b='three.1' WHERE rowid=3
} {
DELETE FROM t1 WHERE rowid=3;
} {
REPLACE
} { SELECT rowid, * FROM t1 } {1 one 2 two}
do_rebase_test 2.3.8 {
INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
} {
INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
} {
REPLACE
} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.2}
do_rebase_test 2.3.9 {
INSERT INTO t1(rowid, b) VALUES(4, 'four.1')
} {
INSERT INTO t1(rowid, b) VALUES(4, 'four.2');
} {
OMIT
} { SELECT rowid, * FROM t1 } {1 one 2 two 3 three 4 four.1}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 3.0 {

View File

@ -0,0 +1,281 @@
# 2011 Mar 16
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the session module.
#
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 sessionrowid
do_execsql_test 0.0 {
CREATE TABLE t1(a, b);
}
foreach {tn rowid bEmpty} {
1 0 1
2 1 0
3 -1 1
} {
do_test 0.$tn {
sqlite3session S db main
if {$rowid>=0} { S object_config rowid $rowid }
S attach t1
execsql { INSERT INTO t1 VALUES(1, 2); }
expr [string length [S changeset]]==0
} $bEmpty
S delete
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 1.0 {
CREATE TABLE t1(a, b);
}
do_iterator_test 1.1 t1 {
INSERT INTO t1 VALUES('i', 'one');
} {
{INSERT t1 0 X.. {} {i 1 t i t one}}
}
do_execsql_test 1.2 {
SELECT rowid, * FROM t1
} {1 i one}
do_iterator_test 1.3 t1 {
UPDATE t1 SET b='two'
} {
{UPDATE t1 0 X.. {i 1 {} {} t one} {{} {} {} {} t two}}
}
do_iterator_test 1.4 t1 {
DELETE FROM t1;
} {
{DELETE t1 0 X.. {i 1 t i t two} {}}
}
do_iterator_test 1.5 t1 {
INSERT INTO t1(rowid, a, b) VALUES(14, 'hello', 'world');
INSERT INTO t1(rowid, a, b) VALUES(NULL, 'yes', 'no');
INSERT INTO t1(rowid, a, b) VALUES(-123, 'ii', 'iii');
} {
{INSERT t1 0 X.. {} {i -123 t ii t iii}}
{INSERT t1 0 X.. {} {i 15 t yes t no}}
{INSERT t1 0 X.. {} {i 14 t hello t world}}
}
do_iterator_test 1.6 t1 {
UPDATE t1 SET a='deluxe' WHERE rowid=14;
DELETE FROM t1 WHERE rowid=-123;
INSERT INTO t1 VALUES('x', 'xi');
} {
{DELETE t1 0 X.. {i -123 t ii t iii} {}}
{UPDATE t1 0 X.. {i 14 t hello {} {}} {{} {} t deluxe {} {}}}
{INSERT t1 0 X.. {} {i 16 t x t xi}}
}
#-------------------------------------------------------------------------
reset_db
forcedelete test.db2
sqlite3 db2 test.db2
do_execsql_test 2.0 {
CREATE TABLE t1(a, b);
}
do_execsql_test -db db2 2.0.1 {
CREATE TABLE t1(a, b);
}
proc xConflict {args} {
puts "CONFLICT!"
return "OMIT"
}
do_test 2.1 {
set C [changeset_from_sql {
INSERT INTO t1 VALUES('abc', 'def');
}]
sqlite3changeset_apply db2 $C xConflict
execsql { SELECT * FROM t1 } db2
} {abc def}
do_test 2.2 {
set C [changeset_from_sql {
UPDATE t1 SET b='hello'
}]
sqlite3changeset_apply db2 $C xConflict
execsql { SELECT * FROM t1 } db2
} {abc hello}
do_test 2.3 {
set C [changeset_from_sql {
DELETE FROM t1 WHERE b='hello'
}]
sqlite3changeset_apply db2 $C xConflict
execsql { SELECT * FROM t1 } db2
} {}
do_test 2.4 {
do_then_apply_sql {
INSERT INTO t1 VALUES('i', 'one');
INSERT INTO t1 VALUES('ii', 'two');
INSERT INTO t1 VALUES('iii', 'three');
INSERT INTO t1 VALUES('iv', 'four');
}
compare_db db db2
} {}
do_test 2.5 {
do_then_apply_sql {
DELETE FROM t1 WHERE a='ii';
UPDATE t1 SET b='THREE' WHERE a='iii';
UPDATE t1 SET a='III' WHERE a='iii';
INSERT INTO t1 VALUES('v', 'five');
}
compare_db db db2
} {}
do_execsql_test 2.6 {SELECT * FROM t1} {i one III THREE iv four v five}
do_execsql_test -db db2 2.7 {SELECT * FROM t1} {i one III THREE iv four v five}
#-------------------------------------------------------------------------
db2 close
reset_db
forcedelete test.db2
sqlite3 db2 test.db2
set init_sql {
CREATE TABlE t4(a, b);
CREATE INDEX t4a ON t4(a);
CREATE UNIQUE INDEX t4b ON t4(b);
}
do_execsql_test 3.0 $init_sql
do_execsql_test -db db2 3.0a $init_sql
do_execsql_test -db db2 3.1 {
INSERT INTO t4(rowid, a, b) VALUES(43, 'hello', 'world');
}
do_conflict_test 3.2 -sql {
INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def');
} -tables t4 -conflicts {
{INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}}
}
do_execsql_test -db db2 3.3 {
SELECT * FROM t4
} {hello world}
do_execsql_test 3.4 { DELETE FROM t4 }
do_conflict_test 3.5 -sql {
INSERT INTO t4(rowid, a, b) VALUES(43, 'abc', 'def');
} -tables t4 -conflicts {
{INSERT t4 CONFLICT {i 43 t abc t def} {i 43 t hello t world}}
} -policy REPLACE
do_execsql_test -db db2 3.6 {
SELECT * FROM t4
} {abc def}
do_execsql_test 3.7 { DELETE FROM t4 }
do_conflict_test 3.8 -sql {
INSERT INTO t4(rowid, a, b) VALUES(45, 'xyz', 'def');
} -tables t4 -conflicts {
{INSERT t4 CONSTRAINT {i 45 t xyz t def}}
}
do_execsql_test -db db2 3.9 {
SELECT * FROM t4
} {abc def}
do_execsql_test -db db 3.10a { DELETE FROM t4 }
do_execsql_test -db db2 3.10b { DELETE FROM t4 }
do_execsql_test -db db 3.11a {
INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one');
INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two');
}
do_execsql_test -db db2 3.11b {
INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip');
}
do_conflict_test 3.12 -sql {
DELETE FROM t4 WHERE a='one';
} -tables t4 -conflicts {
{DELETE t4 DATA {i 111 t one t one} {i 111 t one t blip}}
}
do_execsql_test -db db2 3.13 {
SELECT * FROM t4
} {one blip}
do_conflict_test 3.14 -sql {
DELETE FROM t4 WHERE a='two';
} -tables t4 -conflicts {
{DELETE t4 NOTFOUND {i 222 t two t two}}
}
do_execsql_test -db db2 3.15 {
SELECT * FROM t4
} {one blip}
do_execsql_test -db db 3.16a { DELETE FROM t4 }
do_execsql_test -db db2 3.16b { DELETE FROM t4 }
do_execsql_test -db db 3.17a {
INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'one');
INSERT INTO t4(rowid, a, b) VALUES(222, 'two', 'two');
}
do_execsql_test -db db2 3.17b {
INSERT INTO t4(rowid, a, b) VALUES(111, 'one', 'blip');
}
do_conflict_test 3.18 -sql {
UPDATE t4 SET b='xyz' WHERE a='one'
} -tables t4 -conflicts {
{UPDATE t4 DATA {i 111 {} {} t one} {{} {} {} {} t xyz} {i 111 t one t blip}}
}
do_execsql_test -db db2 3.19 {
SELECT * FROM t4
} {one blip}
do_conflict_test 3.20 -sql {
UPDATE t4 SET b='123' WHERE a='two'
} -tables t4 -conflicts {
{UPDATE t4 NOTFOUND {i 222 {} {} t two} {{} {} {} {} t 123}}
}
do_execsql_test -db db2 3.21 {
SELECT * FROM t4
} {one blip}
#--------------------------------------------------------------------------
breakpoint
do_diff_test 4.0 {
CREATE TABLE t1(x, y);
CREATE TABLE aux.t1(x, y);
INSERT INTO t1 VALUES(1, 2);
}
do_diff_test 4.1 {
CREATE TABLE t1(x, y);
CREATE TABLE aux.t1(x, y);
INSERT INTO aux.t1 VALUES(1, 2);
}
do_diff_test 4.2 {
CREATE TABLE t1(x, y);
CREATE TABLE aux.t1(x, y);
INSERT INTO t1(rowid, x, y) VALUES(413, 'hello', 'there');
INSERT INTO aux.t1(rowid, x, y) VALUES(413, 'hello', 'world');
}
finish_test

View File

@ -113,17 +113,17 @@ do_execsql_test 3.0 {
do_test 3.1 {
sqlite3session S db main
S object_config_size -1
S object_config size -1
} 1
do_test 3.2.1 { S object_config_size 0 } 0
do_test 3.2.2 { S object_config_size -1 } 0
do_test 3.2.3 { S object_config_size 1 } 1
do_test 3.2.4 { S object_config_size -1 } 1
do_test 3.2.1 { S object_config size 0 } 0
do_test 3.2.2 { S object_config size -1 } 0
do_test 3.2.3 { S object_config size 1 } 1
do_test 3.2.4 { S object_config size -1 } 1
do_test 3.3 { S attach t1 } {}
do_test 3.4 { S object_config_size 1 } {SQLITE_MISUSE}
do_test 3.4 { S object_config_size -1 } {1}
do_test 3.4 { S object_config size 1 } {SQLITE_MISUSE}
do_test 3.4 { S object_config size -1 } {1}
S delete

View File

@ -25,6 +25,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
#define SESSIONS_ROWID "_rowid_"
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@ -46,6 +48,7 @@ struct sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@ -122,6 +125,7 @@ struct SessionTable {
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
@ -514,6 +518,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
sqlite3_session *pSession, /* Session object that owns pTab */
i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@ -522,48 +527,53 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
assert( *pbNullPK==0 );
assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
for(i=0; i<pTab->nCol; i++){
if( pTab->abPK[i] ){
int rc;
int eType;
sqlite3_value *pVal;
if( pTab->bRowid ){
assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
h = sessionHashAppendI64(h, iRowid);
}else{
assert( *pbNullPK==0 );
assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
for(i=0; i<pTab->nCol; i++){
if( pTab->abPK[i] ){
int rc;
int eType;
sqlite3_value *pVal;
if( bNew ){
rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
if( rc!=SQLITE_OK ) return rc;
if( bNew ){
rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
if( rc!=SQLITE_OK ) return rc;
eType = sqlite3_value_type(pVal);
h = sessionHashAppendType(h, eType);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
i64 iVal;
if( eType==SQLITE_INTEGER ){
iVal = sqlite3_value_int64(pVal);
eType = sqlite3_value_type(pVal);
h = sessionHashAppendType(h, eType);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
i64 iVal;
if( eType==SQLITE_INTEGER ){
iVal = sqlite3_value_int64(pVal);
}else{
double rVal = sqlite3_value_double(pVal);
assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
memcpy(&iVal, &rVal, 8);
}
h = sessionHashAppendI64(h, iVal);
}else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
const u8 *z;
int n;
if( eType==SQLITE_TEXT ){
z = (const u8 *)sqlite3_value_text(pVal);
}else{
z = (const u8 *)sqlite3_value_blob(pVal);
}
n = sqlite3_value_bytes(pVal);
if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
h = sessionHashAppendBlob(h, n, z);
}else{
double rVal = sqlite3_value_double(pVal);
assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
memcpy(&iVal, &rVal, 8);
assert( eType==SQLITE_NULL );
assert( pTab->bStat1==0 || i!=1 );
*pbNullPK = 1;
}
h = sessionHashAppendI64(h, iVal);
}else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
const u8 *z;
int n;
if( eType==SQLITE_TEXT ){
z = (const u8 *)sqlite3_value_text(pVal);
}else{
z = (const u8 *)sqlite3_value_blob(pVal);
}
n = sqlite3_value_bytes(pVal);
if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
h = sessionHashAppendBlob(h, n, z);
}else{
assert( eType==SQLITE_NULL );
assert( pTab->bStat1==0 || i!=1 );
*pbNullPK = 1;
}
}
}
@ -846,6 +856,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
sqlite3_session *pSession, /* Session object that owns SessionTable */
i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@ -853,6 +864,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
if( pTab->bRowid ){
if( a[0]!=SQLITE_INTEGER ) return 0;
return sessionGetI64(&a[1])==iRowid;
}
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iCol<pTab->nCol; iCol++){
if( !pTab->abPK[iCol] ){
@ -997,7 +1013,8 @@ static int sessionTableInfo(
int *pnCol, /* OUT: number of columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
u8 **pabPK /* OUT: Array of booleans - true for PK col */
u8 **pabPK, /* OUT: Array of booleans - true for PK col */
int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
sqlite3_stmt *pStmt;
@ -1009,6 +1026,7 @@ static int sessionTableInfo(
u8 *pAlloc = 0;
char **azCol = 0;
u8 *abPK = 0;
int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
@ -1053,10 +1071,15 @@ static int sessionTableInfo(
}
nByte = nThis + 1;
bRowid = (pbRowid!=0);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
nByte += sqlite3_column_bytes(pStmt, 1);
nDbCol++;
if( sqlite3_column_int(pStmt, 5) ) bRowid = 0;
}
if( nDbCol==0 ) bRowid = 0;
nDbCol += bRowid;
nByte += strlen(SESSIONS_ROWID);
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
@ -1078,6 +1101,14 @@ static int sessionTableInfo(
}
i = 0;
if( bRowid ){
size_t nName = strlen(SESSIONS_ROWID);
memcpy(pAlloc, SESSIONS_ROWID, nName+1);
azCol[i] = (char*)pAlloc;
pAlloc += nName+1;
abPK[i] = 1;
i++;
}
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int nName = sqlite3_column_bytes(pStmt, 1);
const unsigned char *zName = sqlite3_column_text(pStmt, 1);
@ -1089,7 +1120,6 @@ static int sessionTableInfo(
i++;
}
rc = sqlite3_reset(pStmt);
}
/* If successful, populate the output variables. Otherwise, zero them and
@ -1106,6 +1136,7 @@ static int sessionTableInfo(
if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
if( pbRowid ) *pbRowid = bRowid;
sqlite3_finalize(pStmt);
return rc;
}
@ -1127,7 +1158,8 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK,
(pSession->bImplicitPK ? &pTab->bRowid : 0)
);
if( pSession->rc==SQLITE_OK ){
int i;
@ -1199,6 +1231,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; ii<pTab->nCol; ii++){
@ -1215,12 +1248,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
for(ii=0; ii<pTab->nCol; ii++){
if( pTab->bRowid ){
nNew += 9 + 1;
pCsr += 9;
}
for(ii=pTab->bRowid; ii<pTab->nCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
sqlite3_value *p = 0;
pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@ -1299,6 +1336,7 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
i64 iRowid,
sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
@ -1314,7 +1352,7 @@ static void sessionPreupdateOneChange(
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
if( (pTab->nCol-pTab->bRowid)!=pSession->hook.xCount(pSession->hook.pCtx) ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@ -1347,14 +1385,16 @@ static void sessionPreupdateOneChange(
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
rc = sessionPreupdateHash(
pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull
);
if( rc!=SQLITE_OK ) goto error_out;
if( bNull==0 ){
/* Search the hash table for an existing record for this row. */
SessionChange *pC;
for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@ -1369,7 +1409,7 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
for(i=0; i<pTab->nCol; i++){
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@ -1384,6 +1424,9 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
if( pTab->bRowid ){
nByte += 9; /* Size of rowid field - an integer */
}
/* Allocate the change object */
pC = (SessionChange *)sessionMalloc64(pSession, nByte);
@ -1400,7 +1443,12 @@ static void sessionPreupdateOneChange(
** required values and encodings have already been cached in memory.
** It is not possible for an OOM to occur in this block. */
nByte = 0;
for(i=0; i<pTab->nCol; i++){
if( pTab->bRowid ){
pC->aRecord[0] = SQLITE_INTEGER;
sessionPutI64(&pC->aRecord[1], iRowid);
nByte = 9;
}
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@ -1515,9 +1563,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
sessionPreupdateOneChange(op, pSession, pTab);
assert( op==SQLITE_UPDATE || iKey1==iKey2 );
sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@ -1556,6 +1605,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
sqlite3_stmt *pStmt;
int bRowid;
int nOldOff;
};
@ -1564,17 +1614,17 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
*ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
*ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
*ppVal = sqlite3_column_value(p->pStmt, iVal);
*ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
(void)pCtx;
@ -1653,14 +1703,16 @@ static char *sessionExprCompareOther(
static char *sessionSelectFindNew(
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
"SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
zDb1, zTbl, zDb2, zTbl, zExpr
zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@ -1674,7 +1726,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
char *zStmt = sessionSelectFindNew(
zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
);
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@ -1685,8 +1739,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
sessionPreupdateOneChange(op, pSession, pTab);
i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
@ -1696,6 +1752,27 @@ static int sessionDiffFindNew(
return rc;
}
/*
** Return a comma-separated list of the fully-qualified (with both database
** and table name) column names from table pTab. e.g.
**
** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
*/
static char *sessionAllCols(
const char *zDb,
SessionTable *pTab
){
int ii;
char *zRet = 0;
for(ii=0; ii<pTab->nCol; ii++){
zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
);
if( !zRet ) break;
}
return zRet;
}
static int sessionDiffFindModified(
sqlite3_session *pSession,
SessionTable *pTab,
@ -1710,11 +1787,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
char *z1 = sessionAllCols(pSession->zDb, pTab);
char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
"SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
if( zStmt==0 ){
if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
@ -1725,12 +1804,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
sqlite3_free(zStmt);
}
sqlite3_free(zStmt);
sqlite3_free(z1);
sqlite3_free(z2);
}
return rc;
@ -1769,9 +1851,12 @@ int sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK,
pSession->bImplicitPK ? &bRowid : 0
);
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@ -2320,7 +2405,7 @@ static int sessionAppendUpdate(
/* If at least one field has been modified, this is not a no-op. */
if( bChanged ) bNoop = 0;
/* Add a field to the old.* record. This is omitted if this modules is
/* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@ -2422,6 +2507,7 @@ static int sessionSelectStmt(
int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@ -2430,7 +2516,7 @@ static int sessionSelectStmt(
int rc = SQLITE_OK;
char *zSql = 0;
const char *zSep = "";
const char *zCols = "*";
const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
int i;
@ -2449,7 +2535,6 @@ static int sessionSelectStmt(
zCols = "tbl, ?2, stat";
}else{
for(i=0; i<nCol; i++){
if( abPK[i] ){
sessionAppendStr(&pkfield, zSep, &rc);
sessionAppendStr(&pkvar, zSep, &rc);
@ -2656,10 +2741,18 @@ static int sessionGenerateChangeset(
sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
int nRewind = buf.nBuf; /* Initial size of write buffer */
int nNoop; /* Size of buffer after writing tbl header */
int bRowid = 0;
/* Check the table schema is still Ok. */
rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
rc = sessionTableInfo(
0, db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK,
(pSession->bImplicitPK ? &bRowid : 0)
);
if( rc==SQLITE_OK && (
pTab->nCol!=nCol
|| pTab->bRowid!=bRowid
|| memcmp(abPK, pTab->abPK, nCol)
)){
rc = SQLITE_SCHEMA;
}
@ -2669,7 +2762,7 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
rc = sessionSelectStmt(
db, 0, pSession->zDb, zName, nCol, azCol, abPK, &pSel
db, 0, pSession->zDb, zName, bRowid, nCol, azCol, abPK, &pSel
);
}
@ -2753,7 +2846,7 @@ int sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@ -2871,6 +2964,19 @@ int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){
break;
}
case SQLITE_SESSION_OBJCONFIG_ROWID: {
int iArg = *(int*)pArg;
if( iArg>=0 ){
if( pSession->pTable ){
rc = SQLITE_MISUSE;
}else{
pSession->bImplicitPK = (iArg!=0);
}
}
*(int*)pArg = pSession->bImplicitPK;
break;
}
default:
rc = SQLITE_MISUSE;
}
@ -3860,6 +3966,7 @@ struct SessionApplyCtx {
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
u8 bIgnoreNoop; /* True to ignore no-op conflicts */
int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@ -4110,8 +4217,9 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
/* TODO */
return sessionSelectStmt(db, p->bIgnoreNoop,
"main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect
"main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
);
}
@ -4807,6 +4915,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@ -4826,8 +4935,8 @@ static int sessionChangesetApply(
int i;
sqlite3changeset_pk(pIter, &abPK, 0);
rc = sessionTableInfo(0,
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
rc = sessionTableInfo(0, db, "main", zNew,
&sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){

View File

@ -80,16 +80,20 @@ int sqlite3session_create(
void sqlite3session_delete(sqlite3_session *pSession);
/*
** CAPIREF: Conigure a Session Object
** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
** created. At present the only valid value for the second parameter is
** [SQLITE_SESSION_OBJCONFIG_SIZE].
** created. At present the only valid values for the second parameter are
** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
** Arguments for sqlite3session_object_config()
*/
int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
/*
** CAPI3REF: Options for sqlite3session_object_config
**
** The following values may passed as the the 4th parameter to
** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@ -105,12 +109,21 @@ void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
**
** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
** This option is used to set, clear or query the flag that enables
** collection of data for tables with no explicit PRIMARY KEY.
**
** Normally, tables with no explicit PRIMARY KEY are simply ignored
** by the sessions module. However, if this flag is set, it behaves
** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
** as their leftmost columns.
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
*/
int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
/*
*/
#define SQLITE_SESSION_OBJCONFIG_SIZE 1
#define SQLITE_SESSION_OBJCONFIG_SIZE 1
#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object

View File

@ -76,9 +76,11 @@ int sql_exec_changeset(
){
sqlite3_session *pSession = 0;
int rc;
int val = 1;
/* Create a new session object */
rc = sqlite3session_create(db, "main", &pSession);
sqlite3session_object_config(pSession, SQLITE_SESSION_OBJCONFIG_ROWID, &val);
/* Configure the session object to record changes to all tables */
if( rc==SQLITE_OK ) rc = sqlite3session_attach(pSession, NULL);
@ -260,7 +262,7 @@ static int SQLITE_TCLAPI test_session_cmd(
{ "diff", 2, "FROMDB TBL", }, /* 8 */
{ "memory_used", 0, "", }, /* 9 */
{ "changeset_size", 0, "", }, /* 10 */
{ "object_config_size", 1, "INTEGER", }, /* 11 */
{ "object_config", 2, "OPTION INTEGER", }, /* 11 */
{ 0 }
};
int iSub;
@ -379,15 +381,27 @@ static int SQLITE_TCLAPI test_session_cmd(
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nSize));
break;
}
case 11: {
case 11: { /* object_config */
struct ObjConfOpt {
const char *zName;
int opt;
} aOpt[] = {
{ "size", SQLITE_SESSION_OBJCONFIG_SIZE },
{ "rowid", SQLITE_SESSION_OBJCONFIG_ROWID },
{ 0, 0 }
};
size_t sz = sizeof(aOpt[0]);
int rc;
int iArg;
if( Tcl_GetIntFromObj(interp, objv[2], &iArg) ){
int iOpt;
if( Tcl_GetIndexFromObjStruct(interp,objv[2],aOpt,sz,"option",0,&iOpt) ){
return TCL_ERROR;
}
rc = sqlite3session_object_config(
pSession, SQLITE_SESSION_OBJCONFIG_SIZE, &iArg
);
if( Tcl_GetIntFromObj(interp, objv[3], &iArg) ){
return TCL_ERROR;
}
rc = sqlite3session_object_config(pSession, aOpt[iOpt].opt, &iArg);
if( rc!=SQLITE_OK ){
extern const char *sqlite3ErrName(int);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));

View File

@ -1537,6 +1537,9 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
Full docs: https://sqlite.org/c3ref/db_config.html
Returns capi.SQLITE_MISUSE if op is not a valid operation ID.
The variants which take `(int, int*)` arguments treat a
missing or falsy pointer argument as 0.
*/
capi.sqlite3_db_config = function(pDb, op, ...args){
if(!this.s){
@ -1565,6 +1568,8 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
case capi.SQLITE_DBCONFIG_ENABLE_VIEW:
case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA:
case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS:
case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER:
return this.ip(pDb, op, args[0], args[1] || 0);
case capi.SQLITE_DBCONFIG_LOOKASIDE:
return this.pii(pDb, op, args[0], args[1], args[2]);

View File

@ -353,7 +353,6 @@ const installOpfsVfs = function callee(options){
state.opIds.xClose = i++;
state.opIds.xDelete = i++;
state.opIds.xDeleteNoWait = i++;
state.opIds.xFileControl = i++;
state.opIds.xFileSize = i++;
state.opIds.xLock = i++;
state.opIds.xOpen = i++;
@ -718,12 +717,9 @@ const installOpfsVfs = function callee(options){
return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
},
xFileControl: function(pFile, opId, pArg){
mTimeStart('xFileControl');
const rc = (capi.SQLITE_FCNTL_SYNC===opId)
? opRun('xSync', pFile, 0)
: capi.SQLITE_NOTFOUND;
mTimeEnd();
return rc;
/*mTimeStart('xFileControl');
mTimeEnd();*/
return capi.SQLITE_NOTFOUND;
},
xFileSize: function(pFile,pSz64){
mTimeStart('xFileSize');
@ -779,8 +775,11 @@ const installOpfsVfs = function callee(options){
return rc;
},
xSync: function(pFile,flags){
mTimeStart('xSync');
++metrics.xSync.count;
return 0; // impl'd in xFileControl()
const rc = opRun('xSync', pFile, flags);
mTimeEnd();
return rc;
},
xTruncate: function(pFile,sz64){
mTimeStart('xTruncate');
@ -1189,7 +1188,15 @@ const installOpfsVfs = function callee(options){
/* Truncate journal mode is faster than delete for
this vfs, per speedtest1. That gap seems to have closed with
Chrome version 108 or 109, but "persist" is very roughly 5-6%
faster than truncate in initial tests. */
faster than truncate in initial tests.
For later analysis: Roy Hashimoto notes that TRUNCATE
and PERSIST modes may decrease OPFS concurrency because
multiple connections can open the journal file in those
modes:
https://github.com/rhashimoto/wa-sqlite/issues/68
*/
"pragma journal_mode=persist;",
/*
This vfs benefits hugely from cache on moderate/large

View File

@ -567,6 +567,8 @@ const char * sqlite3_wasm_enum_json(void){
DefInt(SQLITE_DBCONFIG_ENABLE_VIEW);
DefInt(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT);
DefInt(SQLITE_DBCONFIG_TRUSTED_SCHEMA);
DefInt(SQLITE_DBCONFIG_STMT_SCANSTATUS);
DefInt(SQLITE_DBCONFIG_REVERSE_SCANORDER);
DefInt(SQLITE_DBCONFIG_MAX);
} _DefGroup;
@ -1545,6 +1547,8 @@ int sqlite3_wasm_db_config_ip(sqlite3 *pDb, int op, int arg1, int* pArg2){
case SQLITE_DBCONFIG_ENABLE_VIEW:
case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
case SQLITE_DBCONFIG_TRUSTED_SCHEMA:
case SQLITE_DBCONFIG_STMT_SCANSTATUS:
case SQLITE_DBCONFIG_REVERSE_SCANORDER:
return sqlite3_db_config(pDb, op, arg1, pArg2);
default: return SQLITE_MISUSE;
}

View File

@ -23,7 +23,7 @@
</figure>
<div class="emscripten" id="module-status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
<progress value="0" max="100" id="module-progress" hidden='1'></progress>
</div><!-- /emscripten bits -->
<fieldset id='ui-controls' class='hidden'>
<legend>Options</legend>
@ -68,10 +68,9 @@
<ul>
<li>Control-click the flags to (de)select multiple flags.</li>
<li>The <tt>--big-transactions</tt> flag is important for two
of the bigger tests. Without it, those tests create a
combined total of 140k implicit transactions, reducing their
speed to an absolute crawl, especially when WASMFS is
activated.
of the bigger tests. Without it, those tests create many
thousands of implicit transactions, reducing the affected
tests to an absolute crawl, in particular with OPFS.
</li>
<li>The easiest way to try different optimization levels is,
from this directory:

144
manifest
View File

@ -1,5 +1,5 @@
C Add\sa\snew\smodifier\sto\sdate/time\sfunctions:\s"subsecond".\s\sMay\sbe\nabbreviated\sas\sjust\s"subsec".\s\sThis\smodifier\scauses\sfunctions\sto\stry\nto\sshow\sfractional\sseconds\sif\sthey\sdo\snot\salready.
D 2023-04-21T15:30:47.608
C Add\ssome\stests\sof\ssubsecond\smodifier\sfor\sdate/time\sfunctions.\sSync\swith\strunk.
D 2023-05-04T20:19:33.316
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -86,13 +86,13 @@ F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6d
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
F ext/fts5/fts5.h c132a9323f22a972c4c93a8d5a3d901113a6e612faf30ca8e695788438c5ca2a
F ext/fts5/fts5Int.h f473de2bdae0977af0d6c8cce96e3666821b85efba5f6006c7732662c3aabcb3
F ext/fts5/fts5Int.h ed48a096418ff4a7c02ac9bd1e8d40c46de21b79a132b8b08d3f32233703de7d
F ext/fts5/fts5_aux.c 572d5ec92ba7301df2fea3258576332f2f4d2dfd66d8263afd157d9deceac480
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
F ext/fts5/fts5_config.c 46af0b3c3c3f00bfc5bdd307434d7c5f0fa0678a034dd48345cd83b20068efbd
F ext/fts5/fts5_expr.c 48e8e45261c6030cf5c77f606217a22722b1a4d0b34e2ba6cbfc386581627989
F ext/fts5/fts5_config.c 051056a9052f5d3a4d1c695f996fd364f920e341f136c60ab2c04aa7e267113f
F ext/fts5/fts5_expr.c 7d298d76ea010c339b26ca47f6f69e9aef520ea46c083deaa4e83e87cf0e94b1
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
F ext/fts5/fts5_index.c 17dca8e874df04182bc45063dc0b761acc242b91f1264d2257b7e37bd4e4c2ad
F ext/fts5/fts5_index.c de3cdae2e0056594aad97a728be5c43b6d7a6cdc7e9cc16f197892b2d8689c21
F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
@ -137,6 +137,7 @@ F ext/fts5/test/fts5corrupt3.test 7da9895dafa404efd20728f66ff4b94399788bdc042c36
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
F ext/fts5/test/fts5corrupt5.test 550d0884c14424f9acad051a741f1dd99ec9342277d938e91ff3daf9123d1209
F ext/fts5/test/fts5corrupt6.test bf8eeae07825b088b9665d9d8e4accbd8dc9bf3cb85b6c64cf6c9e18ccc420a4
F ext/fts5/test/fts5corrupt7.test f3e68673af2514e31dd67a2ed163f7f597252ab683dec155b8db0cdc0b668342
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
F ext/fts5/test/fts5detail.test 54015e9c43ec4ba542cfb93268abdf280e0300f350efd08ee411284b03595cc4
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
@ -168,7 +169,7 @@ F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc27826807405
F ext/fts5/test/fts5matchinfo.test 10c9a6f7fe61fb132299c4183c012770b10c4d5c2f2edb6df0b6607f683d737a
F ext/fts5/test/fts5merge.test e92a8db28b45931e7a9c7b1bbd36101692759d00274df74d83fd29d25d53b3a6
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
F ext/fts5/test/fts5misc.test d6d4fdd7ec164e69e50af539137c0565362a4124547bf841ba474f092298637b
F ext/fts5/test/fts5misc.test c02f3e78aa7e62891b5f711c498a877f03252f10a6974e23bc722533233f2603
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
F ext/fts5/test/fts5near.test 211477940142d733ac04fad97cb24095513ab2507073a99c2765c3ddd2ef58bd
@ -271,8 +272,8 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23
F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
F ext/misc/base64.c e83a915fcb94c9332e9a92aa4c3beafe2552bd3da2813fc5fff31918cca0b834
F ext/misc/base85.c 77dfd5813d23ea561d0348f922583888e78f8eaeb2b9a4a28226d092389890b8
F ext/misc/base64.c a71b131e50300c654a66c469a25b62874481f3d1cb3beb56aca9a68edd812e0d
F ext/misc/base85.c 073054111988db593ef5fdb87ab8c459df1ea0c3aaaddf0f5bfa3d72b7e6280a
F ext/misc/basexx.c 5e859e1820620aa8080fb9145eb47089de426ae808f6abb01a8e12921c3a8e67
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
@ -301,11 +302,12 @@ F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
F ext/misc/qpvtab.c 09738419e25f603a35c0ac8bd0a04daab794f48d08a9bc07a6085b9057b99009
F ext/misc/randomjson.c 7dd13664155319d47b9facc0d8dbf45e13062966a47168e54e3f26d48240d7ea
F ext/misc/regexp.c f50ab59bfa8934b7ed98de069d2c74c187f2ef523fb09e85f8840f6459a90942
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
F ext/misc/series.c 8d79354f2c3d46b95ee21272a07cf0bcabb58d1f2b06d9e7b8a31dca1dacb3e5
F ext/misc/series.c 37d27377684d3ea14177540d2f2767163197611eaba905790c96abd4ab552cd3
F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
@ -323,7 +325,7 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546
F ext/misc/zipfile.c b9d615e1d9af7577833861cfaa79b253aec0f26c89239c75af8c790d287d1d39
F ext/misc/zipfile.c b1f36004c19fb5f949fb166fc4ab88e96a86f66629e9ddb4736a45b63fc3d553
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
@ -400,7 +402,7 @@ F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c3350
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/geopoly.c 971e0b5bd9adaf0811feb8c0842a310811159da10319eb0e74fdb42bf26b99ca
F ext/rtree/rtree.c e05929e78d127613a9eea5dc372c77a049484892d8e9fac1fe0cce85ce4fba81
F ext/rtree/rtree.c 925888f7672b326fc2a29b3a212ec3ae4aa2331507ecccfaf7f0ac0335020330
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test d47f58832145fcfed9067bc457ca8664962196c4566c17a1ebd679367db55d11
F ext/rtree/rtree2.test 9d9deddbb16fd0c30c36e6b4fdc3ee3132d765567f0f9432ee71e1303d32603d
@ -449,12 +451,12 @@ F ext/session/session9.test 5409d90d8141881d08285ed1c2c0d8d10fb92069
F ext/session/sessionA.test 1feeab0b8e03527f08f2f1defb442da25480138f
F ext/session/sessionB.test c4fb7f8a688787111606e123a555f18ee04f65bb9f2a4bb2aa71d55ce4e6d02c
F ext/session/sessionC.test f8a5508bc059ae646e5ec9bdbca66ad24bc92fe99fda5790ac57e1f59fce2fdf
F ext/session/sessionD.test 4f91d0ca8afc4c3969c72c9f0b5ea9527e21de29039937d0d973f821e8470724
F ext/session/sessionD.test f5c6a762d00bc6ca9d561695c322ba8ecca2bed370486707ef37cf565d2f6c73
F ext/session/sessionE.test b2010949c9d7415306f64e3c2072ddabc4b8250c98478d3c0c4d064bce83111d
F ext/session/sessionF.test d37ed800881e742c208df443537bf29aa49fd56eac520d0f0c6df3e6320f3401
F ext/session/sessionG.test 3efe388282d641b65485b5462e67851002cd91a282dc95b685d085eb8efdad0a
F ext/session/sessionH.test 71bbff6b1abb2c4ac62b84dee53273c37e0b21e5fde3aed80929403e091ef859
F ext/session/session_common.tcl db0dda567c75950604072251744e9a6ad5795a3009963c44eb8510f23a8cda64
F ext/session/session_common.tcl e5598096425486b363718e2cda48ee85d660c96b4f8ea9d9d7a4c3ef514769da
F ext/session/session_speed_test.c dcf0ef58d76b70c8fbd9eab3be77cf9deb8bc1638fed8be518b62d6cbdef88b3
F ext/session/sessionat.test 00c8badb35e43a2f12a716d2734a44d614ff62361979b6b85419035bc04b45ee
F ext/session/sessionbig.test 47c381e7acfabeef17d98519a3080d69151723354d220afa2053852182ca7adf
@ -465,13 +467,14 @@ F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7
F ext/session/sessionnoop2.test 5c9a882219e54711c98dccd2fd81392f189a59325e4fb5d8ed25e33a0c2f0ba2
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
F ext/session/sessionsize.test 6f644aff31c7f1e4871e9ff3542766e18da68fc7e587b83a347ea9820a002dd8
F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2
F ext/session/sessionrowid.test 6323ba831721205fd729929745038fd54e9d128c66c654b8d0b26853095a321c
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test b039e38e2ba83767b464baf39b297cc0b1cc6f3292255cb467ea7e12d0d0280c
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
F ext/session/sqlite3session.c 1795263b72c1a17e48e95a131a69543af3fa31aa8e81271c7c5cb0911f063604
F ext/session/sqlite3session.h c367c3043dbb57f69cca35258ebbeadb24e8738980b1a1ae1e281c1b0fac3989
F ext/session/test_session.c b55a669a2150eb7c491b8b42c69a3eed9bc895cf5fea371a2c813b9618f72163
F ext/session/sqlite3session.c e50a9218ee360db0a25298adc6614162d80ebe65d3f6a5b0a021e0902f6536a1
F ext/session/sqlite3session.h 653e9d49c4edae231df8a4c8d69c2145195aedb32462d4b44229dbee7d2680fb
F ext/session/test_session.c 5285482f83cd92b4c1fe12fcf88210566a18312f4f2aa110f6399dae46aeccbb
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
@ -491,14 +494,14 @@ F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057af
F ext/wasm/api/sqlite3-api-cleanup.js cc21e3486da748463e02bbe51e2464c6ac136587cdfd5aa00cd0b5385f6ca808
F ext/wasm/api/sqlite3-api-glue.js f1b2dcb944de5138bb5bd9a1559d2e76a4f3ec25260963d709e8237476688803
F ext/wasm/api/sqlite3-api-oo1.js 2691a34a741015127b210954a1b9586764d3ff0c8a20f00fd15c00f339ecc79f
F ext/wasm/api/sqlite3-api-prologue.js 461ffa5a95f4c1935b3970a58790d3cdca62b16e9b9a6a8d993a2a47d7561f51
F ext/wasm/api/sqlite3-api-prologue.js 17f4ec398ba34c5c666fea8e8c4eb82064a35b302f2f2eb355283cd8d3f68ed5
F ext/wasm/api/sqlite3-api-worker1.js 40a5b1813fcbe789f23ae196c833432c8c83e7054d660194ddfc51eab1c5b9bf
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 70914ae97784d3028150bbf252e07a423056c42cc345903c81b5fae661ce512f
F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 69987029bead5a35f1b854e50c3453b527a497a2be35910b2cf07a4d36ec2299
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 89640e4874a60cb2d973306b272384ffb45c7915375c7bb0355c7586f88dc39c
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c c42413ca9f3e64c424b2bbfc5decf639670ca38bc8f7afb7760d5379398c9307
F ext/wasm/api/sqlite3-wasm.c 12a096d8e58a0af0589142bae5a3c27a0c7e19846755a1a37d2c206352fbedda
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 2710a06a59620c6bf7ce298ab1fb6c9ce825b9f9379728b74c486db6613beecc
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@ -532,7 +535,7 @@ F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234
F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18
F ext/wasm/speedtest1-wasmfs.html 7a301f4f5b6ad4f5d37fd6e7ca03a2f5d5547fd289da60a39075a93d7646d354
F ext/wasm/speedtest1-worker.html fe6b36a63de1012bb9fb4d2fb888b6de9c589c21b0aa3ae054459b0093e077bf
F ext/wasm/speedtest1-worker.html 82869822e641c1bef3ec0cd2d7d2b6a42d0b4f68a7b160fb2e1dd0b523940a9b
F ext/wasm/speedtest1-worker.js 13b57c4a41729678a1194014afec2bd5b94435dcfc8d1039dfa9a533ac819ee1
F ext/wasm/speedtest1.html ff048b4a623aa192e83e143e48f1ce2a899846dd42c023fdedc8772b6e3f07da
F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x
@ -565,15 +568,15 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
F src/alter.c 482c534877fbb543f8295992cde925df55443febac5db5438d5aaba6f78c4940
F src/analyze.c 01bfd40026632eaae1d93212b684f539c6674cb573535dc90199674cbf7e0cdc
F src/analyze.c a1f3061af16c99f73aed0362160176c31a6452de1b02ada1d68f6839f2a37df0
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
F src/btmutex.c 6ffb0a22c19e2f9110be0964d0731d2ef1c67b5f7fabfbaeb7b9dabc4b7740ca
F src/btree.c af379d801906f21dc18b534fc250a479f56045a450d8d5859ba2f57fd9eefcef
F src/btree.c 1949007d2792cf761799348b3760c8489d1964c49efa9e52591aa1f2fcdbc96f
F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc
F src/btreeInt.h a3268a60cbc91f578001f44ba40aae9c1b8aecbb0d2c095dd7fc54b0872ea4b8
F src/btreeInt.h a9ae91868acc4b3146d47ae2a072aac2cf41ecb7386015752160c8e1a212d9f2
F src/build.c 8357d6ca9a8c9afc297c431df28bc2af407b47f3ef2311875276c944b30c4d54
F src/callback.c 4cd7225b26a97f7de5fee5ae10464bed5a78f2adefe19534cc2095b3a8ca484a
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
@ -582,20 +585,20 @@ F src/date.c aca9e0c08b400b21238b609aea7c09585396cd770985cf8f475560f69222dad3
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
F src/delete.c a9c6d3f51c0a31e9b831e0a0580a98d702904b42d216fee530940e40dec34873
F src/expr.c 6353f4d92d9f67ec3466d8e6978cd31a45e34cb755c4d11e689077f03f7c0a15
F src/expr.c 871cfd80c516ee39d90414b2d3da2b5bc9c9e21fe87b7eb787ea7ae4b6461758
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 03c134cc8bffe54835f742ddea0b72ebfc8f6b32773d175c71b8afeea6cb5c83
F src/func.c d187be57a886ddf4e6b7ef584a494361899be3df5eee6d4a747b68ff4aff4122
F src/global.c 428d2580a1cdf5dbe1f356d1feab83710ae0cc862ece0fb57bc8259e43838c74
F src/global.c bd0892ade7289f6e20bff44c07d06371f2ff9b53cea359e7854b9b72f65adc30
F src/hash.c c6af5f96a7a76d000f07c5402c48c318c2566beecdee9e78b9d9f60ce7119565
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4
F src/json.c edae65fe1f66ce8b1e7fa6eb036a3d8cf525dacd91d58f12068e80a81ac34f61
F src/json.c 7297dbd1d623850578c21bb8a99b87e745d09e14fd36ebc965ace67c86f902b4
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136
F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
F src/main.c 035be2e9ba2a0fc1701a8ab1880af3001a968a24556433538a6c073558ee4341
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@ -604,7 +607,7 @@ F src/mem3.c 30301196cace2a085cbedee1326a49f4b26deff0af68774ca82c1f7c06fda4f6
F src/mem5.c b7da5c10a726aacacc9ad7cdcb0667deec643e117591cc69cf9b4b9e7f3e96ff
F src/memdb.c 559c42e61eb70cd6d4bc692b042497133c6d96c09a3d514d92f3dac72268e223
F src/memjournal.c c283c6c95d940eb9dc70f1863eef3ee40382dbd35e5a1108026e7817c206e8a0
F src/msvc.h 3a15918220367a8876be3fa4f2abe423a861491e84b864fb2b7426bf022a28f8
F src/msvc.h 80b35f95d93bf996ccb3e498535255f2ef1118c78764719a7cd15ab4106ccac9
F src/mutex.c 5e3409715552348732e97b9194abe92fdfcd934cfb681df4ba0ab87ac6c18d25
F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
@ -617,27 +620,27 @@ F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
F src/os_unix.c 1b3ddb7814c4bf37f494c04d2ab30c1ced5b2c927267e1930ce7cd388787a96d
F src/os_win.c 295fe45f18bd86f2477f4cd79f3377c6f883ceb941b1f46808665c73747f2345
F src/os_win.c 2b2411279f7b24f927591561303fc5871845732df42641cbf695c23640b16975
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 9d36ddedc842e993c88c222ed914822dbd6f8ece3c648fde04468637012a034a
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
F src/parse.y e8b5c753e3194e03d69e108753c1dbceb01fa4c158b2c6b726a048023ea0fdc1
F src/parse.y 146f9a1db7db5ef4299c6897d335e5abed348c2626190d2877d45ffa210fd4ca
F src/pcache.c 8ee13acccfd9accbf0af94910b7323dd7f7d55300d92ddafcf40e34fcc8e21be
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc
F src/pragma.c 26ed2cfdc5c12aa1c707178635709684960288cacc9cff9d491a38ff10e395f1
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 06ecbb25db151a009be99471757c73272cd61306903dc3eeb7250bdcf54896dd
F src/printf.c 7eac1a9896a80697e03e08963e210830532ae2ff610e16c193e95af007ca5623
F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e
F src/printf.c 19a25adf1b73892d41af7d8f7cbc55b01b592bf2062e68b9f10e604d8deee7e0
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c f879cef11c462a2c37a8c906932781e384c3bb32042c355a704a043029c90d27
F src/shell.c.in efd4b8def6be9cdd5d8d3eb17940bc23cfce1ee5bdd419fdda933dd601de6e34
F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef
F src/shell.c.in 39ea3d9c17c65c42c6c415222d89a32ae683b245c8af7b4bfc544d9246055d16
F src/sqlite.h.in d6b0b83b2deab8f92ef7cc6f6fb94fa59d21c59f7b55f4c693bfff161ce42238
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
F src/sqliteInt.h bf15f7db635d2e64a227bbf86845bc19755dbd932021a6461d6dd15b0da2cfd3
F src/sqliteInt.h 91303fb4ee858b85ae1a8a48cc8f723339b81ba7138b42ee5c000083bfff0934
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -682,7 +685,7 @@ F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b
F src/test_schema.c f5d6067dfc2f2845c4dd56df63e66ee826fb23877855c785f75cc2ca83fd0c1b
F src/test_sqllog.c 540feaea7280cd5f926168aee9deb1065ae136d0bbbe7361e2ef3541783e187a
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_syscall.c 9fdb13b1df05e639808d44fcb8f6064aaded32b6565c00b215cfd05a060d1aca
F src/test_tclsh.c 3ff5d188a72f00807425954ea3b493dfd3a4b890ecc6700ea83bad2fd1332ecf
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 7ddcf0c8b79fa3c1d172f82f322302c963d923cdb503c6171f3c8081586d0b01
@ -700,27 +703,27 @@ F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
F src/update.c 3f4fb5ad7c9b48d7911974d6579192bb3a6c27f46140b6cbb9139cc8a77b8691
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c b1d8d87c4c8c77e70f48c43f91444fd66d91532693573b70b837afd572010176
F src/util.c d4bcb560471cd94e6e17d448311f8d5bf81a7e5276295a53501058ef1b95dd1a
F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd
F src/vdbe.c a6c52ba65e8ceb574fe0eda62af84e6c50c176ffc5f310c613425f7ab2b1484b
F src/vdbe.c 94d5520d2a287216c47e6fb641ee88ffd934b0d40c235d693d38bcd0e0750357
F src/vdbe.h 637ae853b7d42ae3951034cc63ab7c8af837861f79504cdb5399552fcd89a884
F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb
F src/vdbeapi.c 1a95162e26d5eda3b7b46fbe4fcbc33eb7f801529d66fc2e14c52094a5523339
F src/vdbeaux.c 24637a004cda26aca1970a78ebfb9f7895aec820525bdb784a76933bb4af83f7
F src/vdbeapi.c b4982cde547054c4f7341198db3c3008a48e1eb028f757601bf5bf2fc026cbcf
F src/vdbeaux.c 6ee48db408d4c297a363f1e31145c09793a580e7c508bb36063dd017d67117a2
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
F src/vdbemem.c 1d9a0f37b0097fbb53f0d7ba081f7181b83cee2c6f46364706ea0c3896bd8ec0
F src/vdbemem.c 1cac4028c0dabbf1f3259f107440e2780e05ac9fe419e9709e6eb4e166ba714b
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
F src/vtab.c 4a1b231b5938de0282fbb605eb068ca673a1b6a383130f54d1bcbbac951988ad
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 3f4ac276a60bda76f9f1f6f1c2c38599bacd4987e5efcd3f7fed2647bf97280a
F src/wal.c 7a65f64bfe4a783c5e2df73ffb0efc383dec934dee9e3ac706b2eeb3631d17ac
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
F src/where.c ef9e644d1d76e86f68c941eb05d30a98fc0811eeef2a110906d81fedde81b6bf
F src/where.c f69d94f34e1c523cd9b66041e4afe015cad29888617f3c09a2a5bc36018917d0
F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c
F src/wherecode.c 85790d7e5365ac41085713331ce52e4343586ad3d37d218ffe00572357baa62b
F src/whereexpr.c 1dfda1695e4480c24248157df55bb4d66c732dc8d14ac16b4f076bb15de93d63
F src/wherecode.c b300db0bcd84ad6c2642bf3f509f92fad7b7d697b9856b64dd66d692d184d054
F src/whereexpr.c 22cf19b0ececeaf838daed1039c5231a8778784eba5ad67b991442a23473fd3f
F src/window.c e075ea85bea322e30e361fa6e69eddba74f461e99e2a564dc09973f8a1fb27d9
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@ -752,7 +755,7 @@ F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e5564
F test/altertrig.test fb5951d21a2c954be3b8a8cf8e10b5c0fa20687c53fd67d63cea88d08dd058d5
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7
F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324
F test/analyze3.test 03f4b3d794760cf15da2d85a52df9bae300e51c8fefe9c36cfae1f86dc10d23f
F test/analyze4.test 68bd069f3ac7ac1e652ddd9f04f57d5606ddb4208450f5297005db7aa0dd707d
F test/analyze5.test fa5131952303ac4146aba101b116b9c8cb89e2637531c334a6df7f7d19dddc0d
F test/analyze6.test 028f5bdfc9e5b5294768fa9a7185b8cd1d019aa7aab5b2f8ee42d7271d9a3b28
@ -919,10 +922,10 @@ F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f5414069
F test/cse.test 00b3aea44b16828833c94fbe92475fd6977583fcb064ae0bc590986812b38d0c
F test/csv01.test 2ab5514005fd308995c8910bc313e47f0368b94213b9d6c27f9a2da78796a091
F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c4773
F test/cursorhint.test a44811a341281ebb73b939cb11bdcc2f374dc70e7e0f6cd7bfcb02e6fee67831
F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
F test/date.test 118e04db8c8b4efeb885542b4918c7b869a34c460a6bebbfe927dfd75706b80d
F test/date.test 1d44557f668298b10d3335b22ab8feb133267b67ec4d85538908fe4dfebd2611
F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
F test/dbdata.test 042f49acff3438f940eeba5868d3af080ae64ddf26ae78f80c92bec3ca7d8603
@ -1227,7 +1230,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9
F test/join.test ed1daf99958fed1b9f017e56bae2bb6b49339a1ec0b70b9e8f7259960c6bf387
F test/join.test aea7a4f55b2d9eb8ef3434ea78f55b15bd688ab6136a11105c9c52f77424f199
F test/join2.test 8561fe82ce434ac96de91544072e578dc2cadddf2d9bc9cd802f866a9b92502e
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
@ -1242,18 +1245,24 @@ F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f2
F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be28
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
F test/joinH.test 15f501b33d848521964afde9865a92aeca79c8c41fa84dc4dc3f865c9ed8c868
F test/joinH.test 705157cf9b9b7c207caf960812a7d0e4dc1dd45aa5fb2b563f12df59088645f3
F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9e1946
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test c7707ee623c57a24845ef260d4388a6fade1eb294e450caadd7f1d9ced19dea7
F test/json102.test 327e77275f338c028faefa2da5164daf6b142a165e3015ff2a6e4251ddc6a0ac
F test/json/README.md 506af1f54574b524106acb50d1a341ab5ddfa6d83fe25095007892b07e663e85
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
F test/json/json-q1.txt 335a7c8ab291d354f33b7decc9559e99a2823d4142291c4be7aa339a631f3c2d
F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x
F test/json101.test ff8024cbb8092e723237648cea9bdbd51f31476b5015a4df3a5ecc8a5efda837
F test/json102.test 13dc9e7b7f359ecb861e02f9bd7019f7342a63d1c354273b0a8f3904050560a8
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
F test/json104.test a502dc01853aada95d721b3b275afbe2dc18fffdac1fea6e96fb20c13586bbb5
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
F test/json105.test 11670a4387f4308ae0318cadcbd6a918ea7edcd19fbafde020720a073952675d
F test/json501.test f71710f60fa45b19dc336fbaac9e8362f70f80cf81badefdb845ed3f7c7c2ccc
F test/json502.test 66d150cc098674b8bf4354526a8dd411b926f43ca892306bcb3b6d3f93fef7be
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/kvtest.c feb4358fb022da8ebd098c45811f2f6507688bb6c43aa72b3e840df19026317b
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
@ -1316,7 +1325,7 @@ F test/minmax.test fe638b55d77d2375531a8f549b338eafcd9adfbd2f72df37ed77d9b26ca0a
F test/minmax2.test cf9311babb6f0518d04e42fd6a42c619531c4309a9dd790a2c4e9b3bc595e0de
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 272ca395257f05937dc96441c9dde4bc9fbf116a8d4fa02baeb0d13d50e36c87
F test/misc1.test 9955e70cab5e284d77e358cfa1f1dd43f5e4bc00a421018581b0fbd62206a6a1
F test/misc1.test 8d138a4926ab90617c1aa29ce26e7785ae2b83a4d3a195d543b7374e05589dd1
F test/misc2.test 71e746af479119386ac2ed7ab7d81d99970e75b49ffd3e8efffee100b4b5f350
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
@ -1491,8 +1500,8 @@ F test/sharedA.test 64bdd21216dda2c6a3bd3475348ccdc108160f34682c97f2f51c19fc0e21
F test/sharedB.test 1a84863d7a2204e0d42f2e1606577c5e92e4473fa37ea0f5bdf829e4bf8ee707
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test 291c5c4b313adbe44d847af78b730a3bbfa1598c450e09ffe5601170bf7f28e7
F test/shell2.test 35c0c19d3198ee7669a748c1aedcce27a776ee575cc76128f8fcf665b79672f7
F test/shell1.test 300b77328aaafb9f3e7a53a26e4162fbf92181d92251d259ff105a2275ff998d
F test/shell2.test 09a202f57e7cd99788537f763e0845796a173fcea06a0d199a08d69446fe1daf
F test/shell3.test 91febeac0412812bf6370abb8ed72700e32bf8f9878849414518f662dfd55e8a
F test/shell4.test 9abd0c12a7e20a4c49e84d5be208d2124fa6c09e728f56f1f4bee0f02853935f
F test/shell5.test c8b6c54f26ec537f8558273d7ed293ca3725ef42e6b12b8f151718628bd1473b
@ -1564,7 +1573,7 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309
F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
F test/tabfunc01.test 668e5e39108ce84b2f24e402f9382daecc0417edb9c78c6c8f58170584e80c91
F test/tabfunc01.test 54f27eacd054aa528a8b6e3331192c484104f30aaee351ad035f2b39a00f87c4
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
@ -1951,7 +1960,7 @@ F test/writecrash.test f1da7f7adfe8d7f09ea79b42e5ca6dcc41102f27f8e334ad71539501d
F test/zeroblob.test 7b74cefc7b281dfa2b07cd237987fbe94b4a2037a7771e9e83f2d5f608b1d99e
F test/zeroblobfault.test 861d8191a0d944dfebb3cb4d2c5b4e46a5a119eaec5a63dd996c2389f8063441
F test/zerodamage.test 9c41628db7e8d9e8a0181e59ea5f189df311a9f6ce99cc376dc461f66db6f8dc
F test/zipfile.test 4178a2de98739e9adac41cb8f0be5553df060e470c846f51fdbed247117728a7
F test/zipfile.test 416adb0ca9bb54f978fe2e77978b1b964ce5e1c0199f45e381caa771e9f8cfc1
F test/zipfile2.test 9903388a602a3834189857a985106ff95c3bba6a3969e0134127df991889db5d
F test/zipfilefault.test 44d4d7a7f7cca7521d569d7f71026b241d65a6b1757aa409c1a168827edbbc2c
F tool/GetFile.cs 47852aa0d806fe47ed1ac5138bdce7f000fe87aaa7f28107d0cb1e26682aeb44
@ -2013,7 +2022,7 @@ F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809
F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1
F tool/showwal.c 4699048f68b6dd7b451011abfff404b8890d5a0b7dab78d2ad50d018116239d5
F tool/showwal.c 65ecabae3a2dcff4116301d5a8dbb8c4964814da1b2aff6d85c806a88b71fa4e
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/spaceanal.tcl 1b5be34c6223cb1af06da2a10fb77863eb869b1962d055820b0a11cf2336ab45
F tool/speed-check.sh c24c30cddd0ecb6d1d0775411d22f7619f55fa696a305487645e27b1b8fc05a2
@ -2059,11 +2068,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 13f2638622871db9b91db547dcfd38f61c03e7696e4df5144adefcd86140aeba
R 2529341824942da9d8aad7d6b6ee37a6
T *branch * subsec-modifier
T *sym-subsec-modifier *
T -sym-trunk *
U drh
Z 03013fcb8c96af9e078547fa6f689eef
P 03f2a15e8779d8ca76510badeabde62a0539ce8a6368d7a9688f5aadc215b940 83683e108bce83c105bbcce1aa62880d8f14ebf3383d87d83a1e5c85026a7817
R 8af27f80731782e09fcf7d27c983e6a4
U larrybr
Z e803a0dc2aef84dc50855cfa469da94e
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
03f2a15e8779d8ca76510badeabde62a0539ce8a6368d7a9688f5aadc215b940
6499ebff545e663198bd0534be205a4e9ca68c7fb20fdcfa54fae4d9b79bfe3a

View File

@ -1781,6 +1781,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
if( pIdx->aSample!=0 ){
/* The same index appears in sqlite_stat4 under multiple names */
continue;
}
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@ -1788,6 +1792,7 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
pIdx->mxSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@ -1827,6 +1832,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
if( pIdx->nSample>=pIdx->mxSample ){
/* Too many slots used because the same index appears in
** sqlite_stat4 using multiple names */
continue;
}
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@ -1870,11 +1880,12 @@ static int loadStat4(sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
if( OptimizationEnabled(db, SQLITE_Stat4)
&& (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);

View File

@ -7628,7 +7628,7 @@ static int pageFreeArray(
}
}
if( j>=nFree ){
if( nFree>=sizeof(aOfst)/sizeof(aOfst[0]) ){
if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
for(j=0; j<nFree; j++){
freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
}
@ -9333,7 +9333,7 @@ int sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
|| (pCur->eState==CURSOR_INVALID && loc) );
|| (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );

View File

@ -172,7 +172,7 @@
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
** As a special case, all 8 bytes of the 9th byte are used as data. This
** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000

View File

@ -1113,9 +1113,9 @@ Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
** If one side or the other of the AND is known to be false, then instead
** of returning an AND expression, just return a constant expression with
** a value of false.
** If one side or the other of the AND is known to be false, and neither side
** is part of an ON clause, then instead of returning an AND expression,
** just return a constant expression with a value of false.
*/
Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
sqlite3 *db = pParse->db;
@ -1123,14 +1123,17 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
return pRight;
}else if( pRight==0 ){
return pLeft;
}else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
&& !IN_RENAME_OBJECT
){
sqlite3ExprDeferredDelete(pParse, pLeft);
sqlite3ExprDeferredDelete(pParse, pRight);
return sqlite3Expr(db, TK_INTEGER, "0");
}else{
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
u32 f = pLeft->flags | pRight->flags;
if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
&& !IN_RENAME_OBJECT
){
sqlite3ExprDeferredDelete(pParse, pLeft);
sqlite3ExprDeferredDelete(pParse, pRight);
return sqlite3Expr(db, TK_INTEGER, "0");
}else{
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
}
}
}

View File

@ -97,7 +97,7 @@ const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne];
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
** SQLite identifier character 0x40
** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper

1008
src/json.c

File diff suppressed because it is too large Load Diff

View File

@ -3933,7 +3933,7 @@ int sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}

View File

@ -38,4 +38,8 @@
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
#define HAVE_LOG2 0
#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
#endif /* SQLITE_MSVC_H */

View File

@ -5197,7 +5197,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@ -5214,7 +5214,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@ -5234,7 +5234,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@ -5457,6 +5457,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
if( zFilename==0 ){
*pResOut = 0;
OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
zFilename, pResOut, *pResOut));
return SQLITE_OK;
}
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));

View File

@ -715,7 +715,7 @@ seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N
seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). {
if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){
A = F;
}else if( F->nSrc==1 ){
}else if( ALWAYS(F!=0) && F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N);
if( A ){
SrcItem *pNew = &A->a[A->nSrc-1];

View File

@ -702,7 +702,11 @@ static int sqlite3Prepare(
sParse.db = db;
sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
if( db->mallocFailed ){
sqlite3ErrorMsg(&sParse, "out of memory");
db->errCode = rc = SQLITE_NOMEM;
goto end_prepare;
}
assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of

View File

@ -649,6 +649,7 @@ void sqlite3_str_vappendf(
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
if( cThousand ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
@ -666,10 +667,12 @@ void sqlite3_str_vappendf(
}else if( msd>0 ){
for(; e2>=0; e2--){
*(bufpt++) = et_getdigit_int(&longvalue,&msd);
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}else{
for(; e2>=0; e2--){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}
/* The decimal point */

View File

@ -765,7 +765,7 @@ static void shell_out_of_memory(void){
/* Check a pointer to see if it is NULL. If it is NULL, exit with an
** out-of-memory error.
*/
static void shell_check_oom(void *p){
static void shell_check_oom(const void *p){
if( p==0 ) shell_out_of_memory();
}
@ -994,6 +994,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
fflush(stdout);
do{
zResult = local_getline(zPrior, stdin);
zPrior = 0;
/* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
if( zResult==0 ) sqlite3_sleep(50);
}while( zResult==0 && seenInterrupt>0 );
@ -1145,6 +1146,7 @@ static void appendText(ShellText *p, const char *zAppend, char quote){
*/
static char quoteChar(const char *zName){
int i;
if( zName==0 ) return '"';
if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
for(i=0; zName[i]; i++){
if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
@ -1526,6 +1528,7 @@ static ShellState shellState;
#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */
#define SHFLG_TestingMode 0x00000400 /* allow unsafe testing features */
/*
** Macros for testing and setting shellFlgs
@ -1859,6 +1862,7 @@ static void output_quoted_string(FILE *out, const char *z){
int i;
char c;
setBinaryMode(out, 1);
if( z==0 ) return;
for(i=0; (c = z[i])!=0 && c!='\''; i++){}
if( c==0 ){
utf8_printf(out,"'%s'",z);
@ -1988,6 +1992,7 @@ static void output_c_string(FILE *out, const char *z){
*/
static void output_json_string(FILE *out, const char *z, i64 n){
unsigned int c;
if( z==0 ) z = "";
if( n<0 ) n = strlen(z);
fputc('"', out);
while( n-- ){
@ -3563,10 +3568,14 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC);
if( rc==SQLITE_OK && pQ && sqlite3_step(pQ)==SQLITE_ROW ){
sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0));
#ifdef NAN
}else if( sqlite3_strlike("_NAN", zVar, 0)==0 ){
sqlite3_bind_double(pStmt, i, NAN);
#endif
#ifdef INFINITY
}else if( sqlite3_strlike("_INF", zVar, 0)==0 ){
sqlite3_bind_double(pStmt, i, INFINITY);
#endif
}else{
sqlite3_bind_null(pStmt, i);
}
@ -3810,7 +3819,7 @@ static void exec_prepared_stmt_columnar(
azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
shell_check_oom(azData);
azNextLine = sqlite3_malloc64( nColumn*sizeof(char*) );
shell_check_oom((void*)azNextLine);
shell_check_oom(azNextLine);
memset((void*)azNextLine, 0, nColumn*sizeof(char*) );
if( p->cmOpts.bQuote ){
azQuoted = sqlite3_malloc64( nColumn*sizeof(char*) );
@ -3840,6 +3849,7 @@ static void exec_prepared_stmt_columnar(
}
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
if( uz==0 ) uz = (u8*)"";
azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
}
do{
@ -4773,13 +4783,13 @@ static const char *(azHelp[]) = {
" input text.",
#endif
#ifndef SQLITE_OMIT_TEST_CONTROL
".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
",imposter INDEX TABLE Create imposter table TABLE on index INDEX",
#endif
".indexes ?TABLE? Show names of indexes",
" If TABLE is specified, only show indexes for",
" tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
".iotrace FILE Enable I/O diagnostic logging to FILE",
",iotrace FILE Enable I/O diagnostic logging to FILE",
#endif
".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
".lint OPTIONS Report potential schema issues.",
@ -4888,7 +4898,7 @@ static const char *(azHelp[]) = {
" Options:",
" --indent Try to pretty-print the schema",
" --nosys Omit objects whose names start with \"sqlite_\"",
".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
",selftest ?OPTIONS? Run tests defined in the SELFTEST table",
" Options:",
" --init Create a new SELFTEST table",
" -v Verbose output",
@ -4930,9 +4940,9 @@ static const char *(azHelp[]) = {
#endif
".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
#ifndef SQLITE_SHELL_FIDDLE
".testcase NAME Begin redirecting output to 'testcase-out.txt'",
",testcase NAME Begin redirecting output to 'testcase-out.txt'",
#endif
".testctrl CMD ... Run various sqlite3_test_control() operations",
",testctrl CMD ... Run various sqlite3_test_control() operations",
" Run \".testctrl\" with no arguments for details",
".timeout MS Try opening locked tables for MS milliseconds",
".timer on|off Turn SQL timer on or off",
@ -4984,16 +4994,41 @@ static int showHelp(FILE *out, const char *zPattern){
|| cli_strcmp(zPattern,"-all")==0
|| cli_strcmp(zPattern,"--all")==0
){
/* Show all commands, but only one line per command */
if( zPattern==0 ) zPattern = "";
enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 };
enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 };
/* Show all or most commands
** *zPattern==0 => summary of documented commands only
** *zPattern=='0' => whole help for undocumented commands
** Otherwise => whole help for documented commands
*/
enum HelpWanted hw = HW_SummaryOnly;
enum HelpHave hh = HH_More;
if( zPattern!=0 ){
hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull;
}
for(i=0; i<ArraySize(azHelp); i++){
if( azHelp[i][0]=='.' || zPattern[0] ){
utf8_printf(out, "%s\n", azHelp[i]);
n++;
switch( azHelp[i][0] ){
case ',':
hh = HH_Summary|HH_Undoc;
break;
case '.':
hh = HH_Summary;
break;
default:
hh &= ~HH_Summary;
break;
}
if( ((hw^hh)&HH_Undoc)==0 ){
if( (hh&HH_Summary)!=0 ){
utf8_printf(out, ".%s\n", azHelp[i]+1);
++n;
}else if( (hw&HW_SummaryOnly)==0 ){
utf8_printf(out, "%s\n", azHelp[i]);
}
}
}
}else{
/* Look for commands that for which zPattern is an exact prefix */
/* Seek documented commands for which zPattern is an exact prefix */
zPat = sqlite3_mprintf(".%s*", zPattern);
shell_check_oom(zPat);
for(i=0; i<ArraySize(azHelp); i++){
@ -5006,24 +5041,28 @@ static int showHelp(FILE *out, const char *zPattern){
sqlite3_free(zPat);
if( n ){
if( n==1 ){
/* when zPattern is a prefix of exactly one command, then include the
** details of that command, which should begin at offset j */
while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){
/* when zPattern is a prefix of exactly one command, then include
** the details of that command, which should begin at offset j */
while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){
utf8_printf(out, "%s\n", azHelp[j]);
j++;
}
}
return n;
}
/* Look for commands that contain zPattern anywhere. Show the complete
** text of all commands that match. */
/* Look for documented commands that contain zPattern anywhere.
** Show complete text of all documented commands that match. */
zPat = sqlite3_mprintf("%%%s%%", zPattern);
shell_check_oom(zPat);
for(i=0; i<ArraySize(azHelp); i++){
if( azHelp[i][0]==',' ){
while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i;
continue;
}
if( azHelp[i][0]=='.' ) j = i;
if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
utf8_printf(out, "%s\n", azHelp[j]);
while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){
j++;
utf8_printf(out, "%s\n", azHelp[j]);
}
@ -5349,6 +5388,13 @@ static void open_db(ShellState *p, int openFlags){
}
sqlite3_db_config(p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, (int)0, (int*)0);
/* Reflect the use or absence of --unsafe-testing invocation. */
{
int testmode_on = ShellHasFlag(p,SHFLG_TestingMode);
sqlite3_db_config(p->db, SQLITE_DBCONFIG_TRUSTED_SCHEMA, testmode_on,0);
sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, !testmode_on,0);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
@ -5554,6 +5600,7 @@ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
** \' -> '
** \\ -> backslash
** \NNN -> ascii character NNN in octal
** \xHH -> ascii character HH in hexadecimal
*/
static void resolve_backslashes(char *z){
int i, j;
@ -5582,6 +5629,15 @@ static void resolve_backslashes(char *z){
c = '\'';
}else if( c=='\\' ){
c = '\\';
}else if( c=='x' ){
int nhd = 0, hdv;
u8 hv = 0;
while( nhd<2 && (c=z[i+1+nhd])!=0 && (hdv=hexDigitValue(c))>=0 ){
hv = (u8)((hv<<4)|hdv);
++nhd;
}
i += nhd;
c = (u8)hv;
}else if( c>='0' && c<='7' ){
c -= '0';
if( z[i+1]>='0' && z[i+1]<='7' ){
@ -5681,7 +5737,7 @@ static int sql_trace_callback(
utf8_printf(p->traceOut, "-- closing database connection\n");
return 0;
}
if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
if( mType!=SQLITE_TRACE_ROW && pX!=0 && ((const char*)pX)[0]=='-' ){
zSql = (const char*)pX;
}else{
pStmt = (sqlite3_stmt*)pP;
@ -5713,7 +5769,7 @@ static int sql_trace_callback(
break;
}
case SQLITE_TRACE_PROFILE: {
sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
sqlite3_int64 nNanosec = pX ? *(sqlite3_int64*)pX : 0;
utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", (int)nSql, zSql, nNanosec);
break;
}
@ -5789,8 +5845,8 @@ static void import_append_char(ImportCtx *p, int c){
*/
static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
int c;
int cSep = p->cColSep;
int rSep = p->cRowSep;
int cSep = (u8)p->cColSep;
int rSep = (u8)p->cRowSep;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
@ -5879,8 +5935,8 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
*/
static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){
int c;
int cSep = p->cColSep;
int rSep = p->cRowSep;
int cSep = (u8)p->cColSep;
int rSep = (u8)p->cRowSep;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
@ -6241,7 +6297,9 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
if( sqlite3_step(pStmt)==SQLITE_ROW
&& sqlite3_column_bytes(pStmt,0)>100
){
memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
const u8 *pb = sqlite3_column_blob(pStmt,0);
shell_check_oom(pb);
memcpy(aHdr, pb, 100);
sqlite3_finalize(pStmt);
}else{
raw_printf(stderr, "unable to read database header\n");
@ -7827,7 +7885,7 @@ FROM (\
sqlite3_bind_int(pStmt, 1, nDigits);
rc = sqlite3_step(pStmt);
sqlite3_finalize(pStmt);
assert(rc==SQLITE_DONE);
if( rc!=SQLITE_DONE ) rc_err_oom_die(SQLITE_NOMEM);
}
assert(db_int(*pDb, zHasDupes)==0); /* Consider: remove this */
rc = sqlite3_prepare_v2(*pDb, zCollectVar, -1, &pStmt, 0);
@ -8759,8 +8817,8 @@ static int do_meta_command(char *zLine, ShellState *p){
" for import\n");
goto meta_command_exit;
}
sCtx.cColSep = p->colSeparator[0];
sCtx.cRowSep = p->rowSeparator[0];
sCtx.cColSep = (u8)p->colSeparator[0];
sCtx.cRowSep = (u8)p->rowSeparator[0];
}
sCtx.zFile = zFile;
sCtx.nLine = 1;
@ -8956,6 +9014,12 @@ static int do_meta_command(char *zLine, ShellState *p){
int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
int i;
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
"imposter");
rc = 1;
goto meta_command_exit;
}
if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
" .imposter off\n");
@ -9140,7 +9204,8 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zFile, *zProc;
char *zErrMsg = 0;
failIfSafeMode(p, "cannot run .load in safe mode");
if( nArg<2 ){
if( nArg<2 || azArg[1][0]==0 ){
/* Must have a non-empty FILE. (Will not load self.) */
raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
rc = 1;
goto meta_command_exit;
@ -10465,7 +10530,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( bDebug ) utf8_printf(p->out, "%s\n", zRevText);
lrc = sqlite3_prepare_v2(p->db, zRevText, -1, &pStmt, 0);
if( lrc!=SQLITE_OK ){
assert(lrc==SQLITE_NOMEM);
/* assert(lrc==SQLITE_NOMEM); // might also be SQLITE_ERROR if the
** user does cruel and unnatural things like ".limit expr_depth 0". */
rc = 1;
}else{
if( zLike ) sqlite3_bind_text(pStmt,1,zLike,-1,SQLITE_STATIC);
@ -10755,6 +10821,12 @@ static int do_meta_command(char *zLine, ShellState *p){
int i, n2;
const char *zCmd = 0;
if( !ShellHasFlag(p,SHFLG_TestingMode) ){
utf8_printf(stderr, ".%s unavailable without --unsafe-testing\n",
"testctrl");
rc = 1;
goto meta_command_exit;
}
open_db(p, 0);
zCmd = nArg>=2 ? azArg[1] : "help";
@ -11754,6 +11826,7 @@ static const char zOptions[] =
" -stats print memory stats before each finalize\n"
" -table set output mode to 'table'\n"
" -tabs set output mode to 'tabs'\n"
" -unsafe-testing allow unsafe commands and modes for testing\n"
#if SHELL_WIN_UTF8_OPT
" -utf8 setup interactive console code page for UTF-8\n"
#endif
@ -12134,6 +12207,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(argv[++i]);
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}
@ -12370,6 +12445,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( cli_strcmp(z,"-safe")==0 ){
data.bSafeMode = data.bSafeModePersist = 1;
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
/* Acted upon in first pass. */
}else{
utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
raw_printf(stderr,"Use -help for a list of options.\n");

View File

@ -2398,7 +2398,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
** <dt>SQLITE_DBCONFIG_DQS_DML</td>
** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@ -2407,7 +2407,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@ -2416,7 +2416,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@ -2436,7 +2436,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@ -2445,7 +2445,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
** is now scarcely any need to generated database files that are compatible
** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@ -2458,23 +2458,35 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</td>
** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
** statistics. For statistics to be collected, the flag must be set on
** the database handle both when the SQL statement is prepared and when it
** is stepped. The flag is set (collection of statistics is enabled)
** by default.</dd>
** by default. This option takes two arguments: an integer and a pointer to
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
** leave unchanged the statement scanstatus option. If the second argument
** is not NULL, then the value of the statement scanstatus setting after
** processing the first argument is written into the integer that the second
** argument points to.
** </dd>
**
** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</td>
** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option change the default order
** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
** in which tables and indexes are scanned so that the scans start at the end
** and work toward the beginning rather than starting at the beginning and
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
** same as setting [PRAGMA reverse_unordered_selects]. This configuration option
** is useful for application testing.</dd>
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
** same as setting [PRAGMA reverse_unordered_selects]. This option takes
** two arguments which are an integer and a pointer to an integer. The first
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
** reverse scan order flag, respectively. If the second argument is not NULL,
** then 0 or 1 is written into the integer that the second argument points to
** depending on if the reverse scan order flag is set after processing the
** first argument.
** </dd>
**
** </dl>
*/
@ -2496,7 +2508,7 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
@ -6243,6 +6255,13 @@ void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
**
** If a negative argument is passed to sqlite3_sleep() the results vary by
** VFS and operating system. Some system treat a negative argument as an
** instruction to sleep forever. Others understand it to mean do not sleep
** at all. ^In SQLite version 3.42.0 and later, a negative
** argument passed into sqlite3_sleep() is changed to zero before it is relayed
** down into the xSleep method of the VFS.
*/
int sqlite3_sleep(int);

View File

@ -294,7 +294,7 @@
# define SQLITE_NOINLINE
# define SQLITE_INLINE
#endif
#if defined(SQLITE_COVERAGE_TEST)
#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
# undef SQLITE_INLINE
# define SQLITE_INLINE
#endif
@ -2700,6 +2700,7 @@ struct Index {
** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
@ -4456,6 +4457,8 @@ int sqlite3CantopenError(int);
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42)
# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@ -4465,6 +4468,8 @@ int sqlite3CantopenError(int);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0')
# define sqlite3JsonId2(x) sqlite3IsIdChar(x)
#endif
int sqlite3IsIdChar(u8);

View File

@ -110,15 +110,15 @@ static int ts_stat(const char *zPath, struct stat *p);
static int ts_fstat(int fd, struct stat *p);
static int ts_ftruncate(int fd, off_t n);
static int ts_fcntl(int fd, int cmd, ... );
static int ts_read(int fd, void *aBuf, size_t nBuf);
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
static ssize_t ts_read(int fd, void *aBuf, size_t nBuf);
static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
/* Note: pread64() and pwrite64() actually use off64_t as the type on their
** last parameter. But that datatype is not defined on many systems
** (ex: Mac, OpenBSD). So substitute a likely equivalent: sqlite3_uint64 */
static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off);
static int ts_write(int fd, const void *aBuf, size_t nBuf);
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off);
static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off);
static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf);
static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off);
static int ts_fchmod(int fd, mode_t mode);
static int ts_fallocate(int fd, off_t off, off_t len);
static void *ts_mmap(void *, size_t, int, int, int, off_t);
@ -211,7 +211,7 @@ static int tsErrno(const char *zFunc){
/*
** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the
** value of errno before returning.
*/
*/
static int tsIsFailErrno(const char *zFunc){
if( tsIsFail() ){
errno = tsErrno(zFunc);
@ -313,7 +313,7 @@ static int ts_fcntl(int fd, int cmd, ... ){
/*
** A wrapper around read().
*/
static int ts_read(int fd, void *aBuf, size_t nBuf){
static ssize_t ts_read(int fd, void *aBuf, size_t nBuf){
if( tsIsFailErrno("read") ){
return -1;
}
@ -323,7 +323,7 @@ static int ts_read(int fd, void *aBuf, size_t nBuf){
/*
** A wrapper around pread().
*/
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
static ssize_t ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
if( tsIsFailErrno("pread") ){
return -1;
}
@ -333,7 +333,7 @@ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
/*
** A wrapper around pread64().
*/
static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
static ssize_t ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
if( tsIsFailErrno("pread64") ){
return -1;
}
@ -343,7 +343,7 @@ static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
/*
** A wrapper around write().
*/
static int ts_write(int fd, const void *aBuf, size_t nBuf){
static ssize_t ts_write(int fd, const void *aBuf, size_t nBuf){
if( tsIsFailErrno("write") ){
if( tsErrno("write")==EINTR ) orig_write(fd, aBuf, nBuf/2);
return -1;
@ -354,7 +354,7 @@ static int ts_write(int fd, const void *aBuf, size_t nBuf){
/*
** A wrapper around pwrite().
*/
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
static ssize_t ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
if( tsIsFailErrno("pwrite") ){
return -1;
}
@ -364,7 +364,7 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
/*
** A wrapper around pwrite64().
*/
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){
static ssize_t ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){
if( tsIsFailErrno("pwrite64") ){
return -1;
}

View File

@ -843,7 +843,9 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
return (z[k]==0 && k-i<=16) ? 0 : 2;
if( k-i>16 ) return 2;
if( z[k]!=0 ) return 1;
return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{

View File

@ -2745,7 +2745,7 @@ case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
if( ALWAYS(pC) && pC->nullRow ){
if( pC && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@ -3240,7 +3240,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
pIn1->flags &= ~MEM_Int;
pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);

View File

@ -1337,9 +1337,9 @@ static const void *columnName(
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
u8 prior_mallocFailed = db->mallocFailed;
N += useType*n;
sqlite3_mutex_enter(db->mutex);
assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
@ -1351,7 +1351,8 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
if( db->mallocFailed ){
assert( db->mallocFailed==0 || db->mallocFailed==1 );
if( db->mallocFailed > prior_mallocFailed ){
sqlite3OomClear(db);
ret = 0;
}

View File

@ -5354,6 +5354,16 @@ void sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
#ifdef SQLITE_DEBUG
int nRealCol;
if( pTab->tabFlags & TF_WithoutRowid ){
nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn;
}else if( pTab->tabFlags & TF_HasVirtual ){
nRealCol = pTab->nNVCol;
}else{
nRealCol = pTab->nCol;
}
#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@ -5370,8 +5380,8 @@ void sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
assert( pCsr->nField==pTab->nCol
|| (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
assert( pCsr->nField==nRealCol
|| (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;

View File

@ -157,6 +157,7 @@ int sqlite3VdbeMemValidStrRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */

View File

@ -3710,7 +3710,9 @@ int sqlite3WalFrames(
if( rc ) return rc;
}
}
assert( (int)pWal->szPage==szPage );
if( (int)pWal->szPage!=szPage ){
return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
}
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;

View File

@ -5982,22 +5982,45 @@ WhereInfo *sqlite3WhereBegin(
}
if( pParse->nErr ) goto whereBeginError;
/* Special case: WHERE terms that do not refer to any tables in the join
** (constant expressions). Evaluate each such term, and jump over all the
** generated code if the result is not true.
/* The False-WHERE-Term-Bypass optimization:
**
** Do not do this if the expression contains non-deterministic functions
** that are not within a sub-select. This is not strictly required, but
** preserves SQLite's legacy behaviour in the following two cases:
** If there are WHERE terms that are false, then no rows will be output,
** so skip over all of the code generated here.
**
** FROM ... WHERE random()>0; -- eval random() once per row
** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
** Conditions:
**
** (1) The WHERE term must not refer to any tables in the join.
** (2) The term must not come from an ON clause on the
** right-hand side of a LEFT or FULL JOIN.
** (3) The term must not come from an ON clause, or there must be
** no RIGHT or FULL OUTER joins in pTabList.
** (4) If the expression contains non-deterministic functions
** that are not within a sub-select. This is not required
** for correctness but rather to preserves SQLite's legacy
** behaviour in the following two cases:
**
** WHERE random()>0; -- eval random() once per row
** WHERE (SELECT random())>0; -- eval random() just once overall
**
** Note that the Where term need not be a constant in order for this
** optimization to apply, though it does need to be constant relative to
** the current subquery (condition 1). The term might include variables
** from outer queries so that the value of the term changes from one
** invocation of the current subquery to the next.
*/
for(ii=0; ii<sWLB.pWC->nBase; ii++){
WhereTerm *pT = &sWLB.pWC->a[ii];
WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pX = pT->pExpr;
assert( pX!=0 );
assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
if( pT->prereqAll==0 /* Conditions (1) and (2) */
&& (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
&& !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
&& (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
){
sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}

View File

@ -1030,6 +1030,9 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pExpr->op==TK_TRUEFALSE ){
/* Do not walk disabled expressions. tag-20230504-1 */
return WRC_Prune;
}
return rc;
}

View File

@ -1211,7 +1211,7 @@ static void exprAnalyze(
&& 0==sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pExpr->op = TK_TRUEFALSE;
pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;

View File

@ -736,4 +736,31 @@ do_execsql_test 7.2 {
ANALYZE sqlite_master;
}
# 2023-04-22 https://sqlite.org/forum/info/6c118daad0f1f5ef
# Case differences in the sqlite_stat4.idx field should not matter.
#
reset_db
do_execsql_test 8.0 {
CREATE TABLE t1(a PRIMARY KEY, v) WITHOUT ROWID;
ANALYZE sqlite_schema;
INSERT INTO sqlite_stat1 VALUES('t1','t1','1 1');
INSERT INTO sqlite_stat4 VALUES('t1','t1','1','0','0',X'021b76657273696f6e');
INSERT INTO sqlite_stat4 VALUES('T1','T1','1','0','0',X'021b76657273696f6e');
ANALYZE sqlite_schema;
} {}
# 2023-05-03 https://sqlite.org/forum/forumpost/537d8ab118
# Same index appears by two different names in the sqlite_stat4 table.
#
reset_db
do_execsql_test 8.1 {
CREATE TABLE t1(a INT PRIMARY KEY, b INT) WITHOUT ROWID;
ANALYZE sqlite_schema;
INSERT INTO sqlite_stat4 VALUES
('t1','t1','1','2','2',X'03000103'),
('t1','sqlite_autoindex_t1_1','1','2','2',X'03000103');
ANALYZE sqlite_schema;
PRAGMA integrity_check;
} {ok}
finish_test

View File

@ -191,4 +191,24 @@ do_execsql_test 6.0 {
HAVING (SELECT true FROM t6 AS aa LEFT JOIN t6 AS bb ON length(v1.a)>5);
} {abc 2 uvw 2}
# 2023-05-04 https://sqlite.org/forum/forumpost/29a47cf6d1
#
# codeCursorHint() should not walk expressions that have been optimized
# out and converted to TRUE or FALSE. This only comes up when compiling
# with SQLITE_ENABLE_CURSOR_HINTS
#
reset_db
do_execsql_test 7.1 {
CREATE TABLE t1(a INT PRIMARY KEY) WITHOUT ROWID;
CREATE TABLE t2(b INT PRIMARY KEY) WITHOUT ROWID;
CREATE TABLE t3(c INT PRIMARY KEY) WITHOUT ROWID;
INSERT INTO t1(a) VALUES(1),(2);
INSERT INTO t2(b) VALUES(4),(8);
INSERT INTO t3(c) VALUES(16),(32);
CREATE VIEW v4(d) AS SELECT c FROM t3;
SELECT * FROM t1 RIGHT JOIN t2 ON true JOIN v4 ON (d IS NULL);
} {}
finish_test

View File

@ -544,4 +544,10 @@ datetest 17.7 {datetime(38,'start of year')} {-4712-01-01 00:00:00}
#
datetest 18.1 {strftime('%f',1.234,'unixepoch','localtime')} {01.234}
# 2023-04 The 'subsecond' (or 'subsec') modifier alters resolutions
# to at least milliseconds. Added for release 3.42.0 .
datetest 18.2 {unixepoch('1970-01-01T00:00:00.1', 'subsec')} {0.1}
datetest 18.3 {unixepoch('1970-01-01T00:00:00.2', 'subsecond')} {0.2}
datetest 18.4 {julianday('-4713-11-24 13:40:48.864', 'subsec')} {0.07001}
datetest 18.5 {typeof(unixepoch('now', 'subsecond'))} {real}
finish_test

View File

@ -1245,4 +1245,22 @@ do_eqp_test join-28.2 {
# |--SCAN t4
# `--SEARCH t3 USING AUTOMATIC COVERING INDEX (a=?)
# 2023-05-01 https://sqlite.org/forum/forumpost/96cd4a7e9e
#
reset_db
db null NULL
do_execsql_test join-29.1 {
CREATE TABLE t0(a INT); INSERT INTO t0(a) VALUES (1);
CREATE TABLE t1(b INT); INSERT INTO t1(b) VALUES (2);
CREATE VIEW v2(c) AS SELECT 3 FROM t1;
SELECT * FROM t1 JOIN v2 ON 0 FULL OUTER JOIN t0 ON true;
} {NULL NULL 1}
do_execsql_test join-29.2 {
SELECT * FROM t1 JOIN v2 ON 1=0 FULL OUTER JOIN t0 ON true;
} {NULL NULL 1}
do_execsql_test join-29.3 {
SELECT * FROM t1 JOIN v2 ON false FULL OUTER JOIN t0 ON true;
} {NULL NULL 1}
finish_test

View File

@ -89,5 +89,35 @@ do_execsql_test 4.4 {
SELECT (d IS NULL) FROM t1 RIGHT JOIN t2 ON (j=33);
} {1}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.0 {
CREATE TABLE t0(w);
CREATE TABLE t1(x);
CREATE TABLE t2(y);
CREATE TABLE t3(z);
INSERT INTO t3 VALUES('t3val');
}
do_execsql_test 5.1 {
SELECT * FROM t1 INNER JOIN t2 ON (0) RIGHT OUTER JOIN t3;
} {{} {} t3val}
do_execsql_test 5.2 {
SELECT * FROM t1 INNER JOIN t2 ON (0) FULL OUTER JOIN t3;
} {{} {} t3val}
do_execsql_test 5.3 {
SELECT * FROM t3 LEFT JOIN t2 ON (0);
} {t3val {}}
do_execsql_test 5.4 {
SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) RIGHT JOIN t3
} {{} {} {} t3val}
do_execsql_test 5.5 {
SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0)
} {}
finish_test

27
test/json/README.md Normal file
View File

@ -0,0 +1,27 @@
The files in this subdirectory are used to help measure the performance
of the SQLite JSON parser.
# 1.0 Prerequisites
1. Valgrind
2. Fossil
# 2.0 Setup
1. Run: "`tclsh json-generator.tcl | sqlite3 json100mb.db`" to create
the 100 megabyte test database. Do this so that the "json100mb.db"
file lands in the directory from which you will run tests, not in
the test/json subdirectory of the source tree.
2. Build the baseline sqlite3.c file. ("`make sqlite3.c`")
3. Run "`sh json-speed-check-1.sh trunk`". This creates the baseline
profile in "jout-trunk.txt".
# 3.0 Testing
1. Build the sqlite3.c to be tested.
2. Run "`sh json-speed-check-1.sh x1`". The profile output will appear
in jout-x1.txt. Substitute any label you want in place of "x1".

View File

@ -0,0 +1,401 @@
#!/usr/bin/tclsh
#
# Generate SQL that will populate an SQLite database with about 100 megabytes
# of pseudo-random JSON text.
#
# tclsh json-generator.tcl | sqlite3 json110mb.db
#
# srand() is used to initialize the random seed so that the same JSON
# is generated for every run.
#
expr srand(12345678)
set wordlist {
ability able abroad access account act
action active actor add address adept
adroit advance advice affect age ageless
agency agent agile agree air airfare
airline airport alert almond alpha always
amend amount amplify analyst anchor angel
angelic angle ankle annual answer antique
anybody anyhow appeal apple apricot apt
area argon arm army arrival arsenic
art artful article arugula aside ask
aspect assist assume atom atone attempt
author autumn average avocado award awl
azure back bacon bag bagel bake
baker balance ball balloon bamboo banana
band banjo bank barium base basil
basin basis basket bass bat bath
battery beach beak bean bear bearcub
beauty beef beet beige being bell
belly belt bench bend benefit best
beta better beyond bicycle bid big
bike bill bird biscuit bismuth bisque
bit black blank blest blind bliss
block bloom blue board boat body
bokchoy bone bonus book bookish boot
border boron boss bossy bottle bottom
bow bowl bowtie box brain brainy
branch brave bravely bread break breath
breezy brick bridge brie brief briefly
bright broad broil bromine bronze brother
brow brown brush buddy budget buffalo
bug bugle bull bunch burger burly
burrito bus busy butter button buy
buyer byte cab cabbage cabinet cable
cadet cadmium caesium cake calcium caliper
call caller calm calmly camera camp
can canary cancel candle candy cap
capable caper capital captain car carbon
card care career careful carp carpet
carrot carry case cash cassava casual
cat catch catfish catsear catsup cause
cave celery cell century chain chair
chalk chance change channel chapter chard
charge charity chart check cheddar cheery
cheese chicken chicory chiffon child chin
chip chives choice chowder chum church
circle city claim clam class classic
classy clay clean cleaner clear clearly
clerk click client climate clock clorine
closet clothes cloud clown club clue
cluster coach coast coat cobbler cobolt
cod code coffee colby cold collar
college comb combine comet comfort command
comment common company complex concept concern
concert conduit consist contact contest context
control convert cook cookie copilot copper
copy coral cordial corn corner corny
correct cost count counter country county
couple courage course court cover cow
cowbird crab crack craft crash crazy
cream credit creek cress crevice crew
crimson croaker crop cross crowd cube
cuckoo cuisine culture cup current curve
cut cyan cycle dagger daily dance
dare darter data date day daylily
deal dear dearly debate debit decade
decimal deep deft deftly degree delay
deluxe deposit depth design desk detail
device dew diamond diet dig dill
dinner dip direct dirt dish disk
display diver divide divine doctor dodger
donut door dot double dough draft
drag dragon drama draw drawer drawing
dream drill drink drive driver drop
drum dry dryer drywall duck due
dump dusk dust duty dye eagle
ear earring earth ease east easy
eat economy edge editor eel effect
effort egg eight elbow elegant element
elf elk email emerald employ end
endive endless energy engine enjoy enter
entry equal equip error escape essay
eternal evening event exam example excuse
exit expert extent extreme eye face
fact factor factual fail failure fair
fajita fall family fan fang farm
farmer fat fault feature feed feel
feeling fench fennel festive few fiber
field fig figure file fill film
filter final finance finding finger finish
fire fish fishing fit fitting five
fix flier flight floor floral florine
flour flow flower fly flying focus
fold folding food foot force forest
forever forgive form formal format fortune
forum frame free freedom freely fresh
friend frog front fruit fuchsia fuel
fun funny future gain galaxy gallium
game gamma gap garage garden garlic
gas gate gather gauge gear gem
gene general gentle gently gherkin ghost
gift give glad glass gleeful glossy
glove glue goal goat goby gold
goldeye golf good gouda goulash gourd
grab grace grade gram grand grape
grapes grass gravy gray great green
grits grocery ground group grouper grout
growth guard guave guess guest guide
guitar gumbo guppy habit hacksaw haddock
hafnium hagfish hair half halibut hall
hammer hand handle handy hanger happy
hat havarti hay haybale head health
healthy hearing heart hearty heat heavy
heel height helium hello help helpful
herald herring hide high highly highway
hill hip hipster hire history hit
hoki hold hole holiday holly home
honest honey hook hope hopeful horizon
horn horse host hotel hour house
housing human humane humor hunt hurry
ice icecube icefish icy idea ideal
image impact impress inch income indigo
initial inkpen insect inside intense invite
iodine iridium iron island issue item
ivory jacket jargon javelin jello jelly
jewel job jocund join joint joke
jovial joy joyful joyous judge juice
jump junior jury just justice kale
keel keep kelp ketchup key keyhole
keyway khaki kick kid kidney kiloohm
kind kindly king kitchen kite kiwi
knee knife krill krypton kumquat lab
lace lack ladder lake lamp lamprey
land laser laugh law lawn lawyer
layer lead leader leading leaf leafy
league leather leave lecture leek leg
lemon length lentil lesson let letter
lettuce level library life lift light
lily lime limit line linen link
lip list listen lithium lively living
lizard load loan lobster local lock
log long longfin look lotus love
lovely loving low lucid luck luffa
lunch lung machine magenta magnet mail
main major make mall manager mango
manner many map march market maroon
martian master match math matter maximum
maybe meal meaning meat media medium
meet meeting melody melon member memory
mention menu mercury merry mess message
messy metal meter method micron middle
might mile milk mind mine minimum
minnow minor mint minute mirror miss
mission misty mix mixer mixture mobile
mode model moment monitor monk month
moon moray morning most motor mouse
mouth move mover movie much mud
mudfish muffin mullet munster muon muscle
music mustard nail name nation native
natural nature navy neat neatly nebula
neck needle neon nerve net network
neutron news nibble nice nickel night
niobium nobody noise noodle normal north
nose note nothing notice nova novel
number nurse nursery oar object offer
office officer oil okay okra old
olive one onion open opening opinion
option orange orbit orchid order oregano
other ounce outcome outside oven owner
oxygen oyster pace pack package page
pager paint pair pale pan pancake
papaya paper pardon parent park parking
parsley parsnip part partner party pass
passage past pasta path patient pattern
pause pay pea peace peach peacock
peahen peak peanut pear pearl pen
penalty pencil pension people pepper perch
perfect period permit person phase phone
photo phrase physics piano pick picture
pie piece pigeon pike pilot pin
pink pinkie pious pipe pitch pizza
place plan plane planet plant planter
plastic plate play player playful plenty
pliers plum pod poem poet poetry
point police policy pollock pony pool
pop popover poptart pork port portal
post pot potato pound powder power
present press price pride primary print
prior private prize problem process produce
product profile profit program project promise
prompt proof proper protein proton public
puff puffer pull pumpkin pup pupfish
pure purple purpose push put quality
quark quarter quiet quill quit quote
rabbit raccoon race radiant radio radish
radium radon rain rainbow raise ramp
ranch range rasp rate ratio ray
razor reach read reading real reality
reason recipe record recover red redeem
reed reef refuse region regret regular
relaxed release relief relish remote remove
rent repair repeat reply report request
reserve resist resolve resort rest result
return reveal review reward ribbon rice
rich ride ridge right ring rise
risk river rivet road roast rock
rocket role roll roof room rope
rose rough roughy round row royal
rub ruby rudder ruin rule run
runner rush rust sacred saddle safe
safety sail salad salami sale salmon
salt sample sand sander sandy sauce
save saving saw scale scampi scene
scheme school score screen script sea
search season seat second secret sector
seemly self sell senate senior sense
series serve set shake shape share
shark shell shift shine shiny ship
shock shoe shoot shop shovel show
side sign signal silk silly silver
simple sing singer single sink site
size skill skin sky slate sleep
sleepy slice slide slip smart smell
smelt smile smoke smooth snap snipe
snow snowy sock socket sodium soft
softly soil sole solid song sorrel
sort soul sound soup source south
space spare speech speed spell spend
sphere spice spider spirit spite split
spoon sport spot spray spread spring
squab square squash stable staff stage
stand staple star start state status
stay steak steel step stern stew
stick still stock stone stop store
storm story strain street stress strike
string stroke strong studio study stuff
style sugar suit sulfur summer sun
sunny sunset super superb surf survey
sweet swim swing switch symbol system
table tackle tail tale talk tan
tank tap tape target task taste
tau tea teach teal team tear
tell ten tender tennis tent term
test tetra text thanks theme theory
thing think thread throat thumb ticket
tidy tie tiger till time timely
tin tip title toast today toe
tomato tone tongue tool tooth top
topic total touch tough tour towel
tower town track trade train trash
travel tray treat tree trick trip
trout trowel truck trupet trust truth
try tube tuna tune turf turkey
turn turnip tutor tux tweet twist
two type union unique unit upbeat
upper use useful user usual valley
value van vase vast veil vein
velvet verse very vessel vest video
view violet visit visual vivid voice
volume vowel voyage waffle wait wake
walk wall warm warmth wasabi wash
watch water wave wax way wealth
wear web wedge week weekly weight
west whale what wheat wheel when
where while who whole why will
win wind window wing winner winter
wire wish witty wolf wonder wood
wool woolly word work worker world
worry worth worthy wrap wrench wrist
writer xenon yak yam yard yarrow
year yearly yellow yew yogurt young
youth zebra zephyr zinc zone zoo
}
set nwordlist [llength $wordlist]
proc random_char {} {
return [string index \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
[expr {int(rand()*52)}]]
}
proc random_label {} {
set label [random_char]
while {rand()>0.8} {
append label [random_char]
}
if {rand()>0.9} {append label -}
append label [format %d [expr {int(rand()*100)}]]
return $label
}
proc random_numeric {} {
set n [expr {(rand()*2-1.0)*1e6}]
switch [expr {int(rand()*6)}] {
0 {set format %.3f}
1 {set format %.6E}
2 {set format %.4e}
default {set format %g}
}
return [format $format $n]
}
proc random_json {limit indent} {
global nwordlist wordlist
set res {}
if {$indent==0 || ($limit>0 && rand()>0.5)} {
incr limit -1
incr indent 2
set n [expr {int(rand()*5)+1}]
if {$n==5} {incr n [expr {int(rand()*10)}]}
if {rand()>0.5} {
set res \173\n
for {set i 0} {$i<$n} {incr i} {
append res [string repeat { } $indent]
if {rand()>0.8} {
if {rand()>0.5} {
set sep ":\n [string repeat { } $indent]"
} else {
set sep " : "
}
} else {
set sep :
}
append res \"[random_label]\"$sep[random_json $limit $indent]
if {$i<$n-1} {append res ,}
append res \n
}
incr indent -2
append res [string repeat { } $indent]
append res \175
return $res
} else {
set res \[\n
for {set i 0} {$i<$n} {incr i} {
append res [string repeat { } $indent]
append res [random_json $limit $indent]
if {$i<$n-1} {append res ,}
append res \n
}
incr indent -2
append res [string repeat { } $indent]
append res \]
return $res
}
} elseif {rand()>0.9} {
if {rand()>0.7} {return "true"}
if {rand()>0.5} {return "false"}
return "null"
} elseif {rand()>0.5} {
return [random_numeric]
} else {
set res \"
set n [expr {int(rand()*4)+1}]
if {$n>=4} {set n [expr {$n+int(rand()*6)}]}
for {set i 0} {$i<$n} {incr i} {
if {rand()<0.05} {
set w [random_numeric]
} else {
set k [expr {int(rand()*$nwordlist)}]
set w [lindex $wordlist $k]
}
if {rand()<0.07} {
set w \\\"$w\\\"
}
if {$i<$n-1} {
switch [expr {int(rand()*9)}] {
0 {set sp {, }}
1 {set sp "\\n "}
2 {set sp "-"}
default {set sp { }}
}
append res $w$sp
} else {
append res $w
if {rand()<0.2} {append res .}
}
}
return $res\"
}
}
puts "CREATE TABLE IF NOT EXISTS data1(x JSON);"
puts "BEGIN;"
set sz 0
for {set i 0} {$sz<100000000} {incr i} {
set j [random_json 7 0]
incr sz [string length $j]
puts "INSERT INTO data1(x) VALUES('$j');"
}
puts "COMMIT;"
puts "SELECT sum(length(x)) FROM data1;"

4
test/json/json-q1.txt Normal file
View File

@ -0,0 +1,4 @@
.mode qbox
.timer on
.param set $label 'q87'
SELECT rowid, x->>$label FROM data1 WHERE x->>$label IS NOT NULL;

80
test/json/json-speed-check.sh Executable file
View File

@ -0,0 +1,80 @@
#!/bin/bash
#
# This is a template for a script used for day-to-day size and
# performance monitoring of SQLite. Typical usage:
#
# sh speed-check.sh trunk # Baseline measurement of trunk
# sh speed-check.sh x1 # Measure some experimental change
# fossil xdiff --tk jout-trunk.txt jout-x1.txt # View chanages
#
# There are multiple output files, all with a base name given by
# the first argument:
#
# summary-$BASE.txt # Copy of standard output
# jout-$BASE.txt # cachegrind output
# explain-$BASE.txt # EXPLAIN listings (only with --explain)
#
if test "$1" = ""
then
echo "Usage: $0 OUTPUTFILE [OPTIONS]"
exit
fi
NAME=$1
shift
#CC_OPTS="-DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_MEMSYS5"
CC_OPTS="-DSQLITE_ENABLE_MEMSYS5"
CC=gcc
LEAN_OPTS="-DSQLITE_THREADSAFE=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_MEMSTATUS=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_LIKE_DOESNT_MATCH_BLOBS"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_MAX_EXPR_DEPTH=0"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DECLTYPE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_DEPRECATED"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_PROGRESS_CALLBACK"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE"
LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA"
BASELINE="trunk"
doExplain=0
doCachegrind=1
doVdbeProfile=0
doWal=1
doDiff=1
while test "$1" != ""; do
case $1 in
--nodiff)
doDiff=0
;;
--lean)
CC_OPTS="$CC_OPTS $LEAN_OPTS"
;;
--clang)
CC=clang
;;
--gcc7)
CC=gcc-7
;;
-*)
CC_OPTS="$CC_OPTS $1"
;;
*)
BASELINE=$1
;;
esac
shift
done
echo "NAME = $NAME" | tee summary-$NAME.txt
echo "CC_OPTS = $CC_OPTS" | tee -a summary-$NAME.txt
rm -f cachegrind.out.* jsonshell
$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -ldl -lpthread
ls -l jsonshell | tee -a summary-$NAME.txt
home=`echo $0 | sed -e 's,/[^/]*$,,'`
echo ./jsonshell json100mb.db "<$home/json-q1.txt"
valgrind --tool=cachegrind ./jsonshell json100mb.db <$home/json-q1.txt \
2>&1 | tee -a summary-$NAME.txt
cg_anno.tcl cachegrind.out.* >jout-$NAME.txt
echo '*****************************************************' >>jout-$NAME.txt
sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>jout-$NAME.txt
if test "$NAME" != "$BASELINE"; then
fossil xdiff --tk -c 20 jout-$BASELINE.txt jout-$NAME.txt
fi

View File

@ -310,12 +310,33 @@ do_execsql_test json-6.1 {
SELECT json_valid('{"a":55,"b":72,}');
} {0}
do_execsql_test json-6.2 {
SELECT json_error_position('{"a":55,"b":72,}');
} {0}
do_execsql_test json-6.3 {
SELECT json_valid(json('{"a":55,"b":72,}'));
} {1}
do_execsql_test json-6.4 {
SELECT json_valid('{"a":55,"b":72 , }');
} {0}
do_execsql_test json-6.5 {
SELECT json_error_position('{"a":55,"b":72 , }');
} {0}
do_execsql_test json-6.6 {
SELECT json_error_position('{"a":55,"b":72,,}');
} {16}
do_execsql_test json-6.7 {
SELECT json_valid('{"a":55,"b":72}');
} {1}
do_execsql_test json-6.3 {
SELECT json_valid('["a",55,"b",72,]');
do_execsql_test json-6.8 {
SELECT json_error_position('["a",55,"b",72,]');
} {0}
do_execsql_test json-6.4 {
do_execsql_test json-6.9 {
SELECT json_error_position('["a",55,"b",72 , ]');
} {0}
do_execsql_test json-6.10 {
SELECT json_error_position('["a",55,"b",72,,]');
} {16}
do_execsql_test json-6.11 {
SELECT json_valid('["a",55,"b",72]');
} {1}
@ -897,4 +918,97 @@ do_execsql_test json-20.3 {
SELECT json_object('a',2e370,'b',-3e380)->>'b';
} {-Inf}
# 2023-05-02 https://sqlite.org/forum/forumpost/06c6334412
# JSON functions should normally return NULL when given
# a NULL value as the JSON input.
#
db null NULL
do_execsql_test json-21.1 {
SELECT json_valid(NULL);
} NULL
do_execsql_test json-21.2 {
SELECT json_error_position(NULL);
} NULL
do_execsql_test json-21.3 {
SELECT json(NULL);
} NULL
do_execsql_test json-21.4 {
SELECT json_array(NULL);
} {[null]}
do_execsql_test json-21.5 {
SELECT json_extract(NULL);
} NULL
do_execsql_test json-21.6 {
SELECT json_insert(NULL,'$',123);
} NULL
do_execsql_test json-21.7 {
SELECT NULL->0;
} NULL
do_execsql_test json-21.8 {
SELECT NULL->>0;
} NULL
do_execsql_test json-21.9 {
SELECT '{a:5}'->NULL;
} NULL
do_execsql_test json-21.10 {
SELECT '{a:5}'->>NULL;
} NULL
do_catchsql_test json-21.11 {
SELECT json_object(NULL,5);
} {1 {json_object() labels must be TEXT}}
do_execsql_test json-21.12 {
SELECT json_patch(NULL,'{a:5}');
} NULL
do_execsql_test json-21.13 {
SELECT json_patch('{a:5}',NULL);
} NULL
do_execsql_test json-21.14 {
SELECT json_patch(NULL,NULL);
} NULL
do_execsql_test json-21.15 {
SELECT json_remove(NULL,'$');
} NULL
do_execsql_test json-21.16 {
SELECT json_remove('{a:5,b:7}',NULL);
} NULL
do_execsql_test json-21.17 {
SELECT json_replace(NULL,'$.a',123);
} NULL
do_execsql_test json-21.18 {
SELECT json_replace('{a:5,b:7}',NULL,NULL);
} {{{"a":5,"b":7}}}
do_execsql_test json-21.19 {
SELECT json_set(NULL,'$.a',123);
} NULL
do_execsql_test json-21.20 {
SELECT json_set('{a:5,b:7}',NULL,NULL);
} {{{"a":5,"b":7}}}
do_execsql_test json-21.21 {
SELECT json_type(NULL);
} NULL
do_execsql_test json-21.22 {
SELECT json_type('{a:5,b:7}',NULL);
} NULL
do_execsql_test json-21.23 {
SELECT json_quote(NULL);
} null
do_execsql_test json-21.24 {
SELECT count(*) FROM json_each(NULL);
} 0
do_execsql_test json-21.25 {
SELECT count(*) FROM json_tree(NULL);
} 0
do_execsql_test json-21.26 {
WITH c(x) AS (VALUES(1),(2.0),(NULL),('three'))
SELECT json_group_array(x) FROM c;
} {[1,2.0,null,"three"]}
do_execsql_test json-21.27 {
WITH c(x,y) AS (VALUES('a',1),('b',2.0),('c',NULL),(NULL,'three'),('e','four'))
SELECT json_group_object(x,y) FROM c;
} {{{"a":1,"b":2.0,"c":null,:"three","e":"four"}}}
finish_test

View File

@ -301,18 +301,27 @@ for {set i 0} {$i<100} {incr i} {
# allowing them. The following tests verify that the problem is now
# fixed.
#
do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0
do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0
do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1
do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1
do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1
do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1
do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1
do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1
do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0
do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0
do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0
do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0
foreach {id j x0 x5} {
1401 {'{"x":01}'} 0 0
1402 {'{"x":-01}'} 0 0
1403 {'{"x":0}'} 1 1
1404 {'{"x":-0}'} 1 1
1405 {'{"x":0.1}'} 1 1
1406 {'{"x":-0.1}'} 1 1
1407 {'{"x":0.0000}'} 1 1
1408 {'{"x":-0.0000}'} 1 1
1409 {'{"x":01.5}'} 0 0
1410 {'{"x":-01.5}'} 0 0
1411 {'{"x":00}'} 0 0
1412 {'{"x":-00}'} 0 0
1413 {'{"x":+0}'} 0 1
1414 {'{"x":+5}'} 0 1
1415 {'{"x":+5.5}'} 0 1
} {
do_execsql_test json102-$id "
SELECT json_valid($j), NOT json_error_position($j);
" [list $x0 $x5]
}
#------------------------------------------------------------------------
# 2017-04-10 ticket 6c9b5514077fed34551f98e64c09a10dc2fc8e16

View File

@ -30,6 +30,48 @@ do_execsql_test json104-100 {
}
}');
} {{{"a":"z","c":{"d":"e"}}}}
do_execsql_test json104-101 {
SELECT json_patch('{
"a": "b",
"c": {
"d": "e",
"f": "g"
}
}','{
a:"z",
c: {
f: null
}
}');
} {{{"a":"z","c":{"d":"e"}}}}
do_execsql_test json104-102 {
SELECT json_patch('{
a: "b",
c: {
d: "e",
f: "g"
}
}','{
"a":"z",
"c": {
"f": null
}
}');
} {{{"a":"z","c":{"d":"e"}}}}
do_execsql_test json104-103 {
SELECT json_patch('{
a: "b",
c: {
d: "e",
f: "g"
}
}','{
a:"z",
c: {
f: null
}
}');
} {{{"a":"z","c":{"d":"e"}}}}
# This is the example from pages 4 and 5 of RFC-7396

304
test/json501.test Normal file
View File

@ -0,0 +1,304 @@
# 2023-04-27
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements tests for the JSON5 enhancements to the
# JSON SQL functions extension to the SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json501
# From https://spec.json5.org/#introduction
#
#-----------------------------------------------------------------------------
# Summary of Features
#
# The following ECMAScript 5.1 features, which are not supported in JSON, have
# been extended to JSON5.
#
# Objects
#
# 1) Object keys may be an ECMAScript 5.1 IdentifierName.
# 2) Objects may have a single trailing comma.
#
# Arrays
#
# 3) Arrays may have a single trailing comma.
#
# Strings
#
# 4) Strings may be single quoted.
# 5) Strings may span multiple lines by escaping new line characters.
# 6) Strings may include character escapes.
#
# Numbers
#
# 7) Numbers may be hexadecimal.
# 8) Numbers may have a leading or trailing decimal point.
# 9) Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
# 10) Numbers may begin with an explicit plus sign.
#
# Comments
#
# 11) Single and multi-line comments are allowed.
#
# White Space
#
# 12) Additional white space characters are allowed.
#-----------------------------------------------------------------------------
#
# Test number in this file are of the form X.Y where X is one of the item
# numbers in the feature list above and Y is the test sequence number.
#
###############################################################################
# 1) Object keys may be an ECMAScript 5.1 IdentifierName.
do_execsql_test 1.1 {
WITH c(x) AS (VALUES('{a:5,b:6}'))
SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c;
} {5 {{"a":5,"b":6}} 0 1}
do_execsql_test 1.2 {
SELECT '[7,null,{a:5,b:6},[8,9]]'->>'$[2].b';
} {6}
do_execsql_test 1.3 {
SELECT '{ $123 : 789 }'->>'$."$123"';
} 789
do_execsql_test 1.4 {
SELECT '{ _123$xyz : 789 }'->>'$."_123$xyz"';
} 789
do_execsql_test 1.5 {
SELECT '{ MNO_123$xyz : 789 }'->>'$."MNO_123$xyz"';
} 789
do_execsql_test 1.6 {
SELECT json('{ MNO_123$xyz : 789 }');
} [list {{"MNO_123$xyz":789}}]
do_catchsql_test 1.10 {
SELECT json('{ MNO_123/xyz : 789 }');
} {1 {malformed JSON}}
do_execsql_test 1.11 {
SELECT '{ MNO_123æxyz : 789 }'->>'MNO_123æxyz';
} {789}
###############################################################################
# 2) Objects may have a single trailing comma.
do_execsql_test 2.1 {
WITH c(x) AS (VALUES('{"a":5, "b":6, }'))
SELECT x->>'b', json(x), json_valid(x), NOT json_error_position(x) FROM c;
} {6 {{"a":5,"b":6}} 0 1}
do_execsql_test 2.2 {
SELECT '{a:5, b:6 , }'->>'b';
} 6
do_catchsql_test 2.3 {
SELECT '{a:5, b:6 ,, }'->>'b';
} {1 {malformed JSON}}
do_catchsql_test 2.4 {
SELECT '{a:5, b:6, ,}'->>'b';
} {1 {malformed JSON}}
###############################################################################
# 3) Arrays may have a single trailing comma.
do_execsql_test 3.1 {
WITH c(x) AS (VALUES('[5, 6,]'))
SELECT x->>1, json(x), json_valid(x), NOT json_error_position(x) FROM c;
} {6 {[5,6]} 0 1}
do_execsql_test 3.2 {
SELECT '[5, 6 , ]'->>1;
} 6
do_catchsql_test 3.3 {
SELECT '[5, 6,,]'->>1;
} {1 {malformed JSON}}
do_catchsql_test 3.4 {
SELECT '[5, 6 , , ]'->>1;
} {1 {malformed JSON}}
###############################################################################
# 4) Strings may be single quoted.
do_execsql_test 4.1 {
WITH c(x) AS (VALUES('{"a": ''abcd''}'))
SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c;
} {abcd {{"a":"abcd"}} 0 1}
do_execsql_test 4.2 {
SELECT '{b: 123, ''a'': ''ab\''cd''}'->>'a';
} {ab'cd}
###############################################################################
# 5) Strings may span multiple lines by escaping new line characters.
do_execsql_test 5.1 {
WITH c(x) AS (VALUES('{a: "abc'||char(0x5c,0x0a)||'xyz"}'))
SELECT x->>'a', json(x), json_valid(x), NOT json_error_position(x) FROM c;
} {abcxyz {{"a":"abcxyz"}} 0 1}
do_execsql_test 5.2 {
SELECT ('{a: "abc'||char(0x5c,0x0d)||'xyz"}')->>'a';
} {abcxyz}
do_execsql_test 5.3 {
SELECT ('{a: "abc'||char(0x5c,0x0d,0x0a)||'xyz"}')->>'a';
} {abcxyz}
do_execsql_test 5.4 {
SELECT ('{a: "abc'||char(0x5c,0x2028)||'xyz"}')->>'a';
} {abcxyz}
do_execsql_test 5.5 {
SELECT ('{a: "abc'||char(0x5c,0x2029)||'xyz"}')->>'a';
} {abcxyz}
###############################################################################
# 6) Strings may include character escapes.
do_execsql_test 6.1 {
SELECT ('{a: "abc'||char(0x5c,0x27)||'xyz"}')->>'a';
} {abc'xyz}
do_execsql_test 6.2 {
SELECT ('{a: "abc'||char(0x5c,0x22)||'xyz"}')->>'a';
} {abc"xyz}
do_execsql_test 6.3 {
SELECT ('{a: "abc'||char(0x5c,0x5c)||'xyz"}')->>'a';
} {{abc\xyz}}
do_execsql_test 6.4 {
SELECT hex(('{a: "abc\bxyz"}')->>'a');
} {6162630878797A}
do_execsql_test 6.5 {
SELECT hex(('{a: "abc\f\n\r\t\vxyz"}')->>'a');
} {6162630C0A0D090B78797A}
do_execsql_test 6.6 {
SELECT hex(('{a: "abc\0xyz"}')->>'a');
} {6162630078797A}
do_execsql_test 6.7 {
SELECT '{a: "abc\x35\x4f\x6Exyz"}'->>'a';
} {abc5Onxyz}
do_execsql_test 6.8 {
SELECT '{a: "\x6a\x6A\x6b\x6B\x6c\x6C\x6d\x6D\x6e\x6E\x6f\x6F"}'->>'a';
} {jjkkllmmnnoo}
###############################################################################
# 7) Numbers may be hexadecimal.
do_execsql_test 7.1 {
SELECT '{a: 0x0}'->>'a';
} 0
do_execsql_test 7.2 {
SELECT '{a: -0x0}'->>'a';
} 0
do_execsql_test 7.3 {
SELECT '{a: +0x0}'->>'a';
} 0
do_execsql_test 7.4 {
SELECT '{a: 0xabcdef}'->>'a';
} 11259375
do_execsql_test 7.5 {
SELECT '{a: -0xaBcDeF}'->>'a';
} -11259375
do_execsql_test 7.6 {
SELECT '{a: +0xABCDEF}'->>'a';
} 11259375
###############################################################################
# 8) Numbers may have a leading or trailing decimal point.
do_execsql_test 8.1 {
WITH c(x) AS (VALUES('{x: 4.}')) SELECT x->>'x', json(x) FROM c;
} {4.0 {{"x":4.0}}}
do_execsql_test 8.2 {
WITH c(x) AS (VALUES('{x: +4.}')) SELECT x->>'x', json(x) FROM c;
} {4.0 {{"x":4.0}}}
do_execsql_test 8.3 {
WITH c(x) AS (VALUES('{x: -4.}')) SELECT x->>'x', json(x) FROM c;
} {-4.0 {{"x":-4.0}}}
do_execsql_test 8.3 {
WITH c(x) AS (VALUES('{x: .5}')) SELECT x->>'x', json(x) FROM c;
} {0.5 {{"x":0.5}}}
do_execsql_test 8.4 {
WITH c(x) AS (VALUES('{x: -.5}')) SELECT x->>'x', json(x) FROM c;
} {-0.5 {{"x":-0.5}}}
do_execsql_test 8.5 {
WITH c(x) AS (VALUES('{x: +.5}')) SELECT x->>'x', json(x) FROM c;
} {0.5 {{"x":0.5}}}
do_execsql_test 8.6 {
WITH c(x) AS (VALUES('{x: 4.e0}')) SELECT x->>'x', json(x) FROM c;
} {4.0 {{"x":4.0e0}}}
do_execsql_test 8.7 {
WITH c(x) AS (VALUES('{x: +4.e1}')) SELECT x->>'x', json(x) FROM c;
} {40.0 {{"x":4.0e1}}}
do_execsql_test 8.8 {
WITH c(x) AS (VALUES('{x: -4.e2}')) SELECT x->>'x', json(x) FROM c;
} {-400.0 {{"x":-4.0e2}}}
do_execsql_test 8.9 {
WITH c(x) AS (VALUES('{x: .5e3}')) SELECT x->>'x', json(x) FROM c;
} {500.0 {{"x":0.5e3}}}
do_execsql_test 8.10 {
WITH c(x) AS (VALUES('{x: -.5e-1}')) SELECT x->>'x', json(x) FROM c;
} {-0.05 {{"x":-0.5e-1}}}
do_execsql_test 8.11 {
WITH c(x) AS (VALUES('{x: +.5e-2}')) SELECT x->>'x', json(x) FROM c;
} {0.005 {{"x":0.5e-2}}}
###############################################################################
# 9) Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
do_execsql_test 9.1 {
WITH c(x) AS (VALUES('{x: +Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
do_execsql_test 9.2 {
WITH c(x) AS (VALUES('{x: -Infinity}')) SELECT x->>'x', json(x) FROM c;
} {-Inf {{"x":-9.0e999}}}
do_execsql_test 9.3 {
WITH c(x) AS (VALUES('{x: Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
do_execsql_test 9.4 {
WITH c(x) AS (VALUES('{x: NaN}')) SELECT x->>'x', json(x) FROM c;
} {{} {{"x":null}}}
###############################################################################
# 10) Numbers may begin with an explicit plus sign.
do_execsql_test 10.1 {
SELECT '{a: +123}'->'a';
} 123
###############################################################################
# 11) Single and multi-line comments are allowed.
do_execsql_test 11.1 {
SELECT ' /* abc */ { /*def*/ aaa /* xyz */ : // to the end of line
123 /* xyz */ , /* 123 */ }'->>'aaa';
} 123
###############################################################################
# 12) Additional white space characters are allowed.
do_execsql_test 12.1 {
SELECT (char(0x09,0x0a,0x0b,0x0c,0x0d,0x20,0xa0,0x2028,0x2029)
|| '{a: "xyz"}')->>'a';
} xyz
do_execsql_test 12.2 {
SELECT ('{a:' || char(0x09,0x0a,0x0b,0x0c,0x0d,0x20,0xa0,0x2028,0x2029)
|| '"xyz"}')->>'a';
} xyz
do_execsql_test 12.3 {
SELECT (char(0x1680,0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,
0x2006,0x2007,0x2008,0x2009,0x200a,0x3000,0xfeff)
|| '{a: "xyz"}')->>'a';
} xyz
do_execsql_test 12.4 {
SELECT ('{a: ' ||char(0x1680,0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,
0x2006,0x2007,0x2008,0x2009,0x200a,0x3000,0xfeff)
|| ' "xyz"}')->>'a';
} xyz
finish_test

25
test/json502.test Normal file
View File

@ -0,0 +1,25 @@
# 2023-04-28
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements tests for the JSON5 enhancements to the
# JSON SQL functions extension to the SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix json502
do_execsql_test 1.1 {
CREATE TABLE t1(x JSON);
INSERT INTO t1(x) VALUES('{a:{b:{c:"hello",},},}');
SELECT fullkey FROM t1, json_tree(x);
} {{$} {$.a} {$.a.b} {$.a.b.c}}
finish_test

View File

@ -592,6 +592,9 @@ do_test misc1-18.1 {
set n [sqlite3_sleep 100]
expr {$n>=100}
} {1}
do_test misc1-18.2 {
sqlite3_sleep -100
} {0}
# 2014-01-10: In a CREATE TABLE AS, if one or more of the column names
# are an empty string, that is still OK.

View File

@ -254,6 +254,11 @@ do_test shell1-2.4.2 {
catchcmd "test.db" ".mode \"csv\""
} {0 {}}
# check that certain quoted arg escapes work
do_test shell1-2.5.1 {
catchcmd ":memory:" ".print \"\\060\\077 \\x3f\\x30 \\a\\t\""
} [list 0 "0? ?0 \a\t"]
#----------------------------------------------------------------------------
# Test cases shell1-3.*: Basic test that "dot" command can be called.

View File

@ -216,5 +216,51 @@ do_test shell2-1.4.9 {
done
2}}
# Verify that generate_series stays sane near 64-bit range boundaries.
# See overflow report at https://sqlite.org/forum/forumpost/5d34ce5280
do_test shell2-1.4.10 {
set res [catchcmd :memory: [string trim {
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,1);
SELECT * FROM generate_series(9223372036854775807,9223372036854775807,-1);
SELECT avg(rowid),min(value),max(value) FROM generate_series(
-9223372036854775808,9223372036854775807,1085102592571150095);
SELECT * FROM generate_series(-9223372036854775808,9223372036854775807,
9223372036854775807);
SELECT value,rowid FROM generate_series(-4611686018427387904,
4611686018427387904, 4611686018427387904) ORDER BY value DESC;
SELECT * FROM generate_series(0,-2,-1);
SELECT * FROM generate_series(0,-2);
SELECT * FROM generate_series(0,2) LIMIT 3;}]]
} {0 {9223372036854775807
9223372036854775807
9.5|-9223372036854775808|9223372036854775807
-9223372036854775808
-1
9223372036854775806
4611686018427387904|3
0|2
-4611686018427387904|1
0
-1
-2
0
1
2}}
# Bug discovered while messing around, .import hangs with
# bit 7 set in column separator.
do_test shell2-1.4.11 {
forcedelete dummy.csv
set df [open dummy.csv w]
puts $df dog,cat
close $df
set res [catchcmd :memory: [string trim {
CREATE TABLE t(line text);
.mode ascii
.separator "\377" "\n"
.import dummy.csv t
SELECT count(*) FROM t;}]]
} {0 1}
finish_test

View File

@ -61,7 +61,7 @@ do_execsql_test tabfunc01-1.8 {
} {30 25 20 15 10 5 0}
do_execsql_test tabfunc01-1.9 {
SELECT rowid, * FROM generate_series(0,32,5) ORDER BY value DESC;
} {1 30 2 25 3 20 4 15 5 10 6 5 7 0}
} {7 30 6 25 5 20 4 15 3 10 2 5 1 0}
do_execsql_test tabfunc01-1.10 {
SELECT rowid, * FROM generate_series(0,32,5) ORDER BY +value DESC;
} {7 30 6 25 5 20 4 15 3 10 2 5 1 0}

View File

@ -862,5 +862,26 @@ do_catchsql_test 18.1 {
SELECT * FROM zipfile(NULL);
} {1 {cannot open file: }}
# 2023-05-03 https://sqlite.org/forum/info/f03f1e4c5a5c9959
#
do_test 19.1 {
sqlite3 db :memory:
load_static_extension db zipfile
forcedelete zipfile19.zip
db eval {
CREATE VIRTUAL TABLE t1 USING zipfile('zipfile19.zip');
INSERT INTO t1 DEFAULT VALUES;
}
db close
sqlite3 db :memory:
load_static_extension db zipfile
db eval {
CREATE VIRTUAL TABLE v0 USING zipfile('zipfile19.zip');
SAVEPOINT y;
DELETE FROM v0 WHERE 9;
INSERT INTO v0 DEFAULT VALUES;
}
} {}
forcedelete zipfile19.zip
finish_test

View File

@ -233,16 +233,21 @@ static void print_oneline_frame(int iFrame, Cksum *pCksum){
extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0);
s0 = getInt32(aData+16);
s1 = getInt32(aData+20);
fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n",
fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x",
iFrame,
getInt32(aData),
getInt32(aData+4),
getInt32(aData+8),
getInt32(aData+12),
s0,
s1,
(s0==pCksum->s0 && s1==pCksum->s1) ? "" : "cksum-fail"
s1
);
if( s0==pCksum->s0 && s1==pCksum->s1 ){
fprintf(stdout, "\n");
}else{
fprintf(stdout, " should be 0x%08x,%08x\n",
pCksum->s0, pCksum->s1);
}
/* Reset the checksum so that a single frame checksum failure will not
** cause all subsequent frames to also show a failure. */