#include "sqliteInt.h"
void sqlite3OpenTable(
Parse *pParse,
int iCur,
int iDb,
Table *pTab,
int opcode
){
Vdbe *v;
assert( !IsVirtual(pTab) );
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
sqlite3TableLock(pParse, iDb, pTab->tnum,
(opcode==OP_OpenWrite)?1:0, pTab->zName);
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
assert( pPk->tnum==pTab->tnum || CORRUPT_DB );
sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
VdbeComment((v, "%s", pTab->zName));
}
}
static SQLITE_NOINLINE const char *computeIndexAffStr(sqlite3 *db, Index *pIdx){
int n;
Table *pTab = pIdx->pTable;
pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
sqlite3OomFault(db);
return 0;
}
for(n=0; n<pIdx->nColumn; n++){
i16 x = pIdx->aiColumn[n];
char aff;
if( x>=0 ){
aff = pTab->aCol[x].affinity;
}else if( x==XN_ROWID ){
aff = SQLITE_AFF_INTEGER;
}else{
assert( x==XN_EXPR );
assert( pIdx->bHasExpr );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
pIdx->zColAff[n] = aff;
}
pIdx->zColAff[n] = 0;
return pIdx->zColAff;
}
const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx);
return pIdx->zColAff;
}
char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
char *zColAff;
zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
if( zColAff ){
int i, j;
for(i=j=0; i<pTab->nCol; i++){
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
zColAff[j++] = pTab->aCol[i].affinity;
}
}
do{
zColAff[j--] = 0;
}while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
}
return zColAff;
}
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
int i;
char *zColAff;
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
pPrev = sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3);
}else{
sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
return;
}
zColAff = pTab->zColAff;
if( zColAff==0 ){
zColAff = sqlite3TableAffinityStr(0, pTab);
if( !zColAff ){
sqlite3OomFault(sqlite3VdbeDb(v));
return;
}
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
i = sqlite3Strlen30NN(zColAff);
if( i ){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlite3VdbeDb(v)->mallocFailed );
sqlite3VdbeChangeP4(v, -1, zColAff, i);
}
}
}
static int readsTable(Parse *p, int iDb, Table *pTab){
Vdbe *v = sqlite3GetVdbe(p);
int i;
int iEnd = sqlite3VdbeCurrentAddr(v);
#ifndef SQLITE_OMIT_VIRTUALTABLE
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
#endif
for(i=1; i<iEnd; i++){
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
assert( pOp!=0 );
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
Index *pIndex;
Pgno tnum = pOp->p2;
if( tnum==pTab->tnum ){
return 1;
}
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
if( tnum==pIndex->tnum ){
return 1;
}
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){
assert( pOp->p4.pVtab!=0 );
assert( pOp->p4type==P4_VTAB );
return 1;
}
#endif
}
return 0;
}
static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){
assert( pExpr->iColumn < pWalker->u.pTab->nCol );
pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
}
return WRC_Continue;
}
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
void sqlite3ComputeGeneratedColumns(
Parse *pParse,
int iRegStore,
Table *pTab
){
int i;
Walker w;
Column *pRedo;
int eProgress;
VdbeOp *pOp;
assert( pTab->tabFlags & TF_HasGenerated );
testcase( pTab->tabFlags & TF_HasVirtual );
testcase( pTab->tabFlags & TF_HasStored );
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Affinity ){
int ii, jj;
char *zP4 = pOp->p4.z;
assert( zP4!=0 );
assert( pOp->p4type==P4_DYNAMIC );
for(ii=jj=0; zP4[jj]; ii++){
if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
continue;
}
if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
zP4[jj] = SQLITE_AFF_NONE;
}
jj++;
}
}else if( pOp->opcode==OP_TypeCheck ){
pOp->p3 = 1;
}
}
for(i=0; i<pTab->nCol; i++){
if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL;
}
}
w.u.pTab = pTab;
w.xExprCallback = exprColumnFlagUnion;
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
pParse->iSelfTab = -iRegStore;
do{
eProgress = 0;
pRedo = 0;
for(i=0; i<pTab->nCol; i++){
Column *pCol = pTab->aCol + i;
if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){
int x;
pCol->colFlags |= COLFLAG_BUSY;
w.eCode = 0;
sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol));
pCol->colFlags &= ~COLFLAG_BUSY;
if( w.eCode & COLFLAG_NOTAVAIL ){
pRedo = pCol;
continue;
}
eProgress = 1;
assert( pCol->colFlags & COLFLAG_GENERATED );
x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x);
pCol->colFlags &= ~COLFLAG_NOTAVAIL;
}
}
}while( pRedo && eProgress );
if( pRedo ){
sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName);
}
pParse->iSelfTab = 0;
}
#endif
#ifndef SQLITE_OMIT_AUTOINCREMENT
static int autoIncBegin(
Parse *pParse,
int iDb,
Table *pTab
){
int memId = 0;
assert( pParse->db->aDb[iDb].pSchema!=0 );
if( (pTab->tabFlags & TF_Autoincrement)!=0
&& (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab;
if( pSeqTab==0
|| !HasRowid(pSeqTab)
|| NEVER(IsVirtual(pSeqTab))
|| pSeqTab->nCol!=2
){
pParse->nErr++;
pParse->rc = SQLITE_CORRUPT_SEQUENCE;
return 0;
}
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
if( pInfo==0 ){
pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo);
testcase( pParse->earlyCleanup );
if( pParse->db->mallocFailed ) return 0;
pInfo->pNext = pToplevel->pAinc;
pToplevel->pAinc = pInfo;
pInfo->pTab = pTab;
pInfo->iDb = iDb;
pToplevel->nMem++;
pInfo->regCtr = ++pToplevel->nMem;
pToplevel->nMem +=2;
}
memId = pInfo->regCtr;
}
return memId;
}
void sqlite3AutoincrementBegin(Parse *pParse){
AutoincInfo *p;
sqlite3 *db = pParse->db;
Db *pDb;
int memId;
Vdbe *v = pParse->pVdbe;
assert( pParse->pTriggerTab==0 );
assert( sqlite3IsToplevel(pParse) );
assert( v );
for(p = pParse->pAinc; p; p = p->pNext){
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList autoInc[] = {
{OP_Null, 0, 0, 0},
{OP_Rewind, 0, 10, 0},
{OP_Column, 0, 0, 0},
{OP_Ne, 0, 9, 0},
{OP_Rowid, 0, 0, 0},
{OP_Column, 0, 1, 0},
{OP_AddImm, 0, 0, 0},
{OP_Copy, 0, 0, 0},
{OP_Goto, 0, 11, 0},
{OP_Next, 0, 2, 0},
{OP_Integer, 0, 0, 0},
{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);
sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
if( aOp==0 ) break;
aOp[0].p2 = memId;
aOp[0].p3 = memId+2;
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[6].p1 = memId;
aOp[7].p2 = memId+2;
aOp[7].p1 = memId;
aOp[10].p2 = memId;
if( pParse->nTab==0 ) pParse->nTab = 1;
}
}
static void autoIncStep(Parse *pParse, int memId, int regRowid){
if( memId>0 ){
sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid);
}
}
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[] = {
{OP_NotNull, 0, 2, 0},
{OP_NewRowid, 0, 0, 0},
{OP_MakeRecord, 0, 2, 0},
{OP_Insert, 0, 0, 0},
{OP_Close, 0, 0, 0}
};
VdbeOp *aOp;
Db *pDb = &db->aDb[p->iDb];
int iRec;
int memId = p->regCtr;
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId);
VdbeCoverage(v);
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
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
# define autoIncBegin(A,B,C) (0)
# define autoIncStep(A,B,C)
#endif
static int xferOptimization(
Parse *pParse,
Table *pDest,
Select *pSelect,
int onError,
int iDbDest
);
void sqlite3Insert(
Parse *pParse,
SrcList *pTabList,
Select *pSelect,
IdList *pColumn,
int onError,
Upsert *pUpsert
){
sqlite3 *db;
Table *pTab;
int i, j;
Vdbe *v;
Index *pIdx;
int nColumn;
int nHidden = 0;
int iDataCur = 0;
int iIdxCur = 0;
int ipkColumn = -1;
int endOfLoop;
int srcTab = 0;
int addrInsTop = 0;
int addrCont = 0;
SelectDest dest;
int iDb;
u8 useTempTable = 0;
u8 appendFlag = 0;
u8 withoutRowid;
u8 bIdListInOrder;
ExprList *pList = 0;
int iRegStore;
int regFromSelect = 0;
int regAutoinc = 0;
int regRowCount = 0;
int regIns;
int regRowid;
int regData;
int *aRegIdx = 0;
#ifndef SQLITE_OMIT_TRIGGER
int isView;
Trigger *pTrigger;
int tmask;
#endif
db = pParse->db;
assert( db->pParse==pParse );
if( pParse->nErr ){
goto insert_cleanup;
}
assert( db->mallocFailed==0 );
dest.iSDParm = 0;
if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){
pList = pSelect->pEList;
pSelect->pEList = 0;
sqlite3SelectDelete(db, pSelect);
pSelect = 0;
}
assert( pTabList->nSrc==1 );
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ){
goto insert_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
db->aDb[iDb].zDbSName) ){
goto insert_cleanup;
}
withoutRowid = !HasRowid(pTab);
#ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
isView = IsView(pTab);
#else
# define pTrigger 0
# define tmask 0
# define isView 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList,
onError, pUpsert, pTrigger);
}
#endif
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto insert_cleanup;
}
if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto insert_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb);
#ifndef SQLITE_OMIT_XFER_OPT
if( pColumn==0
&& pSelect!=0
&& pTrigger==0
&& xferOptimization(pParse, pTab, pSelect, onError, iDb)
){
assert( !pTrigger );
assert( pList==0 );
goto insert_end;
}
#endif
regAutoinc = autoIncBegin(pParse, iDb, pTab);
regRowid = regIns = pParse->nMem+1;
pParse->nMem += pTab->nCol + 1;
if( IsVirtual(pTab) ){
regRowid++;
pParse->nMem++;
}
regData = regRowid+1;
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
assert( pColumn->eU4!=EU4_EXPR );
pColumn->eU4 = EU4_IDX;
for(i=0; i<pColumn->nId; i++){
pColumn->a[i].u4.idx = -1;
}
for(i=0; i<pColumn->nId; i++){
for(j=0; j<pTab->nCol; j++){
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
pColumn->a[i].u4.idx = j;
if( i!=j ) bIdListInOrder = 0;
if( j==pTab->iPKey ){
ipkColumn = i; assert( !withoutRowid );
}
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
sqlite3ErrorMsg(pParse,
"cannot INSERT into generated column \"%s\"",
pTab->aCol[j].zCnName);
goto insert_cleanup;
}
#endif
break;
}
}
if( j>=pTab->nCol ){
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
ipkColumn = i;
bIdListInOrder = 0;
}else{
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
pTabList->a, pColumn->a[i].zName);
pParse->checkSchema = 1;
goto insert_cleanup;
}
}
}
}
if( pSelect ){
int regYield;
int addrTop;
int rc;
regYield = ++pParse->nMem;
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
dest.iSdst = bIdListInOrder ? regData : 0;
dest.nSdst = pTab->nCol;
rc = sqlite3Select(pParse, pSelect, &dest);
regFromSelect = dest.iSdst;
assert( db->pParse==pParse );
if( rc || pParse->nErr ) goto insert_cleanup;
assert( db->mallocFailed==0 );
sqlite3VdbeEndCoroutine(v, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1);
assert( pSelect->pEList );
nColumn = pSelect->pEList->nExpr;
if( pTrigger || readsTable(pParse, iDb, pTab) ){
useTempTable = 1;
}
if( useTempTable ){
int regRec;
int regTempRowid;
int addrL;
srcTab = pParse->nTab++;
regRec = sqlite3GetTempReg(pParse);
regTempRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
sqlite3VdbeGoto(v, addrL);
sqlite3VdbeJumpHere(v, addrL);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempReg(pParse, regTempRowid);
}
}else{
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
srcTab = -1;
assert( useTempTable==0 );
if( pList ){
nColumn = pList->nExpr;
if( sqlite3ResolveExprListNames(&sNC, pList) ){
goto insert_cleanup;
}
}else{
nColumn = 0;
}
}
if( pColumn==0 && nColumn>0 ){
ipkColumn = pTab->iPKey;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
testcase( pTab->tabFlags & TF_HasVirtual );
testcase( pTab->tabFlags & TF_HasStored );
for(i=ipkColumn-1; i>=0; i--){
if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
ipkColumn--;
}
}
}
#endif
assert( TF_HasHidden==COLFLAG_HIDDEN );
assert( TF_HasGenerated==COLFLAG_GENERATED );
assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) );
if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){
for(i=0; i<pTab->nCol; i++){
if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
}
}
if( nColumn!=(pTab->nCol-nHidden) ){
sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied",
pTabList->a, pTab->nCol-nHidden, nColumn);
goto insert_cleanup;
}
}
if( pColumn!=0 && nColumn!=pColumn->nId ){
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
goto insert_cleanup;
}
if( (db->flags & SQLITE_CountRows)!=0
&& !pParse->nested
&& !pParse->pTriggerTab
&& !pParse->bReturning
){
regRowCount = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
if( !isView ){
int nIdx;
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
&iDataCur, &iIdxCur);
aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2));
if( aRegIdx==0 ){
goto insert_cleanup;
}
for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
assert( pIdx );
aRegIdx[i] = ++pParse->nMem;
pParse->nMem += pIdx->nColumn;
}
aRegIdx[i] = ++pParse->nMem;
}
#ifndef SQLITE_OMIT_UPSERT
if( pUpsert ){
Upsert *pNx;
if( IsVirtual(pTab) ){
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
pTab->zName);
goto insert_cleanup;
}
if( IsView(pTab) ){
sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
goto insert_cleanup;
}
if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
goto insert_cleanup;
}
pTabList->a[0].iCursor = iDataCur;
pNx = pUpsert;
do{
pNx->pUpsertSrc = pTabList;
pNx->regData = regData;
pNx->iDataCur = iDataCur;
pNx->iIdxCur = iIdxCur;
if( pNx->pUpsertTarget ){
if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
goto insert_cleanup;
}
}
pNx = pNx->pNextUpsert;
}while( pNx!=0 );
}
#endif
if( useTempTable ){
addrInsTop = sqlite3VdbeAddOp1(v, OP_Rewind, srcTab); VdbeCoverage(v);
addrCont = sqlite3VdbeCurrentAddr(v);
}else if( pSelect ){
sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0);
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
if( ipkColumn>=0 ){
sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
}
}
nHidden = 0;
iRegStore = regData; assert( regData==regRowid+1 );
for(i=0; i<pTab->nCol; i++, iRegStore++){
int k;
u32 colFlags;
assert( i>=nHidden );
if( i==pTab->iPKey ){
sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
continue;
}
if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){
nHidden++;
if( (colFlags & COLFLAG_VIRTUAL)!=0 ){
iRegStore--;
continue;
}else if( (colFlags & COLFLAG_STORED)!=0 ){
if( tmask & TRIGGER_BEFORE ){
sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
}
continue;
}else if( pColumn==0 ){
sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue;
}
}
if( pColumn ){
assert( pColumn->eU4==EU4_IDX );
for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
if( j>=pColumn->nId ){
sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue;
}
k = j;
}else if( nColumn==0 ){
sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue;
}else{
k = i - nHidden;
}
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
}else if( pSelect ){
if( regFromSelect!=regData ){
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
Expr *pX = pList->a[k].pExpr;
int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
if( y!=iRegStore ){
sqlite3VdbeAddOp2(v,
ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
}
}
}
endOfLoop = sqlite3VdbeMakeLabel(pParse);
if( tmask & TRIGGER_BEFORE ){
int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1);
if( ipkColumn<0 ){
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
}else{
int addr1;
assert( !withoutRowid );
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
}else{
assert( pSelect==0 );
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
}
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
}
assert( pTab->nNVCol>0 || pParse->nErr>0 );
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( pTab->tabFlags & TF_HasGenerated ){
testcase( pTab->tabFlags & TF_HasVirtual );
testcase( pTab->tabFlags & TF_HasStored );
sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab);
}
#endif
if( !isView ){
sqlite3TableAffinity(v, pTab, regCols+1);
}
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
pTab, regCols-pTab->nCol-1, onError, endOfLoop);
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
}
if( !isView ){
if( IsVirtual(pTab) ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
}
if( ipkColumn>=0 ){
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
}else if( pSelect ){
}else{
Expr *pIpk = pList->a[ipkColumn].pExpr;
if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
appendFlag = 1;
}else{
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
}
}
if( !appendFlag ){
int addr1;
if( !IsVirtual(pTab) ){
addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
sqlite3VdbeJumpHere(v, addr1);
}else{
addr1 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
}
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
}
}else if( IsVirtual(pTab) || withoutRowid ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
}else{
sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
appendFlag = 1;
}
autoIncStep(pParse, regAutoinc, regRowid);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( pTab->tabFlags & TF_HasGenerated ){
sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
}else
#endif
{
int isReplace = 0;
int bUseSeek;
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
if( db->flags & SQLITE_ForeignKeys ){
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
}
bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v));
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
regIns, aRegIdx, 0, appendFlag, bUseSeek
);
}
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
}else if( pParse->bReturning ){
sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
#endif
}
if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
if( pTrigger ){
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
pTab, regData-2-pTab->nCol, onError, endOfLoop);
}
sqlite3VdbeResolveLabel(v, endOfLoop);
if( useTempTable ){
sqlite3VdbeAddOp2(v, OP_Next, srcTab, addrCont); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addrInsTop);
sqlite3VdbeAddOp1(v, OP_Close, srcTab);
}else if( pSelect ){
sqlite3VdbeGoto(v, addrCont);
#ifdef SQLITE_DEBUG
if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){
assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield );
sqlite3VdbeChangeP5(v, 1);
}
#endif
sqlite3VdbeJumpHere(v, addrInsTop);
}
#ifndef SQLITE_OMIT_XFER_OPT
insert_end:
#endif
if( pParse->nested==0 && pParse->pTriggerTab==0 ){
sqlite3AutoincrementEnd(pParse);
}
if( regRowCount ){
sqlite3CodeChangeCount(v, regRowCount, "rows inserted");
}
insert_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pList);
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
}
#ifdef isView
#undef isView
#endif
#ifdef pTrigger
#undef pTrigger
#endif
#ifdef tmask
#undef tmask
#endif
#define CKCNSTRNT_COLUMN 0x01
#define CKCNSTRNT_ROWID 0x02
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;
}
int sqlite3ExprReferencesUpdatedColumn(
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!=0;
}
typedef struct IndexListTerm IndexListTerm;
typedef struct IndexIterator IndexIterator;
struct IndexIterator {
int eType;
int i;
union {
struct {
Index *pIdx;
} lx;
struct {
int nIdx;
IndexListTerm *aIdx;
} ax;
} u;
};
struct IndexListTerm {
Index *p;
int ix;
};
static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){
assert( pIter->i==0 );
if( pIter->eType ){
*pIx = pIter->u.ax.aIdx[0].ix;
return pIter->u.ax.aIdx[0].p;
}else{
*pIx = 0;
return pIter->u.lx.pIdx;
}
}
static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){
if( pIter->eType ){
int i = ++pIter->i;
if( i>=pIter->u.ax.nIdx ){
*pIx = i;
return 0;
}
*pIx = pIter->u.ax.aIdx[i].ix;
return pIter->u.ax.aIdx[i].p;
}else{
++(*pIx);
pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext;
return pIter->u.lx.pIdx;
}
}
void sqlite3GenerateConstraintChecks(
Parse *pParse,
Table *pTab,
int *aRegIdx,
int iDataCur,
int iIdxCur,
int regNewData,
int regOldData,
u8 pkChng,
u8 overrideError,
int ignoreDest,
int *pbMayReplace,
int *aiChng,
Upsert *pUpsert
){
Vdbe *v;
Index *pIdx;
Index *pPk = 0;
sqlite3 *db;
int i;
int ix;
int nCol;
int onError;
int seenReplace = 0;
int nPkField;
Upsert *pUpsertClause = 0;
u8 isUpdate;
u8 bAffinityDone = 0;
int upsertIpkReturn = 0;
int upsertIpkDelay = 0;
int ipkTop = 0;
int ipkBottom = 0;
int regTrigCnt;
int addrRecheck = 0;
int lblRecheckOk = 0;
Trigger *pTrigger;
int nReplaceTrig = 0;
IndexIterator sIdxIter;
isUpdate = regOldData!=0;
db = pParse->db;
v = pParse->pVdbe;
assert( v!=0 );
assert( !IsView(pTab) );
nCol = pTab->nCol;
if( HasRowid(pTab) ){
pPk = 0;
nPkField = 1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
nPkField = pPk->nKeyCol;
}
VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
iDataCur, iIdxCur, regNewData, regOldData, pkChng));
if( pTab->tabFlags & TF_HasNotNull ){
int b2ndPass = 0;
int nSeenReplace = 0;
int nGenerated = 0;
while(1){
for(i=0; i<nCol; i++){
int iReg;
Column *pCol = &pTab->aCol[i];
int isGenerated;
onError = pCol->notNull;
if( onError==OE_None ) continue;
if( i==pTab->iPKey ){
continue;
}
isGenerated = pCol->colFlags & COLFLAG_GENERATED;
if( isGenerated && !b2ndPass ){
nGenerated++;
continue;
}
if( aiChng && aiChng[i]<0 && !isGenerated ){
continue;
}
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
}
if( onError==OE_Replace ){
if( b2ndPass
|| pCol->iDflt==0
){
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
testcase( pCol->colFlags & COLFLAG_STORED );
testcase( pCol->colFlags & COLFLAG_GENERATED );
onError = OE_Abort;
}else{
assert( !isGenerated );
}
}else if( b2ndPass && !isGenerated ){
continue;
}
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
testcase( i!=sqlite3TableColumnToStorage(pTab, i) );
iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1;
switch( onError ){
case OE_Replace: {
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg);
VdbeCoverage(v);
assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
nSeenReplace++;
sqlite3ExprCodeCopy(pParse,
sqlite3ColumnExpr(pTab, pCol), iReg);
sqlite3VdbeJumpHere(v, addr1);
break;
}
case OE_Abort:
sqlite3MayAbort(pParse);
deliberate_fall_through
case OE_Rollback:
case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
pCol->zCnName);
testcase( zMsg==0 && db->mallocFailed==0 );
sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
onError, iReg);
sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
VdbeCoverage(v);
break;
}
default: {
assert( onError==OE_Ignore );
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest);
VdbeCoverage(v);
break;
}
}
}
if( nGenerated==0 && nSeenReplace==0 ){
break;
}
if( b2ndPass ) break;
b2ndPass = 1;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab);
}
#endif
}
}
#ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = pTab->pCheck;
pParse->iSelfTab = -(regNewData+1);
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
int allOk;
Expr *pCopy;
Expr *pExpr = pCheck->a[i].pExpr;
if( aiChng
&& !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
){
continue;
}
if( bAffinityDone==0 ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
allOk = sqlite3VdbeMakeLabel(pParse);
sqlite3VdbeVerifyAbortable(v, onError);
pCopy = sqlite3ExprDup(db, pExpr, 0);
if( !db->mallocFailed ){
sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL);
}
sqlite3ExprDelete(db, pCopy);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
}else{
char *zName = pCheck->a[i].zEName;
assert( zName!=0 || pParse->db->mallocFailed );
if( onError==OE_Replace ) onError = OE_Abort;
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
onError, zName, P4_TRANSIENT,
P5_ConstraintCheck);
}
sqlite3VdbeResolveLabel(v, allOk);
}
pParse->iSelfTab = 0;
}
#endif
sIdxIter.eType = 0;
sIdxIter.i = 0;
sIdxIter.u.ax.aIdx = 0;
sIdxIter.u.lx.pIdx = pTab->pIndex;
if( pUpsert ){
if( pUpsert->pUpsertTarget==0 ){
assert( pUpsert->pNextUpsert==0 );
if( pUpsert->isDoUpdate==0 ){
overrideError = OE_Ignore;
pUpsert = 0;
}else{
overrideError = OE_Update;
}
}else if( pTab->pIndex!=0 ){
int nIdx, jj;
u64 nByte;
Upsert *pTerm;
u8 *bUsed;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
assert( aRegIdx[nIdx]>0 );
}
sIdxIter.eType = 1;
sIdxIter.u.ax.nIdx = nIdx;
nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx;
sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte);
if( sIdxIter.u.ax.aIdx==0 ) return;
bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx];
pUpsert->pToFree = sIdxIter.u.ax.aIdx;
for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){
if( pTerm->pUpsertTarget==0 ) break;
if( pTerm->pUpsertIdx==0 ) continue;
jj = 0;
pIdx = pTab->pIndex;
while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){
pIdx = pIdx->pNext;
jj++;
}
if( bUsed[jj] ) continue;
bUsed[jj] = 1;
sIdxIter.u.ax.aIdx[i].p = pIdx;
sIdxIter.u.ax.aIdx[i].ix = jj;
i++;
}
for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){
if( bUsed[jj] ) continue;
sIdxIter.u.ax.aIdx[i].p = pIdx;
sIdxIter.u.ax.aIdx[i].ix = jj;
i++;
}
assert( i==nIdx );
}
}
if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){
pTrigger = 0;
regTrigCnt = 0;
}else{
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0);
}else{
pTrigger = 0;
regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0);
}
if( regTrigCnt ){
regTrigCnt = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt);
VdbeComment((v, "trigger count"));
lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
addrRecheck = lblRecheckOk;
}
}
if( pkChng && pPk==0 ){
int addrRowidOk = sqlite3VdbeMakeLabel(pParse);
onError = pTab->keyConf;
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
}
if( pUpsert ){
pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0);
if( pUpsertClause!=0 ){
if( pUpsertClause->isDoUpdate==0 ){
onError = OE_Ignore;
}else{
onError = OE_Update;
}
}
if( pUpsertClause!=pUpsert ){
upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto);
}
}
if( onError==OE_Replace
&& onError!=overrideError
&& pTab->pIndex
&& !upsertIpkDelay
){
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
VdbeComment((v, "defer IPK REPLACE until last"));
}
if( isUpdate ){
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
VdbeCoverage(v);
}
VdbeNoopComment((v, "uniqueness check for ROWID"));
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
VdbeCoverage(v);
switch( onError ){
default: {
onError = OE_Abort;
deliberate_fall_through
}
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
testcase( onError==OE_Rollback );
testcase( onError==OE_Abort );
testcase( onError==OE_Fail );
sqlite3RowidConstraint(pParse, onError, pTab);
break;
}
case OE_Replace: {
if( regTrigCnt ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regNewData, 1, 0, OE_Replace, 1, -1);
sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1);
nReplaceTrig++;
}else{
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
assert( HasRowid(pTab) );
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
#endif
if( pTab->pIndex ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
}
}
seenReplace = 1;
break;
}
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
deliberate_fall_through
}
#endif
case OE_Ignore: {
testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
}
sqlite3VdbeResolveLabel(v, addrRowidOk);
if( pUpsert && pUpsertClause!=pUpsert ){
upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto);
}else if( ipkTop ){
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, ipkTop-1);
}
}
for(pIdx = indexIteratorFirst(&sIdxIter, &ix);
pIdx;
pIdx = indexIteratorNext(&sIdxIter, &ix)
){
int regIdx;
int regR;
int iThisCur;
int addrUniqueOk;
int addrConflictCk;
if( aRegIdx[ix]==0 ) continue;
if( pUpsert ){
pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx);
if( upsertIpkDelay && pUpsertClause==pUpsert ){
sqlite3VdbeJumpHere(v, upsertIpkDelay);
}
}
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
if( bAffinityDone==0 ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
VdbeNoopComment((v, "prep index %s", pIdx->zName));
iThisCur = iIdxCur+ix;
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
pParse->iSelfTab = -(regNewData+1);
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
SQLITE_JUMPIFNULL);
pParse->iSelfTab = 0;
}
regIdx = aRegIdx[ix]+1;
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
if( iField==XN_EXPR ){
pParse->iSelfTab = -(regNewData+1);
sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
pParse->iSelfTab = 0;
VdbeComment((v, "%s column %d", pIdx->zName, i));
}else if( iField==XN_ROWID || iField==pTab->iPKey ){
x = regNewData;
sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i);
VdbeComment((v, "rowid"));
}else{
testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField );
x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1;
sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
VdbeComment((v, "%s", pTab->aCol[iField].zCnName));
}
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName));
#ifdef SQLITE_ENABLE_NULL_TRIM
if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
sqlite3SetMakeRecordP5(v, pIdx->pTable);
}
#endif
sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0);
if( isUpdate && pPk==pIdx && pkChng==0 ){
sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue;
}
onError = pIdx->onError;
if( onError==OE_None ){
sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue;
}
if( overrideError!=OE_Default ){
onError = overrideError;
}else if( onError==OE_Default ){
onError = OE_Abort;
}
if( pUpsertClause ){
if( pUpsertClause->isDoUpdate==0 ){
onError = OE_Ignore;
}else{
onError = OE_Update;
}
}
assert( IsOrdinaryTable(pTab) );
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
if( (ix==0 && pIdx->pNext==0)
&& pPk==pIdx
&& onError==OE_Replace
&& ( 0==(db->flags&SQLITE_RecTriggers) ||
0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
&& ( 0==(db->flags&SQLITE_ForeignKeys) ||
(0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab)))
){
sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue;
}
#endif
sqlite3VdbeVerifyAbortable(v, onError);
addrConflictCk =
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField);
if( isUpdate || onError==OE_Replace ){
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
if( isUpdate ){
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
VdbeCoverage(v);
}
}else{
int x;
if( pIdx!=pPk ){
for(i=0; i<pPk->nKeyCol; i++){
assert( pPk->aiColumn[i]>=0 );
x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
pTab->aCol[pPk->aiColumn[i]].zCnName));
}
}
if( isUpdate ){
int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
int op = OP_Ne;
int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
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;
}
x = sqlite3TableColumnToStorage(pTab, x);
sqlite3VdbeAddOp4(v, op,
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
VdbeCoverageIf(v, op==OP_Eq);
VdbeCoverageIf(v, op==OP_Ne);
}
}
}
}
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace || onError==OE_Update );
switch( onError ){
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
testcase( onError==OE_Rollback );
testcase( onError==OE_Abort );
testcase( onError==OE_Fail );
sqlite3UniqueConstraint(pParse, onError, pIdx);
break;
}
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
deliberate_fall_through
}
#endif
case OE_Ignore: {
testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
default: {
int nConflictCk;
assert( onError==OE_Replace );
nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
assert( nConflictCk>0 || db->mallocFailed );
testcase( nConflictCk<=0 );
testcase( nConflictCk>1 );
if( regTrigCnt ){
sqlite3MultiWrite(pParse);
nReplaceTrig++;
}
if( pTrigger && isUpdate ){
sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
if( pTrigger && isUpdate ){
sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
}
if( regTrigCnt ){
int addrBypass;
sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1);
addrBypass = sqlite3VdbeAddOp0(v, OP_Goto);
VdbeComment((v, "bypass recheck"));
sqlite3VdbeResolveLabel(v, lblRecheckOk);
lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk);
VdbeCoverage(v);
}
while( nConflictCk>0 ){
VdbeOp x;
x = *sqlite3VdbeGetOp(v, addrConflictCk);
if( x.opcode!=OP_IdxRowid ){
int p2;
const char *zP4;
if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
p2 = lblRecheckOk;
}else{
p2 = x.p2;
}
zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z;
sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type);
sqlite3VdbeChangeP5(v, x.p5);
VdbeCoverageIf(v, p2!=x.p2);
}
nConflictCk--;
addrConflictCk++;
}
sqlite3UniqueConstraint(pParse, OE_Abort, pIdx);
sqlite3VdbeJumpHere(v, addrBypass);
}
seenReplace = 1;
break;
}
}
sqlite3VdbeResolveLabel(v, addrUniqueOk);
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
if( pUpsertClause
&& upsertIpkReturn
&& sqlite3UpsertNextIsIPK(pUpsertClause)
){
sqlite3VdbeGoto(v, upsertIpkDelay+1);
sqlite3VdbeJumpHere(v, upsertIpkReturn);
upsertIpkReturn = 0;
}
}
if( ipkTop ){
sqlite3VdbeGoto(v, ipkTop);
VdbeComment((v, "Do IPK REPLACE"));
assert( ipkBottom>0 );
sqlite3VdbeJumpHere(v, ipkBottom);
}
testcase( regTrigCnt!=0 && nReplaceTrig==0 );
assert( regTrigCnt!=0 || nReplaceTrig==0 );
if( nReplaceTrig ){
sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v);
if( !pPk ){
if( isUpdate ){
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData);
VdbeCoverage(v);
sqlite3RowidConstraint(pParse, OE_Abort, pTab);
}else{
sqlite3VdbeGoto(v, addrRecheck);
}
sqlite3VdbeResolveLabel(v, lblRecheckOk);
}
if( HasRowid(pTab) ){
int regRec = aRegIdx[ix];
sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec);
sqlite3SetMakeRecordP5(v, pTab);
if( !bAffinityDone ){
sqlite3TableAffinity(v, pTab, 0);
}
}
*pbMayReplace = seenReplace;
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
}
#ifdef SQLITE_ENABLE_NULL_TRIM
void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
u16 i;
if( pTab->pSchema->file_format<2 ) return;
for(i=pTab->nCol-1; i>0; i--){
if( pTab->aCol[i].iDflt!=0 ) break;
if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
}
sqlite3VdbeChangeP5(v, i+1);
}
#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
static void codeWithoutRowidPreupdate(
Parse *pParse,
Table *pTab,
int iCur,
int regData
){
Vdbe *v = pParse->pVdbe;
int r = sqlite3GetTempReg(pParse);
assert( !HasRowid(pTab) );
assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB );
sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
sqlite3ReleaseTempReg(pParse, r);
}
#else
# define codeWithoutRowidPreupdate(a,b,c,d)
#endif
void sqlite3CompleteInsertion(
Parse *pParse,
Table *pTab,
int iDataCur,
int iIdxCur,
int regNewData,
int *aRegIdx,
int update_flags,
int appendBias,
int useSeekResult
){
Vdbe *v;
Index *pIdx;
u8 pik_flags;
int i;
assert( update_flags==0
|| update_flags==OPFLAG_ISUPDATE
|| update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
);
v = pParse->pVdbe;
assert( v!=0 );
assert( !IsView(pTab) );
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
assert( pIdx->onError!=OE_Replace
|| pIdx->pNext==0
|| pIdx->pNext->onError==OE_Replace );
if( aRegIdx[i]==0 ) continue;
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
}
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
pik_flags |= OPFLAG_NCHANGE;
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
if( update_flags==0 ){
codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]);
}
}
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;
if( pParse->nested ){
pik_flags = 0;
}else{
pik_flags = OPFLAG_NCHANGE;
pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID);
}
if( appendBias ){
pik_flags |= OPFLAG_APPEND;
}
if( useSeekResult ){
pik_flags |= OPFLAG_USESEEKRESULT;
}
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData);
if( !pParse->nested ){
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
int sqlite3OpenTableAndIndices(
Parse *pParse,
Table *pTab,
int op,
u8 p5,
int iBase,
u8 *aToOpen,
int *piDataCur,
int *piIdxCur
){
int i;
int iDb;
int iDataCur;
Index *pIdx;
Vdbe *v;
assert( op==OP_OpenRead || op==OP_OpenWrite );
assert( op==OP_OpenWrite || p5==0 );
if( IsVirtual(pTab) ){
*piDataCur = *piIdxCur = -999;
return 0;
}
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = pParse->pVdbe;
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
if( piDataCur ) *piDataCur = iDataCur;
if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
if( piIdxCur ) *piIdxCur = iBase;
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
if( piDataCur ) *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
sqlite3VdbeChangeP5(v, p5);
VdbeComment((v, "%s", pIdx->zName));
}
}
if( iBase>pParse->nTab ) pParse->nTab = iBase;
return i;
}
#ifdef SQLITE_TEST
int sqlite3_xferopt_count;
#endif
#ifndef SQLITE_OMIT_XFER_OPT
static int xferCompatibleIndex(Index *pDest, Index *pSrc){
int i;
assert( pDest && pSrc );
assert( pDest->pTable!=pSrc->pTable );
if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){
return 0;
}
if( pDest->onError!=pSrc->onError ){
return 0;
}
for(i=0; i<pSrc->nKeyCol; i++){
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
return 0;
}
if( pSrc->aiColumn[i]==XN_EXPR ){
assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr,
pDest->aColExpr->a[i].pExpr, -1)!=0 ){
return 0;
}
}
if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
return 0;
}
if( sqlite3_stricmp(pSrc->azColl[i],pDest->azColl[i])!=0 ){
return 0;
}
}
if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
return 0;
}
return 1;
}
static int xferOptimization(
Parse *pParse,
Table *pDest,
Select *pSelect,
int onError,
int iDbDest
){
sqlite3 *db = pParse->db;
ExprList *pEList;
Table *pSrc;
Index *pSrcIdx, *pDestIdx;
SrcItem *pItem;
int i;
int iDbSrc;
int iSrc, iDest;
int addr1, addr2;
int emptyDestTest = 0;
int emptySrcTest = 0;
Vdbe *v;
int regAutoinc;
int destHasUniqueIdx = 0;
int regData, regRowid;
assert( pSelect!=0 );
if( pParse->pWith || pSelect->pWith ){
return 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pDest) ){
return 0;
}
#endif
if( onError==OE_Default ){
if( pDest->iPKey>=0 ) onError = pDest->keyConf;
if( onError==OE_Default ) onError = OE_Abort;
}
assert(pSelect->pSrc);
if( pSelect->pSrc->nSrc!=1 ){
return 0;
}
if( pSelect->pSrc->a[0].pSelect ){
return 0;
}
if( pSelect->pWhere ){
return 0;
}
if( pSelect->pOrderBy ){
return 0;
}
if( pSelect->pGroupBy ){
return 0;
}
if( pSelect->pLimit ){
return 0;
}
if( pSelect->pPrior ){
return 0;
}
if( pSelect->selFlags & SF_Distinct ){
return 0;
}
pEList = pSelect->pEList;
assert( pEList!=0 );
if( pEList->nExpr!=1 ){
return 0;
}
assert( pEList->a[0].pExpr );
if( pEList->a[0].pExpr->op!=TK_ASTERISK ){
return 0;
}
pItem = pSelect->pSrc->a;
pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
if( pSrc==0 ){
return 0;
}
if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){
testcase( pSrc!=pDest );
return 0;
}
if( HasRowid(pDest)!=HasRowid(pSrc) ){
return 0;
}
if( !IsOrdinaryTable(pSrc) ){
return 0;
}
if( pDest->nCol!=pSrc->nCol ){
return 0;
}
if( pDest->iPKey!=pSrc->iPKey ){
return 0;
}
if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){
return 0;
}
for(i=0; i<pDest->nCol; i++){
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0;
}
#endif
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
if( (pDestCol->colFlags & COLFLAG_GENERATED) !=
(pSrcCol->colFlags & COLFLAG_GENERATED) ){
return 0;
}
if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){
if( sqlite3ExprCompare(0,
sqlite3ColumnExpr(pSrc, pSrcCol),
sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){
testcase( pDestCol->colFlags & COLFLAG_VIRTUAL );
testcase( pDestCol->colFlags & COLFLAG_STORED );
return 0;
}
}
#endif
if( pDestCol->affinity!=pSrcCol->affinity ){
return 0;
}
if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol),
sqlite3ColumnColl(pSrcCol))!=0 ){
return 0;
}
if( pDestCol->notNull && !pSrcCol->notNull ){
return 0;
}
if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){
Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol);
Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol);
assert( pDestExpr==0 || pDestExpr->op==TK_SPAN );
assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) );
assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN );
assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) );
if( (pDestExpr==0)!=(pSrcExpr==0)
|| (pDestExpr!=0 && strcmp(pDestExpr->u.zToken,
pSrcExpr->u.zToken)!=0)
){
return 0;
}
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
if( IsUniqueIndex(pDestIdx) ){
destHasUniqueIdx = 1;
}
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
}
if( pSrcIdx==0 ){
return 0;
}
if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema
&& sqlite3FaultSim(411)==SQLITE_OK ){
return 0;
}
}
#ifndef SQLITE_OMIT_CHECK
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
return 0;
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
assert( IsOrdinaryTable(pDest) );
if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){
return 0;
}
#endif
if( (db->flags & SQLITE_CountRows)!=0 ){
return 0;
}
#ifdef SQLITE_TEST
sqlite3_xferopt_count++;
#endif
iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
v = sqlite3GetVdbe(pParse);
sqlite3CodeVerifySchema(pParse, iDbSrc);
iSrc = pParse->nTab++;
iDest = pParse->nTab++;
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
regData = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Null, 0, regData);
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0)
|| destHasUniqueIdx
|| (onError!=OE_Abort && onError!=OE_Rollback)
)){
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto);
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 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
sqlite3VdbeVerifyAbortable(v, onError);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
VdbeCoverage(v);
sqlite3RowidConstraint(pParse, onError, pDest);
sqlite3VdbeJumpHere(v, addr2);
}
autoIncStep(pParse, regAutoinc, regRowid);
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
}else{
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
if( db->mDbFlags & DBFLAG_Vacuum ){
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
}else{
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
}
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
insFlags &= ~OPFLAG_PREFORMAT;
}else
#endif
{
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
}
sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
sqlite3VdbeChangeP4(v, -1, (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);
}else{
sqlite3TableLock(pParse, iDbDest, pDest->tnum, 1, pDest->zName);
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;
}
assert( pSrcIdx );
sqlite3VdbeAddOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, iDbSrc);
sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
VdbeComment((v, "%s", pSrcIdx->zName));
sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest);
sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
if( db->mDbFlags & DBFLAG_Vacuum ){
for(i=0; i<pSrcIdx->nColumn; i++){
const char *zColl = pSrcIdx->azColl[i];
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc);
}
}else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
idxInsFlags |= OPFLAG_NCHANGE;
}
if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& !HasRowid(pDest)
&& IsPrimaryKeyIndex(pDestIdx)
){
codeWithoutRowidPreupdate(pParse, pDest, iDest, regData);
}
}
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);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
}
if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest);
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);
return 0;
}else{
return 1;
}
}
#endif