/ Check-in [2119e7bf]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Rework the way UPDATE works for virtual tables. (CVS 3262)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2119e7bf5577350e4e1236ea729568085620a826
User & Date: drh 2006-06-16 21:13:22
Context
2006-06-17
03:27
Fixes for UPDATE statements on virtual tables. (CVS 3263) check-in: 81c5a5b4 user: danielk1977 tags: trunk
2006-06-16
21:13
Rework the way UPDATE works for virtual tables. (CVS 3262) check-in: 2119e7bf user: drh tags: trunk
16:08
Add code to invoke the virtual table transaction interface. Untested at this point. (CVS 3261) check-in: 61251402 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/select.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.314 2006/06/11 23:41:56 drh Exp $
*/
#include "sqliteInt.h"


/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
................................................................................
  p->n = z ? strlen(z) : 0;
  p->dyn = 0;
}

/*
** Create an expression node for an identifier with the name of zName
*/
static Expr *createIdExpr(const char *zName){
  Token dummy;
  setToken(&dummy, zName);
  return sqlite3Expr(TK_ID, 0, 0, &dummy);
}


/*
................................................................................
  int iRightJoinTable,     /* VDBE cursor for the right table */
  Expr **ppExpr            /* Add the equality term to this expression */
){
  Expr *pE1a, *pE1b, *pE1c;
  Expr *pE2a, *pE2b, *pE2c;
  Expr *pE;

  pE1a = createIdExpr(zCol);
  pE2a = createIdExpr(zCol);
  if( zAlias1==0 ){
    zAlias1 = pTab1->zName;
  }
  pE1b = createIdExpr(zAlias1);
  if( zAlias2==0 ){
    zAlias2 = pTab2->zName;
  }
  pE2b = createIdExpr(zAlias2);
  pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
  pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
  pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
  ExprSetProperty(pE, EP_FromJoin);
  pE->iRightJoinTable = iRightJoinTable;
  *ppExpr = sqlite3ExprAnd(*ppExpr, pE);
}







|







 







|







 







|
|



|



|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.315 2006/06/16 21:13:22 drh Exp $
*/
#include "sqliteInt.h"


/*
** Delete all the content of a Select structure but do not deallocate
** the select structure itself.
................................................................................
  p->n = z ? strlen(z) : 0;
  p->dyn = 0;
}

/*
** Create an expression node for an identifier with the name of zName
*/
Expr *sqlite3CreateIdExpr(const char *zName){
  Token dummy;
  setToken(&dummy, zName);
  return sqlite3Expr(TK_ID, 0, 0, &dummy);
}


/*
................................................................................
  int iRightJoinTable,     /* VDBE cursor for the right table */
  Expr **ppExpr            /* Add the equality term to this expression */
){
  Expr *pE1a, *pE1b, *pE1c;
  Expr *pE2a, *pE2b, *pE2c;
  Expr *pE;

  pE1a = sqlite3CreateIdExpr(zCol);
  pE2a = sqlite3CreateIdExpr(zCol);
  if( zAlias1==0 ){
    zAlias1 = pTab1->zName;
  }
  pE1b = sqlite3CreateIdExpr(zAlias1);
  if( zAlias2==0 ){
    zAlias2 = pTab2->zName;
  }
  pE2b = sqlite3CreateIdExpr(zAlias2);
  pE1c = sqlite3Expr(TK_DOT, pE1b, pE1a, 0);
  pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
  pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
  ExprSetProperty(pE, EP_FromJoin);
  pE->iRightJoinTable = iRightJoinTable;
  *ppExpr = sqlite3ExprAnd(*ppExpr, pE);
}

