Updated SQLite to 3.3.13 - why? I have no idea
This commit is contained in:
@ -16,6 +16,19 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Forward declaration */
|
||||
static void updateVirtualTable(
|
||||
Parse *pParse, /* The parsing context */
|
||||
SrcList *pSrc, /* The virtual table to be modified */
|
||||
Table *pTab, /* The virtual table */
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowidExpr, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
/*
|
||||
** The most recently coded instruction was an OP_Column to retrieve the
|
||||
** i-th column of table pTab. This routine sets the P3 parameter of the
|
||||
@ -90,6 +103,7 @@ void sqlite3Update(
|
||||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
int memCnt = 0; /* Memory cell used for counting rows changed */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* Trying to update a view */
|
||||
@ -130,10 +144,8 @@ void sqlite3Update(
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( isView ){
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );
|
||||
if( aXRef==0 ) goto update_cleanup;
|
||||
@ -242,6 +254,24 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Virtual tables must be handled separately */
|
||||
if( IsVirtual(pTab) ){
|
||||
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
|
||||
pWhere);
|
||||
pWhere = 0;
|
||||
pTabList = 0;
|
||||
goto update_cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve the column names in all the expressions in the
|
||||
** WHERE clause.
|
||||
*/
|
||||
@ -255,20 +285,13 @@ void sqlite3Update(
|
||||
sqlite3AuthContextPush(pParse, &sContext, pTab->zName);
|
||||
}
|
||||
|
||||
/* Begin generating code.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto update_cleanup;
|
||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
|
||||
/* If we are trying to update a view, realize that view into
|
||||
** a ephemeral table.
|
||||
*/
|
||||
if( isView ){
|
||||
Select *pView;
|
||||
pView = sqlite3SelectDup(pTab->pSelect);
|
||||
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);
|
||||
sqlite3SelectDelete(pView);
|
||||
}
|
||||
|
||||
@ -277,9 +300,9 @@ void sqlite3Update(
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
|
||||
if( pWInfo==0 ) goto update_cleanup;
|
||||
|
||||
/* Remember the index of every item to be updated.
|
||||
/* Remember the rowid of every item to be updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
|
||||
|
||||
/* End the database scan loop.
|
||||
@ -289,7 +312,8 @@ void sqlite3Update(
|
||||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
memCnt = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
|
||||
}
|
||||
|
||||
if( triggers_exist ){
|
||||
@ -358,7 +382,7 @@ void sqlite3Update(
|
||||
}
|
||||
}
|
||||
|
||||
if( !isView ){
|
||||
if( !isView && !IsVirtual(pTab) ){
|
||||
/*
|
||||
** Open every index that needs updating. Note that if any
|
||||
** index could potentially invoke a REPLACE conflict resolution
|
||||
@ -390,7 +414,7 @@ void sqlite3Update(
|
||||
/* Loop over every record that needs updating. We have to load
|
||||
** the old data for each record to be updated because some columns
|
||||
** might not change and we will need to copy the old value.
|
||||
** Also, the old data is needed to delete the old index entires.
|
||||
** Also, the old data is needed to delete the old index entries.
|
||||
** So make the cursor point at the old record.
|
||||
*/
|
||||
if( !triggers_exist ){
|
||||
@ -447,7 +471,7 @@ void sqlite3Update(
|
||||
/* Increment the row counter
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
}
|
||||
|
||||
/* If there are triggers, close all the cursors after each iteration
|
||||
@ -492,6 +516,7 @@ void sqlite3Update(
|
||||
** invoke the callback function.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
|
||||
@ -506,3 +531,95 @@ update_cleanup:
|
||||
sqlite3ExprDelete(pWhere);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Generate code for an UPDATE of a virtual table.
|
||||
**
|
||||
** The strategy is that we create an ephemerial table that contains
|
||||
** for each row to be changed:
|
||||
**
|
||||
** (A) The original rowid of that row.
|
||||
** (B) The revised rowid for the row. (note1)
|
||||
** (C) The content of every column in the row.
|
||||
**
|
||||
** Then we loop over this ephemeral table and for each row in
|
||||
** the ephermeral table call VUpdate.
|
||||
**
|
||||
** When finished, drop the ephemeral table.
|
||||
**
|
||||
** (note1) Actually, if we know in advance that (A) is always the same
|
||||
** as (B) we only store (A), then duplicate (A) when pulling
|
||||
** it out of the ephemeral table before calling VUpdate.
|
||||
*/
|
||||
static void updateVirtualTable(
|
||||
Parse *pParse, /* The parsing context */
|
||||
SrcList *pSrc, /* The virtual table to be modified */
|
||||
Table *pTab, /* The virtual table */
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowid, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
|
||||
ExprList *pEList = 0; /* The result set of the SELECT statement */
|
||||
Select *pSelect = 0; /* The SELECT statement */
|
||||
Expr *pExpr; /* Temporary expression */
|
||||
int ephemTab; /* Table holding the result of the SELECT */
|
||||
int i; /* Loop counter */
|
||||
int addr; /* Address of top of loop */
|
||||
|
||||
/* Construct the SELECT statement that will find the new values for
|
||||
** all updated rows.
|
||||
*/
|
||||
pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0);
|
||||
if( pRowid ){
|
||||
pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0);
|
||||
}
|
||||
assert( pTab->iPKey<0 );
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]>=0 ){
|
||||
pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr);
|
||||
}else{
|
||||
pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName);
|
||||
}
|
||||
pEList = sqlite3ExprListAppend(pEList, pExpr, 0);
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
/* Create the ephemeral table into which the update results will
|
||||
** be stored.
|
||||
*/
|
||||
assert( v );
|
||||
ephemTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
|
||||
|
||||
/* fill the ephemeral table
|
||||
*/
|
||||
sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0);
|
||||
|
||||
/*
|
||||
** Generate code to scan the ephemeral table and call VDelete and
|
||||
** VInsert
|
||||
*/
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 0);
|
||||
if( pRowid ){
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||
}
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
|
||||
}
|
||||
pParse->pVirtualLock = pTab;
|
||||
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
|
||||
(const char*)pTab->pVtab, P3_VTAB);
|
||||
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
|
||||
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
|
||||
|
||||
/* Cleanup */
|
||||
sqlite3SelectDelete(pSelect);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
Reference in New Issue
Block a user