diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index 3ff84f1c5e..7c1273bb1a 100644 --- a/ext/session/session_common.tcl +++ b/ext/session/session_common.tcl @@ -201,12 +201,16 @@ proc compare_db {db1 db2} { foreach tbl $lot1 { set col1 [list] set col2 [list] + set quoted [list] $db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name } - $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name } + $db2 eval "PRAGMA table_info = $tbl" { + lappend col2 $name + lappend quoted "\"[string map {\" \"\"} $name]\"" + } if {$col1 != $col2} { error "table $tbl schema mismatch" } - set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]" + set sql "SELECT * FROM $tbl ORDER BY [join $quoted ,]" set data1 [$db1 eval $sql] set data2 [$db2 eval $sql] if {$data1 != $data2} { diff --git a/ext/session/session_gen.test b/ext/session/session_gen.test new file mode 100644 index 0000000000..8d3c5887f3 --- /dev/null +++ b/ext/session/session_gen.test @@ -0,0 +1,190 @@ +# 2025 Jan 28 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] session_common.tcl] +source $testdir/tester.tcl +ifcapable !session {finish_test; return} + +set testprefix session_gen + + +foreach {otn sct} { + 1 VIRTUAL + 2 STORED +} { +eval [string map [list %TYPE% $sct] { + reset_db + set testprefix $testprefix-$otn + +do_execsql_test 1.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + + CREATE TABLE t2(a INTEGER PRIMARY KEY, b AS (c+1) %TYPE%, c); + + CREATE TABLE t3( + a, + b AS (a+10) %TYPE%, + c, + d AS (c+1) %TYPE%, + e, + PRIMARY KEY(c, e) + ) WITHOUT ROWID; + + CREATE TABLE t4(a AS (c*100) %TYPE%, b INTEGER PRIMARY KEY, c); + + CREATE TABLE t5(x, y); +} + +foreach {tn sql changeset} { + + 0.1 { + INSERT INTO t5 VALUES('abc', 'def'); + } { + {INSERT t5 0 X.. {} {i 1 t abc t def}} + } + 0.2 { + UPDATE t5 SET y='xyz' WHERE rowid=1; + } { + {UPDATE t5 0 X.. {i 1 {} {} t def} {{} {} {} {} t xyz}} + } + 0.3 { + DELETE FROM t5; + } { + {DELETE t5 0 X.. {i 1 t abc t xyz} {}} + } + + 1.1 { + INSERT INTO t2 VALUES(1, 2); + INSERT INTO t2 VALUES(2, 123); + } { + {INSERT t2 0 X. {} {i 1 i 2}} + {INSERT t2 0 X. {} {i 2 i 123}} + } + 1.2 { + UPDATE t2 SET c=456 WHERE a=1 + } { + {UPDATE t2 0 X. {i 1 i 2} {{} {} i 456}} + } + + 1.3 { + DELETE FROM t2 WHERE a=2 + } { + {DELETE t2 0 X. {i 2 i 123} {}} + } + + 1.4 { + UPDATE t2 SET a=15 + } { + {INSERT t2 0 X. {} {i 15 i 456}} + {DELETE t2 0 X. {i 1 i 456} {}} + } + + 2.1 { + INSERT INTO t3 VALUES(5, 6, 7); + INSERT INTO t3 VALUES(8, 9, 10); + } { + {INSERT t3 0 .XX {} {i 8 i 9 i 10}} + {INSERT t3 0 .XX {} {i 5 i 6 i 7}} + } + + 2.2 { + UPDATE t3 SET a = 505 WHERE (c, e) = (6, 7); + } { + {UPDATE t3 0 .XX {i 5 i 6 i 7} {i 505 {} {} {} {}}} + } + + 2.3 { + DELETE FROM t3 WHERE (c, e) = (9, 10); + } { + {DELETE t3 0 .XX {i 8 i 9 i 10} {}} + } + + 2.4 { + UPDATE t3 SET c=1000 + } { + {DELETE t3 0 .XX {i 505 i 6 i 7} {}} + {INSERT t3 0 .XX {} {i 505 i 1000 i 7}} + } + + 3.1 { + INSERT INTO t4 VALUES(100, 100); + } { + {INSERT t4 0 X. {} {i 100 i 100}} + } + +} { + do_test 1.$tn.1 { + sqlite3session S db main + S object_config rowid 1 + S attach * + execsql $sql + } {} + + do_changeset_test 1.$tn.2 S $changeset + + S delete +} +#------------------------------------------------------------------------- +reset_db + +forcedelete test.db2 +sqlite3 db2 test.db2 + +do_common_sql { + CREATE TABLE t0(x INTEGER PRIMARY KEY, y); + INSERT INTO t0 VALUES(1, 'one'); + INSERT INTO t0 VALUES(2, 'two'); + + CREATE TABLE t1(a AS (c*10) %TYPE%, b INTEGER PRIMARY KEY, c); + INSERT INTO t1 VALUES(1, 5); + INSERT INTO t1 VALUES(2, 10); + INSERT INTO t1 VALUES(3, 5); + + CREATE TABLE t2( + a, b, c AS (a*b) %TYPE%, + 'k 1', 'k 2', PRIMARY KEY('k 1', 'k 2') + ) WITHOUT ROWID; + INSERT INTO t2 VALUES('a', 'b', 1, 11); + INSERT INTO t2 VALUES('A', 'B', 2, 22); + INSERT INTO t2 VALUES('Aa', 'Bb', 3, 33); +} + +foreach {tn sql} { + 1.1 { INSERT INTO t0 VALUES(4, 15) } + 1.2 { INSERT INTO t1 VALUES(4, 15) } + 1.3 { INSERT INTO t2 VALUES(1, 2, 3, 4) } + + 2.1 { UPDATE t1 SET c=100 WHERE b=2 } + 2.2 { UPDATE t2 SET a=11 } + + 3.1 { DELETE FROM t2 WHERE (t2.'k 1') = 2 } + 3.2 { DELETE FROM t1 } +} { + do_test 2.$tn.1 { + # execsql { PRAGMA vdbe_listing = 1 } db2 + do_then_apply_sql $sql + } {} + do_test 2.$tn.2 { + compare_db db db2 + } {} +} + +}]} + + + + +finish_test diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index a3f132add8..d78dd9b064 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -139,11 +139,13 @@ struct sqlite3_changeset_iter { struct SessionTable { SessionTable *pNext; char *zName; /* Local name of table */ - int nCol; /* Number of columns in table zName */ + int nCol; /* Number of non-hidden columns */ + int nTotalCol; /* Number of columns including hidden */ int bStat1; /* True if this is sqlite_stat1 */ int bRowid; /* True if this table uses rowid for PK */ const char **azCol; /* Column names */ const char **azDflt; /* Default value expressions */ + int *aiIdx; /* Index to pass to xNew/xOld */ u8 *abPK; /* Array of primary key flags */ int nEntry; /* Total number of entries in hash table */ int nChange; /* Size of apChange[] array */ @@ -546,22 +548,22 @@ static int sessionPreupdateHash( unsigned int h = 0; /* Hash value to return */ int i; /* Used to iterate through columns */ + assert( pTab->nTotalCol==pSession->hook.xCount(pSession->hook.pCtx) ); if( pTab->bRowid ){ - assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) ); h = sessionHashAppendI64(h, iRowid); }else{ assert( *pbNullPK==0 ); - assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) ); for(i=0; inCol; i++){ if( pTab->abPK[i] ){ int rc; int eType; sqlite3_value *pVal; + int iIdx = pTab->aiIdx[i]; if( bNew ){ - rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal); + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); }else{ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); } if( rc!=SQLITE_OK ) return rc; @@ -898,6 +900,7 @@ static int sessionPreupdateEqual( sqlite3_value *pVal; /* Value returned by preupdate_new/old */ int rc; /* Error code from preupdate_new/old */ int eType = *a++; /* Type of value from change record */ + int iIdx = pTab->aiIdx[iCol]; /* The following calls to preupdate_new() and preupdate_old() can not ** fail. This is because they cache their return values, and by the @@ -906,10 +909,10 @@ static int sessionPreupdateEqual( ** this (that the method has already been called). */ if( op==SQLITE_INSERT ){ /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */ - rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal); + rc = pSession->hook.xNew(pSession->hook.pCtx, iIdx, &pVal); }else{ /* assert( db->pPreUpdate->pUnpacked ); */ - rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &pVal); } assert( rc==SQLITE_OK ); (void)rc; /* Suppress warning about unused variable */ @@ -1034,9 +1037,11 @@ static int sessionTableInfo( const char *zDb, /* Name of attached database (e.g. "main") */ const char *zThis, /* Table name */ int *pnCol, /* OUT: number of columns */ + int *pnTotalCol, /* OUT: number of hidden columns */ const char **pzTab, /* OUT: Copy of zThis */ const char ***pazCol, /* OUT: Array of column names for table */ const char ***pazDflt, /* OUT: Array of default value expressions */ + int **paiIdx, /* OUT: Array of xNew/xOld indexes */ u8 **pabPK, /* OUT: Array of booleans - true for PK col */ int *pbRowid /* OUT: True if only PK is a rowid */ ){ @@ -1051,6 +1056,7 @@ static int sessionTableInfo( char **azCol = 0; char **azDflt = 0; u8 *abPK = 0; + int *aiIdx = 0; int bRowid = 0; /* Set to true to use rowid as PK */ assert( pazCol && pabPK ); @@ -1058,6 +1064,8 @@ static int sessionTableInfo( *pazCol = 0; *pabPK = 0; *pnCol = 0; + if( pnTotalCol ) *pnTotalCol = 0; + if( paiIdx ) *paiIdx = 0; if( pzTab ) *pzTab = 0; if( pazDflt ) *pazDflt = 0; @@ -1067,9 +1075,9 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */ zPragma = sqlite3_mprintf( - "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " - "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " - "SELECT 2, 'stat', '', 0, '', 0" + "SELECT 0, 'tbl', '', 0, '', 1, 0 UNION ALL " + "SELECT 1, 'idx', '', 0, '', 2, 0 UNION ALL " + "SELECT 2, 'stat', '', 0, '', 0, 0" ); }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); @@ -1077,7 +1085,7 @@ static int sessionTableInfo( return rc; } }else{ - zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); + zPragma = sqlite3_mprintf("PRAGMA '%q'.table_xinfo('%q')", zDb, zThis); } if( !zPragma ){ return SQLITE_NOMEM; @@ -1094,7 +1102,9 @@ static int sessionTableInfo( while( SQLITE_ROW==sqlite3_step(pStmt) ){ nByte += sqlite3_column_bytes(pStmt, 1); /* name */ nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */ - nDbCol++; + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ + nDbCol++; + } if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */ } if( nDbCol==0 ) bRowid = 0; @@ -1103,7 +1113,7 @@ static int sessionTableInfo( rc = sqlite3_reset(pStmt); if( rc==SQLITE_OK ){ - nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1); + nByte += nDbCol * (sizeof(const char *)*2 +sizeof(int)+sizeof(u8) + 1 + 1); pAlloc = sessionMalloc64(pSession, nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; @@ -1114,8 +1124,8 @@ static int sessionTableInfo( if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; azDflt = (char**)&azCol[nDbCol]; - pAlloc = (u8 *)&azDflt[nDbCol]; - abPK = (u8 *)pAlloc; + aiIdx = (int*)&azDflt[nDbCol]; + abPK = (u8 *)&aiIdx[nDbCol]; pAlloc = &abPK[nDbCol]; if( pzTab ){ memcpy(pAlloc, zThis, nThis+1); @@ -1130,27 +1140,32 @@ static int sessionTableInfo( azCol[i] = (char*)pAlloc; pAlloc += nName+1; abPK[i] = 1; + aiIdx[i] = -1; i++; } while( SQLITE_ROW==sqlite3_step(pStmt) ){ - int nName = sqlite3_column_bytes(pStmt, 1); - int nDflt = sqlite3_column_bytes(pStmt, 4); - const unsigned char *zName = sqlite3_column_text(pStmt, 1); - const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); + if( sqlite3_column_int(pStmt, 6)==0 ){ /* !hidden */ + int nName = sqlite3_column_bytes(pStmt, 1); + int nDflt = sqlite3_column_bytes(pStmt, 4); + const unsigned char *zName = sqlite3_column_text(pStmt, 1); + const unsigned char *zDflt = sqlite3_column_text(pStmt, 4); - if( zName==0 ) break; - memcpy(pAlloc, zName, nName+1); - azCol[i] = (char *)pAlloc; - pAlloc += nName+1; - if( zDflt ){ - memcpy(pAlloc, zDflt, nDflt+1); - azDflt[i] = (char *)pAlloc; - pAlloc += nDflt+1; - }else{ - azDflt[i] = 0; + if( zName==0 ) break; + memcpy(pAlloc, zName, nName+1); + azCol[i] = (char *)pAlloc; + pAlloc += nName+1; + if( zDflt ){ + memcpy(pAlloc, zDflt, nDflt+1); + azDflt[i] = (char *)pAlloc; + pAlloc += nDflt+1; + }else{ + azDflt[i] = 0; + } + abPK[i] = sqlite3_column_int(pStmt, 5); + aiIdx[i] = sqlite3_column_int(pStmt, 0); + i++; } - abPK[i] = sqlite3_column_int(pStmt, 5); - i++; + if( pnTotalCol ) (*pnTotalCol)++; } rc = sqlite3_reset(pStmt); } @@ -1163,6 +1178,7 @@ static int sessionTableInfo( if( pazDflt ) *pazDflt = (const char**)azDflt; *pabPK = abPK; *pnCol = nDbCol; + if( paiIdx ) *paiIdx = aiIdx; }else{ sessionFree(pSession, azCol); } @@ -1194,7 +1210,8 @@ static int sessionInitTable( u8 *abPK; assert( pTab->azCol==0 || pTab->abPK==0 ); rc = sessionTableInfo(pSession, db, zDb, - pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK, + pTab->zName, &pTab->nCol, &pTab->nTotalCol, 0, &pTab->azCol, + &pTab->azDflt, &pTab->aiIdx, &abPK, ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0) ); if( rc==SQLITE_OK ){ @@ -1229,15 +1246,17 @@ static int sessionInitTable( */ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ int nCol = 0; + int nTotalCol = 0; const char **azCol = 0; const char **azDflt = 0; + int *aiIdx = 0; u8 *abPK = 0; int bRowid = 0; assert( pSession->rc==SQLITE_OK ); pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb, - pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK, + pTab->zName, &nCol, &nTotalCol, 0, &azCol, &azDflt, &aiIdx, &abPK, (pSession->bImplicitPK ? &bRowid : 0) ); if( pSession->rc==SQLITE_OK ){ @@ -1260,8 +1279,10 @@ static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){ const char **a = pTab->azCol; pTab->azCol = azCol; pTab->nCol = nCol; + pTab->nTotalCol = nTotalCol; pTab->azDflt = azDflt; pTab->abPK = abPK; + pTab->aiIdx = aiIdx; azCol = a; } if( pSession->bEnableSize ){ @@ -1579,7 +1600,7 @@ static int sessionUpdateMaxSize( int ii; for(ii=0; iinCol; ii++){ sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii, &p); + pSession->hook.xNew(pSession->hook.pCtx, pTab->aiIdx[ii], &p); sessionSerializeValue(0, p, &nNew); } } @@ -1599,8 +1620,9 @@ static int sessionUpdateMaxSize( int bChanged = 1; int nOld = 0; int eType; + int iIdx = pTab->aiIdx[ii]; sqlite3_value *p = 0; - pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p); + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); if( p==0 ){ return SQLITE_NOMEM; } @@ -1697,11 +1719,11 @@ static void sessionPreupdateOneChange( /* Check the number of columns in this xPreUpdate call matches the ** number of columns in the table. */ nExpect = pSession->hook.xCount(pSession->hook.pCtx); - if( (pTab->nCol-pTab->bRowid)nTotalColnCol-pTab->bRowid)!=nExpect ){ + if( pTab->nTotalCol!=nExpect ){ pSession->rc = SQLITE_SCHEMA; return; } @@ -1758,14 +1780,15 @@ static void sessionPreupdateOneChange( /* Figure out how large an allocation is required */ nByte = sizeof(SessionChange); - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=pTab->bRowid; inCol; i++){ + int iIdx = pTab->aiIdx[i]; sqlite3_value *p = 0; if( op!=SQLITE_INSERT ){ /* This may fail if the column has a non-NULL default and was added ** using ALTER TABLE ADD COLUMN after this record was created. */ - rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p); + rc = pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); }else if( pTab->abPK[i] ){ - TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p); + TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx,iIdx,&p); assert( trc==SQLITE_OK ); } @@ -1800,12 +1823,13 @@ static void sessionPreupdateOneChange( sessionPutI64(&pC->aRecord[1], iRowid); nByte = 9; } - for(i=0; i<(pTab->nCol-pTab->bRowid); i++){ + for(i=pTab->bRowid; inCol; i++){ sqlite3_value *p = 0; + int iIdx = pTab->aiIdx[i]; if( op!=SQLITE_INSERT ){ - pSession->hook.xOld(pSession->hook.pCtx, i, &p); + pSession->hook.xOld(pSession->hook.pCtx, iIdx, &p); }else if( pTab->abPK[i] ){ - pSession->hook.xNew(pSession->hook.pCtx, i, &p); + pSession->hook.xNew(pSession->hook.pCtx, iIdx, &p); } sessionSerializeValue(&pC->aRecord[nByte], p, &nByte); } @@ -2207,7 +2231,8 @@ int sqlite3session_diff( int bRowid = 0; u8 *abPK; const char **azCol = 0; - rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK, + rc = sessionTableInfo(0, db, zFrom, zTbl, + &nCol, 0, 0, &azCol, 0, 0, &abPK, pSession->bImplicitPK ? &bRowid : 0 ); if( rc==SQLITE_OK ){ @@ -2784,10 +2809,10 @@ static int sessionSelectStmt( int rc = SQLITE_OK; char *zSql = 0; const char *zSep = ""; - const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*"; int nSql = -1; int i; + SessionBuffer cols = {0, 0, 0}; SessionBuffer nooptest = {0, 0, 0}; SessionBuffer pkfield = {0, 0, 0}; SessionBuffer pkvar = {0, 0, 0}; @@ -2800,9 +2825,16 @@ static int sessionSelectStmt( sessionAppendStr(&pkvar, "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc ); - zCols = "tbl, ?2, stat"; + sessionAppendStr(&cols, "tbl, ?2, stat", &rc); }else{ + #if 0 + if( bRowid ){ + sessionAppendStr(&cols, SESSIONS_ROWID, &rc); + } + #endif for(i=0; ipPk ){ - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); + }else{ + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); } - if( iIdx>=p->pCsr->nField || iIdx<0 ){ + if( iStore>=p->pCsr->nField || iStore<0 ){ rc = SQLITE_RANGE; goto preupdate_old_out; } @@ -2224,8 +2227,8 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ p->aRecord = aRec; } - pMem = *ppValue = &p->pUnpacked->aMem[iIdx]; - if( iIdx>=p->pUnpacked->nField ){ + pMem = *ppValue = &p->pUnpacked->aMem[iStore]; + if( iStore>=p->pUnpacked->nField ){ /* This occurs when the table has been extended using ALTER TABLE ** ADD COLUMN. The value to return is the default value of the column. */ Column *pCol = &p->pTab->aCol[iIdx]; @@ -2329,6 +2332,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ PreUpdate *p; int rc = SQLITE_OK; Mem *pMem; + int iStore = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( db==0 || ppValue==0 ){ @@ -2341,9 +2345,12 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ - iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); + iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); + }else{ + iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); } - if( iIdx>=p->pCsr->nField || iIdx<0 ){ + + if( iStore>=p->pCsr->nField || iStore<0 ){ rc = SQLITE_RANGE; goto preupdate_new_out; } @@ -2363,14 +2370,14 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ } p->pNewUnpacked = pUnpack; } - pMem = &pUnpack->aMem[iIdx]; + pMem = &pUnpack->aMem[iStore]; if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); - }else if( iIdx>=pUnpack->nField ){ + }else if( iStore>=pUnpack->nField ){ pMem = (sqlite3_value *)columnNullValue(); } }else{ - /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required + /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required ** value. Make a copy of the cell contents and return a pointer to it. ** It is not safe to return a pointer to the memory cell itself as the ** caller may modify the value text encoding. @@ -2383,13 +2390,13 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ goto preupdate_new_out; } } - assert( iIdx>=0 && iIdxpCsr->nField ); - pMem = &p->aNew[iIdx]; + assert( iStore>=0 && iStorepCsr->nField ); + pMem = &p->aNew[iStore]; if( pMem->flags==0 ){ if( iIdx==p->pTab->iPKey ){ sqlite3VdbeMemSetInt64(pMem, p->iKey2); }else{ - rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]); + rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iStore]); if( rc!=SQLITE_OK ) goto preupdate_new_out; } }