Changes to src/sqlite3ext.h.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance.  Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of 
** sqlite3.h.
**
** @(#) $Id: sqlite3ext.h,v 1.2 2006/06/15 15:38:42 danielk1977 Exp $
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include <sqlite3.h>

typedef struct sqlite3_api_routines sqlite3_api_routines;

................................................................................
  void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
  int  (*complete)(const char*sql);
  int  (*complete16)(const void*sql);
  int  (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
  int  (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
  int  (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
  int  (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
  int (*create_module)(sqlite3*,const char*,sqlite3_module*,void*);
  int  (*data_count)(sqlite3_stmt*pStmt);
  sqlite3 * (*db_handle)(sqlite3_stmt*);
  int (*declare_vtab)(sqlite3*,const char*);
  int  (*enable_shared_cache)(int);
  int  (*errcode)(sqlite3*db);
  const char * (*errmsg)(sqlite3*);
  const void * (*errmsg16)(sqlite3*);







|







 







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
*************************************************************************
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance.  Shared libraries that intend to be loaded
** as extensions by SQLite should #include this file instead of 
** sqlite3.h.
**
** @(#) $Id: sqlite3ext.h,v 1.3 2006/06/16 21:13:22 drh Exp $
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#include <sqlite3.h>

typedef struct sqlite3_api_routines sqlite3_api_routines;

................................................................................
  void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
  int  (*complete)(const char*sql);
  int  (*complete16)(const void*sql);
  int  (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
  int  (*create_collation16)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
  int  (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
  int  (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
  int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
  int  (*data_count)(sqlite3_stmt*pStmt);
  sqlite3 * (*db_handle)(sqlite3_stmt*);
  int (*declare_vtab)(sqlite3*,const char*);
  int  (*enable_shared_cache)(int);
  int  (*errcode)(sqlite3*db);
  const char * (*errmsg)(sqlite3*);
  const void * (*errmsg16)(sqlite3*);

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1627
1628
1629
1630
1631
1632
1633

1634
1635
1636
1637
1638
1639
1640
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.508 2006/06/16 16:08:55 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
................................................................................
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
int sqlite3ExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);

void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);







|







 







>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.509 2006/06/16 21:13:22 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Extra interface definitions for those who need them
*/
................................................................................
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
int sqlite3ExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqlite3ExprResolveNames(NameContext *, Expr *);
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
Expr *sqlite3CreateIdExpr(const char*);
void sqlite3Randomness(int, void*);
void sqlite3RollbackAll(sqlite3*);
void sqlite3CodeVerifySchema(Parse*, int);
void sqlite3BeginTransaction(Parse*, int);
void sqlite3CommitTransaction(Parse*);
void sqlite3RollbackTransaction(Parse*);
int sqlite3ExprIsConstant(Expr*);

Changes to src/update.c.

8
9
10
11
12
13
14
15
16
17











18
19
20
21
22
23
24
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263


















264
265
266
267
268
269
270
...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
...
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
...
539
540
541
542
543
544
545




























































































**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.126 2006/06/16 16:08:55 danielk1977 Exp $
*/
#include "sqliteInt.h"












/*
** 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 
** OP_Column to the default value, if any.
**
** The default value of a column is specified by a DEFAULT clause in the 
................................................................................
      apIdx[nIdx++] = pIdx;
      aIdxUsed[j] = 1;
    }else{
      aIdxUsed[j] = 0;
    }
  }

  /* Resolve the column names in all the expressions in the
  ** WHERE clause.
  */
  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
    goto update_cleanup;
  }

  /* Start the view context
  */
  if( isView ){
    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);
................................................................................
    }

    /* Create the new index entries and the new record.
    */
    sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
  }

#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( !isView && IsVirtual(pTab) ){
    addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);

    /* If the record number will change, push the record number as it
    ** will be after the update. (The old record number is currently
    ** on top of the stack.)
    */
    if( chngRowid ){
      sqlite3ExprCode(pParse, pRowidExpr);
      sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
    }else{
      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
    }

    /* Compute new data for this record.  
    */
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        sqlite3VdbeAddOp(v, OP_Null, 0, 0);
        continue;
      }
      j = aXRef[i];
      if( j<0 ){
        sqlite3VdbeAddOp(v, OP_VNoChange, 0, 0);
      }else{
        sqlite3ExprCode(pParse, pChanges->a[j].pExpr);
      }
    }

    /* Make the update */
    pParse->pVirtualLock = pTab;
    sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2, 
                      (const char*)pTab->pVtab, P3_VTAB);
  }
#endif /* SQLITE_OMIT_VIRTUAL */

  /* Increment the row counter 
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
    sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
  }

  /* If there are triggers, close all the cursors after each iteration
................................................................................
  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
  sqlite3VdbeJumpHere(v, addr);

  /* Close all tables if there were no FOR EACH ROW triggers */
  if( !triggers_exist && !IsVirtual(pTab) ){
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      if( openAll || aIdxUsed[i] ){
        sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
      }
    }
    sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
  }else{
................................................................................
  sqliteFree(apIdx);
  sqliteFree(aXRef);
  sqlite3SrcListDelete(pTabList);
  sqlite3ExprListDelete(pChanges);
  sqlite3ExprDelete(pWhere);
  return;
}



































































































|


