mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
For upsert, the constraint check code generator uses a copy of the index list
for the target table, which can potentially be reordered. FossilOrigin-Name: 3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a
This commit is contained in:
19
manifest
19
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Improved\scomments\sin\ssqliteInt.h.\s\sNo\schanges\sto\scode.
|
C For\supsert,\sthe\sconstraint\scheck\scode\sgenerator\suses\sa\scopy\sof\sthe\sindex\slist\nfor\sthe\starget\stable,\swhich\scan\spotentially\sbe\sreordered.
|
||||||
D 2020-12-09T13:11:02.579
|
D 2020-12-09T20:30:47.480
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@@ -501,7 +501,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
|||||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||||
F src/insert.c 2fdfd14bf872501f041cb2220632dace2df63342151b9b30ebfb798df3f14632
|
F src/insert.c df28564b7d79f146266e906549687c74e3a5e9c4d8ba8697ef9c479ad83407e0
|
||||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||||
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
||||||
F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d
|
F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d
|
||||||
@@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009
|
|||||||
F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706
|
F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||||
F src/sqliteInt.h f8e462357ee34e6859f20e7f83adcca0809bbc1033a85a19d9be50a09930717a
|
F src/sqliteInt.h f01f37844eed0fab3e1fa8efe72cc327cf8e2ac121688ec94199d610978ecb09
|
||||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||||
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
|
||||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||||
@@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97
|
|||||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||||
F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10
|
F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10
|
||||||
F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
|
F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
|
||||||
F src/upsert.c 25673d007c2408fec47a6326b6d7ac265abd2cbc162d11f3b3c333de27d3c78a
|
F src/upsert.c 803c383d493546c71580e9e532d6c7f87fc337316a2ffc202ba1812158dfa8fb
|
||||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||||
F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002
|
F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002
|
||||||
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
|
||||||
@@ -1888,7 +1888,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e
|
P 8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3
|
||||||
R f2e8184a51a526d27f353dba2479feca
|
R cb21a770762087a569cd96190733ebe7
|
||||||
|
T *branch * generalized-upsert-ex1
|
||||||
|
T *sym-generalized-upsert-ex1 *
|
||||||
|
T -sym-generalized-upsert *
|
||||||
U drh
|
U drh
|
||||||
Z 0139a36f3f85012162d949eb364157e1
|
Z d9a35c3fa2c53151f722f0a994f8bfdd
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3
|
3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a
|
||||||
48
src/insert.c
48
src/insert.c
@@ -976,6 +976,9 @@ void sqlite3Insert(
|
|||||||
#ifndef SQLITE_OMIT_UPSERT
|
#ifndef SQLITE_OMIT_UPSERT
|
||||||
if( pUpsert ){
|
if( pUpsert ){
|
||||||
Upsert *pNx;
|
Upsert *pNx;
|
||||||
|
int nIdx;
|
||||||
|
Index *pIdxList;
|
||||||
|
int *aReg;
|
||||||
if( IsVirtual(pTab) ){
|
if( IsVirtual(pTab) ){
|
||||||
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
|
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
|
||||||
pTab->zName);
|
pTab->zName);
|
||||||
@@ -1000,6 +1003,26 @@ void sqlite3Insert(
|
|||||||
}
|
}
|
||||||
pNx = pNx->pNextUpsert;
|
pNx = pNx->pNextUpsert;
|
||||||
}while( pNx!=0 );
|
}while( pNx!=0 );
|
||||||
|
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
||||||
|
assert( pIdx );
|
||||||
|
assert( aRegIdx[nIdx]>0 );
|
||||||
|
}
|
||||||
|
if( nIdx==0 ){
|
||||||
|
pUpsert->pIdxList = 0;
|
||||||
|
}else{
|
||||||
|
u64 nByte = sizeof(Index)*nIdx + sizeof(int)*(nIdx+2);
|
||||||
|
pIdxList = sqlite3DbMallocRaw(db, nByte);
|
||||||
|
if( pIdxList==0 ) goto insert_cleanup;
|
||||||
|
aReg = (int*)&pIdxList[nIdx];
|
||||||
|
for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
|
||||||
|
memcpy(&pIdxList[i], pIdx, sizeof(Index));
|
||||||
|
pIdxList[i].pNext = 0;
|
||||||
|
if( i ) pIdxList[i-1].pNext = &pIdxList[i];
|
||||||
|
aReg[i] = aRegIdx[i];
|
||||||
|
}
|
||||||
|
aReg[i] = aRegIdx[i];
|
||||||
|
pUpsert->pIdxList = pIdxList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1512,7 +1535,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
){
|
){
|
||||||
Vdbe *v; /* VDBE under constrution */
|
Vdbe *v; /* VDBE under constrution */
|
||||||
Index *pIdx; /* Pointer to one of the indices */
|
Index *pIdx; /* Pointer to one of the indices */
|
||||||
Index *pPk = 0; /* The PRIMARY KEY index */
|
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
||||||
sqlite3 *db; /* Database connection */
|
sqlite3 *db; /* Database connection */
|
||||||
int i; /* loop counter */
|
int i; /* loop counter */
|
||||||
int ix; /* Index loop counter */
|
int ix; /* Index loop counter */
|
||||||
@@ -1930,7 +1953,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** This loop also handles the case of the PRIMARY KEY index for a
|
** This loop also handles the case of the PRIMARY KEY index for a
|
||||||
** WITHOUT ROWID table.
|
** WITHOUT ROWID table.
|
||||||
*/
|
*/
|
||||||
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
pIdx = pUpsert ? pUpsert->pIdxList : pTab->pIndex;
|
||||||
|
for(ix=0; pIdx; pIdx=pIdx->pNext, ix++){
|
||||||
int regIdx; /* Range of registers hold conent for pIdx */
|
int regIdx; /* Range of registers hold conent for pIdx */
|
||||||
int regR; /* Range of registers holding conflicting PK */
|
int regR; /* Range of registers holding conflicting PK */
|
||||||
int iThisCur; /* Cursor for this UNIQUE index */
|
int iThisCur; /* Cursor for this UNIQUE index */
|
||||||
@@ -1938,7 +1962,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int addrConflictCk; /* First opcode in the conflict check logic */
|
int addrConflictCk; /* First opcode in the conflict check logic */
|
||||||
|
|
||||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||||
if( pUpIdx==pIdx ){
|
if( pUpIdx && pUpIdx->zName==pIdx->zName ){
|
||||||
addrUniqueOk = upsertJump+1;
|
addrUniqueOk = upsertJump+1;
|
||||||
upsertBypass = sqlite3VdbeGoto(v, 0);
|
upsertBypass = sqlite3VdbeGoto(v, 0);
|
||||||
VdbeComment((v, "Skip upsert subroutine"));
|
VdbeComment((v, "Skip upsert subroutine"));
|
||||||
@@ -1946,7 +1970,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}else{
|
}else{
|
||||||
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
||||||
}
|
}
|
||||||
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
|
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx->zName==pIdx->zName) ){
|
||||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||||
bAffinityDone = 1;
|
bAffinityDone = 1;
|
||||||
}
|
}
|
||||||
@@ -1999,7 +2023,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** of a WITHOUT ROWID table and there has been no change the
|
** of a WITHOUT ROWID table and there has been no change the
|
||||||
** primary key, then no collision is possible. The collision detection
|
** primary key, then no collision is possible. The collision detection
|
||||||
** logic below can all be skipped. */
|
** logic below can all be skipped. */
|
||||||
if( isUpdate && pPk==pIdx && pkChng==0 ){
|
if( isUpdate && pPk && pPk->zName==pIdx->zName && pkChng==0 ){
|
||||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2017,7 +2041,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out if the upsert clause applies to this index */
|
/* Figure out if the upsert clause applies to this index */
|
||||||
if( pUpIdx==pIdx ){
|
if( pUpIdx && pUpIdx->zName==pIdx->zName ){
|
||||||
if( pUpsert->pUpsertSet==0 ){
|
if( pUpsert->pUpsertSet==0 ){
|
||||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||||
}else{
|
}else{
|
||||||
@@ -2037,7 +2061,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
** is invoked. */
|
** is invoked. */
|
||||||
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
|
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||||
if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
|
if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
|
||||||
&& pPk==pIdx /* Condition 2 */
|
&& pPk && pPk->zName==pIdx->zName /* Condition 2 */
|
||||||
&& onError==OE_Replace /* Condition 1 */
|
&& onError==OE_Replace /* Condition 1 */
|
||||||
&& ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
|
&& ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
|
||||||
0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
|
0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
|
||||||
@@ -2056,7 +2080,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
||||||
|
|
||||||
/* Generate code to handle collisions */
|
/* Generate code to handle collisions */
|
||||||
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
regR = (pPk && pIdx->zName==pPk->zName) ?
|
||||||
|
regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||||
if( isUpdate || onError==OE_Replace ){
|
if( isUpdate || onError==OE_Replace ){
|
||||||
if( HasRowid(pTab) ){
|
if( HasRowid(pTab) ){
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||||
@@ -2071,7 +2096,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
int x;
|
int x;
|
||||||
/* Extract the PRIMARY KEY from the end of the index entry and
|
/* Extract the PRIMARY KEY from the end of the index entry and
|
||||||
** store it in registers regR..regR+nPk-1 */
|
** store it in registers regR..regR+nPk-1 */
|
||||||
if( pIdx!=pPk ){
|
if( pPk && pIdx->zName!=pPk->zName ){
|
||||||
for(i=0; i<pPk->nKeyCol; i++){
|
for(i=0; i<pPk->nKeyCol; i++){
|
||||||
assert( pPk->aiColumn[i]>=0 );
|
assert( pPk->aiColumn[i]>=0 );
|
||||||
x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
|
x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
|
||||||
@@ -2152,7 +2177,8 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
}
|
}
|
||||||
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
||||||
regR, nPkField, 0, OE_Replace,
|
regR, nPkField, 0, OE_Replace,
|
||||||
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
|
(pPk && pIdx->zName==pPk->zName ? ONEPASS_SINGLE : ONEPASS_OFF),
|
||||||
|
iThisCur);
|
||||||
if( pTrigger && isUpdate ){
|
if( pTrigger && isUpdate ){
|
||||||
sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
|
sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
|
||||||
}
|
}
|
||||||
@@ -2208,7 +2234,7 @@ void sqlite3GenerateConstraintChecks(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( pUpIdx==pIdx ){
|
if( pUpIdx && pUpIdx->zName==pIdx->zName ){
|
||||||
sqlite3VdbeGoto(v, upsertJump+1);
|
sqlite3VdbeGoto(v, upsertJump+1);
|
||||||
sqlite3VdbeJumpHere(v, upsertBypass);
|
sqlite3VdbeJumpHere(v, upsertBypass);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -3078,10 +3078,14 @@ struct Upsert {
|
|||||||
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
|
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
|
||||||
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
||||||
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
||||||
/* The fields above comprise the parse tree for the upsert clause.
|
/* Above this point is the parse tree for the ON CONFLICT clauses.
|
||||||
** The fields below are used to transfer information from the INSERT
|
** The next group of fields stores intermediate data. */
|
||||||
** processing down into the UPDATE processing while generating code.
|
Index *pIdxList;
|
||||||
** Upsert owns the memory allocated above, but not the memory below. */
|
/* All fields above are owned by the Upsert object and must be freed
|
||||||
|
** when the Upsert is destroyed. The fields below are used to transfer
|
||||||
|
** information from the INSERT processing down into the UPDATE processing
|
||||||
|
** while generating code. The fields below are owned by the INSERT
|
||||||
|
** statement and will be freed by INSERT processing. */
|
||||||
Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
|
Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
|
||||||
SrcList *pUpsertSrc; /* Table to be updated */
|
SrcList *pUpsertSrc; /* Table to be updated */
|
||||||
int regData; /* First register holding array of VALUES */
|
int regData; /* First register holding array of VALUES */
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
|
|||||||
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
|
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
|
||||||
sqlite3ExprListDelete(db, p->pUpsertSet);
|
sqlite3ExprListDelete(db, p->pUpsertSet);
|
||||||
sqlite3ExprDelete(db, p->pUpsertWhere);
|
sqlite3ExprDelete(db, p->pUpsertWhere);
|
||||||
|
sqlite3DbFree(db, p->pIdxList);
|
||||||
sqlite3DbFree(db, p);
|
sqlite3DbFree(db, p);
|
||||||
p = pNext;
|
p = pNext;
|
||||||
}while( p );
|
}while( p );
|
||||||
@@ -60,7 +61,7 @@ Upsert *sqlite3UpsertNew(
|
|||||||
Upsert *pNext /* Next ON CONFLICT clause in the list */
|
Upsert *pNext /* Next ON CONFLICT clause in the list */
|
||||||
){
|
){
|
||||||
Upsert *pNew;
|
Upsert *pNew;
|
||||||
pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
|
pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
|
||||||
if( pNew==0 ){
|
if( pNew==0 ){
|
||||||
sqlite3ExprListDelete(db, pTarget);
|
sqlite3ExprListDelete(db, pTarget);
|
||||||
sqlite3ExprDelete(db, pTargetWhere);
|
sqlite3ExprDelete(db, pTargetWhere);
|
||||||
@@ -73,7 +74,6 @@ Upsert *sqlite3UpsertNew(
|
|||||||
pNew->pUpsertTargetWhere = pTargetWhere;
|
pNew->pUpsertTargetWhere = pTargetWhere;
|
||||||
pNew->pUpsertSet = pSet;
|
pNew->pUpsertSet = pSet;
|
||||||
pNew->pUpsertWhere = pWhere;
|
pNew->pUpsertWhere = pWhere;
|
||||||
pNew->pUpsertIdx = 0;
|
|
||||||
pNew->pNextUpsert = pNext;
|
pNew->pNextUpsert = pNext;
|
||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
|
|||||||
Reference in New Issue
Block a user