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 a5c3f3e92d437dcb0bd349017afae3e5e4c00843..3e4aac8f4dca094596c47f3484c8c5991cbf2bad 100644 |
--- a/third_party/sqlite/src/src/insert.c |
+++ b/third_party/sqlite/src/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); |