mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Merge all recent trunk enhancements and fixes into the ota-update branch.
FossilOrigin-Name: 9bd3e4453d4ad416f7e3f08f0bd283d34f1c319c
This commit is contained in:
@@ -298,7 +298,7 @@ static void detachFunc(
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
pDb->pSchema = 0;
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
sqlite3CollapseDatabaseArray(db);
|
||||
return;
|
||||
|
||||
detach_error:
|
||||
|
||||
@@ -6735,7 +6735,6 @@ static int balance_nonroot(
|
||||
}else if( iParentIdx==i ){
|
||||
nxDiv = i-2+bBulk;
|
||||
}else{
|
||||
assert( bBulk==0 );
|
||||
nxDiv = iParentIdx-1;
|
||||
}
|
||||
i = 2-bBulk;
|
||||
|
||||
@@ -226,7 +226,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){
|
||||
if( v && pParse->nErr==0 && !db->mallocFailed ){
|
||||
assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
|
||||
/* A minimum of one cursor is required if autoincrement is used
|
||||
* See ticket [a696379c1f08866] */
|
||||
@@ -2763,7 +2763,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
||||
@@ -3776,7 +3777,6 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
||||
void sqlite3SrcListShiftJoinType(SrcList *p){
|
||||
if( p ){
|
||||
int i;
|
||||
assert( p->a || p->nSrc==0 );
|
||||
for(i=p->nSrc-1; i>0; i--){
|
||||
p->a[i].jointype = p->a[i-1].jointype;
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ int sqlite3_complete(const char *zSql){
|
||||
int sqlite3_complete16(const void *zSql){
|
||||
sqlite3_value *pVal;
|
||||
char const *zSql8;
|
||||
int rc = SQLITE_NOMEM;
|
||||
int rc;
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
rc = sqlite3_initialize();
|
||||
|
||||
@@ -1691,7 +1691,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
** ephemeral table.
|
||||
*/
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
if( pParse->nErr==0 && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
@@ -2016,6 +2016,7 @@ int sqlite3CodeSubselect(
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
|
||||
&sqlite3IntTokens[1]);
|
||||
pSel->iLimit = 0;
|
||||
pSel->selFlags &= ~SF_AllValues;
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1184,7 +1184,8 @@ static Trigger *fkActionTrigger(
|
||||
|
||||
iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
|
||||
assert( iFromCol>=0 );
|
||||
tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid";
|
||||
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
|
||||
tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
|
||||
tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
|
||||
|
||||
tToCol.n = sqlite3Strlen30(tToCol.z);
|
||||
|
||||
49
src/insert.c
49
src/insert.c
@@ -1765,6 +1765,7 @@ static int xferOptimization(
|
||||
int onError, /* How to handle constraint errors */
|
||||
int iDbDest /* The database of pDest */
|
||||
){
|
||||
sqlite3 *db = pParse->db;
|
||||
ExprList *pEList; /* The result set of the SELECT */
|
||||
Table *pSrc; /* The table in the FROM clause of SELECT */
|
||||
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
||||
@@ -1912,11 +1913,11 @@ static int xferOptimization(
|
||||
** the extra complication to make this rule less restrictive is probably
|
||||
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
||||
*/
|
||||
if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
||||
if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if( (pParse->db->flags & SQLITE_CountRows)!=0 ){
|
||||
if( (db->flags & SQLITE_CountRows)!=0 ){
|
||||
return 0; /* xfer opt does not play well with PRAGMA count_changes */
|
||||
}
|
||||
|
||||
@@ -1927,7 +1928,7 @@ static int xferOptimization(
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_xferopt_count++;
|
||||
#endif
|
||||
iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
|
||||
iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
sqlite3CodeVerifySchema(pParse, iDbSrc);
|
||||
iSrc = pParse->nTab++;
|
||||
@@ -1937,14 +1938,18 @@ static int xferOptimization(
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
assert( HasRowid(pDest) || destHasUniqueIdx );
|
||||
if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|
||||
if( (db->flags & SQLITE_Vacuum)==0 && (
|
||||
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|
||||
|| destHasUniqueIdx /* (2) */
|
||||
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
|
||||
){
|
||||
)){
|
||||
/* In some circumstances, we are able to run the xfer optimization
|
||||
** only if the destination table is initially empty. This code makes
|
||||
** that determination. Conditions under which the destination must
|
||||
** be empty:
|
||||
** only if the destination table is initially empty. Unless the
|
||||
** SQLITE_Vacuum flag is set, this block generates code to make
|
||||
** that determination. If SQLITE_Vacuum is set, then the destination
|
||||
** table is always empty.
|
||||
**
|
||||
** Conditions under which the destination must be empty:
|
||||
**
|
||||
** (1) There is no INTEGER PRIMARY KEY but there are indices.
|
||||
** (If the destination is not initially empty, the rowid fields
|
||||
@@ -1987,6 +1992,7 @@ static int xferOptimization(
|
||||
sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
u8 useSeekResult = 0;
|
||||
for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
|
||||
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
||||
}
|
||||
@@ -2000,7 +2006,34 @@ static int xferOptimization(
|
||||
VdbeComment((v, "%s", pDestIdx->zName));
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
||||
if( db->flags & SQLITE_Vacuum ){
|
||||
/* This INSERT command is part of a VACUUM operation, which guarantees
|
||||
** that the destination table is empty. If all indexed columns use
|
||||
** collation sequence BINARY, then it can also be assumed that the
|
||||
** index will be populated by inserting keys in strictly sorted
|
||||
** order. In this case, instead of seeking within the b-tree as part
|
||||
** of every OP_IdxInsert opcode, an OP_Last is added before the
|
||||
** OP_IdxInsert to seek to the point within the b-tree where each key
|
||||
** should be inserted. This is faster.
|
||||
**
|
||||
** If any of the indexed columns use a collation sequence other than
|
||||
** BINARY, this optimization is disabled. This is because the user
|
||||
** might change the definition of a collation sequence and then run
|
||||
** a VACUUM command. In that case keys may not be written in strictly
|
||||
** sorted order. */
|
||||
int i;
|
||||
for(i=0; i<pSrcIdx->nColumn; i++){
|
||||
char *zColl = pSrcIdx->azColl[i];
|
||||
assert( zColl!=0 );
|
||||
if( sqlite3_stricmp("BINARY", zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
useSeekResult = OPFLAG_USESEEKRESULT;
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
||||
sqlite3VdbeChangeP5(v, useSeekResult);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma warning(disable : 4055)
|
||||
#pragma warning(disable : 4100)
|
||||
#pragma warning(disable : 4127)
|
||||
#pragma warning(disable : 4130)
|
||||
#pragma warning(disable : 4152)
|
||||
#pragma warning(disable : 4189)
|
||||
#pragma warning(disable : 4206)
|
||||
|
||||
@@ -91,6 +91,17 @@
|
||||
# include <sys/param.h>
|
||||
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
||||
|
||||
#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
|
||||
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
|
||||
# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
|
||||
&& (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
|
||||
# define HAVE_GETHOSTUUID 1
|
||||
# else
|
||||
# warning "gethostuuid() is disabled."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if OS_VXWORKS
|
||||
# include <sys/ioctl.h>
|
||||
# include <semaphore.h>
|
||||
@@ -6602,8 +6613,10 @@ int sqlite3_hostid_num = 0;
|
||||
|
||||
#define PROXY_HOSTIDLEN 16 /* conch file host id length */
|
||||
|
||||
#ifdef HAVE_GETHOSTUUID
|
||||
/* Not always defined in the headers as it ought to be */
|
||||
extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
||||
#endif
|
||||
|
||||
/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
|
||||
** bytes of writable memory.
|
||||
@@ -6611,8 +6624,7 @@ extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
||||
static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
||||
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
|
||||
memset(pHostID, 0, PROXY_HOSTIDLEN);
|
||||
# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
|
||||
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
|
||||
#ifdef HAVE_GETHOSTUUID
|
||||
{
|
||||
struct timespec timeout = {1, 0}; /* 1 sec timeout */
|
||||
if( gethostuuid(pHostID, &timeout) ){
|
||||
|
||||
@@ -1041,7 +1041,7 @@ void sqlite3Pragma(
|
||||
}else if( pPk==0 ){
|
||||
k = 1;
|
||||
}else{
|
||||
for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){}
|
||||
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
||||
|
||||
@@ -826,7 +826,7 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
|
||||
** size of the memory allocation for StrAccum if necessary.
|
||||
*/
|
||||
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
assert( z!=0 );
|
||||
assert( z!=0 || N==0 );
|
||||
assert( p->zText!=0 || p->nChar==0 || p->accError );
|
||||
assert( N>=0 );
|
||||
assert( p->accError==0 || p->nAlloc==0 );
|
||||
|
||||
@@ -460,6 +460,7 @@ static int lookupName(
|
||||
if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){
|
||||
pExpr->op = TK_STRING;
|
||||
pExpr->pTab = 0;
|
||||
pExpr->iTable = -1;
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
@@ -993,9 +994,11 @@ static int resolveCompoundOrderBy(
|
||||
if( pItem->pExpr==pE ){
|
||||
pItem->pExpr = pNew;
|
||||
}else{
|
||||
assert( pItem->pExpr->op==TK_COLLATE );
|
||||
assert( pItem->pExpr->pLeft==pE );
|
||||
pItem->pExpr->pLeft = pNew;
|
||||
Expr *pParent = pItem->pExpr;
|
||||
assert( pParent->op==TK_COLLATE );
|
||||
while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft;
|
||||
assert( pParent->pLeft==pE );
|
||||
pParent->pLeft = pNew;
|
||||
}
|
||||
sqlite3ExprDelete(db, pE);
|
||||
pItem->u.x.iOrderByCol = (u16)iCol;
|
||||
@@ -1195,7 +1198,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** after the names have been resolved. */
|
||||
if( p->selFlags & SF_Converted ){
|
||||
Select *pSub = p->pSrc->a[0].pSelect;
|
||||
assert( p->pSrc->nSrc==1 && isCompound==0 && p->pOrderBy );
|
||||
assert( p->pSrc->nSrc==1 && p->pOrderBy );
|
||||
assert( pSub->pPrior && pSub->pOrderBy==0 );
|
||||
pSub->pOrderBy = p->pOrderBy;
|
||||
p->pOrderBy = 0;
|
||||
|
||||
@@ -3071,7 +3071,7 @@ static int multiSelectOrderBy(
|
||||
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
||||
**** subqueries ****/
|
||||
explainComposite(pParse, p->op, iSub1, iSub2, 0);
|
||||
return SQLITE_OK;
|
||||
return pParse->nErr!=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3883,6 +3883,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
pNew->pOrderBy = 0;
|
||||
p->pPrior = 0;
|
||||
p->pNext = 0;
|
||||
p->pWith = 0;
|
||||
p->selFlags &= ~SF_Compound;
|
||||
assert( (p->selFlags & SF_Converted)==0 );
|
||||
p->selFlags |= SF_Converted;
|
||||
|
||||
100
src/sqlite.h.in
100
src/sqlite.h.in
@@ -270,6 +270,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Closing A Database Connection
|
||||
** DESTRUCTOR: sqlite3
|
||||
**
|
||||
** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
|
||||
** for the [sqlite3] object.
|
||||
@@ -321,6 +322,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
|
||||
/*
|
||||
** CAPI3REF: One-Step Query Execution Interface
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** The sqlite3_exec() interface is a convenience wrapper around
|
||||
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
|
||||
@@ -1383,6 +1385,7 @@ int sqlite3_config(int, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure database connections
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** The sqlite3_db_config() interface is used to make configuration
|
||||
** changes to a [database connection]. The interface is similar to
|
||||
@@ -1880,6 +1883,7 @@ struct sqlite3_mem_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extended Result Codes
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_extended_result_codes() routine enables or disables the
|
||||
** [extended result codes] feature of SQLite. ^The extended result
|
||||
@@ -1889,6 +1893,7 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Last Insert Rowid
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables)
|
||||
** has a unique 64-bit signed
|
||||
@@ -1940,6 +1945,7 @@ sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Count The Number Of Rows Modified
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function returns the number of rows modified, inserted or
|
||||
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
||||
@@ -1992,6 +1998,7 @@ int sqlite3_changes(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Total Number Of Rows Modified
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function returns the total number of rows inserted, modified or
|
||||
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
||||
@@ -2015,6 +2022,7 @@ int sqlite3_total_changes(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Interrupt A Long-Running Query
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This function causes any pending database operation to abort and
|
||||
** return at its earliest opportunity. This routine is typically
|
||||
@@ -2091,6 +2099,7 @@ int sqlite3_complete16(const void *sql);
|
||||
/*
|
||||
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
|
||||
** KEYWORDS: {busy-handler callback} {busy handler}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
|
||||
** that might be invoked with argument P whenever
|
||||
@@ -2150,6 +2159,7 @@ int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set A Busy Timeout
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps
|
||||
** for a specified amount of time when a table is locked. ^The handler
|
||||
@@ -2172,6 +2182,7 @@ int sqlite3_busy_timeout(sqlite3*, int ms);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Convenience Routines For Running Queries
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** This is a legacy interface that is preserved for backwards compatibility.
|
||||
** Use of this interface is not recommended.
|
||||
@@ -2507,6 +2518,7 @@ void sqlite3_randomness(int N, void *P);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compile-Time Authorization Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This routine registers an authorizer callback with a particular
|
||||
** [database connection], supplied in the first argument.
|
||||
@@ -2663,6 +2675,7 @@ int sqlite3_set_authorizer(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Tracing And Profiling Functions
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** These routines register callback functions that can be used for
|
||||
** tracing and profiling the execution of SQL statements.
|
||||
@@ -2695,6 +2708,7 @@ SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
|
||||
/*
|
||||
** CAPI3REF: Query Progress Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
|
||||
** function X to be invoked periodically during long running calls to
|
||||
@@ -2728,6 +2742,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Opening A New Database Connection
|
||||
** CONSTRUCTOR: sqlite3
|
||||
**
|
||||
** ^These routines open an SQLite database file as specified by the
|
||||
** filename argument. ^The filename argument is interpreted as UTF-8 for
|
||||
@@ -3013,6 +3028,7 @@ sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Error Codes And Messages
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^If the most recent sqlite3_* API call associated with
|
||||
** [database connection] D failed, then the sqlite3_errcode(D) interface
|
||||
@@ -3058,33 +3074,34 @@ const void *sqlite3_errmsg16(sqlite3*);
|
||||
const char *sqlite3_errstr(int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Statement Object
|
||||
** CAPI3REF: Prepared Statement Object
|
||||
** KEYWORDS: {prepared statement} {prepared statements}
|
||||
**
|
||||
** An instance of this object represents a single SQL statement.
|
||||
** This object is variously known as a "prepared statement" or a
|
||||
** "compiled SQL statement" or simply as a "statement".
|
||||
** An instance of this object represents a single SQL statement that
|
||||
** has been compiled into binary form and is ready to be evaluated.
|
||||
**
|
||||
** The life of a statement object goes something like this:
|
||||
** Think of each SQL statement as a separate computer program. The
|
||||
** original SQL text is source code. A prepared statement object
|
||||
** is the compiled object code. All SQL must be converted into a
|
||||
** prepared statement before it can be run.
|
||||
**
|
||||
** The life-cycle of a prepared statement object usually goes like this:
|
||||
**
|
||||
** <ol>
|
||||
** <li> Create the object using [sqlite3_prepare_v2()] or a related
|
||||
** function.
|
||||
** <li> Bind values to [host parameters] using the sqlite3_bind_*()
|
||||
** <li> Create the prepared statement object using [sqlite3_prepare_v2()].
|
||||
** <li> Bind values to [parameters] using the sqlite3_bind_*()
|
||||
** interfaces.
|
||||
** <li> Run the SQL by calling [sqlite3_step()] one or more times.
|
||||
** <li> Reset the statement using [sqlite3_reset()] then go back
|
||||
** <li> Reset the prepared statement using [sqlite3_reset()] then go back
|
||||
** to step 2. Do this zero or more times.
|
||||
** <li> Destroy the object using [sqlite3_finalize()].
|
||||
** </ol>
|
||||
**
|
||||
** Refer to documentation on individual methods above for additional
|
||||
** information.
|
||||
*/
|
||||
typedef struct sqlite3_stmt sqlite3_stmt;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-time Limits
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(This interface allows the size of various constructs to be limited
|
||||
** on a connection by connection basis. The first parameter is the
|
||||
@@ -3196,6 +3213,8 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
/*
|
||||
** CAPI3REF: Compiling An SQL Statement
|
||||
** KEYWORDS: {SQL statement compiler}
|
||||
** METHOD: sqlite3
|
||||
** CONSTRUCTOR: sqlite3_stmt
|
||||
**
|
||||
** To execute an SQL query, it must first be compiled into a byte-code
|
||||
** program using one of these routines.
|
||||
@@ -3303,6 +3322,7 @@ int sqlite3_prepare16_v2(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieving Statement SQL
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^This interface can be used to retrieve a saved copy of the original
|
||||
** SQL text used to create a [prepared statement] if that statement was
|
||||
@@ -3312,6 +3332,7 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
|
||||
** and only if the [prepared statement] X makes no direct changes to
|
||||
@@ -3343,6 +3364,7 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
|
||||
** [prepared statement] S has been stepped at least once using
|
||||
@@ -3417,6 +3439,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** CAPI3REF: Binding Values To Prepared Statements
|
||||
** KEYWORDS: {host parameter} {host parameters} {host parameter name}
|
||||
** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding}
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants,
|
||||
** literals may be replaced by a [parameter] that matches one of following
|
||||
@@ -3535,6 +3558,7 @@ int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number Of SQL Parameters
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^This routine can be used to find the number of [SQL parameters]
|
||||
** in a [prepared statement]. SQL parameters are tokens of the
|
||||
@@ -3555,6 +3579,7 @@ int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Name Of A Host Parameter
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_bind_parameter_name(P,N) interface returns
|
||||
** the name of the N-th [SQL parameter] in the [prepared statement] P.
|
||||
@@ -3582,6 +3607,7 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Index Of A Parameter With A Given Name
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Return the index of an SQL parameter given its name. ^The
|
||||
** index value returned is suitable for use as the second
|
||||
@@ -3598,6 +3624,7 @@ int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset All Bindings On A Prepared Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset
|
||||
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
|
||||
@@ -3607,6 +3634,7 @@ int sqlite3_clear_bindings(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number Of Columns In A Result Set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Return the number of columns in the result set returned by the
|
||||
** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
|
||||
@@ -3618,6 +3646,7 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Column Names In A Result Set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^These routines return the name assigned to a particular column
|
||||
** in the result set of a [SELECT] statement. ^The sqlite3_column_name()
|
||||
@@ -3647,6 +3676,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Source Of Data In A Query Result
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^These routines provide a means to determine the database, table, and
|
||||
** table column that is the origin of a particular result column in
|
||||
@@ -3699,6 +3729,7 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Declared Datatype Of A Query Result
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(The first parameter is a [prepared statement].
|
||||
** If this statement is a [SELECT] statement and the Nth column of the
|
||||
@@ -3731,6 +3762,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Evaluate An SQL Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** After a [prepared statement] has been prepared using either
|
||||
** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
|
||||
@@ -3810,6 +3842,7 @@ int sqlite3_step(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Number of columns in a result set
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_data_count(P) interface returns the number of columns in the
|
||||
** current row of the result set of [prepared statement] P.
|
||||
@@ -3863,6 +3896,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
/*
|
||||
** CAPI3REF: Result Values From A Query
|
||||
** KEYWORDS: {column access functions}
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** These routines form the "result set" interface.
|
||||
**
|
||||
@@ -4035,6 +4069,7 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Destroy A Prepared Statement Object
|
||||
** DESTRUCTOR: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
|
||||
** ^If the most recent evaluation of the statement encountered no errors
|
||||
@@ -4062,6 +4097,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset A Prepared Statement Object
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** The sqlite3_reset() function is called to reset a [prepared statement]
|
||||
** object back to its initial state, ready to be re-executed.
|
||||
@@ -4091,6 +4127,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** KEYWORDS: {function creation routines}
|
||||
** KEYWORDS: {application-defined SQL function}
|
||||
** KEYWORDS: {application-defined SQL functions}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These functions (collectively known as "function creation routines")
|
||||
** are used to add SQL functions or aggregates or to redefine the behavior
|
||||
@@ -4260,6 +4297,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtaining SQL Function Parameter Values
|
||||
** METHOD: sqlite3_value
|
||||
**
|
||||
** The C-language implementation of SQL functions and aggregates uses
|
||||
** this set of interface routines to access the parameter values on
|
||||
@@ -4318,6 +4356,7 @@ int sqlite3_value_numeric_type(sqlite3_value*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtain Aggregate Function Context
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** Implementations of aggregate SQL functions use this
|
||||
** routine to allocate memory for storing their state.
|
||||
@@ -4362,6 +4401,7 @@ void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
|
||||
|
||||
/*
|
||||
** CAPI3REF: User Data For Functions
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** ^The sqlite3_user_data() interface returns a copy of
|
||||
** the pointer that was the pUserData parameter (the 5th parameter)
|
||||
@@ -4376,6 +4416,7 @@ void *sqlite3_user_data(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection For Functions
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** ^The sqlite3_context_db_handle() interface returns a copy of
|
||||
** the pointer to the [database connection] (the 1st parameter)
|
||||
@@ -4387,6 +4428,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Function Auxiliary Data
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** These functions may be used by (non-aggregate) SQL functions to
|
||||
** associate metadata with argument values. If the same value is passed to
|
||||
@@ -4459,6 +4501,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Setting The Result Of An SQL Function
|
||||
** METHOD: sqlite3_context
|
||||
**
|
||||
** These routines are used by the xFunc or xFinal callbacks that
|
||||
** implement SQL functions and aggregates. See
|
||||
@@ -4594,6 +4637,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Define New Collating Sequences
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These functions add, remove, or modify a [collation] associated
|
||||
** with the [database connection] specified as the first argument.
|
||||
@@ -4696,6 +4740,7 @@ int sqlite3_create_collation16(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Collation Needed Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^To avoid having to register all collation sequences before a database
|
||||
** can be used, a single callback function may be registered with the
|
||||
@@ -4903,6 +4948,7 @@ SQLITE_EXTERN char *sqlite3_data_directory;
|
||||
/*
|
||||
** CAPI3REF: Test For Auto-Commit Mode
|
||||
** KEYWORDS: {autocommit mode}
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_get_autocommit() interface returns non-zero or
|
||||
** zero if the given database connection is or is not in autocommit mode,
|
||||
@@ -4925,6 +4971,7 @@ int sqlite3_get_autocommit(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find The Database Handle Of A Prepared Statement
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^The sqlite3_db_handle interface returns the [database connection] handle
|
||||
** to which a [prepared statement] belongs. ^The [database connection]
|
||||
@@ -4937,6 +4984,7 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Filename For A Database Connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
|
||||
** associated with database N of connection D. ^The main database file
|
||||
@@ -4953,6 +5001,7 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine if a database is read-only
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_readonly(D,N) interface returns 1 if the database N
|
||||
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
|
||||
@@ -4962,6 +5011,7 @@ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find the next prepared statement
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface returns a pointer to the next [prepared statement] after
|
||||
** pStmt associated with the [database connection] pDb. ^If pStmt is NULL
|
||||
@@ -4977,6 +5027,7 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Commit And Rollback Notification Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_commit_hook() interface registers a callback
|
||||
** function to be invoked whenever a transaction is [COMMIT | committed].
|
||||
@@ -5026,6 +5077,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Data Change Notification Callbacks
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_update_hook() interface registers a callback function
|
||||
** with the [database connection] identified by the first argument
|
||||
@@ -5132,6 +5184,7 @@ int sqlite3_release_memory(int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Free Memory Used By A Database Connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
|
||||
** memory as possible from database connection D. Unlike the
|
||||
@@ -5209,6 +5262,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Extract Metadata About A Column Of A Table
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_table_column_metadata(X,D,T,C,....) routine returns
|
||||
** information about column C of table T in database D
|
||||
@@ -5287,6 +5341,7 @@ int sqlite3_table_column_metadata(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Load An Extension
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface loads an SQLite extension library from the named file.
|
||||
**
|
||||
@@ -5328,6 +5383,7 @@ int sqlite3_load_extension(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable Extension Loading
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^So as not to open security holes in older applications that are
|
||||
** unprepared to deal with [extension loading], and as a means of disabling
|
||||
@@ -5577,6 +5633,7 @@ struct sqlite3_index_info {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Virtual Table Implementation
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^These routines are used to register a new [virtual table module] name.
|
||||
** ^Module names must be registered before
|
||||
@@ -5673,6 +5730,7 @@ int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Overload A Function For A Virtual Table
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(Virtual tables can provide alternative implementations of functions
|
||||
** using the [xFindFunction] method of the [virtual table module].
|
||||
@@ -5715,6 +5773,8 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Open A BLOB For Incremental I/O
|
||||
** METHOD: sqlite3
|
||||
** CONSTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
|
||||
** in row iRow, column zColumn, table zTable in database zDb;
|
||||
@@ -5796,6 +5856,7 @@ int sqlite3_blob_open(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Move a BLOB Handle to a New Row
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^This function is used to move an existing blob handle so that it points
|
||||
** to a different row of the same database table. ^The new row is identified
|
||||
@@ -5820,6 +5881,7 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Close A BLOB Handle
|
||||
** DESTRUCTOR: sqlite3_blob
|
||||
**
|
||||
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
||||
** unconditionally. Even if this routine returns an error code, the
|
||||
@@ -5842,6 +5904,7 @@ int sqlite3_blob_close(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Size Of An Open BLOB
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^Returns the size in bytes of the BLOB accessible via the
|
||||
** successfully opened [BLOB handle] in its only argument. ^The
|
||||
@@ -5857,6 +5920,7 @@ int sqlite3_blob_bytes(sqlite3_blob *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Read Data From A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to read data from an open [BLOB handle] into a
|
||||
** caller-supplied buffer. N bytes of data are copied into buffer Z
|
||||
@@ -5885,6 +5949,7 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Write Data Into A BLOB Incrementally
|
||||
** METHOD: sqlite3_blob
|
||||
**
|
||||
** ^(This function is used to write data into an open [BLOB handle] from a
|
||||
** caller-supplied buffer. N bytes of data are copied from the buffer Z
|
||||
@@ -6212,6 +6277,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface returns a pointer the [sqlite3_mutex] object that
|
||||
** serializes access to the [database connection] given in the argument
|
||||
@@ -6223,6 +6289,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Low-Level Control Of Database Files
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_file_control()] interface makes a direct call to the
|
||||
** xFileControl method for the [sqlite3_io_methods] object associated
|
||||
@@ -6439,6 +6506,7 @@ int sqlite3_status64(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Status
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^This interface is used to retrieve runtime status information
|
||||
** about a single [database connection]. ^The first argument is the
|
||||
@@ -6567,6 +6635,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Status
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^(Each prepared statement maintains various
|
||||
** [SQLITE_STMTSTATUS counters] that measure the number
|
||||
@@ -7070,6 +7139,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Unlock Notification
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^When running in shared-cache mode, a database operation may fail with
|
||||
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
|
||||
@@ -7240,6 +7310,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Write-Ahead Log Commit Hook
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_wal_hook()] function is used to register a callback that
|
||||
** is invoked each time data is committed to a database in wal mode.
|
||||
@@ -7279,6 +7350,7 @@ void *sqlite3_wal_hook(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configure an auto-checkpoint
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
|
||||
** [sqlite3_wal_hook()] that causes any database on [database connection] D
|
||||
@@ -7309,6 +7381,7 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
|
||||
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
|
||||
@@ -7330,6 +7403,7 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
|
||||
** operation on database X of [database connection] D in mode M. Status
|
||||
@@ -7584,6 +7658,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Scan Status
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** This interface returns information about the predicted and measured
|
||||
** performance for pStmt. Advanced applications can use this
|
||||
@@ -7621,6 +7696,7 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Zero Scan-Status Counters
|
||||
** METHOD: sqlite3_stmt
|
||||
**
|
||||
** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
|
||||
**
|
||||
|
||||
@@ -1226,6 +1226,7 @@ struct sqlite3 {
|
||||
#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
|
||||
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
|
||||
#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */
|
||||
#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -430,10 +430,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
break;
|
||||
}
|
||||
case TK_ILLEGAL: {
|
||||
sqlite3DbFree(db, *pzErrMsg);
|
||||
*pzErrMsg = sqlite3MPrintf(db, "unrecognized token: \"%T\"",
|
||||
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
|
||||
&pParse->sLastToken);
|
||||
nErr++;
|
||||
goto abort_parse;
|
||||
}
|
||||
case TK_SEMI: {
|
||||
@@ -451,7 +449,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
}
|
||||
}
|
||||
abort_parse:
|
||||
if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){
|
||||
assert( nErr==0 );
|
||||
if( zSql[i]==0 && pParse->rc==SQLITE_OK ){
|
||||
if( lastTokenParsed!=TK_SEMI ){
|
||||
sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
|
||||
pParse->zTail = &zSql[i];
|
||||
|
||||
@@ -680,7 +680,6 @@ static SrcList *targetSrcList(
|
||||
pSrc = sqlite3SrcListAppend(pParse->db, 0, &pStep->target, 0);
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc>0 );
|
||||
assert( pSrc->a!=0 );
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema);
|
||||
if( iDb==0 || iDb>=2 ){
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
@@ -250,6 +250,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
assert( (db->flags & SQLITE_Vacuum)==0 );
|
||||
db->flags |= SQLITE_Vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'"
|
||||
@@ -257,6 +259,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND coalesce(rootpage,1)>0"
|
||||
);
|
||||
assert( (db->flags & SQLITE_Vacuum)!=0 );
|
||||
db->flags &= ~SQLITE_Vacuum;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
|
||||
319
src/vdbe.c
319
src/vdbe.c
@@ -514,6 +514,21 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return the register of pOp->p2 after first preparing it to be
|
||||
** overwritten with an integer value.
|
||||
*/
|
||||
static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
|
||||
Mem *pOut;
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
pOut = &p->aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
|
||||
pOut->flags = MEM_Int;
|
||||
return pOut;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can.
|
||||
@@ -522,9 +537,8 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
int sqlite3VdbeExec(
|
||||
Vdbe *p /* The VDBE */
|
||||
){
|
||||
int pc=0; /* The program counter */
|
||||
Op *aOp = p->aOp; /* Copy of p->aOp */
|
||||
Op *pOp; /* Current operation */
|
||||
Op *pOp = aOp; /* Current operation */
|
||||
int rc = SQLITE_OK; /* Value to return */
|
||||
sqlite3 *db = p->db; /* The database */
|
||||
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
|
||||
@@ -600,23 +614,22 @@ int sqlite3VdbeExec(
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
#endif
|
||||
for(pc=p->pc; rc==SQLITE_OK; pc++){
|
||||
assert( pc>=0 && pc<p->nOp );
|
||||
for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
|
||||
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
|
||||
if( db->mallocFailed ) goto no_mem;
|
||||
#ifdef VDBE_PROFILE
|
||||
start = sqlite3Hwtime();
|
||||
#endif
|
||||
nVmStep++;
|
||||
pOp = &aOp[pc];
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
if( p->anExec ) p->anExec[pc]++;
|
||||
if( p->anExec ) p->anExec[(int)(pOp-aOp)]++;
|
||||
#endif
|
||||
|
||||
/* Only allow tracing if SQLITE_DEBUG is defined.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( db->flags & SQLITE_VdbeTrace ){
|
||||
sqlite3VdbePrintOp(stdout, pc, pOp);
|
||||
sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -633,23 +646,9 @@ int sqlite3VdbeExec(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* On any opcode with the "out2-prerelease" tag, free any
|
||||
** external allocations out of mem[p2] and set mem[p2] to be
|
||||
** an undefined integer. Opcodes will either fill in the integer
|
||||
** value or convert mem[p2] to a different type.
|
||||
*/
|
||||
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
||||
if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
|
||||
assert( pOp->p2>0 );
|
||||
assert( pOp->p2<=(p->nMem-p->nCursor) );
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
|
||||
pOut->flags = MEM_Int;
|
||||
}
|
||||
|
||||
/* Sanity checking on other operands */
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
|
||||
if( (pOp->opflags & OPFLG_IN1)!=0 ){
|
||||
assert( pOp->p1>0 );
|
||||
assert( pOp->p1<=(p->nMem-p->nCursor) );
|
||||
@@ -705,7 +704,7 @@ int sqlite3VdbeExec(
|
||||
**
|
||||
** Other keywords in the comment that follows each case are used to
|
||||
** construct the OPFLG_INITIALIZER value that initializes opcodeProperty[].
|
||||
** Keywords include: in1, in2, in3, out2_prerelease, out2, out3. See
|
||||
** Keywords include: in1, in2, in3, out2, out3. See
|
||||
** the mkopcodeh.awk script for additional information.
|
||||
**
|
||||
** Documentation about VDBE opcodes is generated by scanning this file
|
||||
@@ -733,7 +732,8 @@ int sqlite3VdbeExec(
|
||||
** to the current line should be indented for EXPLAIN output.
|
||||
*/
|
||||
case OP_Goto: { /* jump */
|
||||
pc = pOp->p2 - 1;
|
||||
jump_to_p2_and_check_for_interrupt:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
|
||||
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
|
||||
** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
|
||||
@@ -778,9 +778,13 @@ case OP_Gosub: { /* jump */
|
||||
assert( VdbeMemDynamic(pIn1)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
pIn1->flags = MEM_Int;
|
||||
pIn1->u.i = pc;
|
||||
pIn1->u.i = (int)(pOp-aOp);
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
pc = pOp->p2 - 1;
|
||||
|
||||
/* Most jump operations do a goto to this spot in order to update
|
||||
** the pOp pointer. */
|
||||
jump_to_p2:
|
||||
pOp = &aOp[pOp->p2 - 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -792,7 +796,7 @@ case OP_Gosub: { /* jump */
|
||||
case OP_Return: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
pc = (int)pIn1->u.i;
|
||||
pOp = &aOp[pIn1->u.i];
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
@@ -816,7 +820,7 @@ case OP_InitCoroutine: { /* jump */
|
||||
assert( !VdbeMemDynamic(pOut) );
|
||||
pOut->u.i = pOp->p3 - 1;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->p2 ) pc = pOp->p2 - 1;
|
||||
if( pOp->p2 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -836,7 +840,7 @@ case OP_EndCoroutine: { /* in1 */
|
||||
pCaller = &aOp[pIn1->u.i];
|
||||
assert( pCaller->opcode==OP_Yield );
|
||||
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
|
||||
pc = pCaller->p2 - 1;
|
||||
pOp = &aOp[pCaller->p2 - 1];
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
@@ -860,9 +864,9 @@ case OP_Yield: { /* in1, jump */
|
||||
assert( VdbeMemDynamic(pIn1)==0 );
|
||||
pIn1->flags = MEM_Int;
|
||||
pcDest = (int)pIn1->u.i;
|
||||
pIn1->u.i = pc;
|
||||
pIn1->u.i = (int)(pOp - aOp);
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
pc = pcDest;
|
||||
pOp = &aOp[pcDest];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -913,30 +917,34 @@ case OP_HaltIfNull: { /* in3 */
|
||||
case OP_Halt: {
|
||||
const char *zType;
|
||||
const char *zLogFmt;
|
||||
VdbeFrame *pFrame;
|
||||
int pcx;
|
||||
|
||||
pcx = (int)(pOp - aOp);
|
||||
if( pOp->p1==SQLITE_OK && p->pFrame ){
|
||||
/* Halt the sub-program. Return control to the parent frame. */
|
||||
VdbeFrame *pFrame = p->pFrame;
|
||||
pFrame = p->pFrame;
|
||||
p->pFrame = pFrame->pParent;
|
||||
p->nFrame--;
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
pc = sqlite3VdbeFrameRestore(pFrame);
|
||||
pcx = sqlite3VdbeFrameRestore(pFrame);
|
||||
lastRowid = db->lastRowid;
|
||||
if( pOp->p2==OE_Ignore ){
|
||||
/* Instruction pc is the OP_Program that invoked the sub-program
|
||||
/* Instruction pcx is the OP_Program that invoked the sub-program
|
||||
** currently being halted. If the p2 instruction of this OP_Halt
|
||||
** instruction is set to OE_Ignore, then the sub-program is throwing
|
||||
** an IGNORE exception. In this case jump to the address specified
|
||||
** as the p2 of the calling OP_Program. */
|
||||
pc = p->aOp[pc].p2-1;
|
||||
pcx = p->aOp[pcx].p2-1;
|
||||
}
|
||||
aOp = p->aOp;
|
||||
aMem = p->aMem;
|
||||
pOp = &aOp[pcx];
|
||||
break;
|
||||
}
|
||||
p->rc = pOp->p1;
|
||||
p->errorAction = (u8)pOp->p2;
|
||||
p->pc = pc;
|
||||
p->pc = pcx;
|
||||
if( p->rc ){
|
||||
if( pOp->p5 ){
|
||||
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
|
||||
@@ -960,7 +968,7 @@ case OP_Halt: {
|
||||
}else{
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s constraint failed", zType);
|
||||
}
|
||||
sqlite3_log(pOp->p1, zLogFmt, pc, p->zSql, p->zErrMsg);
|
||||
sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
|
||||
}
|
||||
rc = sqlite3VdbeHalt(p);
|
||||
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
|
||||
@@ -971,6 +979,7 @@ case OP_Halt: {
|
||||
assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
|
||||
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
||||
}
|
||||
pOp = &aOp[pcx];
|
||||
goto vdbe_return;
|
||||
}
|
||||
|
||||
@@ -979,7 +988,8 @@ case OP_Halt: {
|
||||
**
|
||||
** The 32-bit integer value P1 is written into register P2.
|
||||
*/
|
||||
case OP_Integer: { /* out2-prerelease */
|
||||
case OP_Integer: { /* out2 */
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = pOp->p1;
|
||||
break;
|
||||
}
|
||||
@@ -990,7 +1000,8 @@ case OP_Integer: { /* out2-prerelease */
|
||||
** P4 is a pointer to a 64-bit integer value.
|
||||
** Write that value into register P2.
|
||||
*/
|
||||
case OP_Int64: { /* out2-prerelease */
|
||||
case OP_Int64: { /* out2 */
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pOp->p4.pI64!=0 );
|
||||
pOut->u.i = *pOp->p4.pI64;
|
||||
break;
|
||||
@@ -1003,7 +1014,8 @@ case OP_Int64: { /* out2-prerelease */
|
||||
** P4 is a pointer to a 64-bit floating point value.
|
||||
** Write that value into register P2.
|
||||
*/
|
||||
case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
case OP_Real: { /* same as TK_FLOAT, out2 */
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->flags = MEM_Real;
|
||||
assert( !sqlite3IsNaN(*pOp->p4.pReal) );
|
||||
pOut->u.r = *pOp->p4.pReal;
|
||||
@@ -1019,8 +1031,9 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
** this transformation, the length of string P4 is computed and stored
|
||||
** as the P1 parameter.
|
||||
*/
|
||||
case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
case OP_String8: { /* same as TK_STRING, out2 */
|
||||
assert( pOp->p4.z!=0 );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOp->opcode = OP_String;
|
||||
pOp->p1 = sqlite3Strlen30(pOp->p4.z);
|
||||
|
||||
@@ -1057,8 +1070,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
** the same sequence of bytes, it is merely interpreted as a BLOB instead
|
||||
** of a string, as if it had been CAST.
|
||||
*/
|
||||
case OP_String: { /* out2-prerelease */
|
||||
case OP_String: { /* out2 */
|
||||
assert( pOp->p4.z!=0 );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
|
||||
pOut->z = pOp->p4.z;
|
||||
pOut->n = pOp->p1;
|
||||
@@ -1086,9 +1100,10 @@ case OP_String: { /* out2-prerelease */
|
||||
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
|
||||
** OP_Ne or OP_Eq.
|
||||
*/
|
||||
case OP_Null: { /* out2-prerelease */
|
||||
case OP_Null: { /* out2 */
|
||||
int cnt;
|
||||
u16 nullFlag;
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
cnt = pOp->p3-pOp->p2;
|
||||
assert( pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
|
||||
@@ -1123,8 +1138,9 @@ case OP_SoftNull: {
|
||||
** P4 points to a blob of data P1 bytes long. Store this
|
||||
** blob in register P2.
|
||||
*/
|
||||
case OP_Blob: { /* out2-prerelease */
|
||||
case OP_Blob: { /* out2 */
|
||||
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
|
||||
pOut->enc = encoding;
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
@@ -1139,7 +1155,7 @@ case OP_Blob: { /* out2-prerelease */
|
||||
** If the parameter is named, then its name appears in P4.
|
||||
** The P4 value is used by sqlite3_bind_parameter_name().
|
||||
*/
|
||||
case OP_Variable: { /* out2-prerelease */
|
||||
case OP_Variable: { /* out2 */
|
||||
Mem *pVar; /* Value being transferred */
|
||||
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
||||
@@ -1148,6 +1164,7 @@ case OP_Variable: { /* out2-prerelease */
|
||||
if( sqlite3VdbeMemTooBig(pVar) ){
|
||||
goto too_big;
|
||||
}
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
|
||||
UPDATE_MAX_BLOBSIZE(pOut);
|
||||
break;
|
||||
@@ -1324,7 +1341,7 @@ case OP_ResultRow: {
|
||||
|
||||
/* Return SQLITE_ROW
|
||||
*/
|
||||
p->pc = pc + 1;
|
||||
p->pc = (int)(pOp - aOp) + 1;
|
||||
rc = SQLITE_ROW;
|
||||
goto vdbe_return;
|
||||
}
|
||||
@@ -1570,7 +1587,7 @@ case OP_Function: {
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF );
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
ctx.iOp = pc;
|
||||
ctx.iOp = (int)(pOp - aOp);
|
||||
ctx.pVdbe = p;
|
||||
MemSetTypeFlag(ctx.pOut, MEM_Null);
|
||||
ctx.fErrorOrAux = 0;
|
||||
@@ -1584,7 +1601,7 @@ case OP_Function: {
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(ctx.pOut));
|
||||
rc = ctx.isError;
|
||||
}
|
||||
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
|
||||
sqlite3VdbeDeleteAuxData(p, (int)(pOp - aOp), pOp->p1);
|
||||
}
|
||||
|
||||
/* Copy the result of the function into register P3 */
|
||||
@@ -1713,8 +1730,7 @@ case OP_MustBeInt: { /* jump, in1 */
|
||||
rc = SQLITE_MISMATCH;
|
||||
goto abort_due_to_error;
|
||||
}else{
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1900,7 +1916,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
}else{
|
||||
VdbeBranchTaken(2,3);
|
||||
if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
||||
pc = pOp->p2-1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1952,6 +1968,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
default: res = res>=0; break;
|
||||
}
|
||||
|
||||
/* Undo any changes made by applyAffinity() to the input registers. */
|
||||
assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
|
||||
pIn1->flags = flags1;
|
||||
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
|
||||
pIn3->flags = flags3;
|
||||
|
||||
if( pOp->p5 & SQLITE_STOREP2 ){
|
||||
pOut = &aMem[pOp->p2];
|
||||
memAboutToChange(p, pOut);
|
||||
@@ -1961,14 +1983,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
}else{
|
||||
VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
||||
if( res ){
|
||||
pc = pOp->p2-1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
}
|
||||
/* Undo any changes made by applyAffinity() to the input registers. */
|
||||
assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
|
||||
pIn1->flags = flags1;
|
||||
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
|
||||
pIn3->flags = flags3;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2063,11 +2080,11 @@ case OP_Compare: {
|
||||
*/
|
||||
case OP_Jump: { /* jump */
|
||||
if( iCompare<0 ){
|
||||
pc = pOp->p1 - 1; VdbeBranchTaken(0,3);
|
||||
VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
|
||||
}else if( iCompare==0 ){
|
||||
pc = pOp->p2 - 1; VdbeBranchTaken(1,3);
|
||||
VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
|
||||
}else{
|
||||
pc = pOp->p3 - 1; VdbeBranchTaken(2,3);
|
||||
VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2177,7 +2194,7 @@ case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
|
||||
if( p->aOnceFlag[pOp->p1] ){
|
||||
pc = pOp->p2-1;
|
||||
goto jump_to_p2;
|
||||
}else{
|
||||
p->aOnceFlag[pOp->p1] = 1;
|
||||
}
|
||||
@@ -2212,7 +2229,7 @@ case OP_IfNot: { /* jump, in1 */
|
||||
}
|
||||
VdbeBranchTaken(c!=0, 2);
|
||||
if( c ){
|
||||
pc = pOp->p2-1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2226,7 +2243,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
|
||||
if( (pIn1->flags & MEM_Null)!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2240,7 +2257,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
VdbeBranchTaken( (pIn1->flags & MEM_Null)==0, 2);
|
||||
if( (pIn1->flags & MEM_Null)==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2578,7 +2595,7 @@ case OP_MakeRecord: {
|
||||
u64 nData; /* Number of bytes of data space */
|
||||
int nHdr; /* Number of bytes of header space */
|
||||
i64 nByte; /* Data space required for this record */
|
||||
int nZero; /* Number of zero bytes at the end of the record */
|
||||
i64 nZero; /* Number of zero bytes at the end of the record */
|
||||
int nVarint; /* Number of bytes in a varint */
|
||||
u32 serial_type; /* Type field */
|
||||
Mem *pData0; /* First field to be combined into the record */
|
||||
@@ -2670,7 +2687,7 @@ case OP_MakeRecord: {
|
||||
if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++;
|
||||
}
|
||||
nByte = nHdr+nData;
|
||||
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
|
||||
@@ -2721,7 +2738,7 @@ case OP_MakeRecord: {
|
||||
** opened by cursor P1 in register P2
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
case OP_Count: { /* out2-prerelease */
|
||||
case OP_Count: { /* out2 */
|
||||
i64 nEntry;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
@@ -2729,6 +2746,7 @@ case OP_Count: { /* out2-prerelease */
|
||||
assert( pCrsr );
|
||||
nEntry = 0; /* Not needed. Only used to silence a warning. */
|
||||
rc = sqlite3BtreeCount(pCrsr, &nEntry);
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = nEntry;
|
||||
break;
|
||||
}
|
||||
@@ -2842,7 +2860,7 @@ case OP_Savepoint: {
|
||||
}
|
||||
db->autoCommit = 1;
|
||||
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
||||
p->pc = pc;
|
||||
p->pc = (int)(pOp - aOp);
|
||||
db->autoCommit = 0;
|
||||
p->rc = rc = SQLITE_BUSY;
|
||||
goto vdbe_return;
|
||||
@@ -2961,7 +2979,7 @@ case OP_AutoCommit: {
|
||||
}else{
|
||||
db->autoCommit = (u8)desiredAutoCommit;
|
||||
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
||||
p->pc = pc;
|
||||
p->pc = (int)(pOp - aOp);
|
||||
db->autoCommit = (u8)(1-desiredAutoCommit);
|
||||
p->rc = rc = SQLITE_BUSY;
|
||||
goto vdbe_return;
|
||||
@@ -3038,7 +3056,7 @@ case OP_Transaction: {
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
p->pc = pc;
|
||||
p->pc = (int)(pOp - aOp);
|
||||
p->rc = rc = SQLITE_BUSY;
|
||||
goto vdbe_return;
|
||||
}
|
||||
@@ -3117,7 +3135,7 @@ case OP_Transaction: {
|
||||
** must be started or there must be an open cursor) before
|
||||
** executing this instruction.
|
||||
*/
|
||||
case OP_ReadCookie: { /* out2-prerelease */
|
||||
case OP_ReadCookie: { /* out2 */
|
||||
int iMeta;
|
||||
int iDb;
|
||||
int iCookie;
|
||||
@@ -3131,6 +3149,7 @@ case OP_ReadCookie: { /* out2-prerelease */
|
||||
assert( DbMaskTest(p->btreeMask, iDb) );
|
||||
|
||||
sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta);
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = iMeta;
|
||||
break;
|
||||
}
|
||||
@@ -3452,7 +3471,7 @@ case OP_SequenceTest: {
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->pSorter );
|
||||
if( (pC->seqCount++)==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3629,7 +3648,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
if( (pIn3->flags & MEM_Real)==0 ){
|
||||
/* If the P3 value cannot be converted into any kind of a number,
|
||||
** then the seek is not possible, so jump to P2 */
|
||||
pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
|
||||
VdbeBranchTaken(1,2); goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3720,7 +3739,7 @@ case OP_SeekGT: { /* jump, in3 */
|
||||
assert( pOp->p2>0 );
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3814,6 +3833,7 @@ case OP_NoConflict: /* jump, in3 */
|
||||
case OP_NotFound: /* jump, in3 */
|
||||
case OP_Found: { /* jump, in3 */
|
||||
int alreadyExists;
|
||||
int takeJump;
|
||||
int ii;
|
||||
VdbeCursor *pC;
|
||||
int res;
|
||||
@@ -3836,7 +3856,7 @@ case OP_Found: { /* jump, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( pC->pCursor!=0 );
|
||||
assert( pC->isTable==0 );
|
||||
pFree = 0; /* Not needed. Only used to suppress a compiler warning. */
|
||||
pFree = 0;
|
||||
if( pOp->p4.i>0 ){
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
@@ -3859,21 +3879,20 @@ case OP_Found: { /* jump, in3 */
|
||||
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
|
||||
}
|
||||
pIdxKey->default_rc = 0;
|
||||
takeJump = 0;
|
||||
if( pOp->opcode==OP_NoConflict ){
|
||||
/* For the OP_NoConflict opcode, take the jump if any of the
|
||||
** input fields are NULL, since any key with a NULL will not
|
||||
** conflict */
|
||||
for(ii=0; ii<pIdxKey->nField; ii++){
|
||||
if( pIdxKey->aMem[ii].flags & MEM_Null ){
|
||||
pc = pOp->p2 - 1; VdbeBranchTaken(1,2);
|
||||
takeJump = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, pIdxKey, 0, 0, &res);
|
||||
if( pOp->p4.i==0 ){
|
||||
sqlite3DbFree(db, pFree);
|
||||
}
|
||||
sqlite3DbFree(db, pFree);
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
}
|
||||
@@ -3884,10 +3903,10 @@ case OP_Found: { /* jump, in3 */
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( pOp->opcode==OP_Found ){
|
||||
VdbeBranchTaken(alreadyExists!=0,2);
|
||||
if( alreadyExists ) pc = pOp->p2 - 1;
|
||||
if( alreadyExists ) goto jump_to_p2;
|
||||
}else{
|
||||
VdbeBranchTaken(alreadyExists==0,2);
|
||||
if( !alreadyExists ) pc = pOp->p2 - 1;
|
||||
VdbeBranchTaken(takeJump||alreadyExists==0,2);
|
||||
if( takeJump || !alreadyExists ) goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3936,10 +3955,8 @@ case OP_NotExists: { /* jump, in3 */
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->deferredMoveto = 0;
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
pC->seekResult = res;
|
||||
if( res!=0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3951,9 +3968,10 @@ case OP_NotExists: { /* jump, in3 */
|
||||
** The sequence number on the cursor is incremented after this
|
||||
** instruction.
|
||||
*/
|
||||
case OP_Sequence: { /* out2-prerelease */
|
||||
case OP_Sequence: { /* out2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( p->apCsr[pOp->p1]!=0 );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = p->apCsr[pOp->p1]->seqCount++;
|
||||
break;
|
||||
}
|
||||
@@ -3974,7 +3992,7 @@ case OP_Sequence: { /* out2-prerelease */
|
||||
** generated record number. This P3 mechanism is used to help implement the
|
||||
** AUTOINCREMENT feature.
|
||||
*/
|
||||
case OP_NewRowid: { /* out2-prerelease */
|
||||
case OP_NewRowid: { /* out2 */
|
||||
i64 v; /* The new rowid */
|
||||
VdbeCursor *pC; /* Cursor of table to get the new rowid */
|
||||
int res; /* Result of an sqlite3BtreeLast() */
|
||||
@@ -3984,6 +4002,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
|
||||
v = 0;
|
||||
res = 0;
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -4297,9 +4316,7 @@ case OP_SorterCompare: {
|
||||
res = 0;
|
||||
rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ){
|
||||
pc = pOp->p2-1;
|
||||
}
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -4428,12 +4445,13 @@ case OP_RowData: {
|
||||
** be a separate OP_VRowid opcode for use with virtual tables, but this
|
||||
** one opcode now works for both table types.
|
||||
*/
|
||||
case OP_Rowid: { /* out2-prerelease */
|
||||
case OP_Rowid: { /* out2 */
|
||||
VdbeCursor *pC;
|
||||
i64 v;
|
||||
sqlite3_vtab *pVtab;
|
||||
const sqlite3_module *pModule;
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -4486,7 +4504,7 @@ case OP_NullRow: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Last P1 P2 * * *
|
||||
/* Opcode: Last P1 P2 P3 * *
|
||||
**
|
||||
** The next use of the Rowid or Column or Prev instruction for P1
|
||||
** will refer to the last entry in the database table or index.
|
||||
@@ -4513,12 +4531,13 @@ case OP_Last: { /* jump */
|
||||
pC->nullRow = (u8)res;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->seekResult = pOp->p3;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pC->seekOp = OP_Last;
|
||||
#endif
|
||||
if( pOp->p2>0 ){
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) pc = pOp->p2 - 1;
|
||||
if( res ) goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4582,9 +4601,7 @@ case OP_Rewind: { /* jump */
|
||||
pC->nullRow = (u8)res;
|
||||
assert( pOp->p2>0 && pOp->p2<p->nOp );
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4695,11 +4712,11 @@ next_tail:
|
||||
VdbeBranchTaken(res==0,2);
|
||||
if( res==0 ){
|
||||
pC->nullRow = 0;
|
||||
pc = pOp->p2 - 1;
|
||||
p->aCounter[pOp->p5]++;
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_search_count++;
|
||||
#endif
|
||||
goto jump_to_p2_and_check_for_interrupt;
|
||||
}else{
|
||||
pC->nullRow = 1;
|
||||
}
|
||||
@@ -4807,11 +4824,12 @@ case OP_IdxDelete: {
|
||||
**
|
||||
** See also: Rowid, MakeRecord.
|
||||
*/
|
||||
case OP_IdxRowid: { /* out2-prerelease */
|
||||
case OP_IdxRowid: { /* out2 */
|
||||
BtCursor *pCrsr;
|
||||
VdbeCursor *pC;
|
||||
i64 rowid;
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
@@ -4924,9 +4942,7 @@ case OP_IdxGE: { /* jump */
|
||||
res++;
|
||||
}
|
||||
VdbeBranchTaken(res>0,2);
|
||||
if( res>0 ){
|
||||
pc = pOp->p2 - 1 ;
|
||||
}
|
||||
if( res>0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4950,11 +4966,12 @@ case OP_IdxGE: { /* jump */
|
||||
**
|
||||
** See also: Clear
|
||||
*/
|
||||
case OP_Destroy: { /* out2-prerelease */
|
||||
case OP_Destroy: { /* out2 */
|
||||
int iMoved;
|
||||
int iDb;
|
||||
|
||||
assert( p->readOnly==0 );
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->flags = MEM_Null;
|
||||
if( db->nVdbeRead > db->nVDestroy+1 ){
|
||||
rc = SQLITE_LOCKED;
|
||||
@@ -5063,12 +5080,13 @@ case OP_ResetSorter: {
|
||||
**
|
||||
** See documentation on OP_CreateTable for additional information.
|
||||
*/
|
||||
case OP_CreateIndex: /* out2-prerelease */
|
||||
case OP_CreateTable: { /* out2-prerelease */
|
||||
case OP_CreateIndex: /* out2 */
|
||||
case OP_CreateTable: { /* out2 */
|
||||
int pgno;
|
||||
int flags;
|
||||
Db *pDb;
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pgno = 0;
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
||||
@@ -5294,12 +5312,12 @@ case OP_RowSetRead: { /* jump, in1, out3 */
|
||||
){
|
||||
/* The boolean index is empty */
|
||||
sqlite3VdbeMemSetNull(pIn1);
|
||||
pc = pOp->p2 - 1;
|
||||
VdbeBranchTaken(1,2);
|
||||
goto jump_to_p2_and_check_for_interrupt;
|
||||
}else{
|
||||
/* A value was pulled from the index */
|
||||
sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val);
|
||||
VdbeBranchTaken(0,2);
|
||||
sqlite3VdbeMemSetInt64(&aMem[pOp->p3], val);
|
||||
}
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
@@ -5350,10 +5368,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
if( iSet ){
|
||||
exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
|
||||
VdbeBranchTaken(exists!=0,2);
|
||||
if( exists ){
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
if( exists ) goto jump_to_p2;
|
||||
}
|
||||
if( iSet>=0 ){
|
||||
sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
|
||||
@@ -5442,7 +5457,7 @@ case OP_Program: { /* jump */
|
||||
pFrame->v = p;
|
||||
pFrame->nChildMem = nMem;
|
||||
pFrame->nChildCsr = pProgram->nCsr;
|
||||
pFrame->pc = pc;
|
||||
pFrame->pc = (int)(pOp - aOp);
|
||||
pFrame->aMem = p->aMem;
|
||||
pFrame->nMem = p->nMem;
|
||||
pFrame->apCsr = p->apCsr;
|
||||
@@ -5465,7 +5480,7 @@ case OP_Program: { /* jump */
|
||||
pFrame = pRt->u.pFrame;
|
||||
assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
|
||||
assert( pProgram->nCsr==pFrame->nChildCsr );
|
||||
assert( pc==pFrame->pc );
|
||||
assert( (int)(pOp - aOp)==pFrame->pc );
|
||||
}
|
||||
|
||||
p->nFrame++;
|
||||
@@ -5486,7 +5501,7 @@ case OP_Program: { /* jump */
|
||||
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
||||
p->anExec = 0;
|
||||
#endif
|
||||
pc = -1;
|
||||
pOp = &aOp[-1];
|
||||
memset(p->aOnceFlag, 0, p->nOnceFlag);
|
||||
|
||||
break;
|
||||
@@ -5504,9 +5519,10 @@ case OP_Program: { /* jump */
|
||||
** the value of the P1 argument to the value of the P1 argument to the
|
||||
** calling OP_Program instruction.
|
||||
*/
|
||||
case OP_Param: { /* out2-prerelease */
|
||||
case OP_Param: { /* out2 */
|
||||
VdbeFrame *pFrame;
|
||||
Mem *pIn;
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pFrame = p->pFrame;
|
||||
pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
|
||||
sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
|
||||
@@ -5550,10 +5566,10 @@ case OP_FkCounter: {
|
||||
case OP_FkIfZero: { /* jump */
|
||||
if( pOp->p1 ){
|
||||
VdbeBranchTaken(db->nDeferredCons==0 && db->nDeferredImmCons==0, 2);
|
||||
if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
|
||||
if( db->nDeferredCons==0 && db->nDeferredImmCons==0 ) goto jump_to_p2;
|
||||
}else{
|
||||
VdbeBranchTaken(p->nFkConstraint==0 && db->nDeferredImmCons==0, 2);
|
||||
if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) pc = pOp->p2-1;
|
||||
if( p->nFkConstraint==0 && db->nDeferredImmCons==0 ) goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5604,9 +5620,7 @@ case OP_IfPos: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
VdbeBranchTaken( pIn1->u.i>0, 2);
|
||||
if( pIn1->u.i>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
if( pIn1->u.i>0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5621,9 +5635,7 @@ case OP_IfNeg: { /* jump, in1 */
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
pIn1->u.i += pOp->p3;
|
||||
VdbeBranchTaken(pIn1->u.i<0, 2);
|
||||
if( pIn1->u.i<0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
if( pIn1->u.i<0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5640,7 +5652,7 @@ case OP_IfNotZero: { /* jump, in1 */
|
||||
VdbeBranchTaken(pIn1->u.i<0, 2);
|
||||
if( pIn1->u.i ){
|
||||
pIn1->u.i += pOp->p3;
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5656,9 +5668,7 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
pIn1->u.i--;
|
||||
VdbeBranchTaken(pIn1->u.i==0, 2);
|
||||
if( pIn1->u.i==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
if( pIn1->u.i==0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5674,9 +5684,7 @@ case OP_JumpZeroIncr: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
VdbeBranchTaken(pIn1->u.i==0, 2);
|
||||
if( (pIn1->u.i++)==0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
if( (pIn1->u.i++)==0 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5718,7 +5726,7 @@ case OP_AggStep: {
|
||||
ctx.pOut = &t;
|
||||
ctx.isError = 0;
|
||||
ctx.pVdbe = p;
|
||||
ctx.iOp = pc;
|
||||
ctx.iOp = (int)(pOp - aOp);
|
||||
ctx.skipFlag = 0;
|
||||
(ctx.pFunc->xStep)(&ctx, n, apVal); /* IMP: R-24505-23230 */
|
||||
if( ctx.isError ){
|
||||
@@ -5813,7 +5821,7 @@ case OP_Checkpoint: {
|
||||
**
|
||||
** Write a string containing the final journal-mode to register P2.
|
||||
*/
|
||||
case OP_JournalMode: { /* out2-prerelease */
|
||||
case OP_JournalMode: { /* out2 */
|
||||
Btree *pBt; /* Btree to change journal mode of */
|
||||
Pager *pPager; /* Pager associated with pBt */
|
||||
int eNew; /* New journal mode */
|
||||
@@ -5822,6 +5830,7 @@ case OP_JournalMode: { /* out2-prerelease */
|
||||
const char *zFilename; /* Name of database file for pPager */
|
||||
#endif
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
eNew = pOp->p3;
|
||||
assert( eNew==PAGER_JOURNALMODE_DELETE
|
||||
|| eNew==PAGER_JOURNALMODE_TRUNCATE
|
||||
@@ -5938,8 +5947,8 @@ case OP_IncrVacuum: { /* jump */
|
||||
rc = sqlite3BtreeIncrVacuum(pBt);
|
||||
VdbeBranchTaken(rc==SQLITE_DONE,2);
|
||||
if( rc==SQLITE_DONE ){
|
||||
pc = pOp->p2 - 1;
|
||||
rc = SQLITE_OK;
|
||||
goto jump_to_p2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -6149,25 +6158,19 @@ case OP_VFilter: { /* jump */
|
||||
iQuery = (int)pQuery->u.i;
|
||||
|
||||
/* Invoke the xFilter method */
|
||||
{
|
||||
res = 0;
|
||||
apArg = p->apArg;
|
||||
for(i = 0; i<nArg; i++){
|
||||
apArg[i] = &pArgc[i+1];
|
||||
}
|
||||
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
}
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
res = 0;
|
||||
apArg = p->apArg;
|
||||
for(i = 0; i<nArg; i++){
|
||||
apArg[i] = &pArgc[i+1];
|
||||
}
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
sqlite3VtabImportErrmsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
}
|
||||
pCur->nullRow = 0;
|
||||
|
||||
VdbeBranchTaken(res!=0,2);
|
||||
if( res ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -6254,7 +6257,7 @@ case OP_VNext: { /* jump */
|
||||
VdbeBranchTaken(!res,2);
|
||||
if( !res ){
|
||||
/* If there is data, jump to P2 */
|
||||
pc = pOp->p2 - 1;
|
||||
goto jump_to_p2_and_check_for_interrupt;
|
||||
}
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
@@ -6377,7 +6380,8 @@ case OP_VUpdate: {
|
||||
**
|
||||
** Write the current number of pages in database P1 to memory cell P2.
|
||||
*/
|
||||
case OP_Pagecount: { /* out2-prerelease */
|
||||
case OP_Pagecount: { /* out2 */
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
|
||||
break;
|
||||
}
|
||||
@@ -6393,10 +6397,11 @@ case OP_Pagecount: { /* out2-prerelease */
|
||||
**
|
||||
** Store the maximum page count after the change in register P2.
|
||||
*/
|
||||
case OP_MaxPgcnt: { /* out2-prerelease */
|
||||
case OP_MaxPgcnt: { /* out2 */
|
||||
unsigned int newMax;
|
||||
Btree *pBt;
|
||||
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
newMax = 0;
|
||||
if( pOp->p3 ){
|
||||
@@ -6425,9 +6430,6 @@ case OP_Init: { /* jump */
|
||||
char *zTrace;
|
||||
char *z;
|
||||
|
||||
if( pOp->p2 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xTrace
|
||||
&& !p->doingRerun
|
||||
@@ -6455,6 +6457,7 @@ case OP_Init: { /* jump */
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
if( pOp->p2 ) goto jump_to_p2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6497,12 +6500,12 @@ default: { /* This is really OP_Noop and OP_Explain */
|
||||
** the evaluator loop. So we can leave it out when NDEBUG is defined.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
assert( pc>=-1 && pc<p->nOp );
|
||||
assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp] );
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( db->flags & SQLITE_VdbeTrace ){
|
||||
if( rc!=0 ) printf("rc=%d\n",rc);
|
||||
if( pOp->opflags & (OPFLG_OUT2_PRERELEASE|OPFLG_OUT2) ){
|
||||
if( pOp->opflags & (OPFLG_OUT2) ){
|
||||
registerTrace(pOp->p2, &aMem[pOp->p2]);
|
||||
}
|
||||
if( pOp->opflags & OPFLG_OUT3 ){
|
||||
@@ -6521,7 +6524,7 @@ vdbe_error_halt:
|
||||
p->rc = rc;
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
||||
pc, p->zSql, p->zErrMsg);
|
||||
(int)(pOp - aOp), p->zSql, p->zErrMsg);
|
||||
sqlite3VdbeHalt(p);
|
||||
if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1;
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
@@ -213,6 +213,7 @@ int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
|
||||
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
|
||||
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
|
||||
|
||||
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
|
||||
|
||||
@@ -3585,7 +3585,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
||||
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
||||
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
||||
*/
|
||||
static int vdbeRecordCompareWithSkip(
|
||||
int sqlite3VdbeRecordCompareWithSkip(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2, /* Right key */
|
||||
int bSkip /* If true, skip the first field */
|
||||
@@ -3771,7 +3771,7 @@ int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
return vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
||||
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -3859,7 +3859,7 @@ static int vdbeRecordCompareInt(
|
||||
}else if( pPKey2->nField>1 ){
|
||||
/* The first fields of the two keys are equal. Compare the trailing
|
||||
** fields. */
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
/* The first fields of the two keys are equal and there are no trailing
|
||||
** fields. Return pPKey2->default_rc in this case. */
|
||||
@@ -3907,7 +3907,7 @@ static int vdbeRecordCompareString(
|
||||
res = nStr - pPKey2->aMem[0].n;
|
||||
if( res==0 ){
|
||||
if( pPKey2->nField>1 ){
|
||||
res = vdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
||||
}else{
|
||||
res = pPKey2->default_rc;
|
||||
}
|
||||
|
||||
232
src/vdbesort.c
232
src/vdbesort.c
@@ -291,6 +291,7 @@ struct MergeEngine {
|
||||
** after the thread has finished are not dire. So we don't worry about
|
||||
** memory barriers and such here.
|
||||
*/
|
||||
typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
|
||||
struct SortSubtask {
|
||||
SQLiteThread *pThread; /* Background thread, if any */
|
||||
int bDone; /* Set if thread is finished but not joined */
|
||||
@@ -298,10 +299,12 @@ struct SortSubtask {
|
||||
UnpackedRecord *pUnpacked; /* Space to unpack a record */
|
||||
SorterList list; /* List for thread to write to a PMA */
|
||||
int nPMA; /* Number of PMAs currently in file */
|
||||
SorterCompare xCompare; /* Compare function to use */
|
||||
SorterFile file; /* Temp file for level-0 PMAs */
|
||||
SorterFile file2; /* Space for other PMAs */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Main sorter structure. A single instance of this is allocated for each
|
||||
** sorter cursor created by the VDBE.
|
||||
@@ -328,9 +331,13 @@ struct VdbeSorter {
|
||||
u8 bUseThreads; /* True to use background threads */
|
||||
u8 iPrev; /* Previous thread used to flush PMA */
|
||||
u8 nTask; /* Size of aTask[] array */
|
||||
u8 typeMask;
|
||||
SortSubtask aTask[1]; /* One or more subtasks */
|
||||
};
|
||||
|
||||
#define SORTER_TYPE_INTEGER 0x01
|
||||
#define SORTER_TYPE_TEXT 0x02
|
||||
|
||||
/*
|
||||
** An instance of the following object is used to read records out of a
|
||||
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
|
||||
@@ -742,32 +749,162 @@ static int vdbePmaReaderInit(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** A version of vdbeSorterCompare() that assumes that it has already been
|
||||
** determined that the first field of key1 is equal to the first field of
|
||||
** key2.
|
||||
*/
|
||||
static int vdbeSorterCompareTail(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
UnpackedRecord *r2 = pTask->pUnpacked;
|
||||
if( *pbKey2Cached==0 ){
|
||||
sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
|
||||
*pbKey2Cached = 1;
|
||||
}
|
||||
return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
|
||||
** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
|
||||
** used by the comparison. Return the result of the comparison.
|
||||
**
|
||||
** Before returning, object (pTask->pUnpacked) is populated with the
|
||||
** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it
|
||||
** is assumed that the (pTask->pUnpacked) structure already contains the
|
||||
** unpacked key to use as key2.
|
||||
** If IN/OUT parameter *pbKey2Cached is true when this function is called,
|
||||
** it is assumed that (pTask->pUnpacked) contains the unpacked version
|
||||
** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked
|
||||
** version of key2 and *pbKey2Cached set to true before returning.
|
||||
**
|
||||
** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set
|
||||
** to SQLITE_NOMEM.
|
||||
*/
|
||||
static int vdbeSorterCompare(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
UnpackedRecord *r2 = pTask->pUnpacked;
|
||||
if( pKey2 ){
|
||||
if( !*pbKey2Cached ){
|
||||
sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2);
|
||||
*pbKey2Cached = 1;
|
||||
}
|
||||
return sqlite3VdbeRecordCompare(nKey1, pKey1, r2);
|
||||
}
|
||||
|
||||
/*
|
||||
** A specially optimized version of vdbeSorterCompare() that assumes that
|
||||
** the first field of each key is a TEXT value and that the collation
|
||||
** sequence to compare them with is BINARY.
|
||||
*/
|
||||
static int vdbeSorterCompareText(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
const u8 * const p1 = (const u8 * const)pKey1;
|
||||
const u8 * const p2 = (const u8 * const)pKey2;
|
||||
const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
|
||||
const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
int res;
|
||||
|
||||
getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
|
||||
getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
|
||||
res = memcmp(v1, v2, MIN(n1, n2));
|
||||
if( res==0 ){
|
||||
res = n1 - n2;
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
}
|
||||
}else{
|
||||
if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
res = res * -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** A specially optimized version of vdbeSorterCompare() that assumes that
|
||||
** the first field of each key is an INTEGER value.
|
||||
*/
|
||||
static int vdbeSorterCompareInt(
|
||||
SortSubtask *pTask, /* Subtask context (for pKeyInfo) */
|
||||
int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */
|
||||
const void *pKey1, int nKey1, /* Left side of comparison */
|
||||
const void *pKey2, int nKey2 /* Right side of comparison */
|
||||
){
|
||||
const u8 * const p1 = (const u8 * const)pKey1;
|
||||
const u8 * const p2 = (const u8 * const)pKey2;
|
||||
const int s1 = p1[1]; /* Left hand serial type */
|
||||
const int s2 = p2[1]; /* Right hand serial type */
|
||||
const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */
|
||||
const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */
|
||||
int res; /* Return value */
|
||||
|
||||
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
|
||||
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
|
||||
|
||||
if( s1>7 && s2>7 ){
|
||||
res = s1 - s2;
|
||||
}else{
|
||||
if( s1==s2 ){
|
||||
if( (*v1 ^ *v2) & 0x80 ){
|
||||
/* The two values have different signs */
|
||||
res = (*v1 & 0x80) ? -1 : +1;
|
||||
}else{
|
||||
/* The two values have the same sign. Compare using memcmp(). */
|
||||
static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
|
||||
int i;
|
||||
res = 0;
|
||||
for(i=0; i<aLen[s1]; i++){
|
||||
if( (res = v1[i] - v2[i]) ) break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( s2>7 ){
|
||||
res = +1;
|
||||
}else if( s1>7 ){
|
||||
res = -1;
|
||||
}else{
|
||||
res = s1 - s2;
|
||||
}
|
||||
assert( res!=0 );
|
||||
|
||||
if( res>0 ){
|
||||
if( *v1 & 0x80 ) res = -1;
|
||||
}else{
|
||||
if( *v2 & 0x80 ) res = +1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( res==0 ){
|
||||
if( pTask->pSorter->pKeyInfo->nField>1 ){
|
||||
res = vdbeSorterCompareTail(
|
||||
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
|
||||
);
|
||||
}
|
||||
}else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
|
||||
res = res * -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the temporary index cursor just opened as a sorter cursor.
|
||||
**
|
||||
@@ -835,9 +972,13 @@ int sqlite3VdbeSorterInit(
|
||||
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
|
||||
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
|
||||
pKeyInfo->db = 0;
|
||||
if( nField && nWorker==0 ) pKeyInfo->nField = nField;
|
||||
if( nField && nWorker==0 ){
|
||||
pKeyInfo->nXField += (pKeyInfo->nField - nField);
|
||||
pKeyInfo->nField = nField;
|
||||
}
|
||||
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
|
||||
pSorter->nTask = nWorker + 1;
|
||||
pSorter->iPrev = nWorker-1;
|
||||
pSorter->bUseThreads = (pSorter->nTask>1);
|
||||
pSorter->db = db;
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
@@ -863,6 +1004,12 @@ int sqlite3VdbeSorterInit(
|
||||
if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( (pKeyInfo->nField+pKeyInfo->nXField)<13
|
||||
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
|
||||
){
|
||||
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -887,30 +1034,24 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
|
||||
*/
|
||||
static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){
|
||||
sqlite3DbFree(db, pTask->pUnpacked);
|
||||
pTask->pUnpacked = 0;
|
||||
#if SQLITE_MAX_WORKER_THREADS>0
|
||||
/* pTask->list.aMemory can only be non-zero if it was handed memory
|
||||
** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */
|
||||
if( pTask->list.aMemory ){
|
||||
sqlite3_free(pTask->list.aMemory);
|
||||
pTask->list.aMemory = 0;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
assert( pTask->list.aMemory==0 );
|
||||
vdbeSorterRecordFree(0, pTask->list.pList);
|
||||
}
|
||||
pTask->list.pList = 0;
|
||||
if( pTask->file.pFd ){
|
||||
sqlite3OsCloseFree(pTask->file.pFd);
|
||||
pTask->file.pFd = 0;
|
||||
pTask->file.iEof = 0;
|
||||
}
|
||||
if( pTask->file2.pFd ){
|
||||
sqlite3OsCloseFree(pTask->file2.pFd);
|
||||
pTask->file2.pFd = 0;
|
||||
pTask->file2.iEof = 0;
|
||||
}
|
||||
memset(pTask, 0, sizeof(SortSubtask));
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG_SORTER_THREADS
|
||||
@@ -1090,6 +1231,7 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
SortSubtask *pTask = &pSorter->aTask[i];
|
||||
vdbeSortSubtaskCleanup(db, pTask);
|
||||
pTask->pSorter = pSorter;
|
||||
}
|
||||
if( pSorter->list.aMemory==0 ){
|
||||
vdbeSorterRecordFree(0, pSorter->list.pList);
|
||||
@@ -1199,28 +1341,42 @@ static void vdbeSorterMerge(
|
||||
){
|
||||
SorterRecord *pFinal = 0;
|
||||
SorterRecord **pp = &pFinal;
|
||||
void *pVal2 = p2 ? SRVAL(p2) : 0;
|
||||
int bCached = 0;
|
||||
|
||||
while( p1 && p2 ){
|
||||
int res;
|
||||
res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal);
|
||||
res = pTask->xCompare(
|
||||
pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
|
||||
);
|
||||
|
||||
if( res<=0 ){
|
||||
*pp = p1;
|
||||
pp = &p1->u.pNext;
|
||||
p1 = p1->u.pNext;
|
||||
pVal2 = 0;
|
||||
}else{
|
||||
*pp = p2;
|
||||
pp = &p2->u.pNext;
|
||||
pp = &p2->u.pNext;
|
||||
p2 = p2->u.pNext;
|
||||
if( p2==0 ) break;
|
||||
pVal2 = SRVAL(p2);
|
||||
bCached = 0;
|
||||
}
|
||||
}
|
||||
*pp = p1 ? p1 : p2;
|
||||
*ppOut = pFinal;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the SorterCompare function to compare values collected by the
|
||||
** sorter object passed as the only argument.
|
||||
*/
|
||||
static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
|
||||
if( p->typeMask==SORTER_TYPE_INTEGER ){
|
||||
return vdbeSorterCompareInt;
|
||||
}else if( p->typeMask==SORTER_TYPE_TEXT ){
|
||||
return vdbeSorterCompareText;
|
||||
}
|
||||
return vdbeSorterCompare;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sort the linked list of records headed at pTask->pList. Return
|
||||
** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
|
||||
@@ -1235,12 +1391,14 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
|
||||
rc = vdbeSortAllocUnpacked(pTask);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
p = pList->pList;
|
||||
pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
|
||||
|
||||
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
|
||||
if( !aSlot ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
|
||||
p = pList->pList;
|
||||
while( p ){
|
||||
SorterRecord *pNext;
|
||||
if( pList->aMemory ){
|
||||
@@ -1454,13 +1612,12 @@ static int vdbeMergeEngineStep(
|
||||
int i; /* Index of aTree[] to recalculate */
|
||||
PmaReader *pReadr1; /* First PmaReader to compare */
|
||||
PmaReader *pReadr2; /* Second PmaReader to compare */
|
||||
u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */
|
||||
int bCached = 0;
|
||||
|
||||
/* Find the first two PmaReaders to compare. The one that was just
|
||||
** advanced (iPrev) and the one next to it in the array. */
|
||||
pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)];
|
||||
pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)];
|
||||
pKey2 = pReadr2->aKey;
|
||||
|
||||
for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){
|
||||
/* Compare pReadr1 and pReadr2. Store the result in variable iRes. */
|
||||
@@ -1470,8 +1627,8 @@ static int vdbeMergeEngineStep(
|
||||
}else if( pReadr2->pFd==0 ){
|
||||
iRes = -1;
|
||||
}else{
|
||||
iRes = vdbeSorterCompare(pTask,
|
||||
pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey
|
||||
iRes = pTask->xCompare(pTask, &bCached,
|
||||
pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1493,9 +1650,9 @@ static int vdbeMergeEngineStep(
|
||||
if( iRes<0 || (iRes==0 && pReadr1<pReadr2) ){
|
||||
pMerger->aTree[i] = (int)(pReadr1 - pMerger->aReadr);
|
||||
pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
|
||||
pKey2 = pReadr2->aKey;
|
||||
bCached = 0;
|
||||
}else{
|
||||
if( pReadr1->pFd ) pKey2 = 0;
|
||||
if( pReadr1->pFd ) bCached = 0;
|
||||
pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr);
|
||||
pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ];
|
||||
}
|
||||
@@ -1602,6 +1759,16 @@ int sqlite3VdbeSorterWrite(
|
||||
int bFlush; /* True to flush contents of memory to PMA */
|
||||
int nReq; /* Bytes of memory required */
|
||||
int nPMA; /* Bytes of PMA space required */
|
||||
int t; /* serial type of first record field */
|
||||
|
||||
getVarint32((const u8*)&pVal->z[1], t);
|
||||
if( t>0 && t<10 && t!=7 ){
|
||||
pSorter->typeMask &= SORTER_TYPE_INTEGER;
|
||||
}else if( t>10 && (t & 0x01) ){
|
||||
pSorter->typeMask &= SORTER_TYPE_TEXT;
|
||||
}else{
|
||||
pSorter->typeMask = 0;
|
||||
}
|
||||
|
||||
assert( pSorter );
|
||||
|
||||
@@ -1867,10 +2034,12 @@ static void vdbeMergeEngineCompare(
|
||||
}else if( p2->pFd==0 ){
|
||||
iRes = i1;
|
||||
}else{
|
||||
SortSubtask *pTask = pMerger->pTask;
|
||||
int bCached = 0;
|
||||
int res;
|
||||
assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */
|
||||
res = vdbeSorterCompare(
|
||||
pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey
|
||||
assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */
|
||||
res = pTask->xCompare(
|
||||
pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey
|
||||
);
|
||||
if( res<=0 ){
|
||||
iRes = i1;
|
||||
@@ -2288,6 +2457,11 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
|
||||
MergeEngine *pMain = 0;
|
||||
#if SQLITE_MAX_WORKER_THREADS
|
||||
sqlite3 *db = pTask0->pSorter->db;
|
||||
int i;
|
||||
SorterCompare xCompare = vdbeSorterGetCompare(pSorter);
|
||||
for(i=0; i<pSorter->nTask; i++){
|
||||
pSorter->aTask[i].xCompare = xCompare;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
|
||||
|
||||
34
src/vtab.c
34
src/vtab.c
@@ -24,6 +24,8 @@
|
||||
struct VtabCtx {
|
||||
VTable *pVTable; /* The virtual table being constructed */
|
||||
Table *pTab; /* The Table object to which the virtual table belongs */
|
||||
VtabCtx *pPrior; /* Parent context (if any) */
|
||||
int bDeclared; /* True after sqlite3_declare_vtab() is called */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -487,15 +489,27 @@ static int vtabCallConstructor(
|
||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||
char **pzErr
|
||||
){
|
||||
VtabCtx sCtx, *pPriorCtx;
|
||||
VtabCtx sCtx;
|
||||
VTable *pVTable;
|
||||
int rc;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
int nArg = pTab->nModuleArg;
|
||||
char *zErr = 0;
|
||||
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
char *zModuleName;
|
||||
int iDb;
|
||||
VtabCtx *pCtx;
|
||||
|
||||
/* Check that the virtual-table is not already being initialized */
|
||||
for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
|
||||
if( pCtx->pTab==pTab ){
|
||||
*pzErr = sqlite3MPrintf(db,
|
||||
"vtable constructor called recursively: %s", pTab->zName
|
||||
);
|
||||
return SQLITE_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
if( !zModuleName ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@@ -516,11 +530,13 @@ static int vtabCallConstructor(
|
||||
assert( xConstruct );
|
||||
sCtx.pTab = pTab;
|
||||
sCtx.pVTable = pVTable;
|
||||
pPriorCtx = db->pVtabCtx;
|
||||
sCtx.pPrior = db->pVtabCtx;
|
||||
sCtx.bDeclared = 0;
|
||||
db->pVtabCtx = &sCtx;
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
db->pVtabCtx = pPriorCtx;
|
||||
db->pVtabCtx = sCtx.pPrior;
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
assert( sCtx.pTab==pTab );
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( zErr==0 ){
|
||||
@@ -536,7 +552,7 @@ static int vtabCallConstructor(
|
||||
memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
|
||||
pVTable->pVtab->pModule = pMod->pModule;
|
||||
pVTable->nRef = 1;
|
||||
if( sCtx.pTab ){
|
||||
if( sCtx.bDeclared==0 ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||
sqlite3VtabUnlock(pVTable);
|
||||
@@ -706,8 +722,8 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
** virtual table module.
|
||||
*/
|
||||
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
VtabCtx *pCtx;
|
||||
Parse *pParse;
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
Table *pTab;
|
||||
char *zErr = 0;
|
||||
@@ -718,11 +734,13 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
}
|
||||
#endif
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
|
||||
pCtx = db->pVtabCtx;
|
||||
if( !pCtx || pCtx->bDeclared ){
|
||||
sqlite3Error(db, SQLITE_MISUSE);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
pTab = pCtx->pTab;
|
||||
assert( (pTab->tabFlags & TF_Virtual)!=0 );
|
||||
|
||||
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
||||
@@ -745,7 +763,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pParse->pNewTable->nCol = 0;
|
||||
pParse->pNewTable->aCol = 0;
|
||||
}
|
||||
db->pVtabCtx->pTab = 0;
|
||||
pCtx->bDeclared = 1;
|
||||
}else{
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
|
||||
@@ -1730,6 +1730,14 @@ static int walCheckpoint(
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
/* Thread-sanitizer reports that the following is an unsafe read,
|
||||
** as some other thread may be in the process of updating the value
|
||||
** of the aReadMark[] slot. The assumption here is that if that is
|
||||
** happening, the other client may only be increasing the value,
|
||||
** not decreasing it. So assuming either that either the "old" or
|
||||
** "new" version of the value is read, and not some arbitrary value
|
||||
** that would never be written by a real client, things are still
|
||||
** safe. */
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
|
||||
@@ -1534,7 +1534,7 @@ static int findIndexCol(
|
||||
&& p->iTable==iBase
|
||||
){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
||||
if( ALWAYS(pColl) && 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -1808,7 +1808,7 @@ static void constructAutomaticIndex(
|
||||
idxCols |= cMask;
|
||||
pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
||||
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
|
||||
pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY";
|
||||
pIdx->azColl[n] = pColl ? pColl->zName : "BINARY";
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@@ -4786,7 +4786,7 @@ static int whereLoopAddBtreeIndex(
|
||||
}else if( eOp & (WO_EQ) ){
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
|
||||
if( iCol>=0 && !IsUniqueIndex(pProbe) ){
|
||||
if( iCol>=0 && pProbe->uniqNotNull==0 ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
@@ -6245,7 +6245,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
||||
pWInfo->revMask = pFrom->revLoop;
|
||||
}
|
||||
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
|
||||
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr
|
||||
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
|
||||
){
|
||||
Bitmask revMask = 0;
|
||||
int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
|
||||
|
||||
Reference in New Issue
Block a user