From: drh Date: Sat, 26 Oct 2013 15:40:48 +0000 (+0000) Subject: Work on the UPDATE and INSERT logic. This is an incremental check-in so that X-Git-Tag: version-3.8.2~137^2~53 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=11e85273df9f8bc61aad204b34cb1d9477071c58;p=thirdparty%2Fsqlite.git Work on the UPDATE and INSERT logic. This is an incremental check-in so that can switch over to trunk to work on an unrelated issue there. FossilOrigin-Name: 086ec2a177b24ad90d5d705a99d93aa0c1545217 --- diff --git a/manifest b/manifest index c8331f4e7f..ada44a221d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Replace\sthe\sOP_IsUnique\sopcode\swith\sOP_NoConflict.\s\sThis\scode\ssimplification\nmight\sbe\suseful\sto\smove\sonto\strunk\seven\sif\sthis\sbranch\sis\snever\smerged. -D 2013-10-26T13:36:51.811 +C Work\son\sthe\sUPDATE\sand\sINSERT\slogic.\s\sThis\sis\san\sincremental\scheck-in\sso\sthat\ncan\sswitch\sover\sto\strunk\sto\swork\son\san\sunrelated\sissue\sthere. +D 2013-10-26T15:40:48.224 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c e87728415d32d6f572f5578c2107e382d1dd8203 +F src/insert.c 14ae816acbebd927bc070bf684de638f78cfccba F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b @@ -279,9 +279,9 @@ F src/update.c e39378bc5ed0c42e80624229703e59b5c7a4d50a F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 115f2c06e4d943d289599a46634514bf94479db4 +F src/vdbe.c 7d23d61c84cb1116e36a70b050f2a4ae1a2aaae3 F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4 -F src/vdbeInt.h ff57f67aee1ba26a3a47e786533dab155ab6dad6 +F src/vdbeInt.h 42dcff74dbeb2b071e569b53f885fc9c2e4b4cb0 F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed F src/vdbeaux.c 4ccdfd27f97fec98385f53fc8c880f1873137d95 F src/vdbeblob.c ef973d8d9f8170015343dd8824f795da675caa87 @@ -1127,7 +1127,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P ae61a34378d3ed2f454ba8768029d6f5fef849e4 -R 4e2e179014c5b2ce47e50b4ad5c73b59 +P e6650e16dd11327afd25961b2feb29ec8778c2ca +R bb18c22d259a405d56d9b91ea7100e63 U drh -Z bf09176aa6b2dce2a1f786b527e72d8e +Z 6434b0048c9e4cb6010b12b4a2aa5b2d diff --git a/manifest.uuid b/manifest.uuid index 6723151d82..4fd3b112db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e6650e16dd11327afd25961b2feb29ec8778c2ca \ No newline at end of file +086ec2a177b24ad90d5d705a99d93aa0c1545217 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index c6d3900ceb..5ab6b9902d 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1123,14 +1123,50 @@ insert_cleanup: #undef tmask #endif +/* +** If regFirst is a set of value for a table row in table order and pPk +** is the PRIMARY KEY index for that table, then return the index of the +** first register in a contiguous array of registers that are the primary +** key values for the table row. +** +** For the common cases where the PRIMARY KEY has only a single value or +** where a multi-value PRIMARY KEY is contiguous in table order, this +** routine simply returns a pointer into the regFirst array. But if there +** is a multi-value PRIMARY KEY with the values out-of-order, this routine +** has to generate code that will copy PRIMARY KEY values into newly +** allocated contiguous registers. +*/ +static int sqlite3PrimaryKeyRegisters(Parse *pParse, Index *pPk, int regFirst){ + int i; + int nKeyCol = pPk->nKeyCol; + int regPk; + assert( pParse->pVdbe!=0 ); + if( nKeyCol==1 ){ + return regFirst + pPk->aiColumn[0]; + } + for(i=1; iaiColumn[i-1]+1!=pPk->aiColumn[i] ) break; + } + if( i==nKeyCol ){ + return regFirst + pPk->aiColumn[0]; + } + regPk = pParse->nMem+1; + pParse->nMem += nKeyCol; + for(i=0; iaiColumn[i]; + sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i); + } + return regPk; +} + /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** -** 1. The rowid of the row after the update. (This register -** contains a NULL for WITHOUT ROWID tables.) +** 1. The rowid of the row after the update, or NULL +** for WITHOUT ROWID tables. ** ** 2. The data in the first column of the entry after the update. ** @@ -1207,7 +1243,7 @@ void sqlite3GenerateConstraintChecks( int baseCur, /* A read/write cursor pointing at pTab */ int regRowid, /* First register in a range holding values to insert */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ - int pkChng, /* Non-zero if the PRIMARY KEY might collide */ + int pkChng, /* Non-zero if the rowid or PRIMARY KEY changed */ int isUpdate, /* True for UPDATE, False for INSERT */ int overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ @@ -1218,14 +1254,17 @@ void sqlite3GenerateConstraintChecks( int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ - int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index *pIdx; /* Pointer to one of the indices */ + Index *pPk = 0; /* The PRIMARY KEY index */ sqlite3 *db; /* Database connection */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ - int regOldRowid = (pkChng && isUpdate) ? pkChng : regRowid; + int regOldPk; /* Previous rowid or PRIMARY KEY value */ + int regNewPk = 0; /* New PRIMARY KEY value */ + int pkCur = 0; /* Cursor used by the PRIMARY KEY */ + regOldPk = (pkChng && isUpdate) ? pkChng : regRowid; db = pParse->db; v = sqlite3GetVdbe(pParse); assert( v!=0 ); @@ -1233,6 +1272,17 @@ void sqlite3GenerateConstraintChecks( nCol = pTab->nCol; regData = regRowid + 1; + /* For WITHOUT ROWID tables, we'll need to know the Index and the cursor + ** number for the PRIMARY KEY index */ + if( !HasRowid(pTab) ){ + pkCur = baseCur+1; + pPk = pTab->pIndex; + while( ALWAYS(pPk) && pPk->autoIndex!=2 ){ + pPk=pPk->pNext; + pkCur++; + } + } + /* Test all NOT NULL constraints. */ for(i=0; ikeyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } - + if( isUpdate ){ - j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, pkChng); + sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng); } - j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); + sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, addrRowidOk, regRowid); switch( onError ){ default: { onError = OE_Abort; @@ -1379,33 +1433,31 @@ void sqlite3GenerateConstraintChecks( break; } } - sqlite3VdbeJumpHere(v, j3); - if( isUpdate ){ - sqlite3VdbeJumpHere(v, j2); - } + sqlite3VdbeResolveLabel(v, addrRowidOk); } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. - ** Add the new records to the indices as we go. + ** Compute the revised record entries for indices as we go. */ for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ int regIdx; int regR; - int addrSkipRow = sqlite3VdbeMakeLabel(v); + int idxCur = baseCur+iCur+1; + int addrUniqueOk = sqlite3VdbeMakeLabel(v); if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]); pParse->ckBase = regData; - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrSkipRow, + sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, SQLITE_JUMPIFNULL); pParse->ckBase = 0; } /* Create a key for accessing the index entry */ - regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); + regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); for(i=0; inColumn; i++){ i16 idx = pIdx->aiColumn[i]; if( idx<0 || idx==pTab->iPKey ){ @@ -1422,7 +1474,7 @@ void sqlite3GenerateConstraintChecks( onError = pIdx->onError; if( onError==OE_None ){ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1); - sqlite3VdbeResolveLabel(v, addrSkipRow); + sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; /* pIdx is not a UNIQUE index */ } if( overrideError!=OE_Default ){ @@ -1437,11 +1489,35 @@ void sqlite3GenerateConstraintChecks( /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp4Int(v, OP_NoConflict, baseCur+iCur+1, addrSkipRow, + sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk, regIdx, pIdx->nKeyCol); - sqlite3VdbeAddOp2(v, OP_IdxRowid, baseCur+iCur+1, regR); - sqlite3VdbeAddOp3(v, OP_Eq, regR, addrSkipRow, regOldRowid); - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1); + if( HasRowid(pTab) ){ + /* Conflict only if the rowid of the existing entry with the matching + ** key is different from old-rowid */ + sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR); + sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk); + }else if( pIdx->autoIndex==2 ){ + /* If there is a matching entry on the PRIMARY KEY index ... */ + int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; + for(i=0; inKeyCol-1; i++){ + sqlite3VdbeAddOp3(v, OP_Ne, + regOldPk+pPk->aiColumn[i], addrPkConflict, regIdx+i); + } + sqlite3VdbeAddOp3(v, OP_Eq, + regOldPk+pPk->aiColumn[i], addrUniqueOk, regIdx+i); + }else{ + int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2; + assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn ); + for(i=0; inKeyCol-1; i++){ + sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR); + sqlite3VdbeAddOp3(v, OP_Ne, + regOldPk+pPk->aiColumn[i], addrConflict, regR); + } + sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR); + sqlite3VdbeAddOp3(v, OP_Eq, + regOldPk+pPk->aiColumn[i], addrUniqueOk, regR); + } + sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail @@ -1491,7 +1567,7 @@ void sqlite3GenerateConstraintChecks( break; } } - sqlite3VdbeResolveLabel(v, addrSkipRow); + sqlite3VdbeResolveLabel(v, addrUniqueOk); sqlite3ReleaseTempReg(pParse, regR); } diff --git a/src/vdbe.c b/src/vdbe.c index 0747e26fb6..67a9a7bf58 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3737,7 +3737,7 @@ case OP_Found: { /* jump, in3 */ ** The OP_NotFound opcode performs the same operation on index btrees ** (with arbitrary multi-value keys). ** -** See also: Found, NotFound, IsUnique +** See also: Found, NotFound, NoConflict */ case OP_NotExists: { /* jump, in3 */ VdbeCursor *pC; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 3cac04016c..fe32800a56 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -82,8 +82,7 @@ struct VdbeCursor { i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ - /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or - ** OP_IsUnique opcode on this cursor. */ + /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists */ int seekResult; /* Cached information about the header for the data record that the