+** 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.
+**
+** 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*);
# define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0))
#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.
@@ -17150,7 +17171,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 *);
@@ -20908,6 +20929,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 */
@@ -22449,7 +22471,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*, ...);
@@ -32514,7 +32544,7 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
return 0;
}
- z = sqlite3DbMallocRaw(pAccum->db, n);
+ z = sqlite3_malloc(n);
if( z==0 ){
sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
}
@@ -32972,11 +33002,27 @@ SQLITE_API void sqlite3_str_vappendf(
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10;
if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
- if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){
- width = length = 0;
- break;
+ if( szBufNeeded + pAccum->nChar >= pAccum->nAlloc ){
+ if( pAccum->mxAlloc==0 && pAccum->accError==0 ){
+ /* Unable to allocate space in pAccum, perhaps because it
+ ** is coming from sqlite3_snprintf() or similar. We'll have
+ ** to render into temporary space and the memcpy() it over. */
+ bufpt = sqlite3_malloc(szBufNeeded);
+ if( bufpt==0 ){
+ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
+ return;
+ }
+ zExtra = bufpt;
+ }else if( sqlite3StrAccumEnlarge(pAccum, szBufNeeded)zText + pAccum->nChar;
+ }
+ }else{
+ bufpt = pAccum->zText + pAccum->nChar;
}
- bufpt = zOut = pAccum->zText + pAccum->nChar;
+ zOut = bufpt;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
@@ -33077,14 +33123,22 @@ SQLITE_API void sqlite3_str_vappendf(
}
length = width;
}
- pAccum->nChar += length;
- zOut[length] = 0;
- /* Floating point conversions render directly into the output
- ** buffer. Hence, don't just break out of the switch(). Bypass the
- ** output buffer writing that occurs after the switch() by continuing
- ** to the next character in the format string. */
- continue;
+ if( zExtra==0 ){
+ /* The result is being rendered directory into pAccum. This
+ ** is the command and fast case */
+ pAccum->nChar += length;
+ zOut[length] = 0;
+ continue;
+ }else{
+ /* We were unable to render directly into pAccum because we
+ ** couldn't allocate sufficient memory. We need to memcpy()
+ ** the rendering (or some prefix thereof) into the output
+ ** buffer. */
+ bufpt[0] = 0;
+ bufpt = zExtra;
+ break;
+ }
}
case etSIZE:
if( !bArgList ){
@@ -33131,7 +33185,7 @@ SQLITE_API void sqlite3_str_vappendf(
if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){
break;
}
- sqlite3_str_append(pAccum,
+ sqlite3_str_append(pAccum,
&pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
precision -= nPrior;
nPrior *= 2;
@@ -33234,8 +33288,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; k32)))
+#define SQLITE_USE_UINT128
+#endif
+
/*
** Two inputs are multiplied to get a 128-bit result. Write the
** lower 64-bits of the result into *pLo, and return the high-order
** 64 bits.
*/
static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
-#if (defined(__GNUC__) || defined(__clang__)) \
- && (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
- && !defined(SQLITE_DISABLE_INTRINSIC)
+#if defined(SQLITE_USE_UINT128)
__uint128_t r = (__uint128_t)a * b;
*pLo = (u64)r;
return (u64)(r>>64);
@@ -36835,9 +36894,7 @@ static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){
** The lower 64 bits of A*B are discarded.
*/
static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
-#if (defined(__GNUC__) || defined(__clang__)) \
- && (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \
- && !defined(SQLITE_DISABLE_INTRINSIC)
+#if defined(SQLITE_USE_UINT128)
__uint128_t r = (__uint128_t)a * b;
r += ((__uint128_t)aLo * b) >> 32;
*pLo = (r>>32)&0xffffffff;
@@ -36875,6 +36932,8 @@ static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){
#endif
}
+#undef SQLITE_USE_UINT128
+
/*
** Return a u64 with the N-th bit set.
*/
@@ -39527,16 +39586,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 */
@@ -39572,7 +39632,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);
@@ -39618,9 +39678,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;
}
@@ -39650,6 +39708,7 @@ static int kvvfsReadJrnl(
aTxt, szTxt+1);
if( rc>=0 ){
kvvfsDecodeJournal(pFile, aTxt, szTxt);
+ rc = 0;
}
sqlite3_free(aTxt);
if( rc ) return rc;
@@ -45279,9 +45338,9 @@ static int unixShmMap(
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
if( pShmNode->nRegionszRegion = szRegion;
@@ -45312,7 +45371,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 );
@@ -45338,8 +45397,8 @@ static int unixShmMap(
}
pShmNode->apRegion = apNew;
while( pShmNode->nRegionhShm>=0 ){
pMem = osMmap(0, nMap,
@@ -49713,10 +49772,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 },
@@ -52971,11 +53028,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;
}
@@ -53313,7 +53388,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;
@@ -53344,7 +53419,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;
@@ -53366,15 +53441,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,
@@ -53396,7 +53470,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];
@@ -55992,7 +56066,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;
@@ -56002,12 +56076,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 );
@@ -56018,19 +56093,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);
@@ -56064,6 +56137,9 @@ SQLITE_API unsigned char *sqlite3_serialize(
}
}
sqlite3_finalize(pStmt);
+
+ serialize_out:
+ sqlite3_mutex_leave(db->mutex);
return pOut;
}
@@ -56109,10 +56185,10 @@ SQLITE_API int sqlite3_deserialize(
if( rc ) goto end_deserialize;
db->init.iDb = (u8)iDb;
db->init.reopenMemdb = 1;
- rc = sqlite3_step(pStmt);
+ sqlite3_step(pStmt);
db->init.reopenMemdb = 0;
- if( rc!=SQLITE_DONE ){
- rc = SQLITE_ERROR;
+ rc = sqlite3_finalize(pStmt);
+ if( rc!=SQLITE_OK ){
goto end_deserialize;
}
p = memdbFromDbSchema(db, zSchema);
@@ -56133,7 +56209,6 @@ SQLITE_API int sqlite3_deserialize(
}
end_deserialize:
- sqlite3_finalize(pStmt);
if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){
sqlite3_free(pData);
}
@@ -57918,22 +57993,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;
}
@@ -60831,39 +60908,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))
@@ -60873,27 +60954,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; uzJournal */
+
+ /* 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.
@@ -62123,9 +62252,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;
@@ -62134,7 +62262,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;
@@ -62142,43 +62269,56 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){
zJournal = zSuperJournal;
while( (zJournal-zSuperJournal)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);
@@ -62383,19 +62523,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;
}
@@ -62524,30 +62656,20 @@ static int pager_playback(Pager *pPager, int isHot){
*/
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 );
}
@@ -62560,6 +62682,7 @@ static int pager_playback(Pager *pPager, int isHot){
** 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;
}
@@ -68419,6 +68542,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
@@ -70273,7 +70402,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 ){
@@ -72771,6 +72900,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
};
/*
@@ -75232,8 +75364,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( next0 ){
@@ -78279,7 +78415,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)
){
@@ -78384,6 +78522,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);
@@ -79058,14 +79202,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
@@ -79227,14 +79371,17 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(
/* 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
@@ -84099,6 +84246,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));
}
}
@@ -84118,6 +84266,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));
}
}
@@ -84134,6 +84283,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
@@ -84268,6 +84418,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;
@@ -84685,6 +84838,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 */
@@ -84774,10 +84928,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);
}
/*
@@ -84834,27 +84986,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
@@ -84978,7 +85140,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 */
@@ -84994,7 +85156,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 */
@@ -85008,6 +85171,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.
@@ -85017,34 +85181,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
@@ -85262,7 +85440,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;
@@ -93530,8 +93710,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
@@ -111072,6 +111258,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{
@@ -111240,6 +111427,26 @@ static int exprProbability(Expr *p){
return (int)(r*134217728.0);
}
+/*
+** 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; iia[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().
**
@@ -111484,10 +111691,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( (pDef->funcFlags & SQLITE_SUBTYPE)
|| ExprHasProperty(pExpr, EP_SubtArg)
){
- int ii;
- for(ii=0; iia[ii].pExpr, EP_SubtArg);
- }
+ resolveSetExprSubtypeArg(pList);
}
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
@@ -116808,7 +117012,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);
}
}
@@ -116882,9 +117086,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);
@@ -117305,26 +117518,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.
+**
+** The only expressions that can return a subtype are:
+**
+** 1. A function
+** 2. The no-op "+" operator
+** 3. A CASE...END expression
+** 4. A CAST() expression
+** 5. A "expr COLLATE colseq" expression.
**
-** Only a function call is able to return a subtype. So if the node
-** is not a function call, return WRC_Prune immediately.
+** For any other kind of expression, prune the search.
**
-** A function call is able to return a subtype if it has the
-** SQLITE_RESULT_SUBTYPE property.
+** 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.
**
-** 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.
+** 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;
}
@@ -117334,7 +117558,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;
}
@@ -123123,7 +123347,9 @@ SQLITE_PRIVATE void sqlite3AlterDropConstraint(
if( !pTab ) return;
if( pCons ){
- zArg = sqlite3MPrintf(db, "%.*Q", pCons->n, pCons->z);
+ char *z = sqlite3NameFromToken(db, pCons);
+ zArg = sqlite3MPrintf(db, "%Q", z);
+ sqlite3DbFree(db, z);
}else{
int iCol;
if( alterFindCol(pParse, pTab, pCol, &iCol) ) return;
@@ -123310,19 +123536,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. */
@@ -123343,7 +123581,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. */
@@ -125198,9 +125436,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 ){
@@ -125208,7 +125446,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;
@@ -125505,6 +125743,16 @@ static void attachFunc(
** from sqlite3_deserialize() to close database db->init.iDb and
** reopen it as a MemDB */
Btree *pNewBt = 0;
+
+ pNew = &db->aDb[db->init.iDb];
+ assert( pNew->pBt!=0 );
+ if( sqlite3BtreeTxnState(pNew->pBt)!=SQLITE_TXN_NONE
+ || sqlite3BtreeIsInBackup(pNew->pBt)
+ ){
+ rc = SQLITE_BUSY;
+ goto attach_error;
+ }
+
pVfs = sqlite3_vfs_find("memdb");
if( pVfs==0 ) return;
rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
@@ -125514,8 +125762,7 @@ static void attachFunc(
/* Both the Btree and the new Schema were allocated successfully.
** Close the old db and update the aDb[] slot with the new memdb
** values. */
- pNew = &db->aDb[db->init.iDb];
- if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt);
+ sqlite3BtreeClose(pNew->pBt);
pNew->pBt = pNewBt;
pNew->pSchema = pNewSchema;
}else{
@@ -134011,9 +134258,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);
+ }
}
}
@@ -135651,11 +135907,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);
@@ -136628,47 +136889,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]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]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(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=2 ) percentSort(a, iLt);
- if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
-
-/* Uncomment for testing */
-#if 0
- for(i=0; idb;
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;
@@ -151196,6 +151463,8 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c
sqlite3DeleteTable(db, pTab);
return 0;
}
+ pParse->nNestSel--;
+ assert( pParse->nNestSel>=0 );
return pTab;
}
@@ -156058,6 +156327,7 @@ static SQLITE_NOINLINE void existsToJoin(
&& !ExprHasProperty(pWhere, EP_OuterON|EP_InnerON)
&& ALWAYS(p->pSrc!=0)
&& p->pSrc->nSrcpLimit==0 || p->pLimit->pRight==0)
){
if( pWhere->op==TK_AND ){
Expr *pRight = pWhere->pRight;
@@ -156105,7 +156375,6 @@ static SQLITE_NOINLINE void existsToJoin(
sqlite3TreeViewSelect(0, p, 0);
}
#endif
- existsToJoin(pParse, p, pSubWhere);
}
}
}
@@ -156166,8 +156435,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; iia[ii].iCursor!=iTab; ii++){}
+ if( iiiJoin && iTab>pCtx->iJoin ){
sqlite3ErrorMsg(pWalker->pParse,
"%s references tables to its right",
@@ -159136,7 +159408,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 */
@@ -159145,10 +159417,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. */
@@ -161149,7 +161435,8 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
/* excluded.* columns of type REAL need to be converted to a hard real */
for(i=0; inCol; 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),
@@ -161737,6 +162024,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);
@@ -161747,6 +162035,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;
}
@@ -165947,7 +166236,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
*/
- if( pWInfo->nLevel>1 ){
+ if( pWInfo->nLevel>1 || pTabItem->fg.fromExists ){
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
@@ -165960,6 +166249,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
for(k=1; k<=nNotReady; k++){
memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
}
+
+ /* Clear the fromExists flag on the OR-optimized table entry so that
+ ** the calls to sqlite3WhereEnd() do not code early-exits after the
+ ** first row is visited. The early exit applies to this table's
+ ** overall loop - including the multiple OR branches and any WHERE
+ ** conditions not passed to the sub-loops - not to the sub-loops. */
+ pOrTab->a[0].fg.fromExists = 0;
}else{
pOrTab = pWInfo->pTabList;
}
@@ -166203,7 +166499,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
+ if( pWInfo->pTabList!=pOrTab ){ sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -166360,6 +166656,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)
@@ -167113,7 +167410,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) );
+
}
/*
@@ -167552,8 +167852,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
@@ -167561,10 +167861,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
@@ -167579,10 +167878,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;
@@ -167894,6 +168190,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;
@@ -167914,7 +168211,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];
@@ -168104,8 +168401,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; ipLeft); i++){
int idxNew;
idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE);
@@ -171732,7 +172032,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;
}
@@ -176128,27 +176429,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
}
- if( pTabList->a[pLevel->iFrom].fg.fromExists
- && (i==pWInfo->nLevel-1
- || pTabList->a[pWInfo->a[i+1].iFrom].fg.fromExists==0)
- ){
- /* This is an EXISTS-to-JOIN optimization which is either the
- ** inner-most loop, or the inner-most of a group of nested
- ** EXISTS-to-JOIN optimization loops. If this loop sees a successful
- ** row, it should break out of itself as well as other EXISTS-to-JOIN
- ** loops in which is is directly nested. */
- int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
- while( nOutera[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
- nOuter++;
- }
- testcase( nOuter>0 );
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
- if( nOuter ){
- VdbeComment((v, "EXISTS break %d..%d", i-nOuter, i));
- }else{
- VdbeComment((v, "EXISTS break %d", i));
- }
+ if( pTabList->a[pLevel->iFrom].fg.fromExists ){
+ /* This is an EXISTS-to-JOIN optimization loop. If this loop sees a
+ ** successful row, it should break out of itself. */
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
+ VdbeComment((v, "EXISTS break %d", i));
}
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
if( pLevel->op!=OP_Noop ){
@@ -184222,9 +184507,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; inExpr; i++){
+ assert( pList->a[i].pExpr!=0 );
+ yymsp[-4].minor.yy454->flags |= pList->a[i].pExpr->flags & EP_Propagate;
}
}else{
sqlite3ExprListDelete(pParse->db, pList);
@@ -184335,6 +184622,7 @@ static YYACTIONTYPE yy_reduce(
yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0);
if( yymsp[-4].minor.yy454 ){
yymsp[-4].minor.yy454->x.pList = pList;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454);
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
@@ -184691,15 +184979,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);}
@@ -188188,13 +188474,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;
}
/*
@@ -188216,13 +188506,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);
@@ -188232,13 +188526,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);
@@ -188921,6 +189219,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);
@@ -188931,6 +189230,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;
}
@@ -189836,9 +190136,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;
@@ -189892,25 +190194,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;
}
/*
@@ -190105,6 +190425,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] ){
@@ -190114,6 +190435,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 */
}
@@ -190156,7 +190478,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
const char *zVfs = zDefaultVfs;
char *zFile;
char c;
- int nUri = sqlite3Strlen30(zUri);
+ i64 nUri = strlen(zUri);
assert( *pzErrMsg==0 );
@@ -190166,8 +190488,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
@@ -190201,7 +190523,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;
}
@@ -190276,11 +190598,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;
@@ -190326,7 +190648,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;
}
@@ -191011,13 +191333,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;
}
/*
@@ -192042,17 +192368,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 && NnDb ){
+ zRet = db->aDb[N].zDbSName;
}
+ sqlite3_mutex_leave(db->mutex);
+ return zRet;
}
/*
@@ -193903,6 +194231,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 */
@@ -195619,7 +195953,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 ){
@@ -195664,8 +196002,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;
+ }
}
/*
@@ -198019,6 +198362,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;
@@ -198030,7 +198374,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;
@@ -200148,7 +200492,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;
}
@@ -200838,6 +201182,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;
}
}
@@ -207084,6 +207429,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);
}
}
@@ -208310,7 +208659,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;
@@ -210701,7 +211050,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 );
@@ -213191,7 +213540,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: {
@@ -214505,9 +214854,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 ){
@@ -217290,11 +217640,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; inUsed && ((c = z[i])!=',' || inStr || nNest); i++){
if( c=='"' ){
@@ -217323,6 +217671,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,
@@ -217340,7 +217695,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;
@@ -217348,6 +217703,9 @@ static void jsonObjectStep(
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
jsonAppendSqlValue(pStr, argv[1]);
+ }else{
+ pStr->zBuf[0] = '@';
+ jsonAppendRawNZ(pStr, "@", 1);
}
}
}
@@ -217356,20 +217714,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; inUsed; 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+1nUsed );
+ 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 :
@@ -217377,8 +217779,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);
@@ -218230,7 +218633,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
@@ -218370,7 +218773,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 */
@@ -218825,6 +219228,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 ){
@@ -218850,7 +219256,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);
}
@@ -219466,7 +219872,7 @@ static int nodeRowidIndex(
){
int ii;
int nCell = NCELL(pNode);
- assert( nCell<200 );
+ assert( nCell<65536 && nCell>=0 );
for(ii=0; iiRTREE_MAXCELLS ){
+ RTREE_IS_CORRUPT(pRtree);
+ return SQLITE_CORRUPT_VTAB;
+ }
pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
while( p->iCellRTREE_MAX_AUX_COLUMN+3 ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
return SQLITE_ERROR;
@@ -223624,6 +224033,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);
@@ -224758,7 +225172,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;
@@ -224781,7 +225195,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);
@@ -224790,9 +225204,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) ){
@@ -226405,16 +226819,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=0 ){
+ v = (v<<6) + c;
+ z++;
}
- z--;
- *pLen -= (int)(z - zStart);
+
+ *pLen -= (int)(z - (unsigned char*)*pz);
*pz = (char*)z;
return v;
}
@@ -226490,7 +226914,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;
}
@@ -226498,11 +226922,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;
}
@@ -226527,7 +226952,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;
}
@@ -226565,7 +226990,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;
}
@@ -226613,7 +227038,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{
@@ -232507,12 +232932,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{
@@ -233952,10 +234378,11 @@ static int sessionSerialLen(const u8 *a){
int n;
assert( a!=0 );
e = *a;
- if( e==0 || e==0xFF ) return 1;
- if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
- return sessionVarintGet(&a[1], &n) + 1 + n;
+ if( e==SQLITE_TEXT || e==SQLITE_BLOB ){
+ return sessionVarintGet(&a[1], &n) + 1 + n;
+ }
+ return 1;
}
/*
@@ -233978,17 +234405,17 @@ static unsigned int sessionChangeHash(
u8 *a = aRecord; /* Used to iterate through change record */
for(i=0; inCol; i++){
- int eType = *a;
int isPK = pTab->abPK[i];
if( bPkOnly && isPK==0 ) continue;
- assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
- || eType==SQLITE_TEXT || eType==SQLITE_BLOB
- || eType==SQLITE_NULL || eType==0
- );
-
if( isPK ){
- a++;
+ int eType = *a++;
+
+ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
+ || eType==SQLITE_TEXT || eType==SQLITE_BLOB
+ || eType==SQLITE_NULL || eType==0
+ );
+
h = sessionHashAppendType(h, eType);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
h = sessionHashAppendI64(h, sessionGetI64(a));
@@ -234790,7 +235217,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;
@@ -234858,6 +235285,16 @@ static int sessionPrepareDfltStmt(
return rc;
}
+/*
+** 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
@@ -234880,9 +235317,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;
}
@@ -235450,7 +235886,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;
@@ -235513,7 +235949,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;
@@ -236208,11 +236644,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; iiNext+nByte)>pIn->nData ){
+ if( rc==SQLITE_OK && (pIn->iNext+nByte)>pIn->nData ){
rc = SQLITE_CORRUPT_BKPT;
}
}
@@ -237464,7 +237902,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 ){
@@ -237660,6 +238104,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 */
};
@@ -238233,7 +238678,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
){
@@ -238355,7 +238800,7 @@ static int sessionApplyOneOp(
for(i=0; rc==SQLITE_OK && iabPK[i] || (bPatchset==0 && pOld) ){
+ if( pOld && (p->abPK[i] || bPatchset==0) ){
rc = sessionBindValue(pUp, i*2+2, pOld);
}
if( rc==SQLITE_OK && pNew ){
@@ -238481,7 +238926,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; iinCol; 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; iColnCol; 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,
@@ -238492,41 +239194,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;
@@ -238580,6 +239342,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);
}
@@ -239852,14 +240615,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; i0 && (*a1==0 || *a1==0xFF)) ){
memcpy(pOut, a2, nn2);
pOut += nn2;
}else{
@@ -239901,7 +240667,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];
@@ -240391,7 +241157,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;
@@ -244241,7 +245007,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 */
@@ -244266,7 +245032,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);
@@ -246982,7 +247748,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);
}
}
@@ -247933,10 +248699,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;
}
@@ -250975,7 +251741,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;
@@ -251219,7 +251985,7 @@ static int fts5StructureDecode(
i += fts5GetVarint32(&pData[i], nTotal);
if( nTotalnMerge ) rc = FTS5_CORRUPT;
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
- nTotal * sizeof(Fts5StructureSegment)
+ (i64)nTotal * sizeof(Fts5StructureSegment)
);
nSegment -= nTotal;
}
@@ -252175,7 +252941,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 ){
@@ -252629,6 +253395,10 @@ static void fts5LeafSeek(
if( nKeepn ){
+ FTS5_CORRUPT_ITER(p, pIter);
+ return;
+ }
assert( nKeep>=nMatch );
if( nKeep==nMatch ){
@@ -253605,8 +254375,7 @@ static void fts5PoslistFilterCallback(
do {
while( ieState ){
fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
@@ -253755,7 +254524,7 @@ static void fts5IndexExtractColset(
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint */
while( paiCol[i]==iCurrent ){
@@ -253852,8 +254621,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];
@@ -255347,6 +256119,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 );
@@ -258032,8 +258809,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:
@@ -258058,23 +258835,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 */
@@ -258579,9 +259359,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);
@@ -258612,7 +259396,7 @@ static void fts5IndexIntegrityCheckSegment(
/* Check any rowid-less pages that occur before the current leaf. */
for(iPg=iPrevLeaf+1; iPgeContent==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; inCol; 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; inCol; i++){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->abUnindexed[i] ){
+ sqlite3_str_appendf(pDefn, ", c%d", i);
}
- if( pConfig->bLocale ){
- for(i=0; inCol; 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; inCol; 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 ){
@@ -265617,8 +266398,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/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
index 7ae4e90d3..9417bce8d 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
@@ -147,12 +147,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.53.0"
-#define SQLITE_VERSION_NUMBER 3053000
-#define SQLITE_SOURCE_ID "2026-04-09 11:41:38 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b"
-#define SQLITE_SCM_BRANCH "trunk"
-#define SQLITE_SCM_TAGS "release major-release version-3.53.0"
-#define SQLITE_SCM_DATETIME "2026-04-09T11:41:38.498Z"
+#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.3"
+#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -4367,7 +4367,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** or in an ORDER BY or GROUP BY clause.
)^
**
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
+** 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.
+**
+** 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/vendor/github.com/mattn/go-sqlite3/sqlite3.go b/vendor/github.com/mattn/go-sqlite3/sqlite3.go
index b9deb72aa..c30bb8f1e 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3.go
@@ -69,13 +69,13 @@ _sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zV
}
static int
-_sqlite3_bind_text(sqlite3_stmt *stmt, int n, char *p, int np) {
- return sqlite3_bind_text(stmt, n, p, np, SQLITE_TRANSIENT);
+_sqlite3_bind_text(sqlite3_stmt *stmt, int n, char *p, sqlite3_uint64 np) {
+ return sqlite3_bind_text64(stmt, n, p, np, SQLITE_TRANSIENT, SQLITE_UTF8);
}
static int
-_sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) {
- return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT);
+_sqlite3_bind_blob(sqlite3_stmt *stmt, int n, void *p, sqlite3_uint64 np) {
+ return sqlite3_bind_blob64(stmt, n, p, np, SQLITE_TRANSIENT);
}
typedef struct {
@@ -220,8 +220,8 @@ _sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_
}
#endif
-void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
- sqlite3_result_text(ctx, s, -1, &free);
+void _sqlite3_result_text(sqlite3_context* ctx, const char* s, int n) {
+ sqlite3_result_text(ctx, s, n, &free);
}
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l) {
@@ -445,12 +445,12 @@ type SQLiteDriver struct {
// SQLiteConn implements driver.Conn.
type SQLiteConn struct {
- mu sync.Mutex
- db *C.sqlite3
- loc *time.Location
- txlock string
- funcs []*functionInfo
- aggregators []*aggInfo
+ mu sync.Mutex
+ db *C.sqlite3
+ loc *time.Location
+ txlock string
+ funcs []*functionInfo
+ aggregators []*aggInfo
// Prepared-statement cache. The slice is allocated at Open with a
// fixed capacity equal to the configured cache size; cap bounds the
// cache, len is the live count, and entries are ordered LRU-first
@@ -476,6 +476,12 @@ type SQLiteStmt struct {
cls bool // True if the statement was created by SQLiteConn.Query
namedParams map[string][3]int
cacheKey string
+ metadata *sqliteStmtMetadata
+}
+
+type sqliteStmtMetadata struct {
+ cols []string
+ decltype []string
}
// SQLiteResult implements sql.Result.
@@ -1589,6 +1595,20 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
return nil, errors.New("sqlite succeeded without returning a database")
}
+ // Create connection to SQLite
+ conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
+ if stmtCacheSize > 0 {
+ conn.stmtCache = make([]*SQLiteStmt, 0, stmtCacheSize)
+ conn.stmtCacheEnabled = true
+ }
+
+ // fail closes the connection so no error path leaks the database
+ // handle or any callback handles registered on it.
+ fail := func(err error) (driver.Conn, error) {
+ conn.Close()
+ return nil, err
+ }
+
exec := func(s string) error {
cs := C.CString(s)
rv := C.sqlite3_exec(db, cs, nil, nil, nil)
@@ -1601,8 +1621,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// Busy timeout
if err := exec(fmt.Sprintf("PRAGMA busy_timeout = %d;", busyTimeout)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
// USER AUTHENTICATION
@@ -1627,66 +1646,59 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// NO => Continue
//
- // Create connection to SQLite
- conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
- if stmtCacheSize > 0 {
- conn.stmtCache = make([]*SQLiteStmt, 0, stmtCacheSize)
- conn.stmtCacheEnabled = true
- }
-
// Password Cipher has to be registered before authentication
if len(authCrypt) > 0 {
switch strings.ToUpper(authCrypt) {
case "SHA1":
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA1, true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSHA1: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSHA1: %s", err))
}
case "SSHA1":
if len(authSalt) == 0 {
- return nil, fmt.Errorf("_auth_crypt=ssha1, requires _auth_salt")
+ return fail(fmt.Errorf("_auth_crypt=ssha1, requires _auth_salt"))
}
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA1(authSalt), true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSSHA1: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSSHA1: %s", err))
}
case "SHA256":
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA256, true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSHA256: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSHA256: %s", err))
}
case "SSHA256":
if len(authSalt) == 0 {
- return nil, fmt.Errorf("_auth_crypt=ssha256, requires _auth_salt")
+ return fail(fmt.Errorf("_auth_crypt=ssha256, requires _auth_salt"))
}
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA256(authSalt), true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSSHA256: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSSHA256: %s", err))
}
case "SHA384":
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA384, true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSHA384: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSHA384: %s", err))
}
case "SSHA384":
if len(authSalt) == 0 {
- return nil, fmt.Errorf("_auth_crypt=ssha384, requires _auth_salt")
+ return fail(fmt.Errorf("_auth_crypt=ssha384, requires _auth_salt"))
}
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA384(authSalt), true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSSHA384: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSSHA384: %s", err))
}
case "SHA512":
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA512, true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSHA512: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSHA512: %s", err))
}
case "SSHA512":
if len(authSalt) == 0 {
- return nil, fmt.Errorf("_auth_crypt=ssha512, requires _auth_salt")
+ return fail(fmt.Errorf("_auth_crypt=ssha512, requires _auth_salt"))
}
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA512(authSalt), true); err != nil {
- return nil, fmt.Errorf("CryptEncoderSSHA512: %s", err)
+ return fail(fmt.Errorf("CryptEncoderSSHA512: %s", err))
}
}
}
// Preform Authentication
if err := conn.Authenticate(authUser, authPass); err != nil {
- return nil, err
+ return fail(err)
}
// Register: authenticate
@@ -1704,7 +1716,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// If the SQLITE_USER table is not present in the database file, then
// this interface is a harmless no-op returnning SQLITE_OK.
if err := conn.RegisterFunc("authenticate", conn.authenticate, true); err != nil {
- return nil, err
+ return fail(err)
}
//
// Register: auth_user_add
@@ -1717,7 +1729,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// for any ATTACH-ed databases. Any call to AuthUserAdd by a
// non-admin user results in an error.
if err := conn.RegisterFunc("auth_user_add", conn.authUserAdd, true); err != nil {
- return nil, err
+ return fail(err)
}
//
// Register: auth_user_change
@@ -1727,7 +1739,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// credentials or admin privilege setting. No user may change their own
// admin privilege setting.
if err := conn.RegisterFunc("auth_user_change", conn.authUserChange, true); err != nil {
- return nil, err
+ return fail(err)
}
//
// Register: auth_user_delete
@@ -1737,13 +1749,13 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// the database cannot be converted into a no-authentication-required
// database.
if err := conn.RegisterFunc("auth_user_delete", conn.authUserDelete, true); err != nil {
- return nil, err
+ return fail(err)
}
// Register: auth_enabled
// auth_enabled can be used to check if user authentication is enabled
if err := conn.RegisterFunc("auth_enabled", conn.authEnabled, true); err != nil {
- return nil, err
+ return fail(err)
}
// Auto Vacuum
@@ -1754,8 +1766,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// and activating user authentication creates the internal table `sqlite_user`.
if autoVacuum > -1 {
if err := exec(fmt.Sprintf("PRAGMA auto_vacuum = %d;", autoVacuum)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
@@ -1765,17 +1776,17 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// has provided an username and password within the DSN.
// We are not allowed to continue.
if len(authUser) == 0 {
- return nil, fmt.Errorf("Missing '_auth_user' while user authentication was requested with '_auth'")
+ return fail(fmt.Errorf("Missing '_auth_user' while user authentication was requested with '_auth'"))
}
if len(authPass) == 0 {
- return nil, fmt.Errorf("Missing '_auth_pass' while user authentication was requested with '_auth'")
+ return fail(fmt.Errorf("Missing '_auth_pass' while user authentication was requested with '_auth'"))
}
// Check if User Authentication is Enabled
authExists := conn.AuthEnabled()
if !authExists {
if err := conn.AuthUserAdd(authUser, authPass, true); err != nil {
- return nil, err
+ return fail(err)
}
}
}
@@ -1783,40 +1794,35 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// Case Sensitive LIKE
if caseSensitiveLike > -1 {
if err := exec(fmt.Sprintf("PRAGMA case_sensitive_like = %d;", caseSensitiveLike)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Defer Foreign Keys
if deferForeignKeys > -1 {
if err := exec(fmt.Sprintf("PRAGMA defer_foreign_keys = %d;", deferForeignKeys)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Foreign Keys
if foreignKeys > -1 {
if err := exec(fmt.Sprintf("PRAGMA foreign_keys = %d;", foreignKeys)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Ignore CHECK Constraints
if ignoreCheckConstraints > -1 {
if err := exec(fmt.Sprintf("PRAGMA ignore_check_constraints = %d;", ignoreCheckConstraints)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Journal Mode
if journalMode != "" {
if err := exec(fmt.Sprintf("PRAGMA journal_mode = %s;", journalMode)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
@@ -1824,23 +1830,20 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// Because the default is NORMAL and this is not changed in this package
// by using the compile time SQLITE_DEFAULT_LOCKING_MODE this PRAGMA can always be executed
if err := exec(fmt.Sprintf("PRAGMA locking_mode = %s;", lockingMode)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
// Query Only
if queryOnly > -1 {
if err := exec(fmt.Sprintf("PRAGMA query_only = %d;", queryOnly)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Recursive Triggers
if recursiveTriggers > -1 {
if err := exec(fmt.Sprintf("PRAGMA recursive_triggers = %d;", recursiveTriggers)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
@@ -1851,8 +1854,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// you can compile with secure_delete 'ON' and disable it for a specific database connection.
if secureDelete != "DEFAULT" {
if err := exec(fmt.Sprintf("PRAGMA secure_delete = %s;", secureDelete)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
@@ -1860,37 +1862,32 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
//
// Because default is NORMAL this statement is always executed
if err := exec(fmt.Sprintf("PRAGMA synchronous = %s;", synchronousMode)); err != nil {
- conn.Close()
- return nil, err
+ return fail(err)
}
// Writable Schema
if writableSchema > -1 {
if err := exec(fmt.Sprintf("PRAGMA writable_schema = %d;", writableSchema)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
// Cache Size
if cacheSize != nil {
if err := exec(fmt.Sprintf("PRAGMA cache_size = %d;", *cacheSize)); err != nil {
- C.sqlite3_close_v2(db)
- return nil, err
+ return fail(err)
}
}
if len(d.Extensions) > 0 {
if err := conn.loadExtensions(d.Extensions); err != nil {
- conn.Close()
- return nil, err
+ return fail(err)
}
}
if d.ConnectHook != nil {
if err := d.ConnectHook(conn); err != nil {
- conn.Close()
- return nil, err
+ return fail(err)
}
}
runtime.SetFinalizer(conn, (*SQLiteConn).Close)
@@ -1964,6 +1961,10 @@ func (c *SQLiteConn) putCachedStmt(s *SQLiteStmt) bool {
c.mu.Lock()
defer c.mu.Unlock()
+ return c.putCachedStmtLocked(s)
+}
+
+func (c *SQLiteConn) putCachedStmtLocked(s *SQLiteStmt) bool {
if c.db == nil {
return false
}
@@ -2069,7 +2070,9 @@ func (c *SQLiteConn) GetFilename(schemaName string) string {
if schemaName == "" {
schemaName = "main"
}
- return C.GoString(C.sqlite3_db_filename(c.db, C.CString(schemaName)))
+ cSchema := C.CString(schemaName)
+ defer C.free(unsafe.Pointer(cSchema))
+ return C.GoString(C.sqlite3_db_filename(c.db, cSchema))
}
// GetLimit returns the current value of a run-time limit.
@@ -2156,12 +2159,20 @@ func (s *SQLiteStmt) Close() error {
s.c = nil
return nil
}
- if !conn.dbConnOpen() {
+ if s.cacheKey != "" {
+ conn.mu.Lock()
+ if conn.db == nil {
+ conn.mu.Unlock()
+ return errors.New("sqlite statement with already closed database connection")
+ }
+ if conn.putCachedStmtLocked(s) {
+ conn.mu.Unlock()
+ return nil
+ }
+ conn.mu.Unlock()
+ } else if !conn.dbConnOpen() {
return errors.New("sqlite statement with already closed database connection")
}
- if s.cacheKey != "" && conn.putCachedStmt(s) {
- return nil
- }
s.s = nil
s.c = nil
rv := C.sqlite3_finalize(stmt)
@@ -2180,9 +2191,9 @@ var placeHolder = []byte{0}
func bindText(s *C.sqlite3_stmt, n C.int, v string) C.int {
if len(v) == 0 {
- return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.int(0))
+ return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.sqlite3_uint64(0))
}
- return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(unsafe.StringData(v))), C.int(len(v)))
+ return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(unsafe.StringData(v))), C.sqlite3_uint64(len(v)))
}
func bindValue(s *C.sqlite3_stmt, n C.int, value driver.Value) C.int {
@@ -2208,14 +2219,14 @@ func bindValue(s *C.sqlite3_stmt, n C.int, value driver.Value) C.int {
if ln == 0 {
v = placeHolder
}
- return C._sqlite3_bind_blob(s, n, unsafe.Pointer(&v[0]), C.int(ln))
+ return C._sqlite3_bind_blob(s, n, unsafe.Pointer(&v[0]), C.sqlite3_uint64(ln))
case time.Time:
var buf [64]byte
b := v.AppendFormat(buf[:0], SQLiteTimestampFormats[0])
if len(b) == 0 {
- return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.int(0))
+ return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&placeHolder[0])), C.sqlite3_uint64(0))
}
- return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
+ return C._sqlite3_bind_text(s, n, (*C.char)(unsafe.Pointer(&b[0])), C.sqlite3_uint64(len(b)))
default:
return C.SQLITE_MISUSE
}
@@ -2274,6 +2285,17 @@ func stmtArgs(args []driver.NamedValue, start, na int) []driver.NamedValue {
return stmtArgs
}
+// bindError converts a non-OK return code from bindValue into an error.
+// The synthetic SQLITE_MISUSE returned for unsupported Go types is never
+// recorded in the database handle, so lastError may report no error; fall
+// back to an explicit message instead of silently ignoring the failure.
+func (s *SQLiteStmt) bindError(v driver.Value) error {
+ if err := s.c.lastError(); err != nil {
+ return err
+ }
+ return fmt.Errorf("sqlite3: unsupported bind type %T", v)
+}
+
func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
rv := C._sqlite3_reset_clear(s.s)
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
@@ -2293,7 +2315,7 @@ func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
n := C.int(arg.Ordinal)
rv = bindValue(s.s, n, arg.Value)
if rv != C.SQLITE_OK {
- return s.c.lastError()
+ return s.bindError(arg.Value)
}
}
return nil
@@ -2303,7 +2325,7 @@ func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
if arg.Name == "" {
rv = bindValue(s.s, C.int(arg.Ordinal), arg.Value)
if rv != C.SQLITE_OK {
- return s.c.lastError()
+ return s.bindError(arg.Value)
}
continue
}
@@ -2314,7 +2336,7 @@ func (s *SQLiteStmt) bind(args []driver.NamedValue) error {
}
rv = bindValue(s.s, C.int(idx), arg.Value)
if rv != C.SQLITE_OK {
- return s.c.lastError()
+ return s.bindError(arg.Value)
}
}
}
@@ -2475,6 +2497,36 @@ func (rc *SQLiteRows) Close() error {
return nil
}
+func (s *SQLiteStmt) cacheMetadata() bool {
+ return !s.cls || s.cacheKey != ""
+}
+
+func (s *SQLiteStmt) columnNamesLocked(n int) []string {
+ if s.metadata == nil {
+ s.metadata = &sqliteStmtMetadata{}
+ }
+ if len(s.metadata.cols) != n {
+ s.metadata.cols = make([]string, n)
+ for i := range s.metadata.cols {
+ s.metadata.cols[i] = C.GoString(C.sqlite3_column_name(s.s, C.int(i)))
+ }
+ }
+ return s.metadata.cols
+}
+
+func (s *SQLiteStmt) declTypesLocked(n int) []string {
+ if s.metadata == nil {
+ s.metadata = &sqliteStmtMetadata{}
+ }
+ if len(s.metadata.decltype) != n {
+ s.metadata.decltype = make([]string, n)
+ for i := range s.metadata.decltype {
+ s.metadata.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(s.s, C.int(i))))
+ }
+ }
+ return s.metadata.decltype
+}
+
// Columns return column names.
func (rc *SQLiteRows) Columns() []string {
if rc.s == nil {
@@ -2483,9 +2535,13 @@ func (rc *SQLiteRows) Columns() []string {
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
if rc.s.s != nil && int(rc.nc) != len(rc.cols) {
- rc.cols = make([]string, rc.nc)
- for i := range rc.cols {
- rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i)))
+ if rc.s.cacheMetadata() {
+ rc.cols = rc.s.columnNamesLocked(int(rc.nc))
+ } else {
+ rc.cols = make([]string, rc.nc)
+ for i := range rc.cols {
+ rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i)))
+ }
}
}
return rc.cols
@@ -2493,9 +2549,13 @@ func (rc *SQLiteRows) Columns() []string {
func (rc *SQLiteRows) declTypes() []string {
if rc.s.s != nil && rc.decltype == nil {
- rc.decltype = make([]string, rc.nc)
- for i := range rc.decltype {
- rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
+ if rc.s.cacheMetadata() {
+ rc.decltype = rc.s.declTypesLocked(int(rc.nc))
+ } else {
+ rc.decltype = make([]string, rc.nc)
+ for i := range rc.decltype {
+ rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i))))
+ }
}
}
return rc.decltype
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
index 7c7431dcc..4436279e9 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
@@ -28,7 +28,6 @@ import "C"
import (
"math"
- "reflect"
"unsafe"
)
@@ -91,9 +90,15 @@ func (c *SQLiteContext) ResultNull() {
// ResultText sets the result of an SQL function.
// See: sqlite3_result_text, http://sqlite.org/c3ref/result_blob.html
func (c *SQLiteContext) ResultText(s string) {
- h := (*reflect.StringHeader)(unsafe.Pointer(&s))
- cs, l := (*C.char)(unsafe.Pointer(h.Data)), C.int(h.Len)
- C.my_result_text((*C.sqlite3_context)(c), cs, l)
+ if i64 && len(s) > math.MaxInt32 {
+ C.sqlite3_result_error_toobig((*C.sqlite3_context)(c))
+ return
+ }
+ if len(s) == 0 {
+ C.my_result_text((*C.sqlite3_context)(c), (*C.char)(unsafe.Pointer(&placeHolder[0])), 0)
+ return
+ }
+ C.my_result_text((*C.sqlite3_context)(c), (*C.char)(unsafe.Pointer(unsafe.StringData(s))), C.int(len(s)))
}
// ResultZeroblob sets the result of an SQL function.
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
index 03cbc8b68..fbbb64939 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
@@ -74,11 +74,11 @@ func (c *SQLiteConn) loadExtension(lib string, entry *string) error {
}
var errMsg *C.char
- defer C.sqlite3_free(unsafe.Pointer(errMsg))
-
rv := C.sqlite3_load_extension(c.db, clib, centry, &errMsg)
if rv != C.SQLITE_OK {
- return errors.New(C.GoString(errMsg))
+ err := errors.New(C.GoString(errMsg))
+ C.sqlite3_free(unsafe.Pointer(errMsg))
+ return err
}
return nil
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_dbstat.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_dbstat.go
new file mode 100644
index 000000000..d03384614
--- /dev/null
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_dbstat.go
@@ -0,0 +1,15 @@
+// Copyright (C) 2025 Yasuhiro Matsumoto .
+// Copyright (C) 2025 Jakob Borg .
+//
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+//go:build sqlite_dbstat
+// +build sqlite_dbstat
+
+package sqlite3
+
+/*
+#cgo CFLAGS: -DSQLITE_ENABLE_DBSTAT_VTAB
+*/
+import "C"
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go
index 8cce278fd..37e048ffd 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_preupdate_hook.go
@@ -59,13 +59,17 @@ func (d *SQLitePreUpdateData) row(dest []any, new bool) error {
for i := 0; i < d.Count() && i < len(dest); i++ {
var val *C.sqlite3_value
var src any
+ var rc C.int
// Initially I tried making this just a function pointer argument, but
// it's absurdly complicated to pass C function pointers.
if new {
- C.sqlite3_preupdate_new(d.Conn.db, C.int(i), &val)
+ rc = C.sqlite3_preupdate_new(d.Conn.db, C.int(i), &val)
} else {
- C.sqlite3_preupdate_old(d.Conn.db, C.int(i), &val)
+ rc = C.sqlite3_preupdate_old(d.Conn.db, C.int(i), &val)
+ }
+ if rc != C.SQLITE_OK {
+ return Error{Code: ErrNo(rc)}
}
switch C.sqlite3_value_type(val) {
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_serialize.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_serialize.go
index 51dd9c8f0..60019bd5e 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_serialize.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_serialize.go
@@ -60,6 +60,9 @@ func (c *SQLiteConn) Deserialize(b []byte, schema string) error {
defer C.free(unsafe.Pointer(zSchema))
tmpBuf := (*C.uchar)(C.sqlite3_malloc64(C.sqlite3_uint64(len(b))))
+ if tmpBuf == nil && len(b) > 0 {
+ return fmt.Errorf("deserialize failed: out of memory")
+ }
copy(unsafe.Slice((*byte)(unsafe.Pointer(tmpBuf)), len(b)), b)
rc := C.sqlite3_deserialize(c.db, zSchema, tmpBuf, C.sqlite3_int64(len(b)),
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
index 3ac8050a4..dddb655da 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
@@ -21,6 +21,7 @@ package sqlite3
extern void unlock_notify_callback(void *arg, int argc);
*/
import "C"
+
import (
"fmt"
"math"
@@ -82,7 +83,7 @@ func unlock_notify_wait(db *C.sqlite3) C.int {
h := unt.add(c)
defer unt.remove(h)
- pargv := C.malloc(C.sizeof_uint)
+ pargv := C.malloc(C.size_t(unsafe.Sizeof(uint(0))))
defer C.free(pargv)
argv := (*[1]uint)(pargv)
diff --git a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go
index 9761bf357..9e916ea8c 100644
--- a/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go
+++ b/vendor/github.com/mattn/go-sqlite3/sqlite3_opt_vtable.go
@@ -113,6 +113,9 @@ uintptr_t goVOpen(void *pVTab, char **pzErr);
static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
void *vTabCursor = (void *)goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg));
+ if (!vTabCursor) {
+ return SQLITE_ERROR;
+ }
goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor));
if (!pCursor) {
return SQLITE_NOMEM;
@@ -270,7 +273,6 @@ import "C"
import (
"fmt"
"math"
- "reflect"
"unsafe"
)
@@ -329,11 +331,7 @@ type InfoOrderBy struct {
}
func constraints(info *C.sqlite3_index_info) []InfoConstraint {
- slice := *(*[]C.struct_sqlite3_index_constraint)(unsafe.Pointer(&reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(info.aConstraint)),
- Len: int(info.nConstraint),
- Cap: int(info.nConstraint),
- }))
+ slice := unsafe.Slice(info.aConstraint, int(info.nConstraint))
cst := make([]InfoConstraint, 0, len(slice))
for _, c := range slice {
@@ -351,11 +349,7 @@ func constraints(info *C.sqlite3_index_info) []InfoConstraint {
}
func orderBys(info *C.sqlite3_index_info) []InfoOrderBy {
- slice := *(*[]C.struct_sqlite3_index_orderby)(unsafe.Pointer(&reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(info.aOrderBy)),
- Len: int(info.nOrderBy),
- Cap: int(info.nOrderBy),
- }))
+ slice := unsafe.Slice(info.aOrderBy, int(info.nOrderBy))
ob := make([]InfoOrderBy, 0, len(slice))
for _, c := range slice {
@@ -400,10 +394,7 @@ func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **
return 0
}
args := make([]string, argc)
- var A []*C.char
- slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)}
- a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface()
- for i, s := range a.([]*C.char) {
+ for i, s := range unsafe.Slice(argv, int(argc)) {
args[i] = C.GoString(s)
}
var vTab VTab
@@ -466,11 +457,7 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char {
// Get a pointer to constraint_usage struct so we can update in place.
- slice := *(*[]C.struct_sqlite3_index_constraint_usage)(unsafe.Pointer(&reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(info.aConstraintUsage)),
- Len: int(info.nConstraint),
- Cap: int(info.nConstraint),
- }))
+ slice := unsafe.Slice(info.aConstraintUsage, int(info.nConstraint))
index := 1
for i := range slice {
if res.Used[i] {
@@ -488,11 +475,7 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char {
}
info.needToFreeIdxStr = C.int(1)
- idxStr := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
- Data: uintptr(unsafe.Pointer(info.idxStr)),
- Len: len(res.IdxStr) + 1,
- Cap: len(res.IdxStr) + 1,
- }))
+ idxStr := unsafe.Slice((*byte)(unsafe.Pointer(info.idxStr)), len(res.IdxStr)+1)
copy(idxStr, res.IdxStr)
idxStr[len(idxStr)-1] = 0 // null-terminated string
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4c2d99614..2c16cb589 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -167,7 +167,7 @@ github.com/json-iterator/go
# github.com/lucasb-eyer/go-colorful v1.3.0
## explicit; go 1.12
github.com/lucasb-eyer/go-colorful
-# github.com/mattn/go-sqlite3 v1.14.44
+# github.com/mattn/go-sqlite3 v1.14.48
## explicit; go 1.21
github.com/mattn/go-sqlite3
# github.com/moby/spdystream v0.5.1