summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--autosetup/sqlite-config.tcl8
-rw-r--r--shell.c153
-rw-r--r--sqlite3.c1621
-rw-r--r--sqlite3.h28
-rw-r--r--sqlite3rc.h2
6 files changed, 1325 insertions, 489 deletions
diff --git a/VERSION b/VERSION
index 0d767a08f23c..a03878a48a9b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.53.1
+3.53.3
diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl
index 59ecb7192a46..fa36dfb59a4b 100644
--- a/autosetup/sqlite-config.tcl
+++ b/autosetup/sqlite-config.tcl
@@ -1745,8 +1745,12 @@ proc sqlite-handle-env-quirks {} {
set autoDll 0; # true if --out-implib/--dll-basename should be implied
set host [get-define host]
switch -glob -- $host {
- *apple* -
- *darwin* { set instName darwin }
+ *-*-darwin* {
+ set instName darwin
+ # We don't look for *apple* because:
+ # https://sqlite.org/forum/forumpost/7b218c3c9f207646
+ # There's at least one Linux out there which matches *apple*.
+ }
default {
set x [sqlite-env-is-unix-on-windows $host]
if {"" ne $x} {
diff --git a/shell.c b/shell.c
index 57faceb4691f..f9bfe1a9dd89 100644
--- a/shell.c
+++ b/shell.c
@@ -1790,7 +1790,7 @@ static void qrfEncodeText(Qrf *p, sqlite3_str *pOut, const char *zTxt){
sqlite3_str_append(pOut, (const char*)z, i);
}
switch( z[i] ){
- case '>': sqlite3_str_append(pOut, "<", 4); break;
+ case '>': sqlite3_str_append(pOut, ">", 4); break;
case '&': sqlite3_str_append(pOut, "&", 5); break;
case '<': sqlite3_str_append(pOut, "&lt;", 4); break;
case '"': sqlite3_str_append(pOut, "&quot;", 6); break;
@@ -2270,7 +2270,7 @@ static void qrfWrapLine(
for(k=i-1; k>=i/2; k--){
if( qrfSpace(z[k]) ) break;
}
- if( k<i/2 ){
+ if( k<i/2 && i/2>0 ){
for(k=i; k>=i/2; k--){
if( qrfAlnum(z[k-1])!=qrfAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
}
@@ -5810,6 +5810,9 @@ static void decimal_free(Decimal *p){
/*
** Allocate a new Decimal object initialized to the text in zIn[].
** Return NULL if any kind of error occurs.
+**
+** Note that zIn[] is not necessarily zero-terminated. Always
+** respect the boundary imposed by the n argument.
*/
static Decimal *decimalNewFromText(const char *zIn, int n){
Decimal *p = 0;
@@ -5827,11 +5830,11 @@ static Decimal *decimalNewFromText(const char *zIn, int n){
p->nFrac = 0;
p->a = sqlite3_malloc64( n+1 );
if( p->a==0 ) goto new_from_text_failed;
- for(i=0; IsSpace(zIn[i]); i++){}
- if( zIn[i]=='-' ){
+ for(i=0; i<n && IsSpace(zIn[i]); i++){}
+ if( i<n && zIn[i]=='-' ){
p->sign = 1;
i++;
- }else if( zIn[i]=='+' ){
+ }else if( i<n && zIn[i]=='+' ){
i++;
}
while( i<n && zIn[i]=='0' ) i++;
@@ -6042,28 +6045,37 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){
sqlite3_result_text(pCtx, z, i, sqlite3_free);
}
+/* Forward declaration */
+static void decimal_expand(Decimal *p, int nDigit, int nFrac);
+
/*
** Round a decimal value to N significant digits. N must be positive.
*/
static void decimal_round(Decimal *p, int N){
int i;
- int nZero;
+ int nZero; /* Number of leading zeros */
if( N<1 ) return;
if( p==0 ) return;
if( p->nDigit<=N ) return;
for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){}
N += nZero;
if( p->nDigit<=N ) return;
- if( p->a[N]>4 ){
+ if( p->a[N]>=5 ){
+ /* If all leading digits are 9, increase the number of digits
+ ** by adding a new 0 to the front */
+ for(i=0; i<N && p->a[i]==9; i++){}
+ if( i==N ){
+ decimal_expand(p, p->nDigit+1, p->nFrac);
+ if( p->oom ) return;
+ }
+
+ /* Do the rounding */
p->a[N-1]++;
for(i=N-1; i>0 && p->a[i]>9; i--){
p->a[i] = 0;
p->a[i-1]++;
}
- if( p->a[0]>9 ){
- p->a[0] = 1;
- p->nFrac--;
- }
+ assert( p->a[0]<=9 );
}
memset(&p->a[N], 0, p->nDigit - N);
}
@@ -6211,6 +6223,7 @@ static void decimal_expand(Decimal *p, int nDigit, int nFrac){
signed char *a;
if( p==0 ) return;
nAddFrac = nFrac - p->nFrac;
+ assert( nAddFrac>=0 );
nAddSig = (nDigit - p->nDigit) - nAddFrac;
if( nAddFrac==0 && nAddSig==0 ) return;
if( nDigit+1>SQLITE_DECIMAL_MAX_DIGIT ){ p->oom = 1; return; }
@@ -8219,6 +8232,16 @@ static double seriesFloor(double r){
}
#endif
+/* Convert a floating point value to its closest integer. Do so in
+** a way that avoids 'outside the range of representable values' warnings
+** from UBSAN.
+*/
+sqlite3_int64 seriesRealToI64(double r){
+ if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
+ if( r>+9223372036854774784.0 ) return LARGEST_INT64;
+ return (sqlite3_int64)r;
+}
+
/*
** This method is called to "rewind" the series_cursor object back
** to the first row of output. This method is always called at least
@@ -8341,7 +8364,7 @@ static int seriesFilter(
&& r>=(double)SMALLEST_INT64
&& r<=(double)LARGEST_INT64
){
- iMin = iMax = (sqlite3_int64)r;
+ iMin = iMax = seriesRealToI64(r);
}else{
goto series_no_rows;
}
@@ -8349,15 +8372,19 @@ static int seriesFilter(
iMin = iMax = sqlite3_value_int64(argv[iArg++]);
}
}else{
- if( idxNum & 0x0300 ){ /* value>X or value>=X */
+ if( idxNum & 0x0300 ){ /* value>X (0x200) or value>=X (0x100) */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
- if( r<(double)SMALLEST_INT64 ){
+ if( r<=(double)SMALLEST_INT64 ){
iMin = SMALLEST_INT64;
- }else if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
- iMin = (sqlite3_int64)seriesCeil(r+1.0);
+ }else if( r>(double)LARGEST_INT64 ){
+ goto series_no_rows;
}else{
- iMin = (sqlite3_int64)seriesCeil(r);
+ iMin = seriesRealToI64(seriesCeil(r));
+ if( (idxNum & 0x0200)!=0 && r==seriesCeil(r) ){
+ if( iMin==LARGEST_INT64 ) goto series_no_rows;
+ iMin++;
+ }
}
}else{
iMin = sqlite3_value_int64(argv[iArg++]);
@@ -8370,15 +8397,19 @@ static int seriesFilter(
}
}
}
- if( idxNum & 0x3000 ){ /* value<X or value<=X */
+ if( idxNum & 0x3000 ){ /* value<X (0x2000) or value<=X (0x1000) */
if( sqlite3_value_numeric_type(argv[iArg])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[iArg++]);
- if( r>(double)LARGEST_INT64 ){
+ if( r>=(double)LARGEST_INT64 ){
iMax = LARGEST_INT64;
- }else if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
- iMax = (sqlite3_int64)(r-1.0);
+ }else if( r<=(double)SMALLEST_INT64 ){
+ goto series_no_rows;
}else{
- iMax = (sqlite3_int64)seriesFloor(r);
+ iMax = seriesRealToI64(seriesFloor(r));
+ if( (idxNum & 0x2000)!=0 && r==seriesFloor(r) ){
+ if( iMax==SMALLEST_INT64 ) goto series_no_rows;
+ iMax--;
+ }
}
}else{
iMax = sqlite3_value_int64(argv[iArg++]);
@@ -12618,6 +12649,7 @@ static void zipfileResetCursor(ZipfileCsr *pCsr){
pNext = p->pNext;
zipfileEntryFree(p);
}
+ pCsr->pFreeEntry = 0;
}
/*
@@ -13020,7 +13052,13 @@ static int zipfileGetEntry(
if( rc==SQLITE_OK ){
u32 *pt = &pNew->mUnixTime;
- pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead);
+ /* aRead[0..nFile-1] might contain embedded \000 characters
+ ** See Bug 2026-05-31T11:43:05Z */
+ pNew->cds.zFile = sqlite3_malloc64(nFile+1);
+ if( pNew->cds.zFile!=0 ){
+ memcpy(pNew->cds.zFile, aRead, nFile);
+ pNew->cds.zFile[nFile] = 0;
+ }
pNew->aExtra = (u8*)&pNew[1];
memcpy(pNew->aExtra, &aRead[nFile], nExtra);
if( pNew->cds.zFile==0 ){
@@ -14124,10 +14162,10 @@ struct ZipfileCtx {
};
static int zipfileBufferGrow(ZipfileBuffer *pBuf, i64 nByte){
- if( pBuf->n+nByte>pBuf->nAlloc ){
+ if( (pBuf->nAlloc-pBuf->n)<nByte ){
u8 *aNew;
- sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
- int nReq = pBuf->n + nByte;
+ i64 nNew = pBuf->n ? (i64)pBuf->n*2 : 512;
+ i64 nReq = pBuf->n + nByte;
while( nNew<nReq ) nNew = nNew*2;
aNew = sqlite3_realloc64(pBuf->a, nNew);
@@ -14343,7 +14381,7 @@ static void zipfileFinal(sqlite3_context *pCtx){
eocd.nSize = p->cds.n;
eocd.iOffset = p->body.n;
- nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
+ nZip = (i64)p->body.n + (i64)p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
aZip = (u8*)sqlite3_malloc64(nZip);
if( aZip==0 ){
sqlite3_result_error_nomem(pCtx);
@@ -17470,7 +17508,7 @@ static int intckGetToken(const char *z){
}
}
else if( c=='[' ){
- while( z[iRet++]!=']' && z[iRet] );
+ while( z[iRet] && z[iRet++]!=']' ){}
}
else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){
while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){
@@ -29727,7 +29765,7 @@ struct ArCommand {
u8 eCmd; /* An AR_CMD_* value */
u8 bVerbose; /* True if --verbose */
u8 bZip; /* True if the archive is a ZIP */
- u8 bDryRun; /* True if --dry-run */
+ u8 bDryRun; /* 1 for --dry-run, 2 for --debug */
u8 bAppend; /* True if --append */
u8 bGlob; /* True if --glob */
u8 fromCmdLine; /* Run from -A instead of .archive */
@@ -29789,6 +29827,7 @@ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
#define AR_SWITCH_APPEND 11
#define AR_SWITCH_DRYRUN 12
#define AR_SWITCH_GLOB 13
+#define AR_SWITCH_DEBUG 14
static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
switch( eSwitch ){
@@ -29806,7 +29845,10 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
break;
case AR_SWITCH_DRYRUN:
- pAr->bDryRun = 1;
+ if( pAr->bDryRun<2 ) pAr->bDryRun = 1;
+ break;
+ case AR_SWITCH_DEBUG:
+ pAr->bDryRun = 2;
break;
case AR_SWITCH_GLOB:
pAr->bGlob = 1;
@@ -29857,6 +29899,7 @@ static int arParseCommand(
{ "append", 'a', AR_SWITCH_APPEND, 1 },
{ "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
{ "dryrun", 'n', AR_SWITCH_DRYRUN, 0 },
+ { "debug", 0, AR_SWITCH_DEBUG, 0 },
{ "glob", 'g', AR_SWITCH_GLOB, 0 },
};
int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
@@ -30158,13 +30201,27 @@ static int arRemoveCommand(ArCommand *pAr){
*/
static int arExtractCommand(ArCommand *pAr){
const char *zSql1 =
- "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n"
- "SELECT ($dir || name),\n"
- " CASE WHEN $dryrun THEN 0\n"
- " ELSE writefile($dir||name, %s, mode, mtime) END\n"
+ "WITH dest(dpath,dlen) AS (\n"
+#ifdef _WIN32
+ " SELECT realpath($dir) || '\\',\n"
+#else
+ " SELECT realpath($dir) || '/',\n"
+#endif
+ " 1+length(realpath($dir))\n"
+ ")\n"
+ "SELECT\n"
+ " ($dir || name),\n"
+ " CASE $dryrun\n"
+ " WHEN 0 THEN writefile($dir||name, %s, mode, mtime)\n"
+ " WHEN 1 THEN 0\n"
+ " ELSE shell_putsnl(format('writefile(%%Q,%%s,%%0o,%%d)',"
+ "$dir||name,quote(%s),mode,mtime)) IS NULL\n"
+ " END\n"
" FROM dest CROSS JOIN %s\n"
" WHERE (%s)\n"
- " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */
+ " AND (CASE $pass WHEN 0 THEN (mode&0xf000)<>0xa000\n"
+ " WHEN 1 THEN (mode&0xf000)=0xa000\n"
+ " ELSE data IS NULL END)\n"
" AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */
" AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */
@@ -30195,7 +30252,7 @@ static int arExtractCommand(ArCommand *pAr){
}
shellPreparePrintf(pAr->db, &rc, &pSql, zSql1,
- azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
+ azExtraArg[pAr->bZip], azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
);
if( rc==SQLITE_OK ){
@@ -30205,25 +30262,31 @@ static int arExtractCommand(ArCommand *pAr){
sqlite3_bind_int(pSql, j, pAr->bDryRun);
/* Run the SELECT statement twice
- ** (0) writefile() all files and directories
- ** (1) writefile() for directory again
- ** The second pass is so that the timestamps for extracted directories
+ ** (0) writefile() files and directories
+ ** (1) writefile() symlinks
+ ** (2) writefile() for directory again
+ ** The third pass is so that the timestamps for extracted directories
** will be reset to the value in the archive, since populating them
** in the first pass will have changed the timestamp. */
- for(i=0; i<2; i++){
+ for(i=0; i<3; i++){
+ if( pAr->bDryRun>=2 ){
+ cli_printf(pAr->out, "*** BEGIN PASS %d ***\n", i+1);
+ }
j = sqlite3_bind_parameter_index(pSql, "$pass");
sqlite3_bind_int(pSql, j, i);
- if( pAr->bDryRun ){
+ if( pAr->bDryRun && i==0 ){
cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
- if( pAr->bVerbose==0 ) break;
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
if( i==0 && pAr->bVerbose ){
cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0));
}
}
- if( pAr->bDryRun ) break;
+ if( pAr->bDryRun==1 ) break;
shellReset(&rc, pSql);
+ if( pAr->bDryRun>=2 ){
+ cli_printf(pAr->out, "*** END PASS %d ***\n", i+1);
+ }
}
shellFinalize(&rc, pSql);
}
@@ -30738,7 +30801,7 @@ SELECT CASE WHEN (nc < 10) THEN 1 WHEN (nc < 100) THEN 2 \
SELECT\
'('||x'0a'\
|| group_concat(\
- cname||' ANY',\
+ cname,\
','||iif((cpos-1)%4>0, ' ', x'0a'||' '))\
||')' AS ColsSpec \
FROM (\
@@ -36886,8 +36949,10 @@ int SQLITE_CDECL main(int argc, char **argv){
cmdline_option_value(argc,argv,++i));
}else if( cli_strcmp(z,"-header")==0 ){
data.mode.spec.bTitles = QRF_Yes;
+ data.mode.mFlags |= MFLG_HDR;
}else if( cli_strcmp(z,"-noheader")==0 ){
data.mode.spec.bTitles = QRF_No;
+ data.mode.mFlags |= MFLG_HDR;
}else if( cli_strcmp(z,"-echo")==0 ){
data.mode.mFlags |= MFLG_ECHO;
}else if( cli_strcmp(z,"-eqp")==0 ){
diff --git a/sqlite3.c b/sqlite3.c
index dfd557adeda5..09f3e4a9f829 100644
--- a/sqlite3.c
+++ b/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.53.1. By combining all the individual C code files into this
+** version 3.53.3. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
-** c88b22011a54b4f6fbd149e9f8e4de77658c with changes in files:
+** d4c0e51e4aeb96955b99185ab9cde75c339e with changes in files:
**
**
*/
@@ -467,12 +467,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.53.1"
-#define SQLITE_VERSION_NUMBER 3053001
-#define SQLITE_SOURCE_ID "2026-05-05 10:34:17 c88b22011a54b4f6fbd149e9f8e4de77658ce58143a1af0e3785e4e6475127e9"
+#define SQLITE_VERSION "3.53.3"
+#define SQLITE_VERSION_NUMBER 3053003
+#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62"
#define SQLITE_SCM_BRANCH "branch-3.53"
-#define SQLITE_SCM_TAGS "release version-3.53.1"
-#define SQLITE_SCM_DATETIME "2026-05-05T10:34:17.344Z"
+#define SQLITE_SCM_TAGS "release version-3.53.3"
+#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -4687,7 +4687,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** or in an ORDER BY or GROUP BY clause.</dd>)^
**
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
-** <dd>The maximum depth of the parse tree on any expression.</dd>)^
+** <dd>The maximum depth of the parse tree on any expression and
+** the maximum nesting depth for subqueries and VIEWs</dd>)^
**
** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt>
** <dd>The maximum depth of the LALR(1) parser stack used to analyze
@@ -4718,7 +4719,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <dd>The maximum index number of any [parameter] in an SQL statement.)^
**
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
-** <dd>The maximum depth of recursion for triggers.</dd>)^
+** <dd>The maximum depth of recursion for triggers, and the maximum
+** nesting depth for separate triggers.</dd>)^
**
** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
** <dd>The maximum number of auxiliary worker threads that a single
@@ -13174,11 +13176,23 @@ SQLITE_API int sqlite3changeset_apply_v3(
** database behave as if they were declared with "ON UPDATE NO ACTION ON
** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
** or SET DEFAULT.
+**
+** <dt>SQLITE_CHANGESETAPPLY_NOUPDATELOOP <dd>
+** Sometimes, a changeset contains two or more update statements such that
+** although after applying all updates the database will contain no
+** constraint violations, no single update can be applied before the others.
+** The simplest example of this is a pair of UPDATEs that have "swapped"
+** two column values with a UNIQUE constraint.
+** <p>
+** Usually, sqlite3changeset_apply() and similar functions work hard to try
+** to find a way to apply such a changeset. However, if this flag is set,
+** then all such updates are considered CONSTRAINT conflicts.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
+#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -15789,6 +15803,13 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#endif
/*
+** sizeof64() is like sizeof(), but always returns a 64-bit value, even
+** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit
+** arithmetic is used consistently in both 32-bit and 64-bit builds.
+*/
+#define sizeof64(X) ((sqlite3_int64)sizeof(X))
+
+/*
** Work around C99 "flex-array" syntax for pre-C99 compilers, so as
** to avoid complaints from -fsanitize=strict-bounds.
*/
@@ -17149,7 +17170,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *);
SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *);
-SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *);
+SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree*, Btree*);
SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
@@ -20907,6 +20928,7 @@ struct Parse {
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iSelfTab; /* Table associated with an index on expr, or negative
** of the base register during check-constraint eval */
+ int nNestSel; /* Number of nested SELECT statements and/or VIEWs */
int nLabel; /* The *negative* of the number of labels used */
int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
@@ -22448,7 +22470,15 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
SQLITE_PRIVATE void sqlite3AlterDropConstraint(Parse*,SrcList*,Token*,Token*);
-SQLITE_PRIVATE void sqlite3AlterAddConstraint(Parse*,SrcList*,Token*,Token*,const char*,int);
+SQLITE_PRIVATE void sqlite3AlterAddConstraint(
+ Parse *pParse, /* Parse context */
+ SrcList *pSrc, /* Table to add constraint to */
+ Token *pFirst, /* First token of new constraint */
+ Token *pName, /* Name of new constraint. NULL if name omitted. */
+ const char *zExpr, /* Text of CHECK expression */
+ int nExpr, /* Size of pExpr in bytes */
+ Expr *pExpr /* The parsed CHECK expression */
+);
SQLITE_PRIVATE void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*);
SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
@@ -33257,8 +33287,8 @@ SQLITE_API void sqlite3_str_vappendf(
** all control characters, and for backslash itself.
** For %#Q, do the same but only if there is at least
** one control character. */
- u32 nBack = 0;
- u32 nCtrl = 0;
+ i64 nBack = 0;
+ i64 nCtrl = 0;
for(k=0; k<i; k++){
if( escarg[k]=='\\' ){
nBack++;
@@ -39555,16 +39585,17 @@ int kvvfsDecode(const char *a, char *aOut, int nOut){
while( 1 ){
c = kvvfsHexValue[aIn[i]];
if( c<0 ){
- int n = 0;
- int mult = 1;
+ sqlite3_int64 n = 0;
+ sqlite3_int64 mult = 1;
c = aIn[i];
if( c==0 ) break;
while( c>='a' && c<='z' ){
n += (c - 'a')*mult;
+ if( n>nOut ) return -1 /* oversized/malformed input */;
mult *= 26;
c = aIn[++i];
}
- if( j+n>nOut ) return -1;
+ if( j+n>nOut ) return -1 /* oversized/malformed input */;
memset(&aOut[j], 0, n);
j += n;
if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */
@@ -39600,7 +39631,7 @@ static void kvvfsDecodeJournal(
i = 0;
mult = 1;
while( (c = zTxt[i++])>='a' && c<='z' ){
- n += (zTxt[i] - 'a')*mult;
+ n += (c - 'a')*mult;
mult *= 26;
}
sqlite3_free(pFile->aJrnl);
@@ -39646,9 +39677,7 @@ static int kvvfsClose(sqlite3_file *pProtoFile){
pFile->isJournal ? "journal" : "db"));
sqlite3_free(pFile->aJrnl);
sqlite3_free(pFile->aData);
-#ifdef SQLITE_WASM
memset(pFile, 0, sizeof(*pFile));
-#endif
return SQLITE_OK;
}
@@ -39678,6 +39707,7 @@ static int kvvfsReadJrnl(
aTxt, szTxt+1);
if( rc>=0 ){
kvvfsDecodeJournal(pFile, aTxt, szTxt);
+ rc = 0;
}
sqlite3_free(aTxt);
if( rc ) return rc;
@@ -45307,9 +45337,9 @@ static int unixShmMap(
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
if( pShmNode->nRegion<nReqRegion ){
- char **apNew; /* New apRegion[] array */
- int nByte = nReqRegion*szRegion; /* Minimum required file size */
- struct stat sStat; /* Used by fstat() */
+ char **apNew; /* New apRegion[] array */
+ i64 nByte = nReqRegion*(i64)szRegion; /* Minimum required file size */
+ struct stat sStat; /* Used by fstat() */
pShmNode->szRegion = szRegion;
@@ -45340,7 +45370,7 @@ static int unixShmMap(
*/
else{
static const int pgsz = 4096;
- int iPg;
+ i64 iPg;
/* Write to the last byte of each newly allocated or extended page */
assert( (nByte % pgsz)==0 );
@@ -45366,8 +45396,8 @@ static int unixShmMap(
}
pShmNode->apRegion = apNew;
while( pShmNode->nRegion<nReqRegion ){
- int nMap = szRegion*nShmPerMap;
- int i;
+ i64 nMap = (i64)szRegion*(i64)nShmPerMap;
+ i64 i;
void *pMem;
if( pShmNode->hShm>=0 ){
pMem = osMmap(0, nMap,
@@ -49741,10 +49771,8 @@ static struct win_syscall {
#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
BOOL))aSyscall[63].pCurrent)
- { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 },
-
-#define osGetNativeSystemInfo ((VOID(WINAPI*)( \
- LPSYSTEM_INFO))aSyscall[64].pCurrent)
+ { "GetNativeSystemInfo", (SYSCALL)0, 0 },
+ /* ^^^^^^^^^^^^^^^^^^^----------------^------- placeholder only */
#if defined(SQLITE_WIN32_HAS_ANSI)
{ "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 },
@@ -52999,11 +53027,29 @@ SQLITE_API int sqlite3_win_test_unc_locking = 0;
/*
** Return true if the string passed as the only argument is likely
-** to be a UNC path. In other words, if it starts with "\\".
+** to be a UNC path. Return false if note.
+**
+** Return true if:
+**
+** (1) The name begins with "\\"
+** (2) But does not begin with "\\?\C:\" where C can be any alphabetic
+** character.
+**
+** For testing, also return true in all cases if the global variable
+** sqlite3_win_test_unc_locking is true.
*/
static int winIsUNCPath(const char *zFile){
if( zFile[0]=='\\' && zFile[1]=='\\' ){
- return 1;
+ if( zFile[2]=='?'
+ && zFile[3]=='\\'
+ && sqlite3Isalpha(zFile[4])
+ && zFile[5]==':'
+ && winIsDirSep(zFile[6])
+ ){
+ return sqlite3_win_test_unc_locking;
+ }else{
+ return 1;
+ }
}
return sqlite3_win_test_unc_locking;
}
@@ -53341,7 +53387,7 @@ static int winShmMap(
if( pShmNode->nRegion<=iRegion ){
HANDLE hShared = pShmNode->hSharedShm;
struct ShmRegion *apNew; /* New aRegion[] array */
- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ i64 nByte = ((i64)iRegion+1)*(i64)szRegion; /* Minimum file size */
sqlite3_int64 sz; /* Current size of wal-index file */
pShmNode->szRegion = szRegion;
@@ -53372,7 +53418,7 @@ static int winShmMap(
/* Map the requested memory region into this processes address space. */
apNew = (struct ShmRegion*)sqlite3_realloc64(
- pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
+ pShmNode->aRegion, ((i64)iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM_BKPT;
@@ -53394,15 +53440,14 @@ static int winShmMap(
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL);
#endif
-
- OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
+ OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%lld, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
- int iOffset = pShmNode->nRegion*szRegion;
+ i64 iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
pMap = osMapViewOfFile(hMap, flags,
- 0, iOffset - iOffsetShift, szRegion + iOffsetShift
+ 0, iOffset - iOffsetShift, (i64)szRegion + iOffsetShift
);
OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
@@ -53424,7 +53469,7 @@ static int winShmMap(
shmpage_out:
if( pShmNode->nRegion>iRegion ){
- int iOffset = iRegion*szRegion;
+ i64 iOffset = (i64)iRegion*(i64)szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
char *p = (char *)pShmNode->aRegion[iRegion].pMap;
*pp = (void *)&p[iOffsetShift];
@@ -56020,7 +56065,7 @@ SQLITE_API unsigned char *sqlite3_serialize(
sqlite3_int64 sz;
int szPage = 0;
sqlite3_stmt *pStmt = 0;
- unsigned char *pOut;
+ unsigned char *pOut = 0;
char *zSql;
int rc;
@@ -56030,12 +56075,13 @@ SQLITE_API unsigned char *sqlite3_serialize(
return 0;
}
#endif
+ sqlite3_mutex_enter(db->mutex);
if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
p = memdbFromDbSchema(db, zSchema);
iDb = sqlite3FindDbName(db, zSchema);
if( piSize ) *piSize = -1;
- if( iDb<0 ) return 0;
+ if( iDb<0 ) goto serialize_out;
if( p ){
MemStore *pStore = p->pStore;
assert( pStore->pMutex==0 );
@@ -56046,19 +56092,17 @@ SQLITE_API unsigned char *sqlite3_serialize(
pOut = sqlite3_malloc64( pStore->sz );
if( pOut ) memcpy(pOut, pStore->aData, pStore->sz);
}
- return pOut;
+ goto serialize_out;
}
pBt = db->aDb[iDb].pBt;
- if( pBt==0 ) return 0;
+ if( pBt==0 ) goto serialize_out;
szPage = sqlite3BtreeGetPageSize(pBt);
zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
sqlite3_free(zSql);
- if( rc ) return 0;
+ if( rc ) goto serialize_out;
rc = sqlite3_step(pStmt);
- if( rc!=SQLITE_ROW ){
- pOut = 0;
- }else{
+ if( rc==SQLITE_ROW ){
sz = sqlite3_column_int64(pStmt, 0)*szPage;
if( sz==0 ){
sqlite3_reset(pStmt);
@@ -56092,6 +56136,9 @@ SQLITE_API unsigned char *sqlite3_serialize(
}
}
sqlite3_finalize(pStmt);
+
+ serialize_out:
+ sqlite3_mutex_leave(db->mutex);
return pOut;
}
@@ -57945,22 +57992,24 @@ static int pcache1InitBulk(PCache1 *pCache){
if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
szBulk = pCache->szAlloc*(i64)pCache->nMax;
}
- zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
- sqlite3EndBenignMalloc();
- if( zBulk ){
- int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
- do{
- PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
- pX->page.pBuf = zBulk;
- pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX));
- assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) );
- pX->isBulkLocal = 1;
- pX->isAnchor = 0;
- pX->pNext = pCache->pFree;
- pX->pLruPrev = 0; /* Initializing this saves a valgrind error */
- pCache->pFree = pX;
- zBulk += pCache->szAlloc;
- }while( --nBulk );
+ if( szBulk>=pCache->szAlloc ){
+ zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
+ sqlite3EndBenignMalloc();
+ if( zBulk ){
+ int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
+ do{
+ PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
+ pX->page.pBuf = zBulk;
+ pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX));
+ assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) );
+ pX->isBulkLocal = 1;
+ pX->isAnchor = 0;
+ pX->pNext = pCache->pFree;
+ pX->pLruPrev = 0; /* Initializing this saves a valgrind error */
+ pCache->pFree = pX;
+ zBulk += pCache->szAlloc;
+ }while( --nBulk );
+ }
}
return pCache->pFree!=0;
}
@@ -60858,39 +60907,43 @@ static void checkPage(PgHdr *pPg){
#endif /* SQLITE_CHECK_PAGES */
/*
-** When this is called the journal file for pager pPager must be open.
-** This function attempts to read a super-journal file name from the
-** end of the file and, if successful, copies it into memory supplied
-** by the caller. See comments above writeSuperJournal() for the format
-** used to store a super-journal file name at the end of a journal file.
-**
-** zSuper must point to a buffer of at least nSuper bytes allocated by
-** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
-** enough space to write the super-journal name). If the super-journal
-** name in the journal is longer than nSuper bytes (including a
-** nul-terminator), then this is handled as if no super-journal name
-** were present in the journal.
+** Free a buffer allocated by the readSuperJournal() function.
+*/
+static void freeSuperJournal(char *zSuper){
+ if( zSuper ){
+ sqlite3_free(&zSuper[-4]);
+ }
+}
+
+/*
+** Parameter pJrnl is a file-handle open on a journal file. This function
+** attempts to read a super-journal file name from the end of the journal
+** file. If successful, it sets output parameter (*pzSuper) to point to a
+** buffer containing the super-journal name as a nul-terminated string.
+** The caller is responsible for freeing the buffer using freeSuperJournal().
**
-** If a super-journal file name is present at the end of the journal
-** file, then it is copied into the buffer pointed to by zSuper. A
-** nul-terminator byte is appended to the buffer following the
-** super-journal file name.
+** Refer to comments above writeSuperJournal() for the format used to store
+** a super-journal file name at the end of a journal file.
**
-** If it is determined that no super-journal file name is present
-** zSuper[0] is set to 0 and SQLITE_OK returned.
+** Parameter nSuper is passed the maximum allowable size of the super journal
+** name in bytes. If the super-journal name in the journal is longer than
+** nSuper bytes (including a nul-terminator), then this is handled as if no
+** super-journal name were present in the journal.
**
-** If an error occurs while reading from the journal file, an SQLite
-** error code is returned.
+** If there is no super-journal name at the end of pJrnl, (*pzSuper) is
+** set to 0 and SQLITE_OK is returned. Or, if an error occurs while reading
+** the super-journal name, an SQLite error code is returned and (*pzSuper)
+** is set to 0.
*/
-static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){
+static int readSuperJournal(sqlite3_file *pJrnl, u64 nSuper, char **pzSuper){
int rc; /* Return code */
u32 len; /* Length in bytes of super-journal name */
i64 szJ; /* Total size in bytes of journal file pJrnl */
u32 cksum; /* MJ checksum value read from journal */
- u32 u; /* Unsigned loop counter */
unsigned char aMagic[8]; /* A buffer to hold the magic header */
- zSuper[0] = '\0';
+ char *zOut = 0;
+ *pzSuper = 0;
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
@@ -60900,27 +60953,34 @@ static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len))
){
return rc;
}
- /* See if the checksum matches the super-journal name */
- for(u=0; u<len; u++){
- cksum -= zSuper[u];
- }
- if( cksum ){
- /* If the checksum doesn't add up, then one or more of the disk sectors
- ** containing the super-journal filename is corrupted. This means
- ** definitely roll back, so just return SQLITE_OK and report a (nul)
- ** super-journal filename.
- */
- len = 0;
+ zOut = (char*)sqlite3MallocZero(4 + len + 2);
+ if( !zOut ){
+ rc = SQLITE_NOMEM_BKPT;
+ }else{
+ zOut = &zOut[4];
+ if( SQLITE_OK==(rc = sqlite3OsRead(pJrnl, zOut, len, szJ-16-len)) ){
+ u32 u; /* Unsigned loop counter */
+ /* See if the checksum matches the super-journal name */
+ for(u=0; u<len; u++){
+ cksum -= zOut[u];
+ }
+ }
+ if( rc!=SQLITE_OK || cksum ){
+ /* If the checksum doesn't add up, then one or more of the disk sectors
+ ** containing the super-journal filename is corrupted. This means
+ ** definitely roll back, so just return SQLITE_OK and report a (nul)
+ ** super-journal filename. */
+ freeSuperJournal(zOut);
+ zOut = 0;
+ }
}
- zSuper[len] = '\0';
- zSuper[len+1] = '\0';
- return SQLITE_OK;
+ *pzSuper = zOut;
+ return rc;
}
/*
@@ -62075,6 +62135,40 @@ static int pager_playback_one_page(
}
/*
+** Check if zSuper is a valid super-journal name. There are two valid
+** formats:
+**
+** + The 3rd and 4th last bytes of the filename are ".9", and the
+** following 2 bytes are hex digits. This is a file created in 8.3
+** filenames mode.
+**
+** + The 3rd last byte of the filename is "9" and the filename
+** contains the string "-mj" starting at the 12th last byte.
+** All bytes following the "-mj" are hex digits.
+**
+** If the filename matches either of these patterns, return non-zero.
+** Otherwise, return zero.
+*/
+static int pagerIsSuperJrnlName(const char *zSuper){
+ const int nSuper = sqlite3Strlen30(zSuper);
+ int ii;
+
+ if( nSuper<4 ) return 0;
+ if( zSuper[nSuper-3]!='9' ) return 0;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ if( sqlite3Isxdigit(zSuper[nSuper-2])==0 ) return 0;
+ if( sqlite3Isxdigit(zSuper[nSuper-1])==0 ) return 0;
+ if( zSuper[nSuper-4]=='.' ) return 1;
+#endif
+ if( nSuper<12 ) return 0;
+ if( memcmp(&zSuper[nSuper-12], "-mj", 3) ) return 0;
+ for(ii=nSuper-9; ii<nSuper; ii++){
+ if( sqlite3Isxdigit(zSuper[ii])==0 ) return 0;
+ }
+ return 1;
+}
+
+/*
** Parameter zSuper is the name of a super-journal file. A single journal
** file that referred to the super-journal file has just been rolled back.
** This routine checks if it is possible to delete the super-journal file,
@@ -62125,9 +62219,16 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
char *zSuperJournal = 0; /* Contents of super-journal file */
i64 nSuperJournal; /* Size of super-journal file */
char *zJournal; /* Pointer to one journal within MJ file */
- char *zSuperPtr; /* Space to hold super-journal filename */
char *zFree = 0; /* Free this buffer */
- i64 nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
+ int bSeen = 0; /* If super-journal contains pPager->zJournal */
+
+ /* Check if this looks like a real super-journal name. If it does not,
+ ** return SQLITE_OK without attempting to delete it. This is to limit
+ ** the degree to which a crafted journal file can be used to cause
+ ** SQLite to delete arbitrary files. */
+ if( pagerIsSuperJrnlName(zSuper)==0 ){
+ return SQLITE_OK;
+ }
/* Allocate space for both the pJournal and pSuper file descriptors.
** If successful, open the super-journal file for reading.
@@ -62150,9 +62251,8 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
*/
rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
if( rc!=SQLITE_OK ) goto delsuper_out;
- nSuperPtr = 1 + (i64)pVfs->mxPathname;
- assert( nSuperJournal>=0 && nSuperPtr>0 );
- zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
+ assert( nSuperJournal>=0 );
+ zFree = sqlite3Malloc(4 + nSuperJournal + 2);
if( !zFree ){
rc = SQLITE_NOMEM_BKPT;
goto delsuper_out;
@@ -62161,7 +62261,6 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
}
zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
zSuperJournal = &zFree[4];
- zSuperPtr = &zSuperJournal[nSuperJournal+2];
rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
if( rc!=SQLITE_OK ) goto delsuper_out;
zSuperJournal[nSuperJournal] = 0;
@@ -62169,43 +62268,56 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
zJournal = zSuperJournal;
while( (zJournal-zSuperJournal)<nSuperJournal ){
- int exists;
- rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
- if( rc!=SQLITE_OK ){
- goto delsuper_out;
- }
- if( exists ){
- /* One of the journals pointed to by the super-journal exists.
- ** Open it and check if it points at the super-journal. If
- ** so, return without deleting the super-journal file.
- ** NB: zJournal is really a MAIN_JOURNAL. But call it a
- ** SUPER_JOURNAL here so that the VFS will not send the zJournal
- ** name into sqlite3_database_file_object().
- */
- int c;
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
+ if( strcmp(zJournal, pPager->zJournal)==0 ){
+ bSeen = 1;
+ }else{
+ int exists;
+ rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc!=SQLITE_OK ){
goto delsuper_out;
}
+ if( exists ){
+ char *zSuperPtr = 0;
- rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr);
- sqlite3OsClose(pJournal);
- if( rc!=SQLITE_OK ){
- goto delsuper_out;
- }
+ /* One of the journals pointed to by the super-journal exists.
+ ** Open it and check if it points at the super-journal. If
+ ** so, return without deleting the super-journal file.
+ ** NB: zJournal is really a MAIN_JOURNAL. But call it a
+ ** SUPER_JOURNAL here so that the VFS will not send the zJournal
+ ** name into sqlite3_database_file_object().
+ */
+ int c;
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
+ if( rc!=SQLITE_OK ){
+ goto delsuper_out;
+ }
- c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0;
- if( c ){
- /* We have a match. Do not delete the super-journal file. */
- goto delsuper_out;
+ rc = readSuperJournal(pJournal, 1+(u64)pVfs->mxPathname, &zSuperPtr);
+ sqlite3OsClose(pJournal);
+ if( rc!=SQLITE_OK ){
+ assert( zSuperPtr==0 );
+ goto delsuper_out;
+ }
+
+ c = zSuperPtr!=0 && strcmp(zSuperPtr, zSuper)==0;
+ freeSuperJournal(zSuperPtr);
+ if( c ){
+ /* We have a match. Do not delete the super-journal file. */
+ goto delsuper_out;
+ }
}
}
zJournal += (sqlite3Strlen30(zJournal)+1);
}
sqlite3OsClose(pSuper);
- rc = sqlite3OsDelete(pVfs, zSuper, 0);
+ if( bSeen ){
+ /* Only delete the super-journal if bSeen is true - indicating that
+ ** the super-journal contained a pointer to this database's journal
+ ** file. */
+ rc = sqlite3OsDelete(pVfs, zSuper, 0);
+ }
delsuper_out:
sqlite3_free(zFree);
@@ -62410,19 +62522,11 @@ static int pager_playback(Pager *pPager, int isHot){
** If a super-journal file name is specified, but the file is not
** present on disk, then the journal is not hot and does not need to be
** played back.
- **
- ** TODO: Technically the following is an error because it assumes that
- ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
- ** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
- ** mxPathname is 512, which is the same as the minimum allowable value
- ** for pageSize.
*/
- zSuper = pPager->pTmpSpace;
- rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
- if( rc==SQLITE_OK && zSuper[0] ){
+ rc = readSuperJournal(pPager->jfd, 1+(i64)pPager->pVfs->mxPathname, &zSuper);
+ if( rc==SQLITE_OK && zSuper ){
rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}
- zSuper = 0;
if( rc!=SQLITE_OK || !res ){
goto end_playback;
}
@@ -62551,30 +62655,20 @@ end_playback:
*/
pPager->changeCountDone = pPager->tempFile;
- if( rc==SQLITE_OK ){
- /* Leave 4 bytes of space before the super-journal filename in memory.
- ** This is because it may end up being passed to sqlite3OsOpen(), in
- ** which case it requires 4 0x00 bytes in memory immediately before
- ** the filename. */
- zSuper = &pPager->pTmpSpace[4];
- rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname);
- testcase( rc!=SQLITE_OK );
- }
if( rc==SQLITE_OK
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
){
rc = sqlite3PagerSync(pPager, 0);
}
if( rc==SQLITE_OK ){
- rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
+ rc = pager_end_transaction(pPager, zSuper!=0, 0);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && zSuper[0] && res ){
+ if( rc==SQLITE_OK && zSuper && res ){
/* If there was a super-journal and this routine will return success,
** see if it is possible to delete the super-journal.
*/
- assert( zSuper==&pPager->pTmpSpace[4] );
- memset(pPager->pTmpSpace, 0, 4);
+ assert( memcmp(&zSuper[-4], "\0\0\0\0", 4)==0 );
rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
@@ -62587,6 +62681,7 @@ end_playback:
** back a journal created by a process with a different sector size
** value. Reset it to the correct value for this process.
*/
+ freeSuperJournal(zSuper);
setSectorSize(pPager);
return rc;
}
@@ -68446,6 +68541,12 @@ static int walDecodeFrame(
return 0;
}
+ /* Need a valid page size
+ */
+ if( !pWal->szPage ){
+ return 0;
+ }
+
/* A frame is only valid if a checksum of the WAL header,
** all prior frames, the first 16 bytes of this frame-header,
** and the frame-data matches the checksum in the last 8
@@ -70300,7 +70401,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
/* Allocate a buffer to read frames into */
assert( (pWal->szPage & (pWal->szPage-1))==0 );
- assert( pWal->szPage>=512 && pWal->szPage<=65536 );
+ assert( (pWal->szPage>=512 && pWal->szPage<=65536) || pWal->szPage==0 );
szFrame = pWal->szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlite3_malloc64(szFrame);
if( aFrame==0 ){
@@ -72798,6 +72899,9 @@ struct IntegrityCk {
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
i64 nRow; /* Number of rows visited in current tree */
+#ifdef SQLITE_DEBUG
+ u32 mxHeap; /* Maximum number of entries in the Min-heap */
+#endif
};
/*
@@ -75259,8 +75363,12 @@ static int btreeComputeFreeSpace(MemPage *pPage){
}
next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]);
+ if( size<4 ){
+ /* Minimum freeblock size is 4 */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
nFree = nFree + size;
- if( next<=pc+size+3 ) break;
+ if( next<pc+size+4 ) break;
pc = next;
}
if( next>0 ){
@@ -78306,7 +78414,9 @@ static int accessPayload(
** means "not yet known" (the cache is lazily populated).
*/
if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
- int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
+ i64 nOvfl = pCur->info.nPayload;
+ testcase( nOvfl - pCur->info.nLocal + ovflSize - 1 > 0xffffffffU );
+ nOvfl = (nOvfl - pCur->info.nLocal + ovflSize-1)/ovflSize;
if( pCur->aOverflow==0
|| nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
){
@@ -78411,6 +78521,12 @@ static int accessPayload(
(eOp==0 ? PAGER_GET_READONLY : 0)
);
if( rc==SQLITE_OK ){
+ if( eOp!=0
+ && (sqlite3PagerPageRefcount(pDbPage)!=1
+ || NEVER(((MemPage*)sqlite3PagerGetExtra(pDbPage))->isInit)) ){
+ sqlite3PagerUnref(pDbPage);
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
@@ -79085,14 +79201,14 @@ static int indexCellCompare(
/* This branch runs if the record-size field of the cell is a
** single byte varint and the record fits entirely on the main
** b-tree page. */
- testcase( pCell+nCell+1==pPage->aDataEnd );
+ if( pCell + nCell >= pPage->aDataEnd ) return 99;
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
- testcase( pCell+nCell+2==pPage->aDataEnd );
+ if( pCell + nCell >= pPage->aDataEnd ) return 99;
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
}else{
/* If the record extends into overflow pages, do not attempt
@@ -79254,14 +79370,17 @@ bypass_moveto_root:
/* This branch runs if the record-size field of the cell is a
** single byte varint and the record fits entirely on the main
** b-tree page. */
- testcase( pCell+nCell+1==pPage->aDataEnd );
+ if( pCell + nCell >= pPage->aDataEnd ){
+ rc = SQLITE_CORRUPT_PAGE(pPage);
+ goto moveto_index_finish;
+ }
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
}else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
+ && pCell + nCell < pPage->aDataEnd
){
/* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
- testcase( pCell+nCell+2==pPage->aDataEnd );
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
}else{
/* The record flows over onto one or more overflow pages. In
@@ -84126,6 +84245,7 @@ static int checkTreePage(
}
}else{
/* Populate the coverage-checking heap for leaf pages */
+ assert( heap[0] < pCheck->mxHeap );
btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1));
}
}
@@ -84145,6 +84265,7 @@ static int checkTreePage(
u32 size;
pc = get2byteAligned(&data[cellStart+i*2]);
size = pPage->xCellSize(pPage, &data[pc]);
+ assert( heap[0] < pCheck->mxHeap );
btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
@@ -84161,6 +84282,7 @@ static int checkTreePage(
assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */
size = get2byte(&data[i+2]);
assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */
+ assert( heap[0] < pCheck->mxHeap );
btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
** big-endian integer which is the offset in the b-tree page of the next
@@ -84295,6 +84417,9 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
+#ifdef SQLITE_DEBUG
+ sCheck.mxHeap = pBt->pageSize/4 - 1;
+#endif
if( sCheck.heap==0 ){
checkOom(&sCheck);
goto integrity_ck_cleanup;
@@ -84712,6 +84837,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
*/
struct sqlite3_backup {
sqlite3* pDestDb; /* Destination database handle */
+ char *zDestDb;
Btree *pDest; /* Destination b-tree file */
u32 iDestSchema; /* Original schema cookie in destination */
int bDestLocked; /* True once a write-transaction is open on pDest */
@@ -84801,10 +84927,8 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
** Attempt to set the page size of the destination to match the page size
** of the source.
*/
-static int setDestPgsz(sqlite3_backup *p){
- int rc;
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
- return rc;
+static int setDestPgsz(Btree *pDest, Btree *pSrc){
+ return sqlite3BtreeSetPageSize(pDest, sqlite3BtreeGetPageSize(pSrc), 0, 0);
}
/*
@@ -84861,27 +84985,37 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
);
p = 0;
}else {
+ int nDest = sqlite3Strlen30(zDestDb);
+
/* Allocate space for a new sqlite3_backup object...
** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
** call to sqlite3_backup_init() and is destroyed by a call to
** sqlite3_backup_finish(). */
- p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
+ p = (sqlite3_backup*)sqlite3MallocZero(sizeof(sqlite3_backup)+nDest+1);
if( !p ){
sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
+ }else{
+ p->zDestDb = (char*)&p[1];
+ memcpy(p->zDestDb, zDestDb, nDest);
}
}
/* If the allocation succeeded, populate the new object. */
if( p ){
+ /* Do not store the pointer to the destination b-tree at this point.
+ ** This is because there is nothing preventing it from being detached
+ ** or otherwise freed before the first call to sqlite3_backup_step()
+ ** on this object. The source b-tree does not have this problem, as
+ ** incrementing Btree.nBackup (see below) effectively locks the object. */
+ Btree *pDest = findBtree(pDestDb, pDestDb, zDestDb);
p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb);
- p->pDest = findBtree(pDestDb, pDestDb, zDestDb);
p->pDestDb = pDestDb;
p->pSrcDb = pSrcDb;
p->iNext = 1;
p->isAttached = 0;
- if( 0==p->pSrc || 0==p->pDest
- || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
+ if( 0==p->pSrc || 0==pDest
+ || checkReadTransaction(pDestDb, pDest)!=SQLITE_OK
){
/* One (or both) of the named databases did not exist or an OOM
** error was hit. Or there is a transaction open on the destination
@@ -85005,7 +85139,7 @@ static void attachBackupObject(sqlite3_backup *p){
*/
SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
- int destMode; /* Destination journal mode */
+ int destMode = 0; /* Destination journal mode */
int pgszSrc = 0; /* Source page size */
int pgszDest = 0; /* Destination page size */
@@ -85021,7 +85155,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = p->rc;
if( !isFatalError(rc) ){
Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */
- Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */
+ Btree * pDest = 0; /* Dest btree */
+ Pager * pDestPager = 0; /* Dest pager */
int ii; /* Iterator variable */
int nSrcPage = -1; /* Size of source db in pages */
int bCloseTrans = 0; /* True if src db requires unlocking */
@@ -85035,6 +85170,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = SQLITE_OK;
}
+
/* If there is no open read-transaction on the source database, open
** one now. If a transaction is opened here, then it will be closed
** before this function exits.
@@ -85044,34 +85180,48 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
bCloseTrans = 1;
}
+ /* Locate the destination btree and pager. */
+ if( (pDest = p->pDest)==0 ){
+ pDest = findBtree(p->pDestDb, p->pDestDb, p->zDestDb);
+ }
+ if( pDest==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ pDestPager = sqlite3BtreePager(pDest);
+ }
+
/* If the destination database has not yet been locked (i.e. if this
** is the first call to backup_step() for the current backup operation),
** try to set its page size to the same as the source database. This
** is especially important on ZipVFS systems, as in that case it is
** not possible to create a database file that uses one page size by
** writing to it with another. */
- if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
+ if( p->bDestLocked==0 && rc==SQLITE_OK
+ && setDestPgsz(pDest, p->pSrc)==SQLITE_NOMEM
+ ){
rc = SQLITE_NOMEM;
}
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
- && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
+ && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(pDest, 2,
(int*)&p->iDestSchema))
){
p->bDestLocked = 1;
+ p->pDest = pDest;
}
/* Do not allow backup if the destination database is in WAL mode
** and the page sizes are different between source and destination */
- pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
- pgszDest = sqlite3BtreeGetPageSize(p->pDest);
- destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc
- && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
- && pgszSrc!=pgszDest
- ){
- rc = SQLITE_READONLY;
+ if( rc==SQLITE_OK ){
+ pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
+ pgszDest = sqlite3BtreeGetPageSize(p->pDest);
+ destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
+ if( (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
+ rc = SQLITE_READONLY;
+ }
}
/* Now that there is a read-lock on the source database, query the
@@ -85289,7 +85439,9 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
/* If a transaction is still open on the Btree, roll it back. */
- sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
+ if( p->pDest ){
+ sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
+ }
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
@@ -93557,8 +93709,14 @@ SQLITE_PRIVATE const char *sqlite3VdbeFuncName(const sqlite3_context *pCtx){
** added or changed.
*/
SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
- return p==0 || p->expired;
+ int iRet = 1;
+ if( pStmt ){
+ Vdbe *p = (Vdbe*)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
+ iRet = p->expired;
+ sqlite3_mutex_leave(p->db->mutex);
+ }
+ return iRet;
}
#endif
@@ -111099,6 +111257,7 @@ static int lookupName(
pExpr->op = TK_FUNCTION;
pExpr->u.zToken = "coalesce";
pExpr->x.pList = pFJMatch;
+ pExpr->affExpr = SQLITE_AFF_DEFER;
cnt = 1;
goto lookupname_end;
}else{
@@ -111268,6 +111427,26 @@ static int exprProbability(Expr *p){
}
/*
+** Set the EP_SubtArg property on every expression inside of
+** pList. If any subexpression is actually a subquery, then
+** also set the EP_SubtArg property on the first result-set
+** column of that subquery.
+*/
+static SQLITE_NOINLINE void resolveSetExprSubtypeArg(ExprList *pList){
+ int nn, ii;
+ nn = pList ? pList->nExpr : 0;
+ for(ii=0; ii<nn; ii++){
+ Expr *pExpr = pList->a[ii].pExpr;
+ ExprSetProperty(pExpr, EP_SubtArg);
+ if( pExpr->op==TK_SELECT ){
+ assert( ExprUseXSelect(pExpr) );
+ assert( pExpr->x.pSelect!=0 );
+ resolveSetExprSubtypeArg(pExpr->x.pSelect->pEList);
+ }
+ }
+}
+
+/*
** This routine is callback for sqlite3WalkExpr().
**
** Resolve symbolic names into TK_COLUMN operators for the current
@@ -111511,10 +111690,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( (pDef->funcFlags & SQLITE_SUBTYPE)
|| ExprHasProperty(pExpr, EP_SubtArg)
){
- int ii;
- for(ii=0; ii<n; ii++){
- ExprSetProperty(pList->a[ii].pExpr, EP_SubtArg);
- }
+ resolveSetExprSubtypeArg(pList);
}
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
@@ -116835,7 +117011,7 @@ static void sqlite3ExprCodeIN(
Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error;
if( sqlite3ExprCanBeNull(p) ){
- sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
+ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+aiMap[i], destStep2);
VdbeCoverage(v);
}
}
@@ -116909,9 +117085,18 @@ static void sqlite3ExprCodeIN(
CollSeq *pColl;
int r3 = sqlite3GetTempReg(pParse);
p = sqlite3VectorFieldSubexpr(pLeft, i);
- pColl = sqlite3ExprCollSeq(pParse, p);
- sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3);
- sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
+ if( ExprUseXSelect(pExpr) ){
+ Expr *pRhs = pExpr->x.pSelect->pEList->a[i].pExpr;
+ pColl = sqlite3BinaryCompareCollSeq(pParse, p, pRhs);
+ }else{
+ /* If the RHS of the IN(...) expression are scalar expressions, do
+ ** not consider their collation sequences. The documentation says
+ ** "The collating sequence used for expressions of the form "x IN (y, z,
+ ** ...)" is the collating sequence of x.". */
+ pColl = sqlite3ExprCollSeq(pParse, p);
+ }
+ sqlite3VdbeAddOp3(v, OP_Column, iTab, aiMap[i], r3);
+ sqlite3VdbeAddOp4(v, OP_Ne, rLhs+aiMap[i], destNotNull, r3,
(void*)pColl, P4_COLLSEQ);
VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, r3);
@@ -117332,26 +117517,37 @@ static int exprCodeInlineFunction(
}
/*
-** Expression Node callback for sqlite3ExprCanReturnSubtype().
+** Expression Node callback for sqlite3ExprCanReturnSubtype(). If
+** pExpr is able to return a subtype, set pWalker->eCode and abort
+** the search. If pExpr can never return a subtype, prune search.
**
-** Only a function call is able to return a subtype. So if the node
-** is not a function call, return WRC_Prune immediately.
+** The only expressions that can return a subtype are:
**
-** A function call is able to return a subtype if it has the
-** SQLITE_RESULT_SUBTYPE property.
+** 1. A function
+** 2. The no-op "+" operator
+** 3. A CASE...END expression
+** 4. A CAST() expression
+** 5. A "expr COLLATE colseq" expression.
**
-** Assume that every function is able to pass-through a subtype from
-** one of its argument (using sqlite3_result_value()). Most functions
-** are not this way, but we don't have a mechanism to distinguish those
-** that are from those that are not, so assume they all work this way.
-** That means that if one of its arguments is another function and that
-** other function is able to return a subtype, then this function is
-** able to return a subtype.
+** For any other kind of expression, prune the search.
+**
+** For case 1, the expression can yield a subtype if the function has
+** the SQLITE_RESULT_SUBTYPE property. Functions can also return
+** a subtype (via sqlite3_result_value()) if any of the arguments can
+** return a subtype.
+**
+** In all cases 1 through 5, the expression might also return a subtype
+** if any operand can return a subtype.
*/
static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
int n;
FuncDef *pDef;
sqlite3 *db;
+ if( pExpr->op==TK_CASE || pExpr->op==TK_UPLUS
+ || pExpr->op==TK_COLLATE || pExpr->op==TK_CAST
+ ){
+ return WRC_Continue;
+ }
if( pExpr->op!=TK_FUNCTION ){
return WRC_Prune;
}
@@ -117361,7 +117557,7 @@ static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
pWalker->eCode = 1;
- return WRC_Prune;
+ return WRC_Abort;
}
return WRC_Continue;
}
@@ -123339,19 +123535,31 @@ SQLITE_PRIVATE void sqlite3AlterAddConstraint(
SrcList *pSrc, /* Table to add constraint to */
Token *pFirst, /* First token of new constraint */
Token *pName, /* Name of new constraint. NULL if name omitted. */
- const char *pExpr, /* Text of CHECK expression */
- int nExpr /* Size of pExpr in bytes */
+ const char *zExpr, /* Text of CHECK expression */
+ int nExpr, /* Size of pExpr in bytes */
+ Expr *pExpr /* The parsed CHECK expression */
){
Table *pTab = 0; /* Table identified by pSrc */
int iDb = 0; /* Which schema does pTab live in */
const char *zDb = 0; /* Name of the schema in which pTab lives */
const char *pCons = 0; /* Text of the constraint */
int nCons; /* Bytes of text to use from pCons[] */
+ int rc; /* Result from error checking pExpr */
/* Look up the table being altered. */
assert( pSrc->nSrc==1 );
pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1);
- if( !pTab ) return;
+ if( !pTab ){
+ sqlite3ExprDelete(pParse->db, pExpr);
+ return;
+ }
+
+ /* Verify that the new CHECK constraint does not contain any
+ ** internal-use-only function. Forum post 2026-05-10T01:11:28Z
+ */
+ rc = sqlite3ResolveSelfReference(pParse, pTab, NC_IsCheck, pExpr, 0);
+ sqlite3ExprDelete(pParse->db, pExpr);
+ if( rc ) return;
/* If this new constraint has a name, check that it is not a duplicate of
** an existing constraint. It is an error if it is. */
@@ -123372,7 +123580,7 @@ SQLITE_PRIVATE void sqlite3AlterAddConstraint(
sqlite3NestedParse(pParse,
"SELECT sqlite_fail('constraint failed', %d) "
"FROM %Q.%Q WHERE (%.*s) IS NOT TRUE",
- SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, pExpr
+ SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, zExpr
);
/* Edit the SQL for the named table. */
@@ -125227,9 +125435,9 @@ static int loadStatTbl(
}
pIdx->nSampleCol = nIdxCol;
pIdx->mxSample = nSample;
- nByte = ROUND8(sizeof(IndexSample) * nSample);
- nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
- nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
+ nByte = ROUND8(sizeof64(IndexSample) * nSample);
+ nByte += sizeof64(tRowcnt) * nIdxCol * 3 * nSample;
+ nByte += nIdxCol * sizeof64(tRowcnt); /* Space for Index.aAvgEq[] */
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
@@ -125237,7 +125445,7 @@ static int loadStatTbl(
return SQLITE_NOMEM_BKPT;
}
pPtr = (u8*)pIdx->aSample;
- pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0]));
+ pPtr += ROUND8(nSample*sizeof64(pIdx->aSample[0]));
pSpace = (tRowcnt*)pPtr;
assert( EIGHT_BYTE_ALIGNMENT( pSpace ) );
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
@@ -134049,9 +134257,18 @@ static void printfFunc(
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
str.printfFlags = SQLITE_PRINTF_SQLFUNC;
sqlite3_str_appendf(&str, zFormat, &x);
- n = str.nChar;
- sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
- SQLITE_DYNAMIC);
+ if( str.accError==SQLITE_OK ){
+ n = str.nChar;
+ sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
+ SQLITE_DYNAMIC);
+ }else{
+ if( str.accError==SQLITE_NOMEM ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_error_toobig(context);
+ }
+ sqlite3_str_reset(&str);
+ }
}
}
@@ -135689,11 +135906,16 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
assert( p->cnt>0 );
p->cnt--;
if( !p->approx ){
- if( sqlite3SubInt64(&p->iSum, sqlite3_value_int64(argv[0])) ){
- p->ovrfl = 1;
- p->approx = 1;
+ i64 x = p->iSum;
+ if( sqlite3SubInt64(&x, sqlite3_value_int64(argv[0]))==0 ){
+ p->iSum = x;
+ return;
}
- }else if( type==SQLITE_INTEGER ){
+ p->ovrfl = 1;
+ p->approx = 1;
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ }
+ if( type==SQLITE_INTEGER ){
i64 iVal = sqlite3_value_int64(argv[0]);
if( iVal!=SMALLEST_INT64 ){
kahanBabuskaNeumaierStepInt64(p, -iVal);
@@ -136666,47 +136888,46 @@ static void percentSort(double *a, unsigned int n){
int i; /* Loop counter */
double rPivot; /* The pivot value */
- assert( n>=2 );
- if( a[0]>a[n-1] ){
- SWAP_DOUBLE(a[0],a[n-1])
- }
- if( n==2 ) return;
- iGt = n-1;
- i = n/2;
- if( a[0]>a[i] ){
- SWAP_DOUBLE(a[0],a[i])
- }else if( a[i]>a[iGt] ){
- SWAP_DOUBLE(a[i],a[iGt])
- }
- if( n==3 ) return;
- rPivot = a[i];
- iLt = i = 1;
- do{
- if( a[i]<rPivot ){
- if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
- iLt++;
- i++;
- }else if( a[i]>rPivot ){
- do{
- iGt--;
- }while( iGt>i && a[iGt]>rPivot );
+ while( n>=2 ){
+ if( a[0]>a[n-1] ){
+ SWAP_DOUBLE(a[0],a[n-1])
+ }
+ if( n==2 ) return;
+ iGt = n-1;
+ i = n/2;
+ if( a[0]>a[i] ){
+ SWAP_DOUBLE(a[0],a[i])
+ }else if( a[i]>a[iGt] ){
SWAP_DOUBLE(a[i],a[iGt])
+ }
+ if( n==3 ) return;
+ rPivot = a[i];
+ iLt = i = 1;
+ do{
+ if( a[i]<rPivot ){
+ if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
+ iLt++;
+ i++;
+ }else if( a[i]>rPivot ){
+ do{
+ iGt--;
+ }while( iGt>i && a[iGt]>rPivot );
+ SWAP_DOUBLE(a[i],a[iGt])
+ }else{
+ i++;
+ }
+ }while( i<iGt );
+ if( iLt>(int)(n/2) ){
+ if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
+ n = iLt;
}else{
- i++;
+ if( iLt>=2 ) percentSort(a, iLt);
+ a += iGt;
+ n -= iGt;
}
- }while( i<iGt );
- if( iLt>=2 ) percentSort(a, iLt);
- if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
-
-/* Uncomment for testing */
-#if 0
- for(i=0; i<n-1; i++){
- assert( a[i]<=a[i+1] );
}
-#endif
}
-
/*
** The "inverse" function for percentile(Y,P) is called to remove a
** row that was previously inserted by "step".
@@ -151213,6 +151434,13 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c
sqlite3 *db = pParse->db;
u64 savedFlags;
+ pParse->nNestSel++;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){
+ sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep");
+ return 0;
+ }
+#endif
savedFlags = db->flags;
db->flags &= ~(u64)SQLITE_FullColNames;
db->flags |= SQLITE_ShortColNames;
@@ -151234,6 +151462,8 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c
sqlite3DeleteTable(db, pTab);
return 0;
}
+ pParse->nNestSel--;
+ assert( pParse->nNestSel>=0 );
return pTab;
}
@@ -156204,8 +156434,11 @@ static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){
** does not refer to a table to the right of CheckOnCtx.iJoin. */
do {
SrcList *pSrc = pCtx->pSrc;
+ int nSrc = pSrc->nSrc;
int iTab = pExpr->iTable;
- if( iTab>=pSrc->a[0].iCursor && iTab<=pSrc->a[pSrc->nSrc-1].iCursor ){
+ int ii;
+ for(ii=0; ii<nSrc && pSrc->a[ii].iCursor!=iTab; ii++){}
+ if( ii<nSrc ){
if( pCtx->iJoin && iTab>pCtx->iJoin ){
sqlite3ErrorMsg(pWalker->pParse,
"%s references tables to its right",
@@ -159174,7 +159407,7 @@ static TriggerPrg *codeRowTrigger(
Table *pTab, /* The table pTrigger is attached to */
int orconf /* ON CONFLICT policy to code trigger program with */
){
- Parse *pTop = sqlite3ParseToplevel(pParse);
+ Parse *pTop; /* Top level Parse object */
sqlite3 *db = pParse->db; /* Database handle */
TriggerPrg *pPrg; /* Value to return */
Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */
@@ -159183,10 +159416,24 @@ static TriggerPrg *codeRowTrigger(
SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
Parse sSubParse; /* Parse context for sub-vdbe */
+ int nDepth; /* Trigger depth */
+
+ /* Ensure that triggers are not chained too deep. This test is linear
+ ** in the chaining depth, but sensible code ought not be chaining
+ ** triggers excessively, so that shouldn't be a problem.
+ */
+ pTop = pParse;
+ for(nDepth=0; pTop->pOuterParse; pTop = pTop->pOuterParse, nDepth++){}
+ if( nDepth>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
+ sqlite3ErrorMsg(pParse, "triggers nested too deep");
+ return 0;
+ }
+ pTop = sqlite3ParseToplevel(pParse);
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
assert( pTop->pVdbe );
+
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
** are freed if an error occurs, link them into the Parse.pTriggerPrg
** list of the top-level Parse object sooner rather than later. */
@@ -161187,7 +161434,8 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
/* excluded.* columns of type REAL need to be converted to a hard real */
for(i=0; i<pTab->nCol; i++){
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
- sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
+ int iStorage = pTop->regData + sqlite3TableColumnToStorage(pTab, i);
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iStorage);
}
}
sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
@@ -161775,6 +162023,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
+ sqlite3_mutex_enter(db->mutex);
for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){
Module *pMod = (Module*)sqliteHashData(pThis);
pNext = sqliteHashNext(pThis);
@@ -161785,6 +162034,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){
}
createModule(db, pMod->zName, 0, 0, 0);
}
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -166405,6 +166655,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
WO_EQ|WO_IN|WO_IS, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
+ if( ExprHasProperty(pAlt->pExpr, EP_Collate) ) continue;
if( (pAlt->eOperator & WO_IN)
&& ExprUseXSelect(pAlt->pExpr)
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
@@ -167158,7 +167409,10 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){
pWC->a[iChild].iParent = iParent;
pWC->a[iChild].truthProb = pWC->a[iParent].truthProb;
+ assert( pWC->a[iParent].nChild < UMXV(pWC->a[0].nChild) );
pWC->a[iParent].nChild++;
+ testcase( pWC->a[iParent].nChild == UMXV(pWC->a[0].nChild) );
+
}
/*
@@ -167597,8 +167851,8 @@ static void exprAnalyzeOrTerm(
** 3. Not originating in the ON clause of an OUTER JOIN
** 4. The operator is not IS or else the query does not contain RIGHT JOIN
** 5. The affinities of A and B must be compatible
-** 6a. Both operands use the same collating sequence OR
-** 6b. The overall collating sequence is BINARY
+** 6. Both operands use the same collating sequence, and they must not
+** use explicit COLLATE clauses.
** If this routine returns TRUE, that means that the RHS can be substituted
** for the LHS anyplace else in the WHERE clause where the LHS column occurs.
** This is an optimization. No harm comes from returning 0. But if 1 is
@@ -167606,10 +167860,9 @@ static void exprAnalyzeOrTerm(
*/
static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){
char aff1, aff2;
- CollSeq *pColl;
if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; /* (1) */
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; /* (2) */
- if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* (3) */
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_Collate) ) return 0; /* (3) */
assert( pSrc!=0 );
if( pExpr->op==TK_IS
&& pSrc->nSrc>=2
@@ -167624,10 +167877,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr, SrcList *pSrc){
){
return 0; /* (5) */
}
- pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
- if( !sqlite3IsBinary(pColl)
- && !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight)
- ){
+ if( !sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight) ){
return 0; /* (6) */
}
return 1;
@@ -167939,6 +168189,7 @@ static void exprAnalyze(
pList = pExpr->x.pList;
assert( pList!=0 );
assert( pList->nExpr==2 );
+ assert( pWC->a[idxTerm].nChild==0 );
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
@@ -167959,7 +168210,7 @@ static void exprAnalyze(
/* Analyze a term that is composed of two or more subterms connected by
** an OR operator.
*/
- else if( pExpr->op==TK_OR ){
+ else if( pExpr->op==TK_OR && !ExprHasProperty(pExpr, EP_Collate) ){
assert( pWC->op==TK_AND );
exprAnalyzeOrTerm(pSrc, pWC, idxTerm);
pTerm = &pWC->a[idxTerm];
@@ -168149,8 +168400,11 @@ static void exprAnalyze(
&& pExpr->x.pSelect->pWin==0
#endif
&& pWC->op==TK_AND
+ && pExpr->x.pSelect->pEList->nExpr <= UMXV(pTerm->nChild)
+ /* ^-- See bug 2026-06-04T10:00:49Z */
){
int i;
+ assert( pTerm->nChild==0 );
for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
int idxNew;
idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE);
@@ -171777,7 +172031,8 @@ static int whereRangeVectorLen(
idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
if( aff!=idxaff ) break;
- pColl = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr);
+ if( ExprHasProperty(pTerm->pExpr, EP_Commuted) ) SWAP(Expr*, pRhs, pLhs);
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
if( pColl==0 ) break;
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break;
}
@@ -184251,9 +184506,11 @@ static YYACTIONTYPE yy_reduce(
ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454);
yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
if( yymsp[-4].minor.yy454 ){
+ int i;
yymsp[-4].minor.yy454->x.pList = pList;
- if( ALWAYS(pList->nExpr) ){
- yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ for(i=0; i<pList->nExpr; i++){
+ assert( pList->a[i].pExpr!=0 );
+ yymsp[-4].minor.yy454->flags |= pList->a[i].pExpr->flags & EP_Propagate;
}
}else{
sqlite3ExprListDelete(pParse->db, pList);
@@ -184721,15 +184978,13 @@ static YYACTIONTYPE yy_reduce(
break;
case 300: /* cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */
{
- sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1));
+ sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454);
}
- yy_destructor(yypParser,219,&yymsp[-2].minor);
break;
case 301: /* cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */
{
- sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1));
+ sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1), yymsp[-2].minor.yy454);
}
- yy_destructor(yypParser,219,&yymsp[-2].minor);
break;
case 302: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
@@ -188218,13 +188473,17 @@ static int nocaseCollatingFunc(
** Return the ROWID of the most recent insert
*/
SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
+ i64 iRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- return db->lastRowid;
+ sqlite3_mutex_enter(db->mutex);
+ iRet = db->lastRowid;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
/*
@@ -188246,13 +188505,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid)
** Return the number of changes in the most recent call to sqlite3_exec().
*/
SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){
+ i64 iRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- return db->nChange;
+ sqlite3_mutex_enter(db->mutex);
+ iRet = db->nChange;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
SQLITE_API int sqlite3_changes(sqlite3 *db){
return (int)sqlite3_changes64(db);
@@ -188262,13 +188525,17 @@ SQLITE_API int sqlite3_changes(sqlite3 *db){
** Return the number of changes since the database handle was opened.
*/
SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){
+ i64 iRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- return db->nTotalChange;
+ sqlite3_mutex_enter(db->mutex);
+ iRet = db->nTotalChange;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
SQLITE_API int sqlite3_total_changes(sqlite3 *db){
return (int)sqlite3_total_changes64(db);
@@ -188951,6 +189218,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
+ sqlite3_mutex_enter(db->mutex);
if( ms>0 ){
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
@@ -188961,6 +189229,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
}else{
sqlite3_busy_handler(db, 0, 0);
}
+ sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -189866,9 +190135,11 @@ SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zMsg){
*/
SQLITE_API int sqlite3_error_offset(sqlite3 *db){
int iOffset = -1;
- if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){
+ if( db && sqlite3SafetyCheckSickOrOk(db) ){
sqlite3_mutex_enter(db->mutex);
- iOffset = db->errByteOffset;
+ if( db->errCode ){
+ iOffset = db->errByteOffset;
+ }
sqlite3_mutex_leave(db->mutex);
}
return iOffset;
@@ -189922,25 +190193,43 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
SQLITE_API int sqlite3_errcode(sqlite3 *db){
- if( db && !sqlite3SafetyCheckSickOrOk(db) ){
+ int iRet;
+ if( !db ) return SQLITE_NOMEM_BKPT;
+ if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
- if( !db || db->mallocFailed ){
- return SQLITE_NOMEM_BKPT;
+ sqlite3_mutex_enter(db->mutex);
+ if( db->mallocFailed ){
+ iRet = SQLITE_NOMEM_BKPT;
+ }else{
+ iRet = db->errCode & db->errMask;
}
- return db->errCode & db->errMask;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
- if( db && !sqlite3SafetyCheckSickOrOk(db) ){
+ int iRet;
+ if( !db ) return SQLITE_NOMEM_BKPT;
+ if( !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
- if( !db || db->mallocFailed ){
- return SQLITE_NOMEM_BKPT;
+ sqlite3_mutex_enter(db->mutex);
+ if( db->mallocFailed ){
+ iRet = SQLITE_NOMEM_BKPT;
+ }else{
+ iRet = db->errCode;
}
- return db->errCode;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
SQLITE_API int sqlite3_system_errno(sqlite3 *db){
- return db ? db->iSysErrno : 0;
+ int iRet = 0;
+ if( db ){
+ sqlite3_mutex_enter(db->mutex);
+ iRet = db->iSysErrno;
+ sqlite3_mutex_leave(db->mutex);
+ }
+ return iRet;
}
/*
@@ -190135,6 +190424,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
return -1;
}
+ sqlite3_mutex_enter(db->mutex);
oldLimit = db->aLimit[limitId];
if( newLimit>=0 ){ /* IMP: R-52476-28732 */
if( newLimit>aHardLimit[limitId] ){
@@ -190144,6 +190434,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
}
db->aLimit[limitId] = newLimit;
}
+ sqlite3_mutex_leave(db->mutex);
return oldLimit; /* IMP: R-53341-35419 */
}
@@ -190186,7 +190477,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
const char *zVfs = zDefaultVfs;
char *zFile;
char c;
- int nUri = sqlite3Strlen30(zUri);
+ i64 nUri = strlen(zUri);
assert( *pzErrMsg==0 );
@@ -190196,8 +190487,8 @@ SQLITE_PRIVATE int sqlite3ParseUri(
){
char *zOpt;
int eState; /* Parser state when parsing URI */
- int iIn; /* Input character index */
- int iOut = 0; /* Output character index */
+ i64 iIn; /* Input character index */
+ i64 iOut = 0; /* Output character index */
u64 nByte = nUri+8; /* Bytes of space to allocate */
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
@@ -190231,7 +190522,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
*pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
- iIn-7, &zUri[7]);
+ (int)(iIn-7), &zUri[7]);
rc = SQLITE_ERROR;
goto parse_uri_out;
}
@@ -190306,11 +190597,11 @@ SQLITE_PRIVATE int sqlite3ParseUri(
** here. Options that are interpreted here include "vfs" and those that
** correspond to flags that may be passed to the sqlite3_open_v2()
** method. */
- zOpt = &zFile[sqlite3Strlen30(zFile)+1];
+ zOpt = &zFile[strlen(zFile)+1];
while( zOpt[0] ){
- int nOpt = sqlite3Strlen30(zOpt);
+ i64 nOpt = strlen(zOpt);
char *zVal = &zOpt[nOpt+1];
- int nVal = sqlite3Strlen30(zVal);
+ i64 nVal = strlen(zVal);
if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
zVfs = zVal;
@@ -190356,7 +190647,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
int mode = 0;
for(i=0; aMode[i].z; i++){
const char *z = aMode[i].z;
- if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){
+ if( nVal==(i64)strlen(z) && 0==memcmp(zVal, z, nVal) ){
mode = aMode[i].mode;
break;
}
@@ -191041,13 +191332,17 @@ SQLITE_API int sqlite3_global_recover(void){
** by the next COMMIT or ROLLBACK.
*/
SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
+ int iRet;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- return db->autoCommit;
+ sqlite3_mutex_enter(db->mutex);
+ iRet = db->autoCommit;
+ sqlite3_mutex_leave(db->mutex);
+ return iRet;
}
/*
@@ -192072,17 +192367,19 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
** of range.
*/
SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N){
+ const char *zRet = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- if( N<0 || N>=db->nDb ){
- return 0;
- }else{
- return db->aDb[N].zDbSName;
+ sqlite3_mutex_enter(db->mutex);
+ if( N>=0 && N<db->nDb ){
+ zRet = db->aDb[N].zDbSName;
}
+ sqlite3_mutex_leave(db->mutex);
+ return zRet;
}
/*
@@ -193933,6 +194230,12 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
SQLITE_EXTENSION_INIT1
#endif
+
+/*
+** Assume any b-tree layer with more levels than this is corrupt.
+*/
+#define FTS3_MAX_BTREE_HEIGHT 48
+
typedef struct Fts3HashWrapper Fts3HashWrapper;
struct Fts3HashWrapper {
Fts3Hash hash; /* Hash table */
@@ -195649,7 +195952,11 @@ static int fts3SelectLeaf(
assert( piLeaf || piLeaf2 );
fts3GetVarint32(zNode, &iHeight);
- rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
+ if( iHeight>FTS3_MAX_BTREE_HEIGHT ){
+ rc = FTS_CORRUPT_VTAB;
+ }else{
+ rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
+ }
assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
if( rc==SQLITE_OK && iHeight>1 ){
@@ -195694,8 +196001,13 @@ static void fts3PutDeltaVarint(
sqlite3_int64 iVal /* Write this value to the list */
){
assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
- *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
- *piPrev = iVal;
+ if( iVal-(*piPrev)>=0 ){
+ /* Refuse to write a negative delta integer. This only happens with a
+ ** corrupt db (see the assert above) and can cause buffer overwrites
+ ** in some cases. */
+ *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
+ *piPrev = iVal;
+ }
}
/*
@@ -198049,6 +198361,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
char *p1;
char *p2;
char *aOut;
+ i64 nAlloc = (i64)nPoslist*2 + FTS3_BUFFER_PADDING;
if( nMaxUndeferred>iPrev ){
p1 = aPoslist;
@@ -198060,7 +198373,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nDistance = iPrev - nMaxUndeferred;
}
- aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING);
+ aOut = (char *)sqlite3Fts3MallocZero(nAlloc);
if( !aOut ){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
@@ -200178,7 +200491,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
/* State 3. The integer just read is a column number. */
default: assert( eState==3 );
iCol = (int)v;
- if( iCol<1 ){
+ if( iCol<1 || iCol>(pFts3->nColumn+1) ){
rc = SQLITE_CORRUPT_VTAB;
break;
}
@@ -200868,6 +201181,7 @@ static int getNextNode(
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
+ if( nNear>=1000000000 ) nNear = 1000000000;
}
}
@@ -207114,6 +207428,10 @@ static void fts3ReadEndBlockField(
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
+
+ /* This if() clause is just to avoid an integer overflow. The record is
+ ** corrupt in this case. */
+ if( (i64)iVal==SMALLEST_INT64 ) iMul = 1;
*pnByte = ((i64)iVal * (i64)iMul);
}
}
@@ -208340,7 +208658,7 @@ static int fts3IncrmergeLoad(
return FTS_CORRUPT_VTAB;
}
- pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
+ pWriter->nLeafEst = (int)(((iEnd - iStart)+1)/FTS_MAX_APPENDABLE_HEIGHT);
pWriter->iStart = iStart;
pWriter->iEnd = iEnd;
pWriter->iAbsLevel = iAbsLevel;
@@ -210731,7 +211049,7 @@ static int fts3ExprLHits(
if( p->flag==FTS3_MATCHINFO_LHITS ){
p->aMatchinfo[iStart + iCol] = (u32)nHit;
}else if( nHit ){
- p->aMatchinfo[iStart + (iCol+1)/32] |= (1 << (iCol&0x1F));
+ p->aMatchinfo[iStart + iCol/32] |= (1U << (iCol&0x1F));
}
}
assert( *pIter==0x00 || *pIter==0x01 );
@@ -213221,7 +213539,7 @@ static void jsonAppendSqlValue(
break;
}
case SQLITE_FLOAT: {
- jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue));
+ jsonPrintf(100, p, "%!0.17g", sqlite3_value_double(pValue));
break;
}
case SQLITE_INTEGER: {
@@ -214535,9 +214853,10 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
u8 x;
u32 sz;
u32 n;
- assert( i<=pParse->nBlob );
- x = pParse->aBlob[i]>>4;
- if( x<=11 ){
+ if( i>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }else if( (x = pParse->aBlob[i]>>4)<=11 ){
sz = x;
n = 1;
}else if( x==12 ){
@@ -217320,11 +217639,9 @@ static void jsonGroupInverse(
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
-#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
** always have been called to initialize it */
if( NEVER(!pStr) ) return;
-#endif
z = pStr->zBuf;
for(i=1; i<pStr->nUsed && ((c = z[i])!=',' || inStr || nNest); i++){
if( c=='"' ){
@@ -217353,6 +217670,13 @@ static void jsonGroupInverse(
** json_group_obj(NAME,VALUE)
**
** Return a JSON object composed of all names and values in the aggregate.
+**
+** Rows for which NAME is NULL do not result in a new entry. However, we
+** do initially insert a "@" entry into the growing string for each null entry
+** and change the first character of the string to "@" to signal that the
+** string contains null entries. The "@" markers are needed in order to
+** correctly process xInverse() requests. The initial "@" is converted
+** back into "{" and the "@" null values are removed by jsonObjectCompute().
*/
static void jsonObjectStep(
sqlite3_context *ctx,
@@ -217370,7 +217694,7 @@ static void jsonObjectStep(
if( pStr->zBuf==0 ){
jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{');
- }else if( pStr->nUsed>1 && z!=0 ){
+ }else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
@@ -217378,6 +217702,9 @@ static void jsonObjectStep(
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
jsonAppendSqlValue(pStr, argv[1]);
+ }else{
+ pStr->zBuf[0] = '@';
+ jsonAppendRawNZ(pStr, "@", 1);
}
}
}
@@ -217386,20 +217713,64 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
- jsonAppendRawNZ(pStr, "}", 2);
- jsonStringTrimOneChar(pStr);
+ JsonString *pOgStr = pStr;
+ JsonString tmpStr;
+ jsonAppendRawNZ(pOgStr, "}", 2); /* Ensure it is zero-terminated */
+ jsonStringTrimOneChar(pOgStr); /* Remove the zero terminator */
pStr->pCtx = ctx;
if( pStr->eErr ){
jsonReturnString(pStr, 0, 0);
return;
- }else if( flags & JSON_BLOB ){
+ }
+ if( pStr->zBuf[0]!='{' ){
+ /* The string contains null entries that need to be removed */
+ u64 i, j;
+ int inStr = 0;
+ if( !isFinal ){
+ /* Work with a temporary copy of the string if this is not the
+ ** final result */
+ jsonStringInit(&tmpStr, ctx);
+ jsonAppendRawNZ(&tmpStr, pStr->zBuf, pStr->nUsed+1);
+ pStr = &tmpStr;
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }
+ jsonStringTrimOneChar(pStr); /* Remove zero terminator */
+ }
+ /* Fix up the string by changing the initial "@" flag back to
+ ** to "{" and removing all subsequence "@" entries, with their
+ ** associated comma delimeters. */
+ pStr->zBuf[0] = '{';
+ for(i=j=1; i<pStr->nUsed; i++){
+ char c = pStr->zBuf[i];
+ if( c=='"' ){
+ inStr = !inStr;
+ pStr->zBuf[j++] = '"';
+ }else if( c=='\\' ){
+ pStr->zBuf[j++] = '\\';
+ pStr->zBuf[j++] = pStr->zBuf[++i];
+ }else if( c=='@' && !inStr ){
+ assert( i+1<pStr->nUsed );
+ if( pStr->zBuf[i+1]==',' ){
+ i++;
+ }else if( pStr->zBuf[j-1]==',' ){
+ j--;
+ }
+ }else{
+ pStr->zBuf[j++] = c;
+ }
+ }
+ pStr->zBuf[j] = 0; /* Restore zero terminator */
+ pStr->nUsed = j; /* Truncate the string */
+ }
+ if( flags & JSON_BLOB ){
jsonReturnStringAsBlob(pStr);
if( isFinal ){
if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf);
}else{
- jsonStringTrimOneChar(pStr);
+ jsonStringTrimOneChar(pOgStr);
}
- return;
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
pStr->bStatic ? SQLITE_TRANSIENT :
@@ -217407,8 +217778,9 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- jsonStringTrimOneChar(pStr);
+ jsonStringTrimOneChar(pOgStr);
}
+ if( pStr!=pOgStr ) jsonStringReset(pStr);
}else if( flags & JSON_BLOB ){
static const unsigned char emptyObject = 0x0c;
sqlite3_result_blob(ctx, &emptyObject, 1, SQLITE_STATIC);
@@ -218260,7 +218632,7 @@ struct Rtree {
u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
u8 nBytesPerCell; /* Bytes consumed per cell */
u8 inWrTrans; /* True if inside write transaction */
- u8 nAux; /* # of auxiliary columns in %_rowid */
+ u16 nAux; /* # of auxiliary columns in %_rowid */
#ifdef SQLITE_ENABLE_GEOPOLY
u8 nAuxNotNull; /* Number of initial not-null aux columns */
#endif
@@ -218400,7 +218772,7 @@ struct RtreeCursor {
sqlite3_stmt *pReadAux; /* Statement to read aux-data */
RtreeSearchPoint sPoint; /* Cached next search point */
RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */
- u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */
+ u32 anQueue[RTREE_MAX_DEPTH+2]; /* Number of queued entries by iLevel */
};
/* Return the Rtree of a RtreeCursor */
@@ -218855,6 +219227,9 @@ static int nodeAcquire(
rc = SQLITE_CORRUPT_VTAB;
RTREE_IS_CORRUPT(pRtree);
}
+ }else if( iNode<=0 ){
+ RTREE_IS_CORRUPT(pRtree);
+ rc = SQLITE_CORRUPT_VTAB;
}else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize);
if( !pNode ){
@@ -218880,7 +219255,7 @@ static int nodeAcquire(
*/
if( rc==SQLITE_OK && pNode && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData);
- if( pRtree->iDepth>RTREE_MAX_DEPTH ){
+ if( pRtree->iDepth>=RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB;
RTREE_IS_CORRUPT(pRtree);
}
@@ -219496,7 +219871,7 @@ static int nodeRowidIndex(
){
int ii;
int nCell = NCELL(pNode);
- assert( nCell<200 );
+ assert( nCell<65536 && nCell>=0 );
for(ii=0; ii<nCell; ii++){
if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){
*piIndex = ii;
@@ -219758,7 +220133,10 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc);
if( rc ) return rc;
nCell = NCELL(pNode);
- assert( nCell<200 );
+ if( nCell>RTREE_MAXCELLS ){
+ RTREE_IS_CORRUPT(pRtree);
+ return SQLITE_CORRUPT_VTAB;
+ }
pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
while( p->iCell<nCell ){
sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1;
@@ -221735,7 +222113,7 @@ static int rtreeInit(
"Auxiliary rtree columns must be last" /* 4 */
};
- assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
+ assert( RTREE_MAX_AUX_COLUMN<256 );
if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
return SQLITE_ERROR;
@@ -223654,6 +224032,11 @@ static int geopolyInit(
int ii;
(void)pAux;
+ if( argc>=RTREE_MAX_AUX_COLUMN+4 ){
+ *pzErr = sqlite3_mprintf("Too many columns for a geopoly table");
+ return SQLITE_ERROR;
+ }
+
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
@@ -224788,7 +225171,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
const UChar *zInput; /* Pointer to input string */
UChar *zOutput = 0; /* Pointer to output buffer */
int nInput; /* Size of utf-16 input string in bytes */
- int nOut; /* Size of output buffer in bytes */
+ sqlite3_int64 nOut; /* Size of output buffer in bytes */
int cnt;
int bToUpper; /* True for toupper(), false for tolower() */
UErrorCode status;
@@ -224811,7 +225194,7 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
}
for(cnt=0; cnt<2; cnt++){
- UChar *zNew = sqlite3_realloc(zOutput, nOut);
+ UChar *zNew = sqlite3_realloc64(zOutput, nOut);
if( zNew==0 ){
sqlite3_free(zOutput);
sqlite3_result_error_nomem(p);
@@ -224820,9 +225203,9 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
zOutput = zNew;
status = U_ZERO_ERROR;
if( bToUpper ){
- nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ nOut = 2LL*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}else{
- nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ nOut = 2LL*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
}
if( U_SUCCESS(status) ){
@@ -226435,16 +226818,26 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
-1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
unsigned int v = 0;
int c;
unsigned char *z = (unsigned char*)*pz;
- unsigned char *zStart = z;
- while( (c = zValue[0x7f&*(z++)])>=0 ){
- v = (v<<6) + c;
+ unsigned char *zEnd = z + (*pLen);
+ while( z<zEnd && (c = zValue[*z])>=0 ){
+ v = (v<<6) + c;
+ z++;
}
- z--;
- *pLen -= (int)(z - zStart);
+
+ *pLen -= (int)(z - (unsigned char*)*pz);
*pz = (char*)z;
return v;
}
@@ -226520,7 +226913,7 @@ static int rbuDeltaApply(
#endif
limit = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( *zDelta!='\n' ){
+ if( lenDelta<=0 || *zDelta!='\n' ){
/* ERROR: size integer not terminated by "\n" */
return -1;
}
@@ -226528,11 +226921,12 @@ static int rbuDeltaApply(
while( *zDelta && lenDelta>0 ){
unsigned int cnt, ofst;
cnt = rbuDeltaGetInt(&zDelta, &lenDelta);
+ if( lenDelta<=0 ) return -1;
switch( zDelta[0] ){
case '@': {
zDelta++; lenDelta--;
ofst = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( lenDelta>0 && zDelta[0]!=',' ){
+ if( lenDelta>0 || zDelta[0]!=',' ){
/* ERROR: copy command not terminated by ',' */
return -1;
}
@@ -226557,7 +226951,7 @@ static int rbuDeltaApply(
/* ERROR: insert command gives an output larger than predicted */
return -1;
}
- if( (int)cnt>lenDelta ){
+ if( (i64)cnt>(i64)lenDelta ){
/* ERROR: insert count exceeds size of delta */
return -1;
}
@@ -226595,7 +226989,7 @@ static int rbuDeltaApply(
static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){
int size;
size = rbuDeltaGetInt(&zDelta, &lenDelta);
- if( *zDelta!='\n' ){
+ if( lenDelta<=0 || *zDelta!='\n' ){
/* ERROR: size integer not terminated by "\n" */
return -1;
}
@@ -226643,7 +227037,7 @@ static void rbuFossilDeltaFunc(
return;
}
- aOut = sqlite3_malloc(nOut+1);
+ aOut = sqlite3_malloc64((i64)nOut+1);
if( aOut==0 ){
sqlite3_result_error_nomem(context);
}else{
@@ -232537,12 +232931,13 @@ static int dbpageFilter(
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
if( idxNum & 1 ){
+ i64 iPg = sqlite3_value_int64(argv[idxNum>>1]);
assert( argc>(idxNum>>1) );
- pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
- if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
+ if( iPg<1 || iPg>pCsr->mxPgno ){
pCsr->pgno = 1;
pCsr->mxPgno = 0;
}else{
+ pCsr->pgno = (Pgno)iPg;
pCsr->mxPgno = pCsr->pgno;
}
}else{
@@ -234821,7 +235216,7 @@ static void sessionAppendStr(
int *pRc
){
int nStr = sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
+ if( 0==sessionBufferGrow(p, (i64)nStr+1, pRc) ){
memcpy(&p->aBuf[p->nBuf], zStr, nStr);
p->nBuf += nStr;
p->aBuf[p->nBuf] = 0x00;
@@ -234890,6 +235285,16 @@ static int sessionPrepareDfltStmt(
}
/*
+** Finalize statement pStmt. If (*pRc) is SQLITE_OK when this function is
+** called, set it to the results of the sqlite3_finalize() call. Or, if
+** it is already set to an error code, leave it as is.
+*/
+static void sessionFinalizeStmt(sqlite3_stmt *pStmt, int *pRc){
+ int rc = sqlite3_finalize(pStmt);
+ if( *pRc==SQLITE_OK ) *pRc = rc;
+}
+
+/*
** Table pTab has one or more existing change-records with old.* records
** with fewer than pTab->nCol columns. This function updates all such
** change-records with the default values for the missing columns.
@@ -234911,9 +235316,8 @@ static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){
}
}
+ sessionFinalizeStmt(pStmt, &rc);
pSession->rc = rc;
- rc = sqlite3_finalize(pStmt);
- if( pSession->rc==SQLITE_OK ) pSession->rc = rc;
return pSession->rc;
}
@@ -235481,7 +235885,7 @@ static int sessionDiffFindNew(
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
- rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
@@ -235544,7 +235948,7 @@ static int sessionDiffFindModified(
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
- rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v2(pSession->db, zStmt, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
@@ -236239,11 +236643,11 @@ static int sessionSelectStmt(
);
sessionAppendStr(&cols, "tbl, ?2, stat", &rc);
}else{
- #if 0
+#if 0
if( bRowid ){
sessionAppendStr(&cols, SESSIONS_ROWID, &rc);
}
- #endif
+#endif
for(i=0; i<nCol; i++){
if( cols.nBuf ) sessionAppendStr(&cols, ", ", &rc);
sessionAppendIdent(&cols, azCol[i], &rc);
@@ -237497,7 +237901,13 @@ static int sessionChangesetInvert(
/* Test for EOF. */
if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
- if( pInput->iNext>=pInput->nData ) break;
+ if( pInput->iNext+1>=pInput->nData ){
+ if( pInput->iNext!=pInput->nData ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto finished_invert;
+ }
+ break;
+ }
eType = pInput->aData[pInput->iNext];
switch( eType ){
@@ -237693,6 +238103,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 */
+ u8 bNoUpdateLoop; /* No update-loop processing */
int bRowid;
char *zErr; /* Error message, if any */
};
@@ -238266,7 +238677,7 @@ static int sessionConflictHandler(
u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
int nBlob = pIter->in.iNext - pIter->in.iCurrent;
sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
- return SQLITE_OK;
+ return rc;
}else if( p->bIgnoreNoop==0 || op!=SQLITE_DELETE
|| eType==SQLITE_CHANGESET_CONFLICT
){
@@ -238388,7 +238799,7 @@ static int sessionApplyOneOp(
for(i=0; rc==SQLITE_OK && i<nCol; i++){
sqlite3_value *pOld = sessionChangesetOld(pIter, i);
sqlite3_value *pNew = sessionChangesetNew(pIter, i);
- if( p->abPK[i] || (bPatchset==0 && pOld) ){
+ if( pOld && (p->abPK[i] || bPatchset==0) ){
rc = sessionBindValue(pUp, i*2+2, pOld);
}
if( rc==SQLITE_OK && pNew ){
@@ -238514,7 +238925,264 @@ static int sessionApplyOneWithRetry(
}
/*
-** Retry the changes accumulated in the pApply->constraints buffer.
+** Create an iterator to iterate through the retry buffer pRetry.
+*/
+static int sessionRetryIterInit(
+ SessionBuffer *pRetry, /* Buffer to iterate through */
+ int bPatchset, /* True for patchset, false for changeset */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *pApply, /* Session apply context */
+ sqlite3_changeset_iter **ppIter /* OUT: New iterator */
+){
+ sqlite3_changeset_iter *pRet = 0;
+ int rc = SQLITE_OK;
+
+ rc = sessionChangesetStart(
+ &pRet, 0, 0, pRetry->nBuf, pRetry->aBuf, pApply->bInvertConstraints, 1
+ );
+ if( rc==SQLITE_OK ){
+ size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
+ pRet->bPatchset = bPatchset;
+ pRet->zTab = (char*)zTab;
+ pRet->nCol = pApply->nCol;
+ pRet->abPK = pApply->abPK;
+ sessionBufferGrow(&pRet->tblhdr, nByte, &rc);
+ pRet->apValue = (sqlite3_value**)pRet->tblhdr.aBuf;
+ if( rc==SQLITE_OK ){
+ memset(pRet->apValue, 0, nByte);
+ }else{
+ sqlite3changeset_finalize(pRet);
+ pRet = 0;
+ }
+ }
+
+ *ppIter = pRet;
+ return rc;
+}
+
+/*
+** Attempt to apply all the changes in retry buffer pRetry to the database.
+** Except, if parameter iSkip is greater than or equal to 0, skip change
+** iSkip.
+*/
+static int sessionApplyRetryBuffer(
+ SessionBuffer *pRetry, /* Buffer to apply changes from */
+ int iSkip, /* If >=0, index of change to omit */
+ sqlite3 *db, /* Database handle */
+ int bPatchset, /* True for patchset, false for changeset */
+ const char *zTab, /* Name of table to write to */
+ SessionApplyCtx *pApply, /* Apply context */
+ int(*xConflict)(void*, int, sqlite3_changeset_iter*),
+ void *pCtx /* First argument passed to xConflict */
+){
+ int rc = SQLITE_OK;
+ int rc2 = SQLITE_OK;
+ int ii = 0;
+ sqlite3_changeset_iter *pIter = 0;
+
+ assert( pApply->constraints.nBuf==0 );
+
+ rc = sessionRetryIterInit(pRetry, bPatchset, zTab, pApply, &pIter);
+
+ for(ii=0; rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter); ii++){
+ if( ii!=iSkip ){
+ rc = sessionApplyOneWithRetry(db, pIter, pApply, xConflict, pCtx);
+ }
+ }
+
+ rc2 = sqlite3changeset_finalize(pIter);
+ if( rc==SQLITE_OK ) rc = rc2;
+ assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
+
+ return rc;
+}
+
+/*
+** Check if table zTab in the "main" database of db is a WITHOUT ROWID
+** table.
+**
+** If no error occurs, return SQLITE_OK and set output variable (*pbWR) to
+** true if zTab is a WITHOUT ROWID table, or false otherwise. Or, if an
+** error does occur, return an SQLite error code. The final value of (*pbWR)
+** is undefined in this case.
+*/
+static int sessionTableIsWithoutRowid(sqlite3 *db, const char *zTab, int *pbWR){
+ sqlite3_stmt *pList = 0;
+ char *zSql = 0;
+ int rc = SQLITE_OK;
+
+ zSql = sqlite3_mprintf("PRAGMA table_list = %Q", zTab);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pList, 0);
+ sqlite3_free(zSql);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pList);
+ *pbWR = sqlite3_column_int(pList, 4);
+ rc = sqlite3_finalize(pList);
+ }
+
+ return rc;
+}
+
+/*
+** Iterator pUp points to an UPDATE change. This function deletes the
+** affected row from the database and creates an INSERT statement that
+** may be used to reinsert the row as it is after the UPDATE change
+** has been applied.
+**
+** If successful, SQLITE_OK is returned and output variable (*ppInsert)
+** is left pointing to a prepared INSERT statement. It is the responsibility
+** of the caller to eventually free this statement using sqlite3_finalize().
+** Or, if an error occurs, an SQLite error code is returned and (*ppInsert)
+** set to NULL. pApply->zErr may be set to an error message in this case.
+*/
+static int sessionUpdateToDeleteInsert(
+ sqlite3 *db, /* Database to write to */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *pApply, /* Apply context */
+ sqlite3_changeset_iter *pUp, /* Iterator pointing to UPDATE change */
+ sqlite3_stmt **ppInsert /* OUT: INSERT statement */
+){
+ sqlite3_stmt *pRet = 0; /* The INSERT statement */
+ sqlite3_stmt *pSelect = 0; /* SELECT to read current values of row */
+ int rc = SQLITE_OK;
+ int bWR = 0;
+
+ rc = sessionTableIsWithoutRowid(db, zTab, &bWR);
+ if( rc==SQLITE_OK ){
+ char *zSelect = 0;
+ char *zInsert = 0;
+ SessionBuffer cols = {0, 0, 0};
+ SessionBuffer insbind = {0, 0, 0};
+ SessionBuffer pkcols = {0, 0, 0};
+ SessionBuffer selbind = {0, 0, 0};
+
+ const char *zComma = "";
+ const char *zComma2 = "";
+ int ii;
+ for(ii=0; ii<pApply->nCol; ii++){
+ sessionAppendStr(&cols, zComma, &rc);
+ sessionAppendIdent(&cols, pApply->azCol[ii], &rc);
+ sessionAppendStr(&insbind, zComma, &rc);
+ sessionAppendStr(&insbind, "?", &rc);
+ zComma = ", ";
+
+ if( pApply->abPK[ii] ){
+ sessionAppendStr(&pkcols, zComma2, &rc);
+ sessionAppendIdent(&pkcols, pApply->azCol[ii], &rc);
+ sessionAppendStr(&selbind, zComma2, &rc);
+ sessionAppendPrintf(&selbind, &rc, "?%d", ii+1);
+ zComma2 = ", ";
+ }
+ }
+ if( bWR==0 ){
+ sessionAppendStr(&cols, zComma, &rc);
+ sessionAppendStr(&cols, SESSIONS_ROWID, &rc);
+ sessionAppendStr(&insbind, zComma, &rc);
+ sessionAppendStr(&insbind, "?", &rc);
+ }
+
+ if( rc==SQLITE_OK ){
+ zSelect = sqlite3_mprintf("SELECT %s FROM %Q WHERE (%s) IS (%s)",
+ cols.aBuf, zTab, pkcols.aBuf, selbind.aBuf
+ );
+ if( zSelect==0 ) rc = SQLITE_NOMEM;
+ }
+ if( rc==SQLITE_OK ){
+ zInsert = sqlite3_mprintf("INSERT INTO %Q(%s) VALUES(%s)",
+ zTab, cols.aBuf, insbind.aBuf
+ );
+ if( zInsert==0 ) rc = SQLITE_NOMEM;
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sessionPrepare(db, &pSelect, &pApply->zErr, zSelect);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sessionPrepare(db, &pRet, &pApply->zErr, zInsert);
+ }
+
+ sqlite3_free(zSelect);
+ sqlite3_free(zInsert);
+ sqlite3_free(cols.aBuf);
+ sqlite3_free(insbind.aBuf);
+ sqlite3_free(pkcols.aBuf);
+ sqlite3_free(selbind.aBuf);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sessionBindRow(
+ pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pSelect
+ );
+ }
+
+ if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){
+ int iCol;
+ for(iCol=0; iCol<pApply->nCol; iCol++){
+ sqlite3_value *pVal = pUp->apValue[iCol+pApply->nCol];
+ if( pVal==0 ){
+ pVal = sqlite3_column_value(pSelect, iCol);
+ }
+ rc = sqlite3_bind_value(pRet, iCol+1, pVal);
+ }
+ if( bWR==0 ){
+ sqlite3_bind_int64(pRet, iCol+1, sqlite3_column_int64(pSelect, iCol));
+ }
+ }
+ sessionFinalizeStmt(pSelect, &rc);
+
+ /* Delete the row from the database. */
+ if( rc==SQLITE_OK ){
+ rc = sessionBindRow(
+ pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pApply->pDelete
+ );
+ sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pApply->pDelete);
+ rc = sqlite3_reset(pApply->pDelete);
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_finalize(pRet);
+ pRet = 0;
+ }
+
+ *ppInsert = pRet;
+ return rc;
+}
+
+/*
+** Retry the changes accumulated in the pApply->constraints buffer. The
+** pApply->constraints buffer contains all changes to table zTab that
+** could not be applied due to SQLITE_CONSTRAINT errors. This function
+** attempts to apply them as follows:
+**
+** 1) It runs through the buffer and attempts to retry each change,
+** removing any that are successfully applied from the buffer. This
+** is repeated until no further progress can be made.
+**
+** 2) For each UPDATE change in the buffer, try the following in a
+** savepoint transaction:
+**
+** a) DELETE the affected row,
+** b) Attempt step (1) with remaining changes,
+** c) Attempt to INSERT a row equivalent to the one that would be
+** created by applying this UPDATE change.
+**
+** If the INSERT in (c) succeeds, the savepoint is committed and all
+** successfully applied changes are removed from the buffer. Step (2)
+** is then repeated.
+**
+** 3) Once step (2) has been attempted for each UPDATE in the change,
+** a final attempt is made to apply each remaining change. This time,
+** if an SQLITE_CONSTRAINT error is encountered, the conflict handler
+** is invoked and the user has to decide whether to omit the change
+** or rollback the entire _apply() operation.
*/
static int sessionRetryConstraints(
sqlite3 *db,
@@ -238525,41 +239193,101 @@ static int sessionRetryConstraints(
void *pCtx /* First argument passed to xConflict */
){
int rc = SQLITE_OK;
+ int iUpdate = 0;
+ /* Step (1) */
while( pApply->constraints.nBuf ){
- sqlite3_changeset_iter *pIter2 = 0;
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
- rc = sessionChangesetStart(
- &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1
+ rc = sessionApplyRetryBuffer(
+ &cons, -1, db, bPatchset, zTab, pApply, xConflict, pCtx
+ );
+
+ sqlite3_free(cons.aBuf);
+ if( rc!=SQLITE_OK ) break;
+
+ /* If no progress has been made this round, break out of the loop. */
+ if( pApply->constraints.nBuf>=cons.nBuf ) break;
+ }
+
+ /* Step (2) */
+ while( rc==SQLITE_OK && pApply->constraints.nBuf && !pApply->bNoUpdateLoop ){
+ SessionBuffer cons = {0, 0, 0};
+ sqlite3_changeset_iter *pUp = 0;
+ sqlite3_stmt *pInsert = 0;
+ int iSkip = 0;
+
+ rc = sessionRetryIterInit(
+ &pApply->constraints, bPatchset, zTab, pApply, &pUp
);
if( rc==SQLITE_OK ){
- size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
- int rc2;
- pIter2->bPatchset = bPatchset;
- pIter2->zTab = (char*)zTab;
- pIter2->nCol = pApply->nCol;
- pIter2->abPK = pApply->abPK;
- sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
- pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
- if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
+ int iThis = -1;
+ while( SQLITE_ROW==sqlite3changeset_next(pUp) ){
+ if( pUp->op==SQLITE_UPDATE ) iThis++;
+ if( iThis==iUpdate ) break;
+ iSkip++;
+ }
+ if( iThis==iUpdate ){
+ rc = sqlite3_exec(db, "SAVEPOINT update_op", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sessionUpdateToDeleteInsert(db, zTab, pApply, pUp, &pInsert);
+ }
+ }
+ sqlite3changeset_finalize(pUp);
+ if( iThis!=iUpdate ) break;
+ }
+
+ if( rc==SQLITE_OK ){
+ cons = pApply->constraints;
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
- rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
+ while( rc==SQLITE_OK && pApply->constraints.nBuf>0 ){
+ SessionBuffer app = pApply->constraints;
+ memset(&pApply->constraints, 0, sizeof(SessionBuffer));
+ rc = sessionApplyRetryBuffer(
+ &app, iSkip, db, bPatchset, zTab, pApply, xConflict, pCtx
+ );
+ if( app.aBuf!=cons.aBuf ){
+ sqlite3_free(app.aBuf);
+ }
+ if( pApply->constraints.nBuf>=app.nBuf ){
+ break;
+ }
+ iSkip = -1;
}
+ }
- rc2 = sqlite3changeset_finalize(pIter2);
- if( rc==SQLITE_OK ) rc = rc2;
+ iUpdate++;
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pInsert);
+ rc = sqlite3_finalize(pInsert);
+ if( rc==SQLITE_CONSTRAINT ){
+ rc = sqlite3_exec(db, "ROLLBACK TO update_op", 0, 0, 0);
+ sqlite3_free(pApply->constraints.aBuf);
+ pApply->constraints = cons;
+ memset(&cons, 0, sizeof(cons));
+ }else if( rc==SQLITE_OK ){
+ iUpdate = 0;
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "RELEASE update_op", 0, 0, 0);
+ }
+ }else{
+ sqlite3_finalize(pInsert);
}
- assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
sqlite3_free(cons.aBuf);
- if( rc!=SQLITE_OK ) break;
- if( pApply->constraints.nBuf>=cons.nBuf ){
- /* No progress was made on the last round. */
- pApply->bDeferConstraints = 0;
- }
+ }
+
+ /* Step (3) */
+ if( rc==SQLITE_OK && pApply->constraints.nBuf ){
+ SessionBuffer cons = pApply->constraints;
+ memset(&pApply->constraints, 0, sizeof(SessionBuffer));
+ pApply->bDeferConstraints = 0;
+ rc = sessionApplyRetryBuffer(
+ &cons, -1, db, bPatchset, zTab, pApply, xConflict, pCtx
+ );
+ sqlite3_free(cons.aBuf);
}
return rc;
@@ -238613,6 +239341,7 @@ static int sessionChangesetApply(
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
+ sApply.bNoUpdateLoop = !!(flags & SQLITE_CHANGESETAPPLY_NOUPDATELOOP);
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
}
@@ -239885,14 +240614,17 @@ static void sessionAppendRecordMerge(
u8 *a2, int n2, /* Record 2 */
int *pRc /* IN/OUT: error code */
){
- sessionBufferGrow(pBuf, n1+n2, pRc);
+ u8 *a1Eof = &a1[n1];
+ u8 *a2Eof = &a2[n2];
+
+ sessionBufferGrow(pBuf, (i64)n1+n2, pRc);
if( *pRc==SQLITE_OK ){
int i;
u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
for(i=0; i<nCol; i++){
- int nn1 = sessionSerialLen(a1);
- int nn2 = sessionSerialLen(a2);
- if( *a1==0 || *a1==0xFF ){
+ int nn1 = (a1<a1Eof ? sessionSerialLen(a1) : 0);
+ int nn2 = (a2<a2Eof ? sessionSerialLen(a2) : 0);
+ if( nn1==0 || (nn2>0 && (*a1==0 || *a1==0xFF)) ){
memcpy(pOut, a2, nn2);
pOut += nn2;
}else{
@@ -239934,7 +240666,7 @@ static void sessionAppendPartialUpdate(
u8 *aChange, int nChange, /* Record to rebase against */
int *pRc /* IN/OUT: Return Code */
){
- sessionBufferGrow(pBuf, 2+nRec+nChange, pRc);
+ sessionBufferGrow(pBuf, (i64)2+nRec+nChange, pRc);
if( *pRc==SQLITE_OK ){
int bData = 0;
u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
@@ -240424,7 +241156,7 @@ SQLITE_API int sqlite3changegroup_change_blob(
const void *pVal,
int nVal
){
- sqlite3_int64 nByte = 1 + sessionVarintLen(nVal) + nVal;
+ sqlite3_int64 nByte = 1 + sessionVarintLen(nVal) + (i64)nVal;
int rc = SQLITE_OK;
SessionBuffer *pBuf = 0;
@@ -244274,7 +245006,7 @@ static void fts5SnippetFunction(
int rc = SQLITE_OK; /* Return code */
int iCol; /* 1st argument to snippet() */
const char *zEllips; /* 4th argument to snippet() */
- int nToken; /* 5th argument to snippet() */
+ i64 nToken; /* 5th argument to snippet() */
int nInst = 0; /* Number of instance matches this row */
int i; /* Used to iterate through instances */
int nPhrase; /* Number of phrases in query */
@@ -244299,7 +245031,7 @@ static void fts5SnippetFunction(
ctx.zClose = fts5ValueToText(apVal[2]);
ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
- nToken = sqlite3_value_int(apVal[4]);
+ nToken = (int)(MIN( MAX(sqlite3_value_int64(apVal[4]), 0), 64));
iBestCol = (iCol>=0 ? iCol : 0);
nPhrase = pApi->xPhraseCount(pFts);
@@ -247015,7 +247747,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
i64 iPos = a[i].reader.iPos;
Fts5PoslistWriter *pWriter = &a[i].writer;
if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){
- sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos);
+ sqlite3Fts5PoslistSafeAppend(a[i].pOut, &pWriter->iPrev, iPos);
}
}
@@ -247966,10 +248698,10 @@ static int fts5ParseTokenize(
memset(pSyn, 0, (size_t)nByte);
pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
+ memcpy(pSyn->pTerm, pToken, nToken);
if( pCtx->pConfig->bTokendata ){
pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
}
- memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
@@ -251008,7 +251740,7 @@ static void fts5DataRelease(Fts5Data *pData){
static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
Fts5Data *pRet = fts5DataRead(p, iRowid);
if( pRet ){
- if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){
+ if( pRet->szLeaf<4 || pRet->szLeaf>pRet->nn ){
FTS5_CORRUPT_ROWID(p, iRowid);
fts5DataRelease(pRet);
pRet = 0;
@@ -251252,7 +251984,7 @@ static int fts5StructureDecode(
i += fts5GetVarint32(&pData[i], nTotal);
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
- nTotal * sizeof(Fts5StructureSegment)
+ (i64)nTotal * sizeof(Fts5StructureSegment)
);
nSegment -= nTotal;
}
@@ -252208,7 +252940,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){
Fts5Data *pNew;
pIter->iLeafPgno--;
- pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID(
+ pNew = fts5LeafRead(p, FTS5_SEGMENT_ROWID(
pIter->pSeg->iSegid, pIter->iLeafPgno
));
if( pNew ){
@@ -252662,6 +253394,10 @@ static void fts5LeafSeek(
if( nKeep<nMatch ){
goto search_failed;
}
+ if( (iOff+nNew)>n ){
+ FTS5_CORRUPT_ITER(p, pIter);
+ return;
+ }
assert( nKeep>=nMatch );
if( nKeep==nMatch ){
@@ -253638,8 +254374,7 @@ static void fts5PoslistFilterCallback(
do {
while( i<nChunk && pChunk[i]!=0x01 ){
- while( pChunk[i] & 0x80 ) i++;
- i++;
+ fts5IndexSkipVarint(pChunk, i);
}
if( pCtx->eState ){
fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
@@ -253788,7 +254523,7 @@ static void fts5IndexExtractColset(
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( p<pEnd && *p!=0x01 ){
- while( *p++ & 0x80 );
+ while( p<pEnd && (*p++ & 0x80) );
}
if( pColset->aiCol[i]==iCurrent ){
@@ -253885,8 +254620,11 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
assert( pIter->pColset );
+ assert( pIter->poslist.nSpace>=pIter->pIndex->pConfig->nCol );
- if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf ){
+ if( pSeg->iLeafOffset+pSeg->nPos>pSeg->pLeaf->szLeaf
+ || pSeg->nPos>pIter->pIndex->pConfig->nCol
+ ){
fts5IterSetOutputs_Col(pIter, pSeg);
}else{
u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
@@ -255380,6 +256118,11 @@ static void fts5DoSecureDelete(
}else{
iStart = fts5GetU16(&aPg[0]);
}
+ if( iStart>nPg ){
+ FTS5_CORRUPT_IDX(p);
+ sqlite3_free(aIdx);
+ return;
+ }
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
assert_nc( iSOP<=pSeg->iLeafOffset );
@@ -258065,8 +258808,8 @@ static void fts5IndexTombstoneRebuild(
){
const int MINSLOT = 32;
int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
- int nSlot = 0; /* Number of slots in each output page */
- int nOut = 0;
+ i64 nSlot = 0; /* Number of slots in each output page */
+ i64 nOut = 0;
/* Figure out how many output pages (nOut) and how many slots per
** page (nSlot). There are three possibilities:
@@ -258091,23 +258834,26 @@ static void fts5IndexTombstoneRebuild(
nSlot = MINSLOT;
}else if( pSeg->nPgTombstone==1 ){
/* Case 2. */
- int nElem = (int)fts5GetU32(&pData1->p[4]);
+ u32 nElem = fts5GetU32(&pData1->p[4]);
assert( pData1 && iPg1==0 );
- nOut = 1;
- nSlot = MAX(nElem*4, MINSLOT);
- if( nSlot>nSlotPerPage ) nOut = 0;
+ if( nElem>((u32)nSlotPerPage/4) ){
+ nOut = 0;
+ }else{
+ nOut = 1;
+ nSlot = MAX((i64)nElem*4, MINSLOT);
+ }
}
if( nOut==0 ){
/* Case 3. */
- nOut = (pSeg->nPgTombstone * 2 + 1);
+ nOut = ((i64)pSeg->nPgTombstone * 2 + 1);
nSlot = nSlotPerPage;
}
/* Allocate the required array and output pages */
while( 1 ){
int res = 0;
- int ii = 0;
- int szPage = 0;
+ i64 ii = 0;
+ i64 szPage = 0;
Fts5Data **apOut = 0;
/* Allocate space for the new hash table */
@@ -258612,9 +259358,13 @@ static void fts5IndexIntegrityCheckSegment(
FTS5_CORRUPT_ROWID(p, iRow);
}else{
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
- res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
- if( res==0 ) res = nTerm - nIdxTerm;
- if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow);
+ if( iOff+nTerm>pLeaf->szLeaf ){
+ FTS5_CORRUPT_ROWID(p, iRow);
+ }else{
+ res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
+ if( res==0 ) res = nTerm - nIdxTerm;
+ if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow);
+ }
}
fts5IntegrityCheckPgidx(p, iRow, pLeaf);
@@ -258645,7 +259395,7 @@ static void fts5IndexIntegrityCheckSegment(
/* Check any rowid-less pages that occur before the current leaf. */
for(iPg=iPrevLeaf+1; iPg<fts5DlidxIterPgno(pDlidx); iPg++){
iKey = FTS5_SEGMENT_ROWID(iSegid, iPg);
- pLeaf = fts5DataRead(p, iKey);
+ pLeaf = fts5LeafRead(p, iKey);
if( pLeaf ){
if( fts5LeafFirstRowidOff(pLeaf)!=0 ) FTS5_CORRUPT_ROWID(p, iKey);
fts5DataRelease(pLeaf);
@@ -258656,7 +259406,7 @@ static void fts5IndexIntegrityCheckSegment(
/* Check that the leaf page indicated by the iterator really does
** contain the rowid suggested by the same. */
iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf);
- pLeaf = fts5DataRead(p, iKey);
+ pLeaf = fts5LeafRead(p, iKey);
if( pLeaf ){
i64 iRowid;
int iRowidOff = fts5LeafFirstRowidOff(pLeaf);
@@ -263256,7 +264006,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2026-05-05 10:34:17 c88b22011a54b4f6fbd149e9f8e4de77658ce58143a1af0e3785e4e6475127e9", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62", -1, SQLITE_TRANSIENT);
}
/*
@@ -263898,34 +264648,31 @@ static int sqlite3Fts5StorageOpen(
if( pConfig->eContent==FTS5_CONTENT_NORMAL
|| pConfig->eContent==FTS5_CONTENT_UNINDEXED
){
- int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
- if( zDefn==0 ){
- rc = SQLITE_NOMEM;
- }else{
- int i;
- int iOff;
- sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
- iOff = (int)strlen(zDefn);
- for(i=0; i<pConfig->nCol; i++){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL
- || pConfig->abUnindexed[i]
- ){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
- }
+ int i = 0;
+ char *zDefn = 0;
+ sqlite3_str *pDefn = sqlite3_str_new(pConfig->db);
+
+ sqlite3_str_appendf(pDefn, "id INTEGER PRIMARY KEY");
+ for(i=0; i<pConfig->nCol; i++){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->abUnindexed[i] ){
+ sqlite3_str_appendf(pDefn, ", c%d", i);
}
- if( pConfig->bLocale ){
- for(i=0; i<pConfig->nCol; i++){
- if( pConfig->abUnindexed[i]==0 ){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
- }
+ }
+ if( pConfig->bLocale ){
+ for(i=0; i<pConfig->nCol; i++){
+ if( pConfig->abUnindexed[i]==0 ){
+ sqlite3_str_appendf(pDefn, ", l%d", i);
}
}
+ }
+ zDefn = sqlite3_str_finish(pDefn);
+
+ if( zDefn ){
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
+ sqlite3_free(zDefn);
+ }else{
+ rc = SQLITE_NOMEM;
}
- sqlite3_free(zDefn);
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
@@ -265650,8 +266397,14 @@ static int fts5PorterCreate(
const char *zBase = "unicode61";
fts5_tokenizer_v2 *pV2 = 0;
- if( nArg>0 ){
- zBase = azArg[0];
+ while( nArg>0 ){
+ if( sqlite3_stricmp(azArg[0],"porter")==0 ){
+ nArg--;
+ azArg++;
+ }else{
+ zBase = azArg[0];
+ break;
+ }
}
pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer));
diff --git a/sqlite3.h b/sqlite3.h
index 8ee26c99d86e..00b22d9b107c 100644
--- a/sqlite3.h
+++ b/sqlite3.h
@@ -146,12 +146,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.53.1"
-#define SQLITE_VERSION_NUMBER 3053001
-#define SQLITE_SOURCE_ID "2026-05-05 10:34:17 c88b22011a54b4f6fbd149e9f8e4de77658ce58143a1af0e3785e4e6475127e9"
+#define SQLITE_VERSION "3.53.3"
+#define SQLITE_VERSION_NUMBER 3053003
+#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62"
#define SQLITE_SCM_BRANCH "branch-3.53"
-#define SQLITE_SCM_TAGS "release version-3.53.1"
-#define SQLITE_SCM_DATETIME "2026-05-05T10:34:17.344Z"
+#define SQLITE_SCM_TAGS "release version-3.53.3"
+#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -4366,7 +4366,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** or in an ORDER BY or GROUP BY clause.</dd>)^
**
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
-** <dd>The maximum depth of the parse tree on any expression.</dd>)^
+** <dd>The maximum depth of the parse tree on any expression and
+** the maximum nesting depth for subqueries and VIEWs</dd>)^
**
** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt>
** <dd>The maximum depth of the LALR(1) parser stack used to analyze
@@ -4397,7 +4398,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <dd>The maximum index number of any [parameter] in an SQL statement.)^
**
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
-** <dd>The maximum depth of recursion for triggers.</dd>)^
+** <dd>The maximum depth of recursion for triggers, and the maximum
+** nesting depth for separate triggers.</dd>)^
**
** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
** <dd>The maximum number of auxiliary worker threads that a single
@@ -12853,11 +12855,23 @@ SQLITE_API int sqlite3changeset_apply_v3(
** database behave as if they were declared with "ON UPDATE NO ACTION ON
** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
** or SET DEFAULT.
+**
+** <dt>SQLITE_CHANGESETAPPLY_NOUPDATELOOP <dd>
+** Sometimes, a changeset contains two or more update statements such that
+** although after applying all updates the database will contain no
+** constraint violations, no single update can be applied before the others.
+** The simplest example of this is a pair of UPDATEs that have "swapped"
+** two column values with a UNIQUE constraint.
+** <p>
+** Usually, sqlite3changeset_apply() and similar functions work hard to try
+** to find a way to apply such a changeset. However, if this flag is set,
+** then all such updates are considered CONSTRAINT conflicts.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
+#define SQLITE_CHANGESETAPPLY_NOUPDATELOOP 0x0010
/*
** CAPI3REF: Constants Passed To The Conflict Handler
diff --git a/sqlite3rc.h b/sqlite3rc.h
index 498fdc5ca84a..44c7f2dfdd6a 100644
--- a/sqlite3rc.h
+++ b/sqlite3rc.h
@@ -1,3 +1,3 @@
#ifndef SQLITE_RESOURCE_VERSION
-#define SQLITE_RESOURCE_VERSION 3,53,1
+#define SQLITE_RESOURCE_VERSION 3,53,3
#endif