>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
249
250
251
252
253
254
255







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
462
463
464
465
466
467
468





































469
470
471
472
473
474
475
...
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.127 2006/06/16 21:13:22 drh Exp $
*/
#include "sqliteInt.h"

/* 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 */
);

/*
** 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 
** OP_Column to the default value, if any.
**
** The default value of a column is specified by a DEFAULT clause in the 
................................................................................
      apIdx[nIdx++] = pIdx;
      aIdxUsed[j] = 1;
    }else{
      aIdxUsed[j] = 0;
    }
  }








  /* Start the view context
  */
  if( isView ){
    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);

#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.
  */
  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
    goto update_cleanup;
  }

  /* If we are trying to update a view, realize that view into
  ** a ephemeral table.
  */
  if( isView ){
    Select *pView;
    pView = sqlite3SelectDup(pTab->pSelect);
................................................................................
    }

    /* Create the new index entries and the new record.
    */
    sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
  }






































  /* Increment the row counter 
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
    sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
  }

  /* If there are triggers, close all the cursors after each iteration
................................................................................
  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
  sqlite3VdbeJumpHere(v, addr);

  /* Close all tables if there were no FOR EACH ROW triggers */
  if( !triggers_exist ){
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      if( openAll || aIdxUsed[i] ){
        sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
      }
    }
    sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
  }else{
................................................................................
  sqliteFree(apIdx);
  sqliteFree(aXRef);
  sqlite3SrcListDelete(pTabList);
  sqlite3ExprListDelete(pChanges);
  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, pRowid, 0);
  }
  for(i=0; i<pTab->nCol; i++){
    if( i==pTab->iPKey ){
      pExpr = sqlite3Expr(TK_NULL, 0, 0, 0);
    }else 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, 1, 0);
  }
  for(i=0; i<pTab->nCol; i++){
    sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0));
  }
  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 */

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
....
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
....
4826
4827
4828
4829
4830
4831
4832
4833

4834
4835
4836
4837
4838
4839
4840
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.563 2006/06/16 16:08:55 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }
  }

  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */


#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VNoChange * * *
**
** Push an entry onto the stack which says to the VUpdate command
** that the corresponding column of the row should not be modified.
*/
case OP_VNoChange: {
  pTos++;
  pTos->flags = 0;
  pTos->n = 0;
  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */


#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VUpdate P1 P2 P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** This opcode invokes the corresponding xUpdate method. P2 values
** are taken from the stack to pass to the xUpdate invocation. The
................................................................................
**
** The xUpdate method will do a DELETE or an INSERT or both.
** The argv[0] element (which corresponds to the P2-th element down
** on the stack) is the rowid of a row to delete.  If argv[0] is
** NULL then no deletion occurs.  The argv[1] element is the rowid
** of the new row.  This can be NULL to have the virtual table
** select the new rowid for itself.  The higher elements in the
** stack are the values of columns in the new row.  if any argv[i]
** where i>=2 is a NULL pointer (that is to say if argv[i]==NULL 
** which is different from if sqlite3_value_type(argv[i])==SQLITE_NULL)
** that means to preserve a copy of that element.  In other words,
** copy the corresponding value from the argv[0] row into the new row.
**
** If P2==1 then no insert is performed.  argv[0] is the rowid of
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
** is successful, then the value returned by sqlite3_last_insert_rowid() 
** is set to the value of the rowid for the row just inserted.
................................................................................
    rc = SQLITE_ERROR;
  }else{
    int i;
    sqlite_int64 rowid;
    Mem **apArg = p->apArg;
    Mem *pX = &pTos[1-nArg];
    for(i = 0; i<nArg; i++, pX++){
      apArg[i] = pX->flags ? storeTypeInfo(pX,0), pX : 0;

    }
    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
    if( pOp->p1 && rc==SQLITE_OK ){
      assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
      db->lastRowid = rowid;







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







|
<
<
<
<







 







|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
4768
4769
4770
4771
4772
4773
4774















4775
4776
4777
4778
4779
4780
4781
....
4784
4785
4786
4787
4788
4789
4790
4791




4792
4793
4794
4795
4796
4797
4798
....
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.564 2006/06/16 21:13:22 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }
  }

  break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

















#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VUpdate P1 P2 P3
**
** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
** This opcode invokes the corresponding xUpdate method. P2 values
** are taken from the stack to pass to the xUpdate invocation. The
................................................................................
**
** The xUpdate method will do a DELETE or an INSERT or both.
** The argv[0] element (which corresponds to the P2-th element down
** on the stack) is the rowid of a row to delete.  If argv[0] is
** NULL then no deletion occurs.  The argv[1] element is the rowid
** of the new row.  This can be NULL to have the virtual table
** select the new rowid for itself.  The higher elements in the
** stack are the values of columns in the new row.




