| Index: third_party/sqlite/sqlite-src-3100200/src/insert.c
|
| diff --git a/third_party/sqlite/src/src/insert.c b/third_party/sqlite/sqlite-src-3100200/src/insert.c
|
| similarity index 90%
|
| copy from third_party/sqlite/src/src/insert.c
|
| copy to third_party/sqlite/sqlite-src-3100200/src/insert.c
|
| index a5c3f3e92d437dcb0bd349017afae3e5e4c00843..3e4aac8f4dca094596c47f3484c8c5991cbf2bad 100644
|
| --- a/third_party/sqlite/src/src/insert.c
|
| +++ b/third_party/sqlite/sqlite-src-3100200/src/insert.c
|
| @@ -42,7 +42,7 @@ void sqlite3OpenTable(
|
| }else{
|
| Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
| assert( pPk!=0 );
|
| - assert( pPk->tnum=pTab->tnum );
|
| + assert( pPk->tnum==pTab->tnum );
|
| sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
|
| sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
| VdbeComment((v, "%s", pTab->zName));
|
| @@ -56,7 +56,7 @@ void sqlite3OpenTable(
|
| **
|
| ** Character Column affinity
|
| ** ------------------------------
|
| -** 'A' NONE
|
| +** 'A' BLOB
|
| ** 'B' TEXT
|
| ** 'C' NUMERIC
|
| ** 'D' INTEGER
|
| @@ -69,7 +69,7 @@ void sqlite3OpenTable(
|
| ** is managed along with the rest of the Index structure. It will be
|
| ** released when sqlite3DeleteIndex() is called.
|
| */
|
| -const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
| +const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
| if( !pIdx->zColAff ){
|
| /* The first time a column affinity string for a particular index is
|
| ** required, it is allocated and populated here. It is then stored as
|
| @@ -81,7 +81,6 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
| */
|
| int n;
|
| Table *pTab = pIdx->pTable;
|
| - sqlite3 *db = sqlite3VdbeDb(v);
|
| pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
|
| if( !pIdx->zColAff ){
|
| db->mallocFailed = 1;
|
| @@ -89,7 +88,18 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
| }
|
| for(n=0; n<pIdx->nColumn; n++){
|
| i16 x = pIdx->aiColumn[n];
|
| - pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity;
|
| + if( x>=0 ){
|
| + pIdx->zColAff[n] = pTab->aCol[x].affinity;
|
| + }else if( x==XN_ROWID ){
|
| + pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
|
| + }else{
|
| + char aff;
|
| + assert( x==XN_EXPR );
|
| + assert( pIdx->aColExpr!=0 );
|
| + aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
|
| + if( aff==0 ) aff = SQLITE_AFF_BLOB;
|
| + pIdx->zColAff[n] = aff;
|
| + }
|
| }
|
| pIdx->zColAff[n] = 0;
|
| }
|
| @@ -99,9 +109,9 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
|
|
| /*
|
| ** Compute the affinity string for table pTab, if it has not already been
|
| -** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities.
|
| +** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
|
| **
|
| -** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and
|
| +** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and
|
| ** if iReg>0 then code an OP_Affinity opcode that will set the affinities
|
| ** for register iReg and following. Or if affinities exists and iReg==0,
|
| ** then just set the P4 operand of the previous opcode (which should be
|
| @@ -111,7 +121,7 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
| **
|
| ** Character Column affinity
|
| ** ------------------------------
|
| -** 'A' NONE
|
| +** 'A' BLOB
|
| ** 'B' TEXT
|
| ** 'C' NUMERIC
|
| ** 'D' INTEGER
|
| @@ -133,7 +143,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
| }
|
| do{
|
| zColAff[i--] = 0;
|
| - }while( i>=0 && zColAff[i]==SQLITE_AFF_NONE );
|
| + }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB );
|
| pTab->zColAff = zColAff;
|
| }
|
| i = sqlite3Strlen30(zColAff);
|
| @@ -250,7 +260,7 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
| /* This routine is never called during trigger-generation. It is
|
| ** only called from the top-level */
|
| assert( pParse->pTriggerTab==0 );
|
| - assert( pParse==sqlite3ParseToplevel(pParse) );
|
| + assert( sqlite3IsToplevel(pParse) );
|
|
|
| assert( v ); /* We failed long ago if this is not so */
|
| for(p = pParse->pAinc; p; p = p->pNext){
|
| @@ -260,14 +270,14 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
| sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
| sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
| addr = sqlite3VdbeCurrentAddr(v);
|
| - sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
|
| + 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);
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
|
| + sqlite3VdbeGoto(v, addr+9);
|
| sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
|
| sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
|
| sqlite3VdbeAddOp0(v, OP_Close);
|
| @@ -303,16 +313,16 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
| assert( v );
|
| for(p = pParse->pAinc; p; p = p->pNext){
|
| Db *pDb = &db->aDb[p->iDb];
|
| - int j1;
|
| + 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);
|
| - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
|
| sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
|
| - sqlite3VdbeJumpHere(v, j1);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
|
| sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
|
| sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
| @@ -342,20 +352,23 @@ static int xferOptimization(
|
| /*
|
| ** This routine is called to handle SQL of the following forms:
|
| **
|
| -** insert into TABLE (IDLIST) values(EXPRLIST)
|
| +** insert into TABLE (IDLIST) values(EXPRLIST),(EXPRLIST),...
|
| ** insert into TABLE (IDLIST) select
|
| +** insert into TABLE (IDLIST) default values
|
| **
|
| ** The IDLIST following the table name is always optional. If omitted,
|
| -** then a list of all columns for the table is substituted. The IDLIST
|
| -** appears in the pColumn parameter. pColumn is NULL if IDLIST is omitted.
|
| +** then a list of all (non-hidden) columns for the table is substituted.
|
| +** The IDLIST appears in the pColumn parameter. pColumn is NULL if IDLIST
|
| +** is omitted.
|
| **
|
| -** The pList parameter holds EXPRLIST in the first form of the INSERT
|
| -** statement above, and pSelect is NULL. For the second form, pList is
|
| -** NULL and pSelect is a pointer to the select statement used to generate
|
| -** data for the insert.
|
| +** For the pSelect parameter holds the values to be inserted for the
|
| +** first two forms shown above. A VALUES clause is really just short-hand
|
| +** for a SELECT statement that omits the FROM clause and everything else
|
| +** that follows. If the pSelect parameter is NULL, that means that the
|
| +** DEFAULT VALUES form of the INSERT statement is intended.
|
| **
|
| ** The code generated follows one of four templates. For a simple
|
| -** insert with data coming from a VALUES clause, the code executes
|
| +** insert with data coming from a single-row VALUES clause, the code executes
|
| ** once straight down through. Pseudo-code follows (we call this
|
| ** the "1st template"):
|
| **
|
| @@ -462,7 +475,7 @@ void sqlite3Insert(
|
| 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 */
|
| - u8 bIdListInOrder = 1; /* True if IDLIST is in table order */
|
| + u8 bIdListInOrder; /* True if IDLIST is in table order */
|
| ExprList *pList = 0; /* List of VALUES() to be inserted */
|
|
|
| /* Register allocations */
|
| @@ -487,8 +500,8 @@ void sqlite3Insert(
|
| }
|
|
|
| /* If the Select object is really just a simple VALUES() list with a
|
| - ** single row values (the common case) then keep that one row of values
|
| - ** and go ahead and discard the Select object
|
| + ** single row (the common case) then keep that one row of values
|
| + ** and discard the other (unused) parts of the pSelect object
|
| */
|
| if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){
|
| pList = pSelect->pEList;
|
| @@ -596,6 +609,7 @@ void sqlite3Insert(
|
| ** is appears in the original table. (The index of the INTEGER
|
| ** PRIMARY KEY in the original table is pTab->iPKey.)
|
| */
|
| + bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
|
| if( pColumn ){
|
| for(i=0; i<pColumn->nId; i++){
|
| pColumn->a[i].idx = -1;
|
| @@ -631,7 +645,8 @@ void sqlite3Insert(
|
| ** co-routine is the common header to the 3rd and 4th templates.
|
| */
|
| if( pSelect ){
|
| - /* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
|
| + /* Data is coming from a SELECT or from a multi-row VALUES clause.
|
| + ** Generate a co-routine to run the SELECT. */
|
| int regYield; /* Register holding co-routine entry-point */
|
| int addrTop; /* Top of the co-routine */
|
| int rc; /* Result code */
|
| @@ -644,8 +659,7 @@ void sqlite3Insert(
|
| dest.nSdst = pTab->nCol;
|
| rc = sqlite3Select(pParse, pSelect, &dest);
|
| regFromSelect = dest.iSdst;
|
| - assert( pParse->nErr==0 || rc );
|
| - if( rc || db->mallocFailed ) goto insert_cleanup;
|
| + if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
| sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
| sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
| assert( pSelect->pEList );
|
| @@ -687,25 +701,27 @@ void sqlite3Insert(
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
| sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
| sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrL);
|
| + sqlite3VdbeGoto(v, addrL);
|
| sqlite3VdbeJumpHere(v, addrL);
|
| sqlite3ReleaseTempReg(pParse, regRec);
|
| sqlite3ReleaseTempReg(pParse, regTempRowid);
|
| }
|
| }else{
|
| - /* This is the case if the data for the INSERT is coming from a VALUES
|
| - ** clause
|
| + /* This is the case if the data for the INSERT is coming from a
|
| + ** single-row VALUES clause
|
| */
|
| NameContext sNC;
|
| memset(&sNC, 0, sizeof(sNC));
|
| sNC.pParse = pParse;
|
| srcTab = -1;
|
| assert( useTempTable==0 );
|
| - nColumn = pList ? pList->nExpr : 0;
|
| - for(i=0; i<nColumn; i++){
|
| - if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
| + if( pList ){
|
| + nColumn = pList->nExpr;
|
| + if( sqlite3ResolveExprListNames(&sNC, pList) ){
|
| goto insert_cleanup;
|
| }
|
| + }else{
|
| + nColumn = 0;
|
| }
|
| }
|
|
|
| @@ -720,10 +736,8 @@ void sqlite3Insert(
|
| /* Make sure the number of columns in the source data matches the number
|
| ** of columns to be inserted into the table.
|
| */
|
| - if( IsVirtual(pTab) ){
|
| - for(i=0; i<pTab->nCol; i++){
|
| - nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
|
| - }
|
| + for(i=0; i<pTab->nCol; i++){
|
| + nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
|
| }
|
| if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
| sqlite3ErrorMsg(pParse,
|
| @@ -746,7 +760,7 @@ void sqlite3Insert(
|
| /* If this is not a view, open the table and and all indices */
|
| if( !isView ){
|
| int nIdx;
|
| - nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0,
|
| + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
|
| &iDataCur, &iIdxCur);
|
| aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
|
| if( aRegIdx==0 ){
|
| @@ -798,7 +812,7 @@ void sqlite3Insert(
|
| if( ipkColumn<0 ){
|
| sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
| }else{
|
| - int j1;
|
| + int addr1;
|
| assert( !withoutRowid );
|
| if( useTempTable ){
|
| sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
|
| @@ -806,9 +820,9 @@ void sqlite3Insert(
|
| assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
| sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
|
| }
|
| - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
|
| sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
|
| - sqlite3VdbeJumpHere(v, j1);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
|
| }
|
|
|
| @@ -819,15 +833,14 @@ void sqlite3Insert(
|
|
|
| /* Create the new column data
|
| */
|
| - for(i=0; i<pTab->nCol; i++){
|
| - if( pColumn==0 ){
|
| - j = i;
|
| - }else{
|
| + for(i=j=0; i<pTab->nCol; i++){
|
| + if( pColumn ){
|
| for(j=0; j<pColumn->nId; j++){
|
| if( pColumn->a[j].idx==i ) break;
|
| }
|
| }
|
| - if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
|
| + if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
|
| + || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
|
| sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
|
| }else if( useTempTable ){
|
| sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
|
| @@ -835,6 +848,7 @@ void sqlite3Insert(
|
| assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
| sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
|
| }
|
| + if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
|
| }
|
|
|
| /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
|
| @@ -882,14 +896,14 @@ void sqlite3Insert(
|
| ** to generate a unique primary key value.
|
| */
|
| if( !appendFlag ){
|
| - int j1;
|
| + int addr1;
|
| if( !IsVirtual(pTab) ){
|
| - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
|
| sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
|
| - sqlite3VdbeJumpHere(v, j1);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| }else{
|
| - j1 = sqlite3VdbeCurrentAddr(v);
|
| - sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v);
|
| + addr1 = sqlite3VdbeCurrentAddr(v);
|
| + sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
|
| }
|
| sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
|
| }
|
| @@ -918,7 +932,6 @@ void sqlite3Insert(
|
| }
|
| if( pColumn==0 ){
|
| if( IsHiddenColumn(&pTab->aCol[i]) ){
|
| - assert( IsVirtual(pTab) );
|
| j = -1;
|
| nHidden++;
|
| }else{
|
| @@ -986,7 +999,7 @@ void sqlite3Insert(
|
| sqlite3VdbeJumpHere(v, addrInsTop);
|
| sqlite3VdbeAddOp1(v, OP_Close, srcTab);
|
| }else if( pSelect ){
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont);
|
| + sqlite3VdbeGoto(v, addrCont);
|
| sqlite3VdbeJumpHere(v, addrInsTop);
|
| }
|
|
|
| @@ -1143,7 +1156,7 @@ void sqlite3GenerateConstraintChecks(
|
| int ix; /* Index loop counter */
|
| int nCol; /* Number of columns */
|
| int onError; /* Conflict resolution strategy */
|
| - int j1; /* Address of jump instruction */
|
| + int addr1; /* Address of jump instruction */
|
| int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
| int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
| int ipkTop = 0; /* Top of the rowid change constraint check */
|
| @@ -1214,9 +1227,10 @@ void sqlite3GenerateConstraintChecks(
|
| }
|
| default: {
|
| assert( onError==OE_Replace );
|
| - j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v);
|
| + addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
|
| + VdbeCoverage(v);
|
| sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
|
| - sqlite3VdbeJumpHere(v, j1);
|
| + sqlite3VdbeJumpHere(v, addr1);
|
| break;
|
| }
|
| }
|
| @@ -1233,7 +1247,7 @@ void sqlite3GenerateConstraintChecks(
|
| int allOk = sqlite3VdbeMakeLabel(v);
|
| sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
|
| if( onError==OE_Ignore ){
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| }else{
|
| char *zName = pCheck->a[i].zName;
|
| if( zName==0 ) zName = pTab->zName;
|
| @@ -1331,17 +1345,20 @@ void sqlite3GenerateConstraintChecks(
|
| if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
|
| sqlite3MultiWrite(pParse);
|
| sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| - regNewData, 1, 0, OE_Replace, 1);
|
| - }else if( pTab->pIndex ){
|
| - sqlite3MultiWrite(pParse);
|
| - sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
|
| + regNewData, 1, 0, OE_Replace,
|
| + ONEPASS_SINGLE, -1);
|
| + }else{
|
| + if( pTab->pIndex ){
|
| + sqlite3MultiWrite(pParse);
|
| + sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
|
| + }
|
| }
|
| seenReplace = 1;
|
| break;
|
| }
|
| case OE_Ignore: {
|
| /*assert( seenReplace==0 );*/
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| break;
|
| }
|
| }
|
| @@ -1377,8 +1394,8 @@ void sqlite3GenerateConstraintChecks(
|
| if( pIdx->pPartIdxWhere ){
|
| sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
|
| pParse->ckBase = regNewData+1;
|
| - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
| - SQLITE_JUMPIFNULL);
|
| + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
|
| + SQLITE_JUMPIFNULL);
|
| pParse->ckBase = 0;
|
| }
|
|
|
| @@ -1389,15 +1406,22 @@ void sqlite3GenerateConstraintChecks(
|
| for(i=0; i<pIdx->nColumn; i++){
|
| int iField = pIdx->aiColumn[i];
|
| int x;
|
| - if( iField<0 || iField==pTab->iPKey ){
|
| - if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
|
| - x = regNewData;
|
| - regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
|
| + if( iField==XN_EXPR ){
|
| + pParse->ckBase = regNewData+1;
|
| + sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
|
| + pParse->ckBase = 0;
|
| + VdbeComment((v, "%s column %d", pIdx->zName, i));
|
| }else{
|
| - x = iField + regNewData + 1;
|
| + 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;
|
| + }
|
| + sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
|
| + VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
|
| }
|
| - sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
|
| - VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
|
| }
|
| sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
| VdbeComment((v, "for %s", pIdx->zName));
|
| @@ -1447,6 +1471,7 @@ void sqlite3GenerateConstraintChecks(
|
| ** store it in registers regR..regR+nPk-1 */
|
| if( pIdx!=pPk ){
|
| for(i=0; i<pPk->nKeyCol; i++){
|
| + assert( pPk->aiColumn[i]>=0 );
|
| x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
|
| sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
|
| VdbeComment((v, "%s.%s", pTab->zName,
|
| @@ -1468,6 +1493,7 @@ void sqlite3GenerateConstraintChecks(
|
| for(i=0; i<pPk->nKeyCol; i++){
|
| char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
|
| x = pPk->aiColumn[i];
|
| + assert( x>=0 );
|
| if( i==(pPk->nKeyCol-1) ){
|
| addrJump = addrUniqueOk;
|
| op = OP_Eq;
|
| @@ -1494,7 +1520,7 @@ void sqlite3GenerateConstraintChecks(
|
| break;
|
| }
|
| case OE_Ignore: {
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
| + sqlite3VdbeGoto(v, ignoreDest);
|
| break;
|
| }
|
| default: {
|
| @@ -1505,7 +1531,8 @@ void sqlite3GenerateConstraintChecks(
|
| pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
| }
|
| sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
| - regR, nPkField, 0, OE_Replace, pIdx==pPk);
|
| + regR, nPkField, 0, OE_Replace,
|
| + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
|
| seenReplace = 1;
|
| break;
|
| }
|
| @@ -1515,7 +1542,7 @@ void sqlite3GenerateConstraintChecks(
|
| if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
| }
|
| if( ipkTop ){
|
| - sqlite3VdbeAddOp2(v, OP_Goto, 0, ipkTop+1);
|
| + sqlite3VdbeGoto(v, ipkTop+1);
|
| sqlite3VdbeJumpHere(v, ipkBottom);
|
| }
|
|
|
| @@ -1620,6 +1647,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 */
|
| 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 */
|
| @@ -1632,6 +1660,7 @@ int sqlite3OpenTableAndIndices(
|
| Vdbe *v;
|
|
|
| assert( op==OP_OpenRead || op==OP_OpenWrite );
|
| + assert( op==OP_OpenWrite || p5==0 );
|
| if( IsVirtual(pTab) ){
|
| /* This routine is a no-op for virtual tables. Leave the output
|
| ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
|
| @@ -1659,6 +1688,7 @@ int sqlite3OpenTableAndIndices(
|
| if( aToOpen==0 || aToOpen[i+1] ){
|
| sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
|
| sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
| + sqlite3VdbeChangeP5(v, p5);
|
| VdbeComment((v, "%s", pIdx->zName));
|
| }
|
| }
|
| @@ -1680,20 +1710,6 @@ int sqlite3_xferopt_count;
|
|
|
| #ifndef SQLITE_OMIT_XFER_OPT
|
| /*
|
| -** Check to collation names to see if they are compatible.
|
| -*/
|
| -static int xferCompatibleCollation(const char *z1, const char *z2){
|
| - if( z1==0 ){
|
| - return z2==0;
|
| - }
|
| - if( z2==0 ){
|
| - return 0;
|
| - }
|
| - return sqlite3StrICmp(z1, z2)==0;
|
| -}
|
| -
|
| -
|
| -/*
|
| ** Check to see if index pSrc is compatible as a source of data
|
| ** for index pDest in an insert transfer optimization. The rules
|
| ** for a compatible index:
|
| @@ -1718,10 +1734,17 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
| if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
|
| return 0; /* Different columns indexed */
|
| }
|
| + if( pSrc->aiColumn[i]==XN_EXPR ){
|
| + assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
|
| + if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
|
| + pDest->aColExpr->a[i].pExpr, -1)!=0 ){
|
| + return 0; /* Different expressions in the index */
|
| + }
|
| + }
|
| if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
|
| return 0; /* Different sort orders */
|
| }
|
| - if( !xferCompatibleCollation(pSrc->azColl[i],pDest->azColl[i]) ){
|
| + if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
|
| return 0; /* Different collating sequences */
|
| }
|
| }
|
| @@ -1765,6 +1788,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 */
|
| @@ -1835,7 +1859,7 @@ static int xferOptimization(
|
| return 0; /* The result set must have exactly one column */
|
| }
|
| assert( pEList->a[0].pExpr );
|
| - if( pEList->a[0].pExpr->op!=TK_ALL ){
|
| + if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
|
| return 0; /* The result set must be the special operator "*" */
|
| }
|
|
|
| @@ -1871,10 +1895,17 @@ static int xferOptimization(
|
| for(i=0; i<pDest->nCol; i++){
|
| Column *pDestCol = &pDest->aCol[i];
|
| Column *pSrcCol = &pSrc->aCol[i];
|
| +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
|
| + if( (db->flags & SQLITE_Vacuum)==0
|
| + && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
|
| + ){
|
| + return 0; /* Neither table may have __hidden__ columns */
|
| + }
|
| +#endif
|
| if( pDestCol->affinity!=pSrcCol->affinity ){
|
| return 0; /* Affinity must be the same on all columns */
|
| }
|
| - if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
|
| + if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
|
| return 0; /* Collating sequence must be the same on all columns */
|
| }
|
| if( pDestCol->notNull && !pSrcCol->notNull ){
|
| @@ -1912,11 +1943,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 +1958,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 +1968,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
|
| @@ -1956,7 +1991,7 @@ static int xferOptimization(
|
| ** (3) onError is something other than OE_Abort and OE_Rollback.
|
| */
|
| addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
|
| - emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
| + emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto);
|
| sqlite3VdbeJumpHere(v, addr1);
|
| }
|
| if( HasRowid(pSrc) ){
|
| @@ -1987,6 +2022,7 @@ static int xferOptimization(
|
| sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName);
|
| }
|
| for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
| + u8 idxInsFlags = 0;
|
| for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){
|
| if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
|
| }
|
| @@ -2000,7 +2036,37 @@ 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. */
|
| + for(i=0; i<pSrcIdx->nColumn; i++){
|
| + const char *zColl = pSrcIdx->azColl[i];
|
| + assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
|
| + || sqlite3StrBINARY==zColl );
|
| + if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
| + }
|
| + if( i==pSrcIdx->nColumn ){
|
| + idxInsFlags = OPFLAG_USESEEKRESULT;
|
| + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
|
| + }
|
| + }
|
| + if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
|
| + idxInsFlags |= OPFLAG_NCHANGE;
|
| + }
|
| sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
| + sqlite3VdbeChangeP5(v, idxInsFlags);
|
| sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
| sqlite3VdbeJumpHere(v, addr1);
|
| sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
|
|