| Index: third_party/sqlite/src/src/insert.c
|
| diff --git a/third_party/sqlite/src/src/insert.c b/third_party/sqlite/src/src/insert.c
|
| index 3e4aac8f4dca094596c47f3484c8c5991cbf2bad..894bfc2cc17b3e81b5629e822460288e771729f7 100644
|
| --- a/third_party/sqlite/src/src/insert.c
|
| +++ b/third_party/sqlite/src/src/insert.c
|
| @@ -83,7 +83,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
| Table *pTab = pIdx->pTable;
|
| pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
|
| if( !pIdx->zColAff ){
|
| - db->mallocFailed = 1;
|
| + sqlite3OomFault(db);
|
| return 0;
|
| }
|
| for(n=0; n<pIdx->nColumn; n++){
|
| @@ -134,7 +134,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
| sqlite3 *db = sqlite3VdbeDb(v);
|
| zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
|
| if( !zColAff ){
|
| - db->mallocFailed = 1;
|
| + sqlite3OomFault(db);
|
| return;
|
| }
|
|
|
| @@ -200,7 +200,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
|
| /*
|
| ** Locate or create an AutoincInfo structure associated with table pTab
|
| ** which is in database iDb. Return the register number for the register
|
| -** that holds the maximum rowid.
|
| +** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT
|
| +** table. (Also return zero when doing a VACUUM since we do not want to
|
| +** update the AUTOINCREMENT counters during a VACUUM.)
|
| **
|
| ** There is at most one AutoincInfo structure per table even if the
|
| ** same table is autoincremented multiple times due to inserts within
|
| @@ -223,14 +225,16 @@ static int autoIncBegin(
|
| Table *pTab /* The table we are writing to */
|
| ){
|
| int memId = 0; /* Register holding maximum rowid */
|
| - if( pTab->tabFlags & TF_Autoincrement ){
|
| + if( (pTab->tabFlags & TF_Autoincrement)!=0
|
| + && (pParse->db->flags & SQLITE_Vacuum)==0
|
| + ){
|
| Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
| AutoincInfo *pInfo;
|
|
|
| pInfo = pToplevel->pAinc;
|
| while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
|
| if( pInfo==0 ){
|
| - pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
|
| + pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
|
| if( pInfo==0 ) return 0;
|
| pInfo->pNext = pToplevel->pAinc;
|
| pToplevel->pAinc = pInfo;
|
| @@ -254,7 +258,6 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
| sqlite3 *db = pParse->db; /* The database connection */
|
| Db *pDb; /* Database only autoinc table */
|
| int memId; /* Register holding max rowid */
|
| - int addr; /* A VDBE address */
|
| Vdbe *v = pParse->pVdbe; /* VDBE under construction */
|
|
|
| /* This routine is never called during trigger-generation. It is
|
| @@ -264,33 +267,46 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
|
|
| assert( v ); /* We failed long ago if this is not so */
|
| for(p = pParse->pAinc; p; p = p->pNext){
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList autoInc[] = {
|
| + /* 0 */ {OP_Null, 0, 0, 0},
|
| + /* 1 */ {OP_Rewind, 0, 9, 0},
|
| + /* 2 */ {OP_Column, 0, 0, 0},
|
| + /* 3 */ {OP_Ne, 0, 7, 0},
|
| + /* 4 */ {OP_Rowid, 0, 0, 0},
|
| + /* 5 */ {OP_Column, 0, 1, 0},
|
| + /* 6 */ {OP_Goto, 0, 9, 0},
|
| + /* 7 */ {OP_Next, 0, 2, 0},
|
| + /* 8 */ {OP_Integer, 0, 0, 0},
|
| + /* 9 */ {OP_Close, 0, 0, 0}
|
| + };
|
| + VdbeOp *aOp;
|
| pDb = &db->aDb[p->iDb];
|
| memId = p->regCtr;
|
| assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
| sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
| - sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
| - addr = sqlite3VdbeCurrentAddr(v);
|
| sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
|
| - sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
|
| - sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
|
| - sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
|
| - sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
| - sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
|
| - sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
|
| - sqlite3VdbeGoto(v, addr+9);
|
| - sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
|
| - sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
| - sqlite3VdbeAddOp0(v, OP_Close);
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
|
| + if( aOp==0 ) break;
|
| + aOp[0].p2 = memId;
|
| + aOp[0].p3 = memId+1;
|
| + aOp[2].p3 = memId;
|
| + aOp[3].p1 = memId-1;
|
| + aOp[3].p3 = memId;
|
| + aOp[3].p5 = SQLITE_JUMPIFNULL;
|
| + aOp[4].p2 = memId+1;
|
| + aOp[5].p3 = memId;
|
| + aOp[8].p2 = memId;
|
| }
|
| }
|
|
|
| /*
|
| ** Update the maximum rowid for an autoincrement calculation.
|
| **
|
| -** This routine should be called when the top of the stack holds a
|
| +** This routine should be called when the regRowid register holds a
|
| ** new rowid that is about to be inserted. If that new rowid is
|
| ** larger than the maximum rowid in the memId memory cell, then the
|
| -** memory cell is updated. The stack is unchanged.
|
| +** memory cell is updated.
|
| */
|
| static void autoIncStep(Parse *pParse, int memId, int regRowid){
|
| if( memId>0 ){
|
| @@ -305,31 +321,44 @@ static void autoIncStep(Parse *pParse, int memId, int regRowid){
|
| ** table (either directly or through triggers) needs to call this
|
| ** routine just before the "exit" code.
|
| */
|
| -void sqlite3AutoincrementEnd(Parse *pParse){
|
| +static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
|
| AutoincInfo *p;
|
| Vdbe *v = pParse->pVdbe;
|
| sqlite3 *db = pParse->db;
|
|
|
| assert( v );
|
| for(p = pParse->pAinc; p; p = p->pNext){
|
| + static const int iLn = VDBE_OFFSET_LINENO(2);
|
| + static const VdbeOpList autoIncEnd[] = {
|
| + /* 0 */ {OP_NotNull, 0, 2, 0},
|
| + /* 1 */ {OP_NewRowid, 0, 0, 0},
|
| + /* 2 */ {OP_MakeRecord, 0, 2, 0},
|
| + /* 3 */ {OP_Insert, 0, 0, 0},
|
| + /* 4 */ {OP_Close, 0, 0, 0}
|
| + };
|
| + VdbeOp *aOp;
|
| Db *pDb = &db->aDb[p->iDb];
|
| - int addr1;
|
| int iRec;
|
| int memId = p->regCtr;
|
|
|
| iRec = sqlite3GetTempReg(pParse);
|
| assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
| sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
|
| - addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
| - sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
|
| - sqlite3VdbeJumpHere(v, addr1);
|
| - sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
|
| - sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
|
| - sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| - sqlite3VdbeAddOp0(v, OP_Close);
|
| + aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
|
| + if( aOp==0 ) break;
|
| + aOp[0].p1 = memId+1;
|
| + aOp[1].p2 = memId+1;
|
| + aOp[2].p1 = memId-1;
|
| + aOp[2].p3 = iRec;
|
| + aOp[3].p2 = iRec;
|
| + aOp[3].p3 = memId+1;
|
| + aOp[3].p5 = OPFLAG_APPEND;
|
| sqlite3ReleaseTempReg(pParse, iRec);
|
| }
|
| }
|
| +void sqlite3AutoincrementEnd(Parse *pParse){
|
| + if( pParse->pAinc ) autoIncrementEnd(pParse);
|
| +}
|
| #else
|
| /*
|
| ** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
|
| @@ -456,8 +485,7 @@ void sqlite3Insert(
|
| sqlite3 *db; /* The main database structure */
|
| Table *pTab; /* The table to insert into. aka TABLE */
|
| char *zTab; /* Name of the table into which we are inserting */
|
| - const char *zDb; /* Name of the database holding this table */
|
| - int i, j, idx; /* Loop counters */
|
| + int i, j; /* Loop counters */
|
| Vdbe *v; /* Generate code into this virtual machine */
|
| Index *pIdx; /* For looping over indices of the table */
|
| int nColumn; /* Number of columns in the data */
|
| @@ -471,7 +499,6 @@ void sqlite3Insert(
|
| int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
|
| SelectDest dest; /* Destination for SELECT on rhs of INSERT */
|
| int iDb; /* Index of database holding TABLE */
|
| - Db *pDb; /* The database containing table being inserted into */
|
| u8 useTempTable = 0; /* Store SELECT results in intermediate table */
|
| u8 appendFlag = 0; /* True if the insert is likely to be an append */
|
| u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
| @@ -521,9 +548,8 @@ void sqlite3Insert(
|
| }
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| assert( iDb<db->nDb );
|
| - pDb = &db->aDb[iDb];
|
| - zDb = pDb->zName;
|
| - if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
|
| + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
|
| + db->aDb[iDb].zDbSName) ){
|
| goto insert_cleanup;
|
| }
|
| withoutRowid = !HasRowid(pTab);
|
| @@ -660,7 +686,7 @@ void sqlite3Insert(
|
| rc = sqlite3Select(pParse, pSelect, &dest);
|
| regFromSelect = dest.iSdst;
|
| if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
| - sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
| + sqlite3VdbeEndCoroutine(v, regYield);
|
| sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
| assert( pSelect->pEList );
|
| nColumn = pSelect->pEList->nExpr;
|
| @@ -762,12 +788,14 @@ void sqlite3Insert(
|
| int nIdx;
|
| nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
|
| &iDataCur, &iIdxCur);
|
| - aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
|
| + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
|
| if( aRegIdx==0 ){
|
| goto insert_cleanup;
|
| }
|
| - for(i=0; i<nIdx; i++){
|
| + for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
|
| + assert( pIdx );
|
| aRegIdx[i] = ++pParse->nMem;
|
| + pParse->nMem += pIdx->nColumn;
|
| }
|
| }
|
|
|
| @@ -969,12 +997,26 @@ void sqlite3Insert(
|
| #endif
|
| {
|
| int isReplace; /* Set to true if constraints may cause a replace */
|
| + int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
|
| sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
|
| - regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace
|
| + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
|
| );
|
| sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
| +
|
| + /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
|
| + ** constraints or (b) there are no triggers and this table is not a
|
| + ** parent table in a foreign key constraint. It is safe to set the
|
| + ** flag in the second case as if any REPLACE constraint is hit, an
|
| + ** OP_Delete or OP_IdxDelete instruction will be executed on each
|
| + ** cursor that is disturbed. And these instructions both clear the
|
| + ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
|
| + ** functionality. */
|
| + bUseSeek = (isReplace==0 || (pTrigger==0 &&
|
| + ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0)
|
| + ));
|
| sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
|
| - regIns, aRegIdx, 0, appendFlag, isReplace==0);
|
| + regIns, aRegIdx, 0, appendFlag, bUseSeek
|
| + );
|
| }
|
| }
|
|
|
| @@ -1003,14 +1045,6 @@ void sqlite3Insert(
|
| sqlite3VdbeJumpHere(v, addrInsTop);
|
| }
|
|
|
| - if( !IsVirtual(pTab) && !isView ){
|
| - /* Close all tables opened */
|
| - if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
|
| - for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
|
| - sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
|
| - }
|
| - }
|
| -
|
| insert_end:
|
| /* Update the sqlite_sequence table by storing the content of the
|
| ** maximum rowid counter values recorded while inserting into
|
| @@ -1053,6 +1087,59 @@ insert_cleanup:
|
| #endif
|
|
|
| /*
|
| +** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
|
| +*/
|
| +#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
|
| +#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */
|
| +
|
| +/* This is the Walker callback from checkConstraintUnchanged(). Set
|
| +** bit 0x01 of pWalker->eCode if
|
| +** pWalker->eCode to 0 if this expression node references any of the
|
| +** columns that are being modifed by an UPDATE statement.
|
| +*/
|
| +static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
|
| + if( pExpr->op==TK_COLUMN ){
|
| + assert( pExpr->iColumn>=0 || pExpr->iColumn==-1 );
|
| + if( pExpr->iColumn>=0 ){
|
| + if( pWalker->u.aiCol[pExpr->iColumn]>=0 ){
|
| + pWalker->eCode |= CKCNSTRNT_COLUMN;
|
| + }
|
| + }else{
|
| + pWalker->eCode |= CKCNSTRNT_ROWID;
|
| + }
|
| + }
|
| + return WRC_Continue;
|
| +}
|
| +
|
| +/*
|
| +** pExpr is a CHECK constraint on a row that is being UPDATE-ed. The
|
| +** only columns that are modified by the UPDATE are those for which
|
| +** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
|
| +**
|
| +** Return true if CHECK constraint pExpr does not use any of the
|
| +** changing columns (or the rowid if it is changing). In other words,
|
| +** return true if this CHECK constraint can be skipped when validating
|
| +** the new row in the UPDATE statement.
|
| +*/
|
| +static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
|
| + Walker w;
|
| + memset(&w, 0, sizeof(w));
|
| + w.eCode = 0;
|
| + w.xExprCallback = checkConstraintExprNode;
|
| + w.u.aiCol = aiChng;
|
| + sqlite3WalkExpr(&w, pExpr);
|
| + if( !chngRowid ){
|
| + testcase( (w.eCode & CKCNSTRNT_ROWID)!=0 );
|
| + w.eCode &= ~CKCNSTRNT_ROWID;
|
| + }
|
| + testcase( w.eCode==0 );
|
| + testcase( w.eCode==CKCNSTRNT_COLUMN );
|
| + testcase( w.eCode==CKCNSTRNT_ROWID );
|
| + testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
|
| + return !w.eCode;
|
| +}
|
| +
|
| +/*
|
| ** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
| ** on table pTab.
|
| **
|
| @@ -1146,7 +1233,8 @@ void sqlite3GenerateConstraintChecks(
|
| u8 pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */
|
| u8 overrideError, /* Override onError to this if not OE_Default */
|
| int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
|
| - int *pbMayReplace /* OUT: Set to true if constraint may cause a replace */
|
| + int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */
|
| + int *aiChng /* column i is unchanged if aiChng[i]<0 */
|
| ){
|
| Vdbe *v; /* VDBE under constrution */
|
| Index *pIdx; /* Pointer to one of the indices */
|
| @@ -1163,7 +1251,6 @@ void sqlite3GenerateConstraintChecks(
|
| int ipkBottom = 0; /* Bottom of the rowid change constraint check */
|
| u8 isUpdate; /* True if this is an UPDATE operation */
|
| u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
| - int regRowid = -1; /* Register holding ROWID value */
|
|
|
| isUpdate = regOldData!=0;
|
| db = pParse->db;
|
| @@ -1192,10 +1279,14 @@ void sqlite3GenerateConstraintChecks(
|
| */
|
| for(i=0; i<nCol; i++){
|
| if( i==pTab->iPKey ){
|
| + continue; /* ROWID is never NULL */
|
| + }
|
| + if( aiChng && aiChng[i]<0 ){
|
| + /* Don't bother checking for NOT NULL on columns that do not change */
|
| continue;
|
| }
|
| onError = pTab->aCol[i].notNull;
|
| - if( onError==OE_None ) continue;
|
| + if( onError==OE_None ) continue; /* This column is allowed to be NULL */
|
| if( overrideError!=OE_Default ){
|
| onError = overrideError;
|
| }else if( onError==OE_Default ){
|
| @@ -1214,8 +1305,9 @@ void sqlite3GenerateConstraintChecks(
|
| case OE_Fail: {
|
| char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
|
| pTab->aCol[i].zName);
|
| - sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
|
| - regNewData+1+i, zMsg, P4_DYNAMIC);
|
| + sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
|
| + regNewData+1+i);
|
| + sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
|
| sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
|
| VdbeCoverage(v);
|
| break;
|
| @@ -1244,8 +1336,11 @@ void sqlite3GenerateConstraintChecks(
|
| pParse->ckBase = regNewData+1;
|
| onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
| for(i=0; i<pCheck->nExpr; i++){
|
| - int allOk = sqlite3VdbeMakeLabel(v);
|
| - sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
|
| + int allOk;
|
| + Expr *pExpr = pCheck->a[i].pExpr;
|
| + if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
|
| + allOk = sqlite3VdbeMakeLabel(v);
|
| + sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
|
| if( onError==OE_Ignore ){
|
| sqlite3VdbeGoto(v, ignoreDest);
|
| }else{
|
| @@ -1276,7 +1371,7 @@ void sqlite3GenerateConstraintChecks(
|
| }
|
|
|
| if( isUpdate ){
|
| - /* pkChng!=0 does not mean that the rowid has change, only that
|
| + /* pkChng!=0 does not mean that the rowid has changed, only that
|
| ** it might have changed. Skip the conflict logic below if the rowid
|
| ** is unchanged. */
|
| sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
|
| @@ -1345,9 +1440,18 @@ void sqlite3GenerateConstraintChecks(
|
| if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
| sqlite3MultiWrite(pParse);
|
| sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| - regNewData, 1, 0, OE_Replace,
|
| - ONEPASS_SINGLE, -1);
|
| + regNewData, 1, 0, OE_Replace, 1, -1);
|
| }else{
|
| +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
| + if( HasRowid(pTab) ){
|
| + /* This OP_Delete opcode fires the pre-update-hook only. It does
|
| + ** not modify the b-tree. It is more efficient to let the coming
|
| + ** OP_Insert replace the existing entry than it is to delete the
|
| + ** existing entry and then insert a new one. */
|
| + sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
|
| + sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
| + }
|
| +#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
| if( pTab->pIndex ){
|
| sqlite3MultiWrite(pParse);
|
| sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
|
| @@ -1402,7 +1506,7 @@ void sqlite3GenerateConstraintChecks(
|
| /* Create a record for this index entry as it should appear after
|
| ** the insert or update. Store that record in the aRegIdx[ix] register
|
| */
|
| - regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
|
| + regIdx = aRegIdx[ix]+1;
|
| for(i=0; i<pIdx->nColumn; i++){
|
| int iField = pIdx->aiColumn[i];
|
| int x;
|
| @@ -1413,9 +1517,7 @@ void sqlite3GenerateConstraintChecks(
|
| VdbeComment((v, "%s column %d", pIdx->zName, i));
|
| }else{
|
| if( iField==XN_ROWID || iField==pTab->iPKey ){
|
| - if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
|
| x = regNewData;
|
| - regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
|
| }else{
|
| x = iField + regNewData + 1;
|
| }
|
| @@ -1425,7 +1527,6 @@ void sqlite3GenerateConstraintChecks(
|
| }
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
| VdbeComment((v, "for %s", pIdx->zName));
|
| - sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
|
|
|
| /* In an UPDATE operation, if this index is the PRIMARY KEY index
|
| ** of a WITHOUT ROWID table and there has been no change the
|
| @@ -1439,7 +1540,6 @@ void sqlite3GenerateConstraintChecks(
|
| /* Find out what action to take in case there is a uniqueness conflict */
|
| onError = pIdx->onError;
|
| if( onError==OE_None ){
|
| - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
| sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| continue; /* pIdx is not a UNIQUE index */
|
| }
|
| @@ -1448,7 +1548,26 @@ void sqlite3GenerateConstraintChecks(
|
| }else if( onError==OE_Default ){
|
| onError = OE_Abort;
|
| }
|
| -
|
| +
|
| + /* Collision detection may be omitted if all of the following are true:
|
| + ** (1) The conflict resolution algorithm is REPLACE
|
| + ** (2) The table is a WITHOUT ROWID table
|
| + ** (3) There are no secondary indexes on the table
|
| + ** (4) No delete triggers need to be fired if there is a conflict
|
| + ** (5) No FK constraint counters need to be updated if a conflict occurs.
|
| + */
|
| + if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
|
| + && pPk==pIdx /* Condition 2 */
|
| + && onError==OE_Replace /* Condition 1 */
|
| + && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
|
| + 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
|
| + && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */
|
| + (0==pTab->pFKey && 0==sqlite3FkReferences(pTab)))
|
| + ){
|
| + sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| + continue;
|
| + }
|
| +
|
| /* Check to see if the new index entry will be unique */
|
| sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
| regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
| @@ -1532,13 +1651,12 @@ void sqlite3GenerateConstraintChecks(
|
| }
|
| sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| regR, nPkField, 0, OE_Replace,
|
| - (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
|
| + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
|
| seenReplace = 1;
|
| break;
|
| }
|
| }
|
| sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
| - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
| if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
| }
|
| if( ipkTop ){
|
| @@ -1550,6 +1668,25 @@ void sqlite3GenerateConstraintChecks(
|
| VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
|
| }
|
|
|
| +#ifdef SQLITE_ENABLE_NULL_TRIM
|
| +/*
|
| +** Change the P5 operand on the last opcode (which should be an OP_MakeRecord)
|
| +** to be the number of columns in table pTab that must not be NULL-trimmed.
|
| +**
|
| +** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero.
|
| +*/
|
| +void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
|
| + u16 i;
|
| +
|
| + /* Records with omitted columns are only allowed for schema format
|
| + ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */
|
| + if( pTab->pSchema->file_format<2 ) return;
|
| +
|
| + for(i=pTab->nCol; i>1 && pTab->aCol[i-1].pDflt==0; i--){}
|
| + sqlite3VdbeChangeP5(v, i);
|
| +}
|
| +#endif
|
| +
|
| /*
|
| ** This routine generates code to finish the INSERT or UPDATE operation
|
| ** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
| @@ -1566,7 +1703,7 @@ void sqlite3CompleteInsertion(
|
| int iIdxCur, /* First index cursor */
|
| int regNewData, /* Range of content */
|
| int *aRegIdx, /* Register used by each index. 0 for unused indices */
|
| - int isUpdate, /* True for UPDATE, False for INSERT */
|
| + int update_flags, /* True for UPDATE, False for INSERT */
|
| int appendBias, /* True if this is likely to be an append */
|
| int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
|
| ){
|
| @@ -1578,6 +1715,11 @@ void sqlite3CompleteInsertion(
|
| int i; /* Loop counter */
|
| u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
|
|
|
| + assert( update_flags==0
|
| + || update_flags==OPFLAG_ISUPDATE
|
| + || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
|
| + );
|
| +
|
| v = sqlite3GetVdbe(pParse);
|
| assert( v!=0 );
|
| assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
| @@ -1588,26 +1730,39 @@ void sqlite3CompleteInsertion(
|
| sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
| VdbeCoverage(v);
|
| }
|
| - sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
| - pik_flags = 0;
|
| - if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
| + pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
|
| if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
| assert( pParse->nested==0 );
|
| pik_flags |= OPFLAG_NCHANGE;
|
| + pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
|
| +#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
| + if( update_flags==0 ){
|
| + sqlite3VdbeAddOp4(v, OP_InsertInt,
|
| + iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE
|
| + );
|
| + sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
| + }
|
| +#endif
|
| }
|
| - if( pik_flags ) sqlite3VdbeChangeP5(v, pik_flags);
|
| + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
| + aRegIdx[i]+1,
|
| + pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
| + sqlite3VdbeChangeP5(v, pik_flags);
|
| }
|
| if( !HasRowid(pTab) ) return;
|
| regData = regNewData + 1;
|
| regRec = sqlite3GetTempReg(pParse);
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
|
| - if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
|
| - sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
|
| + sqlite3SetMakeRecordP5(v, pTab);
|
| + if( !bAffinityDone ){
|
| + sqlite3TableAffinity(v, pTab, 0);
|
| + sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
|
| + }
|
| if( pParse->nested ){
|
| pik_flags = 0;
|
| }else{
|
| pik_flags = OPFLAG_NCHANGE;
|
| - pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
|
| + pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID);
|
| }
|
| if( appendBias ){
|
| pik_flags |= OPFLAG_APPEND;
|
| @@ -1617,7 +1772,7 @@ void sqlite3CompleteInsertion(
|
| }
|
| sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
|
| if( !pParse->nested ){
|
| - sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
|
| + sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
| }
|
| sqlite3VdbeChangeP5(v, pik_flags);
|
| }
|
| @@ -1647,7 +1802,7 @@ int sqlite3OpenTableAndIndices(
|
| Parse *pParse, /* Parsing context */
|
| Table *pTab, /* Table to be opened */
|
| int op, /* OP_OpenRead or OP_OpenWrite */
|
| - u8 p5, /* P5 value for OP_Open* instructions */
|
| + u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
|
| int iBase, /* Use this for the table cursor, if there is one */
|
| u8 *aToOpen, /* If not NULL: boolean for each table and index */
|
| int *piDataCur, /* Write the database source cursor number here */
|
| @@ -1682,8 +1837,9 @@ int sqlite3OpenTableAndIndices(
|
| for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
| int iIdxCur = iBase++;
|
| assert( pIdx->pSchema==pTab->pSchema );
|
| - if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
|
| - *piDataCur = iIdxCur;
|
| + if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
| + if( piDataCur ) *piDataCur = iIdxCur;
|
| + p5 = 0;
|
| }
|
| if( aToOpen==0 || aToOpen[i+1] ){
|
| sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
|
| @@ -1912,11 +2068,15 @@ static int xferOptimization(
|
| return 0; /* tab2 must be NOT NULL if tab1 is */
|
| }
|
| /* Default values for second and subsequent columns need to match. */
|
| - if( i>0
|
| - && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|
| - || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
|
| - ){
|
| - return 0; /* Default values must be the same for all columns */
|
| + if( i>0 ){
|
| + assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
|
| + assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
|
| + if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|
| + || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
|
| + pSrcCol->pDflt->u.zToken)!=0)
|
| + ){
|
| + return 0; /* Default values must be the same for all columns */
|
| + }
|
| }
|
| }
|
| for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
| @@ -1995,6 +2155,7 @@ static int xferOptimization(
|
| sqlite3VdbeJumpHere(v, addr1);
|
| }
|
| if( HasRowid(pSrc) ){
|
| + u8 insFlags;
|
| sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
| emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
| if( pDest->iPKey>=0 ){
|
| @@ -2010,10 +2171,17 @@ static int xferOptimization(
|
| addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
| assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
| }
|
| - sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
|
| - sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
| - sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
|
| - sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
|
| + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
| + if( db->flags & SQLITE_Vacuum ){
|
| + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
| + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
|
| + OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
| + }else{
|
| + insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
|
| + }
|
| + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
| + (char*)pDest, P4_TABLE);
|
| + sqlite3VdbeChangeP5(v, insFlags);
|
| sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
| sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
| sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
| @@ -2035,7 +2203,7 @@ static int xferOptimization(
|
| sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
|
| VdbeComment((v, "%s", pDestIdx->zName));
|
| addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
| - sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
| + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
| 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
|
| @@ -2065,8 +2233,8 @@ static int xferOptimization(
|
| if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
|
| idxInsFlags |= OPFLAG_NCHANGE;
|
| }
|
| - sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
| - sqlite3VdbeChangeP5(v, idxInsFlags);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
| + sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
| sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
| sqlite3VdbeJumpHere(v, addr1);
|
| sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
| @@ -2076,6 +2244,7 @@ static int xferOptimization(
|
| sqlite3ReleaseTempReg(pParse, regRowid);
|
| sqlite3ReleaseTempReg(pParse, regData);
|
| if( emptyDestTest ){
|
| + sqlite3AutoincrementEnd(pParse);
|
| sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
|
| sqlite3VdbeJumpHere(v, emptyDestTest);
|
| sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
|
|