diff options
Diffstat (limited to 'src/insert.c')
-rw-r--r-- | src/insert.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/src/insert.c b/src/insert.c index 7124e6658..fb4f442e9 100644 --- a/src/insert.c +++ b/src/insert.c @@ -488,7 +488,8 @@ void sqlite3Insert( SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ IdList *pColumn, /* Column names corresponding to IDLIST. */ - int onError /* How to handle constraint errors */ + int onError, /* How to handle constraint errors */ + Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ sqlite3 *db; /* The main database structure */ Table *pTab; /* The table to insert into. aka TABLE */ @@ -803,6 +804,13 @@ void sqlite3Insert( pParse->nMem += pIdx->nColumn; } } +#ifndef SQLITE_OMIT_UPSERT + if( pUpsert && pUpsert->pUpsertTarget ){ + pTabList->a[0].iCursor = iDataCur; + sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert); + } +#endif + /* This is the top of the main insertion loop */ if( useTempTable ){ @@ -1005,7 +1013,7 @@ void sqlite3Insert( int isReplace; /* Set to true if constraints may cause a replace */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, - regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0 + regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert ); sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); @@ -1074,6 +1082,7 @@ insert_end: insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); + sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); @@ -1240,7 +1249,8 @@ void sqlite3GenerateConstraintChecks( u8 overrideError, /* Override onError to this if not OE_Default */ int ignoreDest, /* Jump to this label on an OE_Ignore resolution */ int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */ - int *aiChng /* column i is unchanged if aiChng[i]<0 */ + int *aiChng, /* column i is unchanged if aiChng[i]<0 */ + Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */ ){ Vdbe *v; /* VDBE under constrution */ Index *pIdx; /* Pointer to one of the indices */ @@ -1386,6 +1396,15 @@ void sqlite3GenerateConstraintChecks( VdbeCoverage(v); } + /* figure out whether or not upsert applies in this case */ + if( pUpsert && (pUpsert->pUpsertTarget==0 || pUpsert->pUpsertIdx==0) ){ + if( pUpsert->pUpsertSet==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + /* If the response to a rowid conflict is REPLACE but the response ** to some other UNIQUE constraint is FAIL or IGNORE, then we need ** to defer the running of the rowid conflict checking until after @@ -1405,7 +1424,6 @@ void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); - /* Generate code that deals with a rowid collision */ switch( onError ){ default: { onError = OE_Abort; @@ -1467,7 +1485,6 @@ void sqlite3GenerateConstraintChecks( break; } case OE_Ignore: { - /*assert( seenReplace==0 );*/ sqlite3VdbeGoto(v, ignoreDest); break; } @@ -1558,6 +1575,15 @@ void sqlite3GenerateConstraintChecks( onError = OE_Abort; } + /* Figure out if the upsert clause applies to this index */ + if( pUpsert && (pUpsert->pUpsertTarget==0 || pUpsert->pUpsertIdx==pIdx) ){ + if( pUpsert->pUpsertSet==0 ){ + onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ + }else{ + onError = OE_Update; /* DO UPDATE */ + } + } + /* Collision detection may be omitted if all of the following are true: ** (1) The conflict resolution algorithm is REPLACE ** (2) The table is a WITHOUT ROWID table |