aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze.c7
-rw-r--r--src/build.c79
-rw-r--r--src/delete.c15
-rw-r--r--src/expr.c27
-rw-r--r--src/insert.c38
-rw-r--r--src/resolve.c54
-rw-r--r--src/shell.c2
-rw-r--r--src/sqliteInt.h5
-rw-r--r--src/update.c8
-rw-r--r--src/vdbeblob.c3
10 files changed, 153 insertions, 85 deletions
diff --git a/src/analyze.c b/src/analyze.c
index 59518cdc3..3e531bd72 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -1186,6 +1186,7 @@ static void analyzeOneTable(
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+ assert( k>=0 && k<pTab->nCol );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
}
@@ -1235,12 +1236,10 @@ static void analyzeOneTable(
** be taken */
VdbeCoverageNeverTaken(v);
#ifdef SQLITE_ENABLE_STAT3
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
- pIdx->aiColumn[0], regSample);
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
#else
for(i=0; i<nCol; i++){
- i16 iCol = pIdx->aiColumn[i];
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
#endif
diff --git a/src/build.c b/src/build.c
index ae602378f..fc50fdd82 100644
--- a/src/build.c
+++ b/src/build.c
@@ -443,6 +443,7 @@ static void freeIndex(sqlite3 *db, Index *p){
sqlite3DeleteIndexSamples(db, p);
#endif
sqlite3ExprDelete(db, p->pPartIdxWhere);
+ sqlite3ExprListDelete(db, p->aColExpr);
sqlite3DbFree(db, p->zColAff);
if( p->isResized ) sqlite3DbFree(db, p->azColl);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -2889,7 +2890,6 @@ Index *sqlite3CreateIndex(
int iDb; /* Index of the database that is being written */
Token *pName = 0; /* Unqualified name of the index to create */
struct ExprList_item *pListItem; /* For looping over pList */
- const Column *pTabCol; /* A column in the table */
int nExtra = 0; /* Space allocated for zExtra[] */
int nExtraCol; /* Number of extra columns needed */
char *zExtra = 0; /* Extra space after the Index object */
@@ -3102,39 +3102,48 @@ Index *sqlite3CreateIndex(
sortOrderMask = 0; /* Ignore DESC */
}
- /* Scan the names of the columns of the table to be indexed and
- ** load the column indices into the Index structure. Report an error
- ** if any column is not found.
+ /* Analyze the list of expressions that form the terms of the index and
+ ** report any errors. In the common case where the expression is exactly
+ ** a table column, store that column in aiColumn[]. For general expressions,
+ ** populate pIndex->aColExpr and store -2 in aiColumn[].
**
- ** TODO: Add a test to make sure that the same column is not named
- ** more than once within the same index. Only the first instance of
- ** the column will ever be used by the optimizer. Note that using the
- ** same column more than once cannot be an error because that would
- ** break backwards compatibility - it needs to be a warning.
+ ** TODO: Issue a warning if two or more columns of the index are identical.
+ ** TODO: Issue a warning if the table primary key is used as part of the
+ ** index key.
*/
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
- const char *zColName;
- Expr *pCExpr;
- int requestedSortOrder;
+ Expr *pCExpr; /* The i-th index expression */
+ int requestedSortOrder; /* ASC or DESC on the i-th expression */
char *zColl; /* Collation sequence name */
+ sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
+ if( pParse->nErr ) goto exit_create_index;
pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
- if( pCExpr->op!=TK_ID ){
- sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported");
- continue;
- }
- zColName = pCExpr->u.zToken;
- for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
- if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
- }
- if( j>=pTab->nCol ){
- sqlite3ErrorMsg(pParse, "table %s has no column named %s",
- pTab->zName, zColName);
- pParse->checkSchema = 1;
- goto exit_create_index;
+ if( pCExpr->op!=TK_COLUMN ){
+ if( pTab==pParse->pNewTable ){
+ sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
+ "UNIQUE constraints");
+ goto exit_create_index;
+ }
+ if( pIndex->aColExpr==0 ){
+ pIndex->aColExpr = sqlite3ExprListDup(db, pList, 0);
+ }
+ j = -2;
+ pIndex->aiColumn[i] = -2;
+ if( sqlite3ExprCanBeNull(pList->a[i].pExpr) ){
+ pIndex->uniqNotNull = 1;
+ }
+ }else{
+ j = pCExpr->iColumn;
+ assert( j<=0x7fff );
+ if( j<0 ){
+ j = pTab->iPKey;
+ }else if( pTab->aCol[j].notNull==0 ){
+ pIndex->uniqNotNull = 0;
+ }
+ pIndex->aiColumn[i] = (i16)j;
}
- assert( j<=0x7fff );
- pIndex->aiColumn[i] = (i16)j;
+ zColl = 0;
if( pListItem->pExpr->op==TK_COLLATE ){
int nColl;
zColl = pListItem->pExpr->u.zToken;
@@ -3144,21 +3153,26 @@ Index *sqlite3CreateIndex(
zColl = zExtra;
zExtra += nColl;
nExtra -= nColl;
- }else{
+ }else if( j>=0 ){
zColl = pTab->aCol[j].zColl;
- if( !zColl ) zColl = "BINARY";
}
+ if( !zColl ) zColl = "BINARY";
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
goto exit_create_index;
}
pIndex->azColl[i] = zColl;
requestedSortOrder = pListItem->sortOrder & sortOrderMask;
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
- if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
}
+
+ /* Append the table key to the end of the index. For WITHOUT ROWID
+ ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For
+ ** normal tables (when pPk==0) this will be the rowid.
+ */
if( pPk ){
for(j=0; j<pPk->nKeyCol; j++){
int x = pPk->aiColumn[j];
+ assert( x>=0 );
if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
pIndex->nColumn--;
}else{
@@ -3209,6 +3223,7 @@ Index *sqlite3CreateIndex(
for(k=0; k<pIdx->nKeyCol; k++){
const char *z1;
const char *z2;
+ assert( pIdx->aiColumn[k]>=0 );
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k];
@@ -4100,7 +4115,9 @@ void sqlite3UniqueConstraint(
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
for(j=0; j<pIdx->nKeyCol; j++){
- char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
+ char *zCol;
+ assert( pIdx->aiColumn[j]>=0 );
+ zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
sqlite3StrAccumAppend(&errMsg, ".", 1);
diff --git a/src/delete.c b/src/delete.c
index 917157743..5403224a8 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -411,6 +411,7 @@ void sqlite3DeleteFrom(
/* Extract the rowid or primary key for the current row */
if( pPk ){
for(i=0; i<nPk; i++){
+ assert( pPk->aiColumn[i]>=(-1) );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
pPk->aiColumn[i], iPk+i);
}
@@ -789,14 +790,13 @@ int sqlite3GenerateIndexKey(
){
Vdbe *v = pParse->pVdbe;
int j;
- Table *pTab = pIdx->pTable;
int regBase;
int nCol;
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
- pParse->iPartIdxTab = iDataCur;
+ pParse->iSelfTab = iDataCur;
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
@@ -808,9 +808,14 @@ int sqlite3GenerateIndexKey(
regBase = sqlite3GetTempRange(pParse, nCol);
if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;
for(j=0; j<nCol; j++){
- if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] ) continue;
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
- regBase+j);
+ if( pPrior
+ && pPrior->aiColumn[j]==pIdx->aiColumn[j]
+ && pPrior->aiColumn[j]>=(-1)
+ ){
+ /* This column was already computed by the previous index */
+ continue;
+ }
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
/* If the column affinity is REAL but the number is an integer, then it
** might be stored in the table as an integer (using a compact
** representation) then converted to REAL by an OP_RealAffinity opcode.
diff --git a/src/expr.c b/src/expr.c
index 1aebef6b1..34c382a19 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2432,6 +2432,28 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
}
}
+/* Generate code that will load into register regOut a value that is
+** appropriate for the iIdxCol-th column of index pIdx.
+*/
+void sqlite3ExprCodeLoadIndexColumn(
+ Parse *pParse, /* The parsing context */
+ Index *pIdx, /* The index whose column is to be loaded */
+ int iTabCur, /* Cursor pointing to a table row */
+ int iIdxCol, /* The column of the index to be loaded */
+ int regOut /* Store the index column value in this register */
+){
+ i16 iTabCol = pIdx->aiColumn[iIdxCol];
+ if( iTabCol>=(-1) ){
+ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
+ iTabCol, regOut);
+ return;
+ }
+ assert( pIdx->aColExpr );
+ assert( pIdx->aColExpr->nExpr>iIdxCol );
+ pParse->iSelfTab = iTabCur;
+ sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
+}
+
/*
** Generate code to extract the value of the iCol-th column of a table.
*/
@@ -2617,8 +2639,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
inReg = pExpr->iColumn + pParse->ckBase;
break;
}else{
- /* Deleting from a partial index */
- iTab = pParse->iPartIdxTab;
+ /* Coding an expression that is part of an index where column names
+ ** in the index refer to the table to which the index belongs */
+ iTab = pParse->iSelfTab;
}
}
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
diff --git a/src/insert.c b/src/insert.c
index e94af0985..6c70470ac 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -88,7 +88,15 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
}
for(n=0; n<pIdx->nColumn; n++){
i16 x = pIdx->aiColumn[n];
- pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity;
+ if( x>=0 ){
+ pIdx->zColAff[n] = pTab->aCol[x].affinity;
+ }else if( x==(-1) ){
+ pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
+ }else{
+ assert( x==(-2) );
+ assert( pIdx->aColExpr!=0 );
+ pIdx->zColAff[n] = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
+ }
}
pIdx->zColAff[n] = 0;
}
@@ -1404,15 +1412,22 @@ void sqlite3GenerateConstraintChecks(
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
- if( iField<0 || iField==pTab->iPKey ){
- if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
- x = regNewData;
- regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
+ if( iField==(-2) ){
+ pParse->ckBase = regNewData+1;
+ sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
+ pParse->ckBase = 0;
+ VdbeComment((v, "%s column %d", pIdx->zName, i));
}else{
- x = iField + regNewData + 1;
+ if( iField==(-1) || iField==pTab->iPKey ){
+ if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
+ x = regNewData;
+ regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
+ }else{
+ x = iField + regNewData + 1;
+ }
+ sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
+ VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
}
- sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
- VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName));
@@ -1733,6 +1748,13 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
return 0; /* Different columns indexed */
}
+ if( pSrc->aiColumn[i]==(-2) ){
+ assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
+ if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
+ pDest->aColExpr->a[i].pExpr, -1)!=0 ){
+ return 0; /* Different expressions in the index */
+ }
+ }
if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
return 0; /* Different sort orders */
}
diff --git a/src/resolve.c b/src/resolve.c
index 4ef8fe051..a85543f09 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -547,36 +547,28 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
}
/*
-** Report an error that an expression is not valid for a partial index WHERE
-** clause.
+** Report an error that an expression is not valid for some set of
+** pNC->ncFlags values determined by validMask. If
*/
-static void notValidPartIdxWhere(
+static void notValid(
Parse *pParse, /* Leave error message here */
NameContext *pNC, /* The name context */
- const char *zMsg /* Type of error */
+ const char *zMsg, /* Type of error */
+ int validMask, /* Set of contexts for which prohibited */
+ int okForInit /* No error if pParse->db->init.busy is true */
){
- if( (pNC->ncFlags & NC_PartIdx)!=0 ){
- sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses",
- zMsg);
- }
-}
-
+ assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
+ if( (pNC->ncFlags & validMask)!=0
+ && (pParse->db->init.busy==0 || !okForInit)
+ ){
+ const char *zIn = "partial index WHERE clauses";
+ if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
#ifndef SQLITE_OMIT_CHECK
-/*
-** Report an error that an expression is not valid for a CHECK constraint.
-*/
-static void notValidCheckConstraint(
- Parse *pParse, /* Leave error message here */
- NameContext *pNC, /* The name context */
- const char *zMsg /* Type of error */
-){
- if( (pNC->ncFlags & NC_IsCheck)!=0 ){
- sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg);
+ else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
+#endif
+ sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
}
}
-#else
-# define notValidCheckConstraint(P,N,M)
-#endif
/*
** Expression p should encode a floating point value between 1.0 and 0.0.
@@ -661,6 +653,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Expr *pRight;
/* if( pSrcList==0 ) break; */
+ notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr, 0);
+ /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
@@ -690,7 +684,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- notValidPartIdxWhere(pParse, pNC, "functions");
+ notValid(pParse, pNC, "functions", NC_PartIdx, 0);
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@@ -740,6 +734,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
ExprSetProperty(pExpr,EP_ConstFunc);
+ }else{
+ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr, 0);
}
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
@@ -786,8 +782,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
- notValidCheckConstraint(pParse, pNC, "subqueries");
- notValidPartIdxWhere(pParse, pNC, "subqueries");
+ notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr,0);
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
@@ -797,8 +792,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
break;
}
case TK_VARIABLE: {
- notValidCheckConstraint(pParse, pNC, "parameters");
- notValidPartIdxWhere(pParse, pNC, "parameters");
+ notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr, 0);
break;
}
}
@@ -1501,14 +1495,14 @@ void sqlite3ResolveSelectNames(
void sqlite3ResolveSelfReference(
Parse *pParse, /* Parsing context */
Table *pTab, /* The table being referenced */
- int type, /* NC_IsCheck or NC_PartIdx */
+ int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NUL. */
){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
- assert( type==NC_IsCheck || type==NC_PartIdx );
+ assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr );
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
diff --git a/src/shell.c b/src/shell.c
index c289998a7..da7f78e10 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -4252,8 +4252,8 @@ static int process_input(ShellState *p, FILE *in){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
errCnt++;
}
- free(zSql);
}
+ free(zSql);
free(zLine);
return errCnt>0;
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 288b25616..7dd0402dd 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1871,6 +1871,7 @@ struct Index {
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
+ ExprList *aColExpr; /* Column expressions */
int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
@@ -2391,6 +2392,7 @@ struct NameContext {
#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
+#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */
#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
/*
@@ -2660,7 +2662,7 @@ struct Parse {
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
int ckBase; /* Base register of data during check constraints */
- int iPartIdxTab; /* Table corresponding to a partial index */
+ int iSelfTab; /* Table of an index whose exprs are being coded */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
int nLabel; /* Number of labels used */
@@ -3361,6 +3363,7 @@ int sqlite3WhereIsSorted(WhereInfo*);
int sqlite3WhereContinueLabel(WhereInfo*);
int sqlite3WhereBreakLabel(WhereInfo*);
int sqlite3WhereOkOnePass(WhereInfo*, int*);
+void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
diff --git a/src/update.c b/src/update.c
index a8bcd4efa..4b7431ef3 100644
--- a/src/update.c
+++ b/src/update.c
@@ -272,7 +272,9 @@ void sqlite3Update(
/* There is one entry in the aRegIdx[] array for each index on the table
** being updated. Fill in aRegIdx[] with a register number that will hold
- ** the key for accessing each index.
+ ** the key for accessing each index.
+ **
+ ** FIXME: Be smarter about omitting indexes that use expressions.
*/
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
@@ -281,7 +283,8 @@ void sqlite3Update(
}else{
reg = 0;
for(i=0; i<pIdx->nKeyCol; i++){
- if( aXRef[pIdx->aiColumn[i]]>=0 ){
+ i16 iIdxCol = pIdx->aiColumn[i];
+ if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
reg = ++pParse->nMem;
break;
}
@@ -381,6 +384,7 @@ void sqlite3Update(
if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
for(i=0; i<nPk; i++){
+ assert( pPk->aiColumn[i]>=(-1) );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
iPk+i);
}
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index ea01f5ce8..2cdc3edb0 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -247,7 +247,8 @@ int sqlite3_blob_open(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int j;
for(j=0; j<pIdx->nKeyCol; j++){
- if( pIdx->aiColumn[j]==iCol ){
+ /* FIXME: Be smarter about indexes that use expressions */
+ if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==(-2) ){
zFault = "indexed";
}
}