mirror of
https://github.com/php/php-src.git
synced 2025-08-20 09:24:05 +02:00
Update bundled library to version 2.8.2.
Make OnUpdateInt compatible with ZE2. Fix the makefile fragment for non-gnu makes
This commit is contained in:
parent
82a1818fde
commit
80e7f7001d
42 changed files with 11143 additions and 7558 deletions
|
@ -79,6 +79,11 @@ typedef unsigned char Bool;
|
|||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
**
|
||||
** If the Cursor.isTriggerRow flag is set it means that this cursor is
|
||||
** really a single row that represents the NEW or OLD pseudo-table of
|
||||
** a row trigger. The data for the row is stored in Cursor.pData and
|
||||
** the rowid is in Cursor.iKey.
|
||||
*/
|
||||
struct Cursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
|
@ -90,7 +95,11 @@ struct Cursor {
|
|||
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
|
||||
Bool nullRow; /* True if pointing to a row with no data */
|
||||
Bool nextRowidValid; /* True if the nextRowid field is valid */
|
||||
Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
int nData; /* Number of bytes in pData */
|
||||
char *pData; /* Data for a NEW or OLD pseudo-table */
|
||||
int iKey; /* Key for the NEW or OLD pseudo-table row */
|
||||
};
|
||||
typedef struct Cursor Cursor;
|
||||
|
||||
|
@ -243,7 +252,6 @@ struct Keylist {
|
|||
struct Vdbe {
|
||||
sqlite *db; /* The whole database */
|
||||
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
||||
Btree *pBt; /* Opaque context structure used by DB backend */
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
int nOp; /* Number of instructions in the program */
|
||||
int nOpAlloc; /* Number of slots allocated for aOp[] */
|
||||
|
@ -315,7 +323,6 @@ Vdbe *sqliteVdbeCreate(sqlite *db){
|
|||
Vdbe *p;
|
||||
p = sqliteMalloc( sizeof(Vdbe) );
|
||||
if( p==0 ) return 0;
|
||||
p->pBt = db->pBe;
|
||||
p->db = db;
|
||||
if( db->pVdbe ){
|
||||
db->pVdbe->pPrev = p;
|
||||
|
@ -478,6 +485,7 @@ int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
|
|||
return addr;
|
||||
}
|
||||
|
||||
#if 0 /* NOT USED */
|
||||
/*
|
||||
** Change the value of the P1 operand for a specific instruction.
|
||||
** This routine is useful when a large program is loaded from a
|
||||
|
@ -490,6 +498,7 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
|
|||
p->aOp[addr].p1 = val;
|
||||
}
|
||||
}
|
||||
#endif /* NOT USED */
|
||||
|
||||
/*
|
||||
** Change the value of the P2 operand for a specific instruction.
|
||||
|
@ -605,17 +614,26 @@ void sqliteVdbeCompressSpace(Vdbe *p, int addr){
|
|||
|
||||
/*
|
||||
** Search for the current program for the given opcode and P2
|
||||
** value. Return 1 if found and 0 if not found.
|
||||
** value. Return the address plus 1 if found and 0 if not found.
|
||||
*/
|
||||
int sqliteVdbeFindOp(Vdbe *p, int op, int p2){
|
||||
int i;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
for(i=0; i<p->nOp; i++){
|
||||
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return 1;
|
||||
if( p->aOp[i].opcode==op && p->aOp[i].p2==p2 ) return i+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the opcode for a given address.
|
||||
*/
|
||||
VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( addr>=0 && addr<p->nOp );
|
||||
return &p->aOp[addr];
|
||||
}
|
||||
|
||||
/*
|
||||
** The following group or routines are employed by installable functions
|
||||
** to return their results.
|
||||
|
@ -994,6 +1012,7 @@ static int toInt(const char *zNum, int *pNum){
|
|||
}else{
|
||||
neg = 0;
|
||||
}
|
||||
if( *zNum==0 ) return 0;
|
||||
while( isdigit(*zNum) ){
|
||||
v = v*10 + *zNum - '0';
|
||||
zNum++;
|
||||
|
@ -1072,27 +1091,6 @@ static void PopStack(Vdbe *p, int N){
|
|||
if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \
|
||||
p->tos--;
|
||||
|
||||
/*
|
||||
** Return TRUE if zNum is a floating-point or integer number.
|
||||
*/
|
||||
static int isNumber(const char *zNum){
|
||||
if( *zNum=='-' || *zNum=='+' ) zNum++;
|
||||
if( !isdigit(*zNum) ) return 0;
|
||||
while( isdigit(*zNum) ) zNum++;
|
||||
if( *zNum==0 ) return 1;
|
||||
if( *zNum!='.' ) return 0;
|
||||
zNum++;
|
||||
if( !isdigit(*zNum) ) return 0;
|
||||
while( isdigit(*zNum) ) zNum++;
|
||||
if( *zNum==0 ) return 1;
|
||||
if( *zNum!='e' && *zNum!='E' ) return 0;
|
||||
zNum++;
|
||||
if( *zNum=='-' || *zNum=='+' ) zNum++;
|
||||
if( !isdigit(*zNum) ) return 0;
|
||||
while( isdigit(*zNum) ) zNum++;
|
||||
return *zNum==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete a keylist
|
||||
*/
|
||||
|
@ -1115,6 +1113,7 @@ static void cleanupCursor(Cursor *pCx){
|
|||
if( pCx->pBt ){
|
||||
sqliteBtreeClose(pCx->pBt);
|
||||
}
|
||||
sqliteFree(pCx->pData);
|
||||
memset(pCx, 0, sizeof(Cursor));
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1299,7 @@ int sqliteVdbeList(
|
|||
p->rc = SQLITE_MISUSE;
|
||||
}
|
||||
}
|
||||
return p->rc==SQLITE_OK ? SQLITE_OK : SQLITE_ERROR;
|
||||
return p->rc==SQLITE_OK ? SQLITE_DONE : SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1498,6 +1497,9 @@ void sqliteVdbeMakeReady(
|
|||
int isExplain /* True if the EXPLAIN keywords is present */
|
||||
){
|
||||
int n;
|
||||
#ifdef MEMORY_DEBUG
|
||||
extern int access(const char*,int);
|
||||
#endif
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->aStack==0 );
|
||||
|
@ -1569,8 +1571,8 @@ void sqliteVdbeMakeReady(
|
|||
** immediately. There will be no error message but the p->rc field is
|
||||
** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
|
||||
**
|
||||
** A memory allocation error causes p->rc to be set SQLITE_NOMEM and this
|
||||
** routien to return SQLITE_ERROR.
|
||||
** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
|
||||
** routine to return SQLITE_ERROR.
|
||||
**
|
||||
** Other fatal errors return SQLITE_ERROR.
|
||||
**
|
||||
|
@ -1583,7 +1585,6 @@ int sqliteVdbeExec(
|
|||
int pc; /* The program counter */
|
||||
Op *pOp; /* Current operation */
|
||||
int rc = SQLITE_OK; /* Value to return */
|
||||
Btree *pBt = p->pBt; /* The backend driver */
|
||||
sqlite *db = p->db; /* The database */
|
||||
char **zStack = p->zStack; /* Text stack */
|
||||
Stack *aStack = p->aStack; /* Additional stack information */
|
||||
|
@ -1893,6 +1894,7 @@ case OP_Push: {
|
|||
** to all column names is passed as the 4th parameter to the callback.
|
||||
*/
|
||||
case OP_ColumnName: {
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nOp );
|
||||
p->azColName[pOp->p1] = pOp->p3;
|
||||
p->nCallback = 0;
|
||||
break;
|
||||
|
@ -3061,7 +3063,7 @@ case OP_MakeKey: {
|
|||
Stringify(p, i);
|
||||
aStack[i].flags &= ~(STK_Int|STK_Real);
|
||||
nByte += aStack[i].n+1;
|
||||
}else if( (flags & (STK_Real|STK_Int))!=0 || isNumber(zStack[i]) ){
|
||||
}else if( (flags & (STK_Real|STK_Int))!=0 || sqliteIsNumber(zStack[i]) ){
|
||||
if( (flags & (STK_Real|STK_Int))==STK_Int ){
|
||||
aStack[i].r = aStack[i].i;
|
||||
}else if( (flags & (STK_Real|STK_Int))==0 ){
|
||||
|
@ -3153,17 +3155,21 @@ case OP_IncrKey: {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Checkpoint * * *
|
||||
/* Opcode: Checkpoint P1 * *
|
||||
**
|
||||
** Begin a checkpoint. A checkpoint is the beginning of a operation that
|
||||
** is part of a larger transaction but which might need to be rolled back
|
||||
** itself without effecting the containing transaction. A checkpoint will
|
||||
** be automatically committed or rollback when the VDBE halts.
|
||||
**
|
||||
** The checkpoint is begun on the database file with index P1. The main
|
||||
** database file has an index of 0 and the file used for temporary tables
|
||||
** has an index of 1.
|
||||
*/
|
||||
case OP_Checkpoint: {
|
||||
rc = sqliteBtreeBeginCkpt(pBt);
|
||||
if( rc==SQLITE_OK && db->pBeTemp ){
|
||||
rc = sqliteBtreeBeginCkpt(db->pBeTemp);
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<db->nDb && db->aDb[i].pBt ){
|
||||
rc = sqliteBtreeBeginCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3174,10 +3180,9 @@ case OP_Checkpoint: {
|
|||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
** transaction might also be rolled back if an error is encountered.
|
||||
**
|
||||
** If P1 is true, then the transaction is started on the temporary
|
||||
** tables of the database only. The main database file is not write
|
||||
** locked and other processes can continue to read the main database
|
||||
** file.
|
||||
** P1 is the index of the database file on which the transaction is
|
||||
** started. Index 0 is the main database file and index 1 is the
|
||||
** file used for temporary tables.
|
||||
**
|
||||
** A write lock is obtained on the database file when a transaction is
|
||||
** started. No other process can read or write the file while the
|
||||
|
@ -3187,15 +3192,11 @@ case OP_Checkpoint: {
|
|||
*/
|
||||
case OP_Transaction: {
|
||||
int busy = 1;
|
||||
if( db->pBeTemp && !p->inTempTrans ){
|
||||
rc = sqliteBtreeBeginTrans(db->pBeTemp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
p->inTempTrans = 1;
|
||||
}
|
||||
while( pOp->p1==0 && busy ){
|
||||
rc = sqliteBtreeBeginTrans(pBt);
|
||||
int i = pOp->p1;
|
||||
assert( i>=0 && i<db->nDb );
|
||||
if( db->aDb[i].inTrans ) break;
|
||||
while( db->aDb[i].pBt!=0 && busy ){
|
||||
rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
|
||||
switch( rc ){
|
||||
case SQLITE_BUSY: {
|
||||
if( db->xBusyCallback==0 ){
|
||||
|
@ -3223,6 +3224,7 @@ case OP_Transaction: {
|
|||
}
|
||||
}
|
||||
}
|
||||
db->aDb[i].inTrans = 1;
|
||||
p->undoTransOnError = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -3236,53 +3238,47 @@ case OP_Transaction: {
|
|||
** A read lock continues to be held if there are still cursors open.
|
||||
*/
|
||||
case OP_Commit: {
|
||||
if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
|
||||
rc = p->inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
if( db->aDb[i].inTrans ){
|
||||
rc = sqliteBtreeCommit(db->aDb[i].pBt);
|
||||
db->aDb[i].inTrans = 0;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqliteCommitInternalChanges(db);
|
||||
}else{
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
sqliteRollbackAll(db);
|
||||
}
|
||||
p->inTempTrans = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Rollback * * *
|
||||
/* Opcode: Rollback P1 * *
|
||||
**
|
||||
** Cause all modifications to the database that have been made since the
|
||||
** last Transaction to be undone. The database is restored to its state
|
||||
** before the Transaction opcode was executed. No additional modifications
|
||||
** are allowed until another transaction is started.
|
||||
**
|
||||
** P1 is the index of the database file that is committed. An index of 0
|
||||
** is used for the main database and an index of 1 is used for the file used
|
||||
** to hold temporary tables.
|
||||
**
|
||||
** This instruction automatically closes all cursors and releases both
|
||||
** the read and write locks on the database.
|
||||
** the read and write locks on the indicated database.
|
||||
*/
|
||||
case OP_Rollback: {
|
||||
if( db->pBeTemp ){
|
||||
sqliteBtreeRollback(db->pBeTemp);
|
||||
}
|
||||
rc = sqliteBtreeRollback(pBt);
|
||||
sqliteRollbackInternalChanges(db);
|
||||
sqliteRollbackAll(db);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ReadCookie * P2 *
|
||||
/* Opcode: ReadCookie P1 P2 *
|
||||
**
|
||||
** When P2==0,
|
||||
** read the schema cookie from the database file and push it onto the
|
||||
** stack. The schema cookie is an integer that is used like a version
|
||||
** number for the database schema. Everytime the schema changes, the
|
||||
** cookie changes to a new random value. This opcode is used during
|
||||
** initialization to read the initial cookie value so that subsequent
|
||||
** database accesses can verify that the cookie has not changed.
|
||||
**
|
||||
** If P2>0, then read global database parameter number P2. There is
|
||||
** a small fixed number of global database parameters. P2==1 is the
|
||||
** database version number. P2==2 is the recommended pager cache size.
|
||||
** Other parameters are currently unused.
|
||||
** Read cookie number P2 from database P1 and push it onto the stack.
|
||||
** P2==0 is the schema version. P2==1 is the database format.
|
||||
** P2==2 is the recommended pager cache size, and so forth. P1==0 is
|
||||
** the main database file and P1==1 is the database file used to store
|
||||
** temporary tables.
|
||||
**
|
||||
** There must be a read-lock on the database (either a transaction
|
||||
** must be started or there must be an open cursor) before
|
||||
|
@ -3292,36 +3288,35 @@ case OP_ReadCookie: {
|
|||
int i = ++p->tos;
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( db->aDb[pOp->p1].pBt!=0 );
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
aStack[i].i = aMeta[1+pOp->p2];
|
||||
aStack[i].flags = STK_Int;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SetCookie * P2 *
|
||||
/* Opcode: SetCookie P1 P2 *
|
||||
**
|
||||
** When P2==0,
|
||||
** this operation changes the value of the schema cookie on the database.
|
||||
** The new value is top of the stack.
|
||||
** When P2>0, the value of global database parameter
|
||||
** number P2 is changed. See ReadCookie for more information about
|
||||
** global database parametes.
|
||||
**
|
||||
** The schema cookie changes its value whenever the database schema changes.
|
||||
** That way, other processes can recognize when the schema has changed
|
||||
** and reread it.
|
||||
** Write the top of the stack into cookie number P2 of database P1.
|
||||
** P2==0 is the schema version. P2==1 is the database format.
|
||||
** P2==2 is the recommended pager cache size, and so forth. P1==0 is
|
||||
** the main database file and P1==1 is the database file used to store
|
||||
** temporary tables.
|
||||
**
|
||||
** A transaction must be started before executing this opcode.
|
||||
*/
|
||||
case OP_SetCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( db->aDb[pOp->p1].pBt!=0 );
|
||||
VERIFY( if( p->tos<0 ) goto not_enough_stack; )
|
||||
Integerify(p, p->tos)
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
if( rc==SQLITE_OK ){
|
||||
aMeta[1+pOp->p2] = aStack[p->tos].i;
|
||||
rc = sqliteBtreeUpdateMeta(pBt, aMeta);
|
||||
rc = sqliteBtreeUpdateMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
|
@ -3329,10 +3324,11 @@ case OP_SetCookie: {
|
|||
|
||||
/* Opcode: VerifyCookie P1 P2 *
|
||||
**
|
||||
** Check the value of global database parameter number P2 and make
|
||||
** sure it is equal to P1. P2==0 is the schema cookie. P1==1 is
|
||||
** the database version. If the values do not match, abort with
|
||||
** an SQLITE_SCHEMA error.
|
||||
** Check the value of global database parameter number 0 (the
|
||||
** schema version) and make sure it is equal to P2.
|
||||
** P1 is the database number which is 0 for the main database file
|
||||
** and 1 for the file holding temporary tables and some higher number
|
||||
** for auxiliary databases.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
|
@ -3344,23 +3340,26 @@ case OP_SetCookie: {
|
|||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int aMeta[SQLITE_N_BTREE_META];
|
||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
||||
rc = sqliteBtreeGetMeta(pBt, aMeta);
|
||||
if( rc==SQLITE_OK && aMeta[1+pOp->p2]!=pOp->p1 ){
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
rc = sqliteBtreeGetMeta(db->aDb[pOp->p1].pBt, aMeta);
|
||||
if( rc==SQLITE_OK && aMeta[1]!=pOp->p2 ){
|
||||
sqliteSetString(&p->zErrMsg, "database schema has changed", 0);
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Open P1 P2 P3
|
||||
/* Opcode: OpenRead P1 P2 P3
|
||||
**
|
||||
** Open a read-only cursor for the database table whose root page is
|
||||
** P2 in the main database file. Give the new cursor an identifier
|
||||
** of P1. The P1 values need not be contiguous but all P1 values
|
||||
** should be small integers. It is an error for P1 to be negative.
|
||||
** P2 in a database file. The database file is determined by an
|
||||
** integer from the top of the stack. 0 means the main database and
|
||||
** 1 means the database used for temporary tables. Give the new
|
||||
** cursor an identifier of P1. The P1 values need not be contiguous
|
||||
** but all P1 values should be small integers. It is an error for
|
||||
** P1 to be negative.
|
||||
**
|
||||
** If P2==0 then take the root page number from the top of the stack.
|
||||
** If P2==0 then take the root page number from the next of the stack.
|
||||
**
|
||||
** There will be a read lock on the database whenever there is an
|
||||
** open cursor. If the database was unlocked prior to this instruction
|
||||
|
@ -3376,52 +3375,39 @@ case OP_VerifyCookie: {
|
|||
** omitted. But the code generator usually inserts the index or
|
||||
** table name into P3 to make the code easier to read.
|
||||
**
|
||||
** See also OpenAux and OpenWrite.
|
||||
*/
|
||||
/* Opcode: OpenAux P1 P2 P3
|
||||
**
|
||||
** Open a read-only cursor in the auxiliary table set. This opcode
|
||||
** works exactly like OP_Open except that it opens the cursor on the
|
||||
** auxiliary table set (the file used to store tables created using
|
||||
** CREATE TEMPORARY TABLE) instead of in the main database file.
|
||||
** See OP_Open for additional information.
|
||||
** See also OpenWrite.
|
||||
*/
|
||||
/* Opcode: OpenWrite P1 P2 P3
|
||||
**
|
||||
** Open a read/write cursor named P1 on the table or index whose root
|
||||
** page is P2. If P2==0 then take the root page number from the stack.
|
||||
**
|
||||
** This instruction works just like Open except that it opens the cursor
|
||||
** This instruction works just like OpenRead except that it opens the cursor
|
||||
** in read/write mode. For a given table, there can be one or more read-only
|
||||
** cursors or a single read/write cursor but not both.
|
||||
**
|
||||
** See also OpWrAux.
|
||||
** See also OpenRead.
|
||||
*/
|
||||
/* Opcode: OpenWrAux P1 P2 P3
|
||||
**
|
||||
** Open a read/write cursor in the auxiliary table set. This opcode works
|
||||
** just like OpenWrite except that the auxiliary table set (the file used
|
||||
** to store tables created using CREATE TEMPORARY TABLE) is used in place
|
||||
** of the main database file.
|
||||
*/
|
||||
case OP_OpenAux:
|
||||
case OP_OpenWrAux:
|
||||
case OP_OpenWrite:
|
||||
case OP_Open: {
|
||||
case OP_OpenRead:
|
||||
case OP_OpenWrite: {
|
||||
int busy = 0;
|
||||
int i = pOp->p1;
|
||||
int tos = p->tos;
|
||||
int p2 = pOp->p2;
|
||||
int wrFlag;
|
||||
Btree *pX;
|
||||
switch( pOp->opcode ){
|
||||
case OP_Open: wrFlag = 0; pX = pBt; break;
|
||||
case OP_OpenWrite: wrFlag = 1; pX = pBt; break;
|
||||
case OP_OpenAux: wrFlag = 0; pX = db->pBeTemp; break;
|
||||
case OP_OpenWrAux: wrFlag = 1; pX = db->pBeTemp; break;
|
||||
}
|
||||
int iDb;
|
||||
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; );
|
||||
Integerify(p, tos);
|
||||
iDb = p->aStack[tos].i;
|
||||
tos--;
|
||||
VERIFY( if( iDb<0 || iDb>=db->nDb ) goto bad_instruction; );
|
||||
VERIFY( if( db->aDb[iDb].pBt==0 ) goto bad_instruction; );
|
||||
pX = db->aDb[iDb].pBt;
|
||||
wrFlag = pOp->opcode==OP_OpenWrite;
|
||||
if( p2<=0 ){
|
||||
if( tos<0 ) goto not_enough_stack;
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; );
|
||||
Integerify(p, tos);
|
||||
p2 = p->aStack[tos].i;
|
||||
POPSTACK;
|
||||
|
@ -3463,15 +3449,16 @@ case OP_Open: {
|
|||
if( p2<=0 ){
|
||||
POPSTACK;
|
||||
}
|
||||
POPSTACK;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenTemp P1 P2 *
|
||||
**
|
||||
** Open a new cursor that points to a table or index in a temporary
|
||||
** database file. The temporary file is opened read/write even if
|
||||
** the main database is read-only. The temporary file is deleted
|
||||
** when the cursor is closed.
|
||||
** Open a new cursor to a transient table.
|
||||
** The transient cursor is always opened read/write even if
|
||||
** the main database is read-only. The transient table is deleted
|
||||
** automatically when the cursor is closed.
|
||||
**
|
||||
** The cursor points to a BTree table if P2==0 and to a BTree index
|
||||
** if P2==1. A BTree table must have an integer key and can have arbitrary
|
||||
|
@ -3479,7 +3466,7 @@ case OP_Open: {
|
|||
**
|
||||
** This opcode is used for tables that exist for the duration of a single
|
||||
** SQL statement only. Tables created using CREATE TEMPORARY TABLE
|
||||
** are opened using OP_OpenAux or OP_OpenWrAux. "Temporary" in the
|
||||
** are opened using OP_OpenRead or OP_OpenWrite. "Temporary" in the
|
||||
** context of this opcode means for the duration of a single SQL statement
|
||||
** whereas "Temporary" in the context of CREATE TABLE means for the duration
|
||||
** of the connection to the database. Same word; different meanings.
|
||||
|
@ -3493,7 +3480,8 @@ case OP_OpenTemp: {
|
|||
cleanupCursor(pCx);
|
||||
memset(pCx, 0, sizeof(*pCx));
|
||||
pCx->nullRow = 1;
|
||||
rc = sqliteBtreeOpen(0, 1, TEMP_PAGES, &pCx->pBt);
|
||||
rc = sqliteBtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqliteBtreeBeginTrans(pCx->pBt);
|
||||
}
|
||||
|
@ -3511,24 +3499,26 @@ case OP_OpenTemp: {
|
|||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Opcode: RenameCursor P1 P2 *
|
||||
/* Opcode: OpenPseudo P1 * *
|
||||
**
|
||||
** Rename cursor number P1 as cursor number P2. If P2 was previously
|
||||
** opened is is closed before the renaming occurs.
|
||||
** Open a new cursor that points to a fake table that contains a single
|
||||
** row of data. Any attempt to write a second row of data causes the
|
||||
** first row to be deleted. All data is deleted when the cursor is
|
||||
** closed.
|
||||
**
|
||||
** A pseudo-table created by this opcode is useful for holding the
|
||||
** NEW or OLD tables in a trigger.
|
||||
*/
|
||||
case OP_RenameCursor: {
|
||||
int from = pOp->p1;
|
||||
int to = pOp->p2;
|
||||
VERIFY( if( from<0 || to<0 ) goto bad_instruction; )
|
||||
if( to<p->nCursor && p->aCsr[to].pCursor ){
|
||||
cleanupCursor(&p->aCsr[to]);
|
||||
}
|
||||
expandCursorArraySize(p, to);
|
||||
if( from<p->nCursor ){
|
||||
memcpy(&p->aCsr[to], &p->aCsr[from], sizeof(p->aCsr[0]));
|
||||
memset(&p->aCsr[from], 0, sizeof(p->aCsr[0]));
|
||||
}
|
||||
case OP_OpenPseudo: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pCx;
|
||||
VERIFY( if( i<0 ) goto bad_instruction; )
|
||||
if( expandCursorArraySize(p, i) ) goto no_mem;
|
||||
pCx = &p->aCsr[i];
|
||||
cleanupCursor(pCx);
|
||||
memset(pCx, 0, sizeof(*pCx));
|
||||
pCx->nullRow = 1;
|
||||
pCx->pseudoTable = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3539,7 +3529,7 @@ case OP_RenameCursor: {
|
|||
*/
|
||||
case OP_Close: {
|
||||
int i = pOp->p1;
|
||||
if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
|
||||
if( i>=0 && i<p->nCursor ){
|
||||
cleanupCursor(&p->aCsr[i]);
|
||||
}
|
||||
break;
|
||||
|
@ -3573,7 +3563,9 @@ case OP_MoveTo: {
|
|||
Cursor *pC;
|
||||
|
||||
VERIFY( if( tos<0 ) goto not_enough_stack; )
|
||||
if( i>=0 && i<p->nCursor && (pC = &p->aCsr[i])->pCursor!=0 ){
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pC = &p->aCsr[i];
|
||||
if( pC->pCursor!=0 ){
|
||||
int res, oc;
|
||||
if( aStack[tos].flags & STK_Int ){
|
||||
int iKey = intToKey(aStack[tos].i);
|
||||
|
@ -3905,7 +3897,8 @@ case OP_NewRecno: {
|
|||
** be an integer. The stack is popped twice by this instruction.
|
||||
**
|
||||
** If P2==1 then the row change count is incremented. If P2==0 the
|
||||
** row change count is unmodified.
|
||||
** row change count is unmodified. The rowid is stored for subsequent
|
||||
** return by the sqlite_last_insert_rowid() function if P2 is 1.
|
||||
*/
|
||||
/* Opcode: PutStrKey P1 * *
|
||||
**
|
||||
|
@ -3914,6 +3907,8 @@ case OP_NewRecno: {
|
|||
** entry is overwritten. The data is the value on the top of the
|
||||
** stack. The key is the next value down on the stack. The key must
|
||||
** be a string. The stack is popped twice by this instruction.
|
||||
**
|
||||
** P1 may not be a pseudo-table opened using the OpenPseudo opcode.
|
||||
*/
|
||||
case OP_PutIntKey:
|
||||
case OP_PutStrKey: {
|
||||
|
@ -3922,7 +3917,8 @@ case OP_PutStrKey: {
|
|||
int i = pOp->p1;
|
||||
Cursor *pC;
|
||||
VERIFY( if( nos<0 ) goto not_enough_stack; )
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
|
||||
if( VERIFY( i>=0 && i<p->nCursor && )
|
||||
((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
|
||||
char *zKey;
|
||||
int nKey, iKey;
|
||||
if( pOp->opcode==OP_PutStrKey ){
|
||||
|
@ -3934,14 +3930,38 @@ case OP_PutStrKey: {
|
|||
nKey = sizeof(int);
|
||||
iKey = intToKey(aStack[nos].i);
|
||||
zKey = (char*)&iKey;
|
||||
db->lastRowid = aStack[nos].i;
|
||||
if( pOp->p2 ) db->nChange++;
|
||||
if( pOp->p2 ){
|
||||
db->nChange++;
|
||||
db->lastRowid = aStack[nos].i;
|
||||
}
|
||||
if( pC->nextRowidValid && aStack[nos].i>=pC->nextRowid ){
|
||||
pC->nextRowidValid = 0;
|
||||
}
|
||||
}
|
||||
rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey,
|
||||
zStack[tos], aStack[tos].n);
|
||||
if( pC->pseudoTable ){
|
||||
/* PutStrKey does not work for pseudo-tables.
|
||||
** The following assert makes sure we are not trying to use
|
||||
** PutStrKey on a pseudo-table
|
||||
*/
|
||||
assert( pOp->opcode==OP_PutIntKey );
|
||||
sqliteFree(pC->pData);
|
||||
pC->iKey = iKey;
|
||||
pC->nData = aStack[tos].n;
|
||||
if( aStack[tos].flags & STK_Dyn ){
|
||||
pC->pData = zStack[tos];
|
||||
zStack[tos] = 0;
|
||||
aStack[tos].flags = STK_Null;
|
||||
}else{
|
||||
pC->pData = sqliteMallocRaw( pC->nData );
|
||||
if( pC->pData ){
|
||||
memcpy(pC->pData, zStack[tos], pC->nData);
|
||||
}
|
||||
}
|
||||
pC->nullRow = 0;
|
||||
}else{
|
||||
rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey,
|
||||
zStack[tos], aStack[tos].n);
|
||||
}
|
||||
pC->recnoIsValid = 0;
|
||||
}
|
||||
POPSTACK;
|
||||
|
@ -3960,11 +3980,15 @@ case OP_PutStrKey: {
|
|||
**
|
||||
** The row change counter is incremented if P2==1 and is unmodified
|
||||
** if P2==0.
|
||||
**
|
||||
** If P1 is a pseudo-table, then this instruction is a no-op.
|
||||
*/
|
||||
case OP_Delete: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pC;
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pC = &p->aCsr[i];
|
||||
if( pC->pCursor!=0 ){
|
||||
rc = sqliteBtreeDelete(pC->pCursor);
|
||||
pC->nextRowidValid = 0;
|
||||
}
|
||||
|
@ -3975,14 +3999,67 @@ case OP_Delete: {
|
|||
/* Opcode: KeyAsData P1 P2 *
|
||||
**
|
||||
** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
|
||||
** off (if P2==0). In key-as-data mode, the Field opcode pulls
|
||||
** data off of the key rather than the data. This is useful for
|
||||
** off (if P2==0). In key-as-data mode, the OP_Column opcode pulls
|
||||
** data off of the key rather than the data. This is used for
|
||||
** processing compound selects.
|
||||
*/
|
||||
case OP_KeyAsData: {
|
||||
int i = pOp->p1;
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
|
||||
p->aCsr[i].keyAsData = pOp->p2;
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
p->aCsr[i].keyAsData = pOp->p2;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: RowData P1 * *
|
||||
**
|
||||
** Push onto the stack the complete row data for cursor P1.
|
||||
** There is no interpretation of the data. It is just copied
|
||||
** onto the stack exactly as it is found in the database file.
|
||||
**
|
||||
** If the cursor is not pointing to a valid row, a NULL is pushed
|
||||
** onto the stack.
|
||||
*/
|
||||
case OP_RowData: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
Cursor *pC;
|
||||
int n;
|
||||
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pC = &p->aCsr[i];
|
||||
if( pC->nullRow ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
}else if( pC->pCursor!=0 ){
|
||||
BtCursor *pCrsr = pC->pCursor;
|
||||
if( pC->nullRow ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}else if( pC->keyAsData ){
|
||||
sqliteBtreeKeySize(pCrsr, &n);
|
||||
}else{
|
||||
sqliteBtreeDataSize(pCrsr, &n);
|
||||
}
|
||||
aStack[tos].n = n;
|
||||
if( n<=NBFS ){
|
||||
aStack[tos].flags = STK_Str;
|
||||
zStack[tos] = aStack[tos].z;
|
||||
}else{
|
||||
char *z = sqliteMallocRaw( n );
|
||||
if( z==0 ) goto no_mem;
|
||||
aStack[tos].flags = STK_Str | STK_Dyn;
|
||||
zStack[tos] = z;
|
||||
}
|
||||
if( pC->keyAsData ){
|
||||
sqliteBtreeKey(pCrsr, 0, n, zStack[tos]);
|
||||
}else{
|
||||
sqliteBtreeData(pCrsr, 0, n, zStack[tos]);
|
||||
}
|
||||
}else if( pC->pseudoTable ){
|
||||
aStack[tos].n = pC->nData;
|
||||
zStack[tos] = pC->pData;
|
||||
aStack[tos].flags = STK_Str|STK_Ephem;
|
||||
}else{
|
||||
aStack[tos].flags = STK_Null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4017,12 +4094,13 @@ case OP_Column: {
|
|||
int idxWidth;
|
||||
unsigned char aHdr[10];
|
||||
|
||||
assert( i<p->nCursor );
|
||||
if( i<0 ){
|
||||
VERIFY( if( tos+i<0 ) goto bad_instruction; )
|
||||
VERIFY( if( (aStack[tos+i].flags & STK_Str)==0 ) goto bad_instruction; )
|
||||
zRec = zStack[tos+i];
|
||||
payloadSize = aStack[tos+i].n;
|
||||
}else if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
|
||||
}else if( (pC = &p->aCsr[i])->pCursor!=0 ){
|
||||
zRec = 0;
|
||||
pCrsr = pC->pCursor;
|
||||
if( pC->nullRow ){
|
||||
|
@ -4032,6 +4110,10 @@ case OP_Column: {
|
|||
}else{
|
||||
sqliteBtreeDataSize(pCrsr, &payloadSize);
|
||||
}
|
||||
}else if( pC->pseudoTable ){
|
||||
payloadSize = pC->nData;
|
||||
zRec = pC->pData;
|
||||
assert( payloadSize==0 || zRec!=0 );
|
||||
}else{
|
||||
payloadSize = 0;
|
||||
}
|
||||
|
@ -4121,22 +4203,24 @@ case OP_Column: {
|
|||
case OP_Recno: {
|
||||
int i = pOp->p1;
|
||||
int tos = ++p->tos;
|
||||
BtCursor *pCrsr;
|
||||
Cursor *pC;
|
||||
int v;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int v;
|
||||
if( p->aCsr[i].recnoIsValid ){
|
||||
v = p->aCsr[i].lastRecno;
|
||||
}else if( p->aCsr[i].nullRow ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}else{
|
||||
sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v);
|
||||
v = keyToInt(v);
|
||||
}
|
||||
aStack[tos].i = v;
|
||||
aStack[tos].flags = STK_Int;
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
if( (pC = &p->aCsr[i])->recnoIsValid ){
|
||||
v = pC->lastRecno;
|
||||
}else if( pC->nullRow ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
break;
|
||||
}else if( pC->pseudoTable ){
|
||||
v = keyToInt(pC->iKey);
|
||||
}else{
|
||||
assert( pC->pCursor!=0 );
|
||||
sqliteBtreeKey(pC->pCursor, 0, sizeof(u32), (char*)&v);
|
||||
v = keyToInt(v);
|
||||
}
|
||||
aStack[tos].i = v;
|
||||
aStack[tos].flags = STK_Int;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4148,6 +4232,8 @@ case OP_Recno: {
|
|||
** Compare this opcode to Recno. The Recno opcode extracts the first
|
||||
** 4 bytes of the key and pushes those bytes onto the stack as an
|
||||
** integer. This instruction pushes the entire key as a string.
|
||||
**
|
||||
** This opcode may not be used on a pseudo-table.
|
||||
*/
|
||||
case OP_FullKey: {
|
||||
int i = pOp->p1;
|
||||
|
@ -4155,6 +4241,7 @@ case OP_FullKey: {
|
|||
BtCursor *pCrsr;
|
||||
|
||||
VERIFY( if( !p->aCsr[i].keyAsData ) goto bad_instruction; )
|
||||
VERIFY( if( p->aCsr[i].pseudoTable ) goto bad_instruction; )
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
int amt;
|
||||
char *z;
|
||||
|
@ -4187,11 +4274,10 @@ case OP_FullKey: {
|
|||
*/
|
||||
case OP_NullRow: {
|
||||
int i = pOp->p1;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
p->aCsr[i].nullRow = 1;
|
||||
}
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
p->aCsr[i].nullRow = 1;
|
||||
p->aCsr[i].recnoIsValid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4205,15 +4291,20 @@ case OP_NullRow: {
|
|||
*/
|
||||
case OP_Last: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pC = &p->aCsr[i];
|
||||
if( (pCrsr = pC->pCursor)!=0 ){
|
||||
int res;
|
||||
sqliteBtreeLast(pCrsr, &res);
|
||||
rc = sqliteBtreeLast(pCrsr, &res);
|
||||
p->aCsr[i].nullRow = res;
|
||||
if( res && pOp->p2>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
}else{
|
||||
pC->nullRow = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4228,16 +4319,21 @@ case OP_Last: {
|
|||
*/
|
||||
case OP_Rewind: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
|
||||
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
pC = &p->aCsr[i];
|
||||
if( (pCrsr = pC->pCursor)!=0 ){
|
||||
int res;
|
||||
sqliteBtreeFirst(pCrsr, &res);
|
||||
p->aCsr[i].atFirst = res==0;
|
||||
p->aCsr[i].nullRow = res;
|
||||
rc = sqliteBtreeFirst(pCrsr, &res);
|
||||
pC->atFirst = res==0;
|
||||
pC->nullRow = res;
|
||||
if( res && pOp->p2>0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
}else{
|
||||
pC->nullRow = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4264,8 +4360,9 @@ case OP_Next: {
|
|||
BtCursor *pCrsr;
|
||||
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( VERIFY( pOp->p1>=0 && pOp->p1<p->nCursor && )
|
||||
(pCrsr = (pC = &p->aCsr[pOp->p1])->pCursor)!=0 ){
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = &p->aCsr[pOp->p1];
|
||||
if( (pCrsr = pC->pCursor)!=0 ){
|
||||
int res;
|
||||
if( pC->nullRow ){
|
||||
res = 1;
|
||||
|
@ -4278,8 +4375,10 @@ case OP_Next: {
|
|||
pc = pOp->p2 - 1;
|
||||
sqlite_search_count++;
|
||||
}
|
||||
pC->recnoIsValid = 0;
|
||||
}else{
|
||||
pC->nullRow = 1;
|
||||
}
|
||||
pC->recnoIsValid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4373,10 +4472,14 @@ case OP_IdxRecno: {
|
|||
int v;
|
||||
int sz;
|
||||
sqliteBtreeKeySize(pCrsr, &sz);
|
||||
sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
|
||||
v = keyToInt(v);
|
||||
aStack[tos].i = v;
|
||||
aStack[tos].flags = STK_Int;
|
||||
if( sz<sizeof(u32) ){
|
||||
aStack[tos].flags = STK_Null;
|
||||
}else{
|
||||
sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
|
||||
v = keyToInt(v);
|
||||
aStack[tos].i = v;
|
||||
aStack[tos].flags = STK_Int;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4446,7 +4549,7 @@ case OP_IdxGE: {
|
|||
** See also: Clear
|
||||
*/
|
||||
case OP_Destroy: {
|
||||
sqliteBtreeDropTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4463,7 +4566,7 @@ case OP_Destroy: {
|
|||
** See also: Destroy
|
||||
*/
|
||||
case OP_Clear: {
|
||||
sqliteBtreeClearTable(pOp->p2 ? db->pBeTemp : pBt, pOp->p1);
|
||||
rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4497,10 +4600,12 @@ case OP_CreateTable: {
|
|||
int i = ++p->tos;
|
||||
int pgno;
|
||||
assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
|
||||
assert( pOp->p2>=0 && pOp->p2<db->nDb );
|
||||
assert( db->aDb[pOp->p2].pBt!=0 );
|
||||
if( pOp->opcode==OP_CreateTable ){
|
||||
rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
rc = sqliteBtreeCreateTable(db->aDb[pOp->p2].pBt, &pgno);
|
||||
}else{
|
||||
rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno);
|
||||
rc = sqliteBtreeCreateIndex(db->aDb[pOp->p2].pBt, &pgno);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
aStack[i].i = pgno;
|
||||
|
@ -4544,7 +4649,7 @@ case OP_IntegrityCk: {
|
|||
toInt((char*)sqliteHashKey(i), &aRoot[j]);
|
||||
}
|
||||
aRoot[j] = 0;
|
||||
z = sqliteBtreeIntegrityCheck(pOp->p2 ? db->pBeTemp : pBt, aRoot, nRoot);
|
||||
z = sqliteBtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
|
||||
if( z==0 || z[0]==0 ){
|
||||
if( z ) sqliteFree(z);
|
||||
zStack[tos] = "ok";
|
||||
|
@ -5669,8 +5774,7 @@ bad_instruction:
|
|||
*/
|
||||
int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
||||
sqlite *db = p->db;
|
||||
Btree *pBt = p->pBt;
|
||||
int rc;
|
||||
int i, rc;
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
|
||||
|
@ -5689,23 +5793,24 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
|||
switch( p->errorAction ){
|
||||
case OE_Abort: {
|
||||
if( !p->undoTransOnError ){
|
||||
sqliteBtreeRollbackCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollbackCkpt(db->pBeTemp);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeRollbackCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Fall through to ROLLBACK */
|
||||
}
|
||||
case OE_Rollback: {
|
||||
sqliteBtreeRollback(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
|
||||
sqliteRollbackAll(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( p->undoTransOnError ){
|
||||
sqliteBtreeCommit(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommit(db->pBeTemp);
|
||||
sqliteRollbackAll(db);
|
||||
db->flags &= ~SQLITE_InTrans;
|
||||
db->onError = OE_Default;
|
||||
}
|
||||
|
@ -5714,8 +5819,11 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
|
|||
}
|
||||
sqliteRollbackInternalChanges(db);
|
||||
}
|
||||
sqliteBtreeCommitCkpt(pBt);
|
||||
if( db->pBeTemp ) sqliteBtreeCommitCkpt(db->pBeTemp);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt ){
|
||||
sqliteBtreeCommitCkpt(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
assert( p->tos<p->pc || sqlite_malloc_failed==1 );
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue