static void UpdateVirtualTable(Parse parse, SrcList src, Table table, ExprList changes, Expr rowid, int[] xrefs, Expr where_, int onError)
{
int i;
Context ctx = parse.Ctx; // Database connection
VTable vtable = VTable.GetVTable(ctx, table);
SelectDest dest = new SelectDest();
// Construct the SELECT statement that will find the new values for all updated rows.
ExprList list = ExprList.Append(parse, 0, Expr.Expr(ctx, TK.ID, "_rowid_")); // The result set of the SELECT statement
if (rowid != null)
{
list = ExprList.Append(parse, list, Expr.Dup(ctx, rowid, 0));
}
Debug.Assert(table.PKey < 0);
for (i = 0; i < table.Cols.length; i++)
{
Expr expr = (xrefs[i] >= 0 ? Expr.Dup(ctx, changes.Ids[xrefs[i]].Expr, 0) : Expr.Expr(ctx, TK.ID, table.Cols[i].Name)); // Temporary expression
list = ExprList.Append(parse, list, expr);
}
Select select = Select.New(parse, list, src, where_, null, null, null, 0, null, null); // The SELECT statement
// Create the ephemeral table into which the update results will be stored.
Vdbe v = parse.V; // Virtual machine under construction
Debug.Assert(v != null);
int ephemTab = parse.Tabs++; // Table holding the result of the SELECT
v.AddOp2(OP.OpenEphemeral, ephemTab, table.Cols.length + 1 + (rowid != null ? 1 : 0));
v.ChangeP5(BTREE_UNORDERED);
// fill the ephemeral table
Select.DestInit(dest, SRT.Table, ephemTab);
Select.Select(parse, select, ref dest);
// Generate code to scan the ephemeral table and call VUpdate.
int regId = ++parse.Mems;// First register in set passed to OP_VUpdate
parse.Mems += table.Cols.length + 1;
int addr = v.AddOp2(OP.Rewind, ephemTab, 0); // Address of top of loop
v.AddOp3(OP.Column, ephemTab, 0, regId);
v.AddOp3(OP.Column, ephemTab, (rowid != null ? 1 : 0), regId + 1);
for (i = 0; i < table.nCol; i++)
{
v.AddOp3(OP.Column, ephemTab, i + 1 + (rowid != null ? 1 : 0), regId + 2 + i);
}
sqlite3VtabMakeWritable(parse, table);
v.AddOp4(OP_VUpdate, 0, table.Cols.length + 2, regId, vtable, P4_VTAB);
v.ChangeP5((byte)(onError == OE_Default ? OE_Abort : onError));
parse.MayAbort();
v.AddOp2(OP.Next, ephemTab, addr + 1);
v.JumpHere(addr);
v.AddOp2(OP.Close, ephemTab, 0);
// Cleanup
Select.Delete(ctx, ref select);
}