**
** If P2==1 then no insert is performed.  argv[0] is the rowid of
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
** is successful, then the value returned by sqlite3_last_insert_rowid() 
** is set to the value of the rowid for the row just inserted.
................................................................................
    rc = SQLITE_ERROR;
  }else{
    int i;
    sqlite_int64 rowid;
    Mem **apArg = p->apArg;
    Mem *pX = &pTos[1-nArg];
    for(i = 0; i<nArg; i++, pX++){
      storeTypeInfo(pX, 0);
      apArg[i] = pX;
    }
    if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
    rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
    if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
    if( pOp->p1 && rc==SQLITE_OK ){
      assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
      db->lastRowid = rowid;

Changes to test/vtab1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
404
405
406
407
408
409
410


411
412
413
414
415
416
417
...
456
457
458
459
460
461
462

463
464
465
466
467
468
469
...
487
488
489
490
491
492
493


494
495
496
497
498
499
500
...
576
577
578
579
580
581
582

583
584
585
#    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.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.18 2006/06/16 06:17:47 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !vtab {
  finish_test
  return
................................................................................
} [list xBestIndex {SELECT rowid, * FROM 'treal'} \
        xFilter    {SELECT rowid, * FROM 'treal'} ]

execsql {
  DROP TABLE t1;
  DROP TABLE treal;
}



#----------------------------------------------------------------------
# Test cases vtab1-6 test INSERT, UPDATE and DELETE operations 
# on virtual tables.
do_test vtab1-6-1 {
  execsql { SELECT sql FROM sqlite_master }
} {}
................................................................................

do_test vtab1-6-7 {
  execsql {
    DELETE FROM techo;
    SELECT * FROM techo;
  }
} {}


file delete -force test2.db
file delete -force test2.db-journal
sqlite3 db2 test2.db
execsql {
  CREATE TABLE techo(a PRIMARY KEY, b, c);
} db2
................................................................................
] {
  execsql $stmt
  execsql $stmt db2
  check_echo_table vtab1-6.8.[incr tn]
}

db2 close



#----------------------------------------------------------------------
# Test cases vtab1-7 tests that the value returned by 
# sqlite3_last_insert_rowid() is set correctly when rows are inserted
# into virtual tables.
do_test vtab1.7-1 {
  execsql {
................................................................................
  }
} {31429}
do_test vtab1.7-13 {
  execsql {
    SELECT rowid, a, b, c FROM real_abc
  }
} {}


finish_test








|







 







>
>







 







>







 







>
>







 







>


<
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
...
581
582
583
584
585
586
587
588
589
590

#    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.  The
# focus of this file is creating and dropping virtual tables.
#
# $Id: vtab1.test,v 1.19 2006/06/16 21:13:23 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !vtab {
  finish_test
  return
................................................................................
} [list xBestIndex {SELECT rowid, * FROM 'treal'} \
        xFilter    {SELECT rowid, * FROM 'treal'} ]

execsql {
  DROP TABLE t1;
  DROP TABLE treal;
}

if 0 {   # FIXME

#----------------------------------------------------------------------
# Test cases vtab1-6 test INSERT, UPDATE and DELETE operations 
# on virtual tables.
do_test vtab1-6-1 {
  execsql { SELECT sql FROM sqlite_master }
} {}
................................................................................

do_test vtab1-6-7 {
  execsql {
    DELETE FROM techo;
    SELECT * FROM techo;
  }
} {}


file delete -force test2.db
file delete -force test2.db-journal
sqlite3 db2 test2.db
execsql {
  CREATE TABLE techo(a PRIMARY KEY, b, c);
} db2
................................................................................
] {
  execsql $stmt
  execsql $stmt db2
  check_echo_table vtab1-6.8.[incr tn]
}

db2 close



#----------------------------------------------------------------------
# Test cases vtab1-7 tests that the value returned by 
# sqlite3_last_insert_rowid() is set correctly when rows are inserted
# into virtual tables.
do_test vtab1.7-1 {
  execsql {
................................................................................
  }
} {31429}
do_test vtab1.7-13 {
  execsql {
    SELECT rowid, a, b, c FROM real_abc
  }
} {}
} ;# END if 0

finish_test