/ Check-in [ba59a7e2]
Login

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

Overview
Comment:Allow the ota extension to write to tables with no PRIMARY KEY declaration.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: ba59a7e2ba97244492cbca9247456df0f3f19248
User & Date: dan 2014-12-06 19:30:41
Context
2014-12-08
07:22
Extra tests for the ota_rowid column. check-in: 46069393 user: dan tags: ota-update
2014-12-06
19:30
Allow the ota extension to write to tables with no PRIMARY KEY declaration. check-in: ba59a7e2 user: dan tags: ota-update
2014-11-27
18:09
Update ota so that the hidden columns of virtual tables may be written. check-in: ccee9996 user: dan tags: ota-update
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/ota/ota1.test.

   173    173   # Check that an OTA cannot be applied to a table that has no PK.
   174    174   #
   175    175   # UPDATE: At one point OTA required that all tables featured either
   176    176   # explicit IPK columns or were declared WITHOUT ROWID. This has been
   177    177   # relaxed so that external PRIMARY KEYs on tables with automatic rowids
   178    178   # are now allowed.
   179    179   #
          180  +# UPDATE 2: Tables without any PRIMARY KEY declaration are now allowed.
          181  +# However the input table must feature an "ota_rowid" column.
          182  +#
   180    183   reset_db
   181    184   create_ota1 ota.db
   182    185   do_execsql_test 2.1 { CREATE TABLE t1(a, b, c) }
   183    186   do_test 2.2 {
   184    187     sqlite3ota ota test.db ota.db
   185    188     ota step
   186    189   } {SQLITE_ERROR}
   187    190   do_test 2.3 {
   188    191     list [catch { ota close } msg] $msg
   189         -} {1 {SQLITE_ERROR - table t1 has no PRIMARY KEY}}
          192  +} {1 {SQLITE_ERROR - table data_t1 requires ota_rowid column}}
   190    193   reset_db
   191    194   do_execsql_test 2.4 { CREATE TABLE t1(a PRIMARY KEY, b, c) }
   192    195   do_test 2.5 {
   193    196     sqlite3ota ota test.db ota.db
   194    197     ota step
   195    198   } {SQLITE_OK}
   196    199   do_test 2.6 {

Changes to ext/ota/ota9.test.

     5      5   #
     6      6   #    May you do good and not evil.
     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   #
    12         -# Test OTA with virtual tables
           12  +# Test OTA with virtual tables. And tables with no PRIMARY KEY declarations.
    13     13   #
    14     14   
    15     15   if {![info exists testdir]} {
    16     16     set testdir [file join [file dirname [info script]] .. .. test]
    17     17   }
    18     18   source $testdir/tester.tcl
    19     19   set ::testprefix ota9
................................................................................
    56     56     12 d e f
    57     57     13 g h X
    58     58     14 x y z
    59     59   }
    60     60   do_execsql_test 1.2.3 { INSERT INTO f1(f1) VALUES('integrity-check') }
    61     61   integrity_check 1.2.4
    62     62   
           63  +#-------------------------------------------------------------------------
           64  +# Tables with no PK declaration.
           65  +#
           66  +
           67  +# Run the OTA in file $ota on target database $target until completion.
           68  +#
           69  +proc run_ota {target ota} {
           70  +  sqlite3ota ota $target $ota
           71  +  while { [ota step]=="SQLITE_OK" } {}
           72  +  ota close
           73  +}
           74  +
           75  +foreach {tn idx} {
           76  +  1 { }
           77  +  2 { 
           78  +    CREATE INDEX i1 ON t1(a);
           79  +  }
           80  +  3 { 
           81  +    CREATE INDEX i1 ON t1(b, c);
           82  +    CREATE INDEX i2 ON t1(c, b);
           83  +    CREATE INDEX i3 ON t1(a, a, a, b, b, b, c, c, c);
           84  +  }
           85  +} {
           86  +
           87  +  reset_db
           88  +  do_execsql_test 2.$tn.1 {
           89  +    CREATE TABLE t1(a, b, c);
           90  +    INSERT INTO t1 VALUES(1, 2, 3);
           91  +    INSERT INTO t1 VALUES(4, 5, 6);
           92  +    INSERT INTO t1(rowid, a, b, c) VALUES(-1, 'a', 'b', 'c');
           93  +    INSERT INTO t1(rowid, a, b, c) VALUES(-2, 'd', 'e', 'f');
           94  +  }
           95  +
           96  +  db eval $idx
           97  +  
           98  +  do_test 2.$tn.2 {
           99  +    forcedelete ota.db
          100  +    sqlite3 db2 ota.db
          101  +    db2 eval {
          102  +      CREATE TABLE data_t1(ota_rowid, a, b, c, ota_control);
          103  +      INSERT INTO data_t1 VALUES(3, 'x', 'y', 'z', 0);
          104  +      INSERT INTO data_t1 VALUES(NULL, 'X', 'Y', 'Z', 0);
          105  +      INSERT INTO data_t1 VALUES('1', NULL, NULL, NULL, 1);
          106  +      INSERT INTO data_t1 VALUES(-2, NULL, NULL, 'fff', '..x');
          107  +    }
          108  +    db2 close
          109  +  } {}
          110  +  
          111  +  run_ota test.db ota.db
          112  +  
          113  +  do_execsql_test 2.$tn.3 {
          114  +    SELECT rowid, a, b, c FROM t1 ORDER BY rowid;
          115  +  } {
          116  +    -2 d e fff
          117  +    -1 a b c
          118  +     2 4 5 6
          119  +     3 x y z
          120  +     4 X Y Z
          121  +  }
          122  +  
          123  +  integrity_check 2.$tn.4
          124  +}
    63    125   
    64    126   
    65    127   finish_test
    66    128   

Changes to ext/ota/sqlite3ota.c.

   100    100   */
   101    101   struct OtaObjIter {
   102    102     sqlite3_stmt *pTblIter;         /* Iterate through tables */
   103    103     sqlite3_stmt *pIdxIter;         /* Index iterator */
   104    104     int nTblCol;                    /* Size of azTblCol[] array */
   105    105     char **azTblCol;                /* Array of quoted column names */
   106    106     unsigned char *abTblPk;         /* Array of flags - true for PK columns */
          107  +  int eType;
          108  +#if 0
   107    109     unsigned char bRowid;           /* True for implicit IPK tables */
   108    110     unsigned char bVtab;            /* True for a virtual table */
          111  +#endif
   109    112   
   110    113     /* Output variables. zTbl==0 implies EOF. */
   111    114     int bCleanup;                   /* True in "cleanup" state */
   112    115     const char *zTbl;               /* Name of target db table */
   113    116     const char *zIdx;               /* Name of target db index (or null) */
   114    117     int iVisit;                     /* Number of points visited, incl. current */
   115    118   
................................................................................
   120    123     sqlite3_stmt *pDelete;          /* Statement for DELETE ops */
   121    124   
   122    125     /* Last UPDATE used (for PK b-tree updates only), or NULL. */
   123    126     char *zMask;                    /* Copy of update mask used with pUpdate */
   124    127     sqlite3_stmt *pUpdate;          /* Last update statement (or NULL) */
   125    128   };
   126    129   
          130  +/*
          131  +** Values for OtaObjIter.eType
          132  +*/
          133  +#define OTA_PK_REAL     1         /* Table has a real primary key */
          134  +#define OTA_PK_EXTERNAL 2         /* Table has an external primary key index */
          135  +#define OTA_PK_NONE     3         /* Table has no PK (use rowid) */
          136  +#define OTA_PK_VTAB     4         /* Table is a virtual table (use rowid) */
          137  +
   127    138   /*
   128    139   ** OTA handle.
   129    140   */
   130    141   struct sqlite3ota {
   131    142     int eStage;                     /* Value of OTA_STATE_STAGE field */
   132    143     sqlite3 *db;                    /* "main" -> target db, "ota" -> ota db */
   133    144     char *zTarget;                  /* Path to target db */
................................................................................
   224    235     }
   225    236     sqlite3_free(pIter->azTblCol);
   226    237     pIter->azTblCol = 0;
   227    238     pIter->abTblPk = 0;
   228    239     pIter->nTblCol = 0;
   229    240     sqlite3_free(pIter->zMask);
   230    241     pIter->zMask = 0;
   231         -  pIter->bRowid = 0;
   232         -  pIter->bVtab = 0;
          242  +  pIter->eType = 0;               /* Invalid value */
   233    243   }
   234    244   
   235    245   /*
   236    246   ** Finalize all statements and free all allocations that are specific to
   237    247   ** the current object (table/index pair).
   238    248   */
   239    249   static void otaObjIterClearStatements(OtaObjIter *pIter){
................................................................................
   467    477   ** an error does occur, an error code and error message are also left in 
   468    478   ** the OTA handle.
   469    479   */
   470    480   static int otaObjIterGetCols(sqlite3ota *p, OtaObjIter *pIter){
   471    481     if( pIter->azTblCol==0 ){
   472    482       sqlite3_stmt *pStmt = 0;
   473    483       int nCol = 0;
   474         -    int bSeenPk = 0;
   475    484       int i;                        /* for() loop iterator variable */
   476    485       int rc2;                      /* sqlite3_finalize() return value */
          486  +    int bOtaRowid = 0;            /* If input table has column "ota_rowid" */
   477    487   
   478         -    assert( pIter->bRowid==0 && pIter->bVtab==0 );
          488  +    assert( pIter->eType==0 );
   479    489   
   480    490       /* Populate the azTblCol[] and nTblCol variables based on the columns
   481    491       ** of the input table. Ignore any input table columns that begin with
   482    492       ** "ota_".  */
   483    493       p->rc = prepareFreeAndCollectError(p->db, &pStmt, &p->zErrmsg, 
   484    494           sqlite3_mprintf("SELECT * FROM 'data_%q'", pIter->zTbl)
   485    495       );
................................................................................
   489    499       }
   490    500       for(i=0; p->rc==SQLITE_OK && i<nCol; i++){
   491    501         const char *zName = (const char*)sqlite3_column_name(pStmt, i);
   492    502         if( sqlite3_strnicmp("ota_", zName, 4) ){
   493    503           char *zCopy = otaQuoteName(zName);
   494    504           pIter->azTblCol[pIter->nTblCol++] = zCopy;
   495    505           if( zCopy==0 ) p->rc = SQLITE_NOMEM;
          506  +      }
          507  +      else if( 0==sqlite3_stricmp("ota_rowid", zName) ){
          508  +        bOtaRowid = 1;
   496    509         }
   497    510       }
   498    511       sqlite3_finalize(pStmt);
   499    512       pStmt = 0;
   500    513   
   501    514       /* Check that all non-HIDDEN columns in the destination table are also
   502    515       ** present in the input table. Populate the abTblPk[] array at the
................................................................................
   515    528           p->rc = SQLITE_ERROR;
   516    529           p->zErrmsg = sqlite3_mprintf("column missing from data_%q: %s",
   517    530               pIter->zTbl, zName
   518    531           );
   519    532         }else{
   520    533           int iPk = sqlite3_column_int(pStmt, 5);
   521    534           pIter->abTblPk[i] = (iPk!=0);
   522         -        if( iPk ) bSeenPk = 1;
   523         -        if( iPk<0 ) pIter->bRowid = 1;
          535  +        if( iPk ){
          536  +          pIter->eType = (iPk<0) ? OTA_PK_EXTERNAL : OTA_PK_REAL;
          537  +        }
   524    538         }
   525    539       }
   526    540       rc2 = sqlite3_finalize(pStmt);
   527    541       if( p->rc==SQLITE_OK ) p->rc = rc2;
   528    542   
   529         -    if( p->rc==SQLITE_OK && bSeenPk==0 ){
   530         -      const char *zTab = pIter->zTbl;
   531         -      if( otaIsVtab(p, zTab) ){
   532         -        pIter->bVtab = 1;
   533         -      }else{
   534         -        p->zErrmsg = sqlite3_mprintf("table %s has no PRIMARY KEY", zTab);
          543  +    if( p->rc==SQLITE_OK ){
          544  +      if( pIter->eType==0 ){
          545  +        /* This must either be a virtual table, or a regular table with no
          546  +        ** PRIMARY KEY declaration whatsoever.  */
          547  +        if( bOtaRowid==0 ){
          548  +          p->rc = SQLITE_ERROR;
          549  +          p->zErrmsg = sqlite3_mprintf(
          550  +              "table data_%q requires ota_rowid column", pIter->zTbl
          551  +          );
          552  +        }else if( otaIsVtab(p, pIter->zTbl) ){
          553  +          pIter->eType = OTA_PK_VTAB;
          554  +        }else{
          555  +          pIter->eType = OTA_PK_NONE;
          556  +        }
          557  +      }else if( bOtaRowid ){
   535    558           p->rc = SQLITE_ERROR;
          559  +        p->zErrmsg = sqlite3_mprintf(
          560  +            "table data_%q may not have ota_rowid column", pIter->zTbl
          561  +        );
   536    562         }
   537    563       }
   538    564     }
   539    565   
   540    566     return p->rc;
   541    567   }
   542    568   
................................................................................
   614    640           break;
   615    641         }
   616    642       }
   617    643     }
   618    644     return zList;
   619    645   }
   620    646   
          647  +/*
          648  +** Assuming the current table columns are "a", "b" and "c", and the zObj
          649  +** paramter is passed "old", return a string of the form:
          650  +**
          651  +**     "old.a, old.b, old.b"
          652  +**
          653  +** With the column names escaped.
          654  +**
          655  +** For tables with implicit rowids - OTA_PK_EXTERNAL and OTA_PK_NONE, append
          656  +** the text ", old._rowid_" to the returned value.
          657  +*/
   621    658   static char *otaObjIterGetOldlist(
   622    659     sqlite3ota *p, 
   623    660     OtaObjIter *pIter,
   624    661     const char *zObj
   625    662   ){
   626    663     char *zList = 0;
   627    664     if( p->rc==SQLITE_OK ){
................................................................................
   633    670         if( zList==0 ){
   634    671           p->rc = SQLITE_NOMEM;
   635    672           break;
   636    673         }
   637    674       }
   638    675   
   639    676       /* For a table with implicit rowids, append "old._rowid_" to the list. */
   640         -    if( pIter->bRowid ){
          677  +    if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
   641    678         zList = sqlite3_mprintf("%z, %s._rowid_", zList, zObj);
   642    679       }
   643    680     }
   644    681     return zList;
   645    682   }
   646    683   
          684  +/*
          685  +** Return an expression that can be used in a WHERE clause to match the
          686  +** primary key of the current table. For example, if the table is:
          687  +**
          688  +**   CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c));
          689  +**
          690  +** Return the string:
          691  +**
          692  +**   "b = ?1 AND c = ?2"
          693  +*/
   647    694   static char *otaObjIterGetWhere(
   648    695     sqlite3ota *p, 
   649    696     OtaObjIter *pIter
   650    697   ){
   651    698     char *zList = 0;
   652    699     if( p->rc==SQLITE_OK ){
   653         -    if( pIter->bVtab ){
   654         -      zList = otaMPrintfAndCollectError(p, "rowid = ?%d", pIter->nTblCol+1);
          700  +    if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){
          701  +      zList = otaMPrintfAndCollectError(p, "_rowid_ = ?%d", pIter->nTblCol+1);
   655    702       }else{
   656    703         const char *zSep = "";
   657    704         int i;
   658    705         for(i=0; i<pIter->nTblCol; i++){
   659    706           if( pIter->abTblPk[i] ){
   660    707             const char *zCol = pIter->azTblCol[i];
   661    708             zList = otaMPrintfAndCollectError(
................................................................................
   755    802         if( !zLimit ) p->rc = SQLITE_NOMEM;
   756    803       }
   757    804   
   758    805       if( zIdx ){
   759    806         int *aiCol;                 /* Column map */
   760    807         const char **azColl;        /* Collation sequences */
   761    808   
   762         -      assert( pIter->bVtab==0 );
          809  +      assert( pIter->eType!=OTA_PK_VTAB );
   763    810   
   764    811         /* Create the index writers */
   765    812         if( p->rc==SQLITE_OK ){
   766    813           p->rc = sqlite3_index_writer(
   767    814               p->db, 0, zIdx, &pIter->pInsert, &azColl, &aiCol, &pIter->nCol
   768    815           );
   769    816         }
................................................................................
   773    820           );
   774    821         }
   775    822   
   776    823         /* Create the SELECT statement to read keys in sorted order */
   777    824         zCollist = otaObjIterGetCollist(p, pIter, pIter->nCol, aiCol, azColl);
   778    825         if( p->rc==SQLITE_OK ){
   779    826           char *zSql;
   780         -        if( pIter->bRowid ){
          827  +        if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
   781    828             zSql = sqlite3_mprintf(
   782    829                 "SELECT %s, ota_control FROM ota.'ota_tmp_%q' ORDER BY %s%s",
   783         -              zCollist, pIter->zTbl, 
          830  +              zCollist, pIter->zTbl,
   784    831                 zCollist, zLimit
   785    832             );
   786    833           }else{
   787    834             zSql = sqlite3_mprintf(
   788    835                 "SELECT %s, ota_control FROM ota.'data_%q' "
   789    836                 "WHERE typeof(ota_control)='integer' AND ota_control!=1 "
   790    837                 "UNION ALL "
................................................................................
   794    841                 zCollist, pIter->zTbl, 
   795    842                 zCollist, zLimit
   796    843             );
   797    844           }
   798    845           p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, zSql);
   799    846         }
   800    847       }else{
          848  +      int bOtaRowid = (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE);
   801    849         const char *zTbl = pIter->zTbl;
   802         -      char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol+pIter->bVtab);
   803    850         char *zWhere = otaObjIterGetWhere(p, pIter);
   804    851         char *zOldlist = otaObjIterGetOldlist(p, pIter, "old");
   805    852         char *zNewlist = otaObjIterGetOldlist(p, pIter, "new");
          853  +      char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol + bOtaRowid);
          854  +
   806    855         zCollist = otaObjIterGetCollist(p, pIter, pIter->nTblCol, 0, 0);
   807    856         pIter->nCol = pIter->nTblCol;
   808    857   
   809    858         /* Create the SELECT statement to read keys from data_xxx */
   810    859         if( p->rc==SQLITE_OK ){
   811    860           p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz,
   812    861               sqlite3_mprintf(
   813    862                 "SELECT %s, ota_control%s FROM ota.'data_%q'%s", 
   814         -              zCollist, (pIter->bVtab ? ", ota_rowid" : ""), zTbl, zLimit
          863  +              zCollist, (bOtaRowid ? ", ota_rowid" : ""), zTbl, zLimit
   815    864               )
   816    865           );
   817    866         }
   818    867   
   819    868         /* Create the INSERT statement to write to the target PK b-tree */
   820    869         if( p->rc==SQLITE_OK ){
   821    870           p->rc = prepareFreeAndCollectError(p->db, &pIter->pInsert, pz,
   822    871               sqlite3_mprintf(
   823    872                 "INSERT INTO main.%Q(%s%s) VALUES(%s)", 
   824         -              zTbl, zCollist, (pIter->bVtab ? ", rowid" : ""), zBindings
          873  +              zTbl, zCollist, (bOtaRowid ? ", _rowid_" : ""), zBindings
   825    874               )
   826    875           );
   827    876         }
   828    877   
   829    878         /* Create the DELETE statement to write to the target PK b-tree */
   830    879         if( p->rc==SQLITE_OK ){
   831    880           p->rc = prepareFreeAndCollectError(p->db, &pIter->pDelete, pz,
   832    881               sqlite3_mprintf(
   833    882                 "DELETE FROM main.%Q WHERE %s", zTbl, zWhere
   834    883               )
   835    884           );
   836    885         }
   837    886   
   838         -      if( pIter->bVtab==0 ){
   839         -        const char *zOtaRowid = (pIter->bRowid ? ", ota_rowid" : "");
          887  +      if( pIter->eType!=OTA_PK_VTAB ){
          888  +        const char *zOtaRowid = "";
          889  +        if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
          890  +          zOtaRowid = ", ota_rowid";
          891  +        }
   840    892   
   841    893           /* Create the ota_tmp_xxx table and the triggers to populate it. */
   842    894           otaMPrintfExec(p, 
   843    895               "PRAGMA ota_mode = 1;"
   844    896               "CREATE TABLE IF NOT EXISTS ota.'ota_tmp_%q' AS "
   845    897               "SELECT *%s FROM ota.'data_%q' WHERE 0;"
   846    898   
................................................................................
   854    906               "  INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(2, %s);"
   855    907               "END;"
   856    908   
   857    909               "CREATE TEMP TRIGGER ota_update2_%q AFTER UPDATE ON main.%Q "
   858    910               "BEGIN "
   859    911               "  INSERT INTO 'ota_tmp_%q'(ota_control, %s%s) VALUES(3, %s);"
   860    912               "END;"
   861         -            , zTbl, (pIter->bRowid ? ", 0 AS ota_rowid" : ""), zTbl, 
          913  +            , zTbl, (pIter->eType==OTA_PK_EXTERNAL ? ", 0 AS ota_rowid" : "")
          914  +            , zTbl, 
   862    915               zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist,
   863    916               zTbl, zTbl, zTbl, zCollist, zOtaRowid, zOldlist,
   864    917               zTbl, zTbl, zTbl, zCollist, zOtaRowid, zNewlist
   865    918           );
   866         -        if( pIter->bRowid ){
          919  +        if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
   867    920             otaMPrintfExec(p, 
   868    921                 "CREATE TEMP TRIGGER ota_insert_%q AFTER INSERT ON main.%Q "
   869    922                 "BEGIN "
   870    923                 "  INSERT INTO 'ota_tmp_%q'(ota_control, %s, ota_rowid)"
   871    924                 "  VALUES(0, %s);"
   872    925                 "END;"
   873    926                 , zTbl, zTbl, zTbl, zCollist, zNewlist
................................................................................
  1070   1123   
  1071   1124     if( res==0 ){
  1072   1125       otaBadControlError(p);
  1073   1126     }
  1074   1127     return res;
  1075   1128   }
  1076   1129   
         1130  +#ifdef SQLITE_DEBUG
         1131  +static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
         1132  +  const char *zCol = sqlite3_column_name(pStmt, iCol);
         1133  +  assert( 0==sqlite3_stricmp(zName, zCol) );
         1134  +}
         1135  +#else
         1136  +# define assertColumnName(x,y,z)
         1137  +#endif
         1138  +
  1077   1139   /*
  1078   1140   ** This function does the work for an sqlite3ota_step() call.
  1079   1141   **
  1080   1142   ** The object-iterator (p->objiter) currently points to a valid object,
  1081   1143   ** and the input cursor (p->objiter.pSelect) currently points to a valid
  1082   1144   ** input row. Perform whatever processing is required and return.
  1083   1145   **
................................................................................
  1118   1180         for(i=0; i<pIter->nCol; i++){
  1119   1181           if( eType==SQLITE_DELETE && pIter->zIdx==0 && pIter->abTblPk[i]==0 ){
  1120   1182             continue;
  1121   1183           }
  1122   1184           pVal = sqlite3_column_value(pIter->pSelect, i);
  1123   1185           sqlite3_bind_value(pWriter, i+1, pVal);
  1124   1186         }
  1125         -      if( pIter->bVtab ){
  1126         -        /* For a virtual table, the SELECT statement is:
         1187  +      if( pIter->zIdx==0
         1188  +       && (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE) 
         1189  +      ){
         1190  +        /* For a virtual table, or a table with no primary key, the 
         1191  +        ** SELECT statement is:
  1127   1192           **
  1128   1193           **   SELECT <cols>, ota_control, ota_rowid FROM ....
  1129   1194           **
  1130   1195           ** Hence column_value(pIter->nCol+1).
  1131   1196           */
         1197  +        assertColumnName(pIter->pSelect, pIter->nCol+1, "ota_rowid");
  1132   1198           pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
  1133   1199           sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
  1134   1200         }
  1135   1201         sqlite3_step(pWriter);
  1136   1202         p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
  1137   1203       }else if( eType==OTA_UPDATE ){
  1138   1204         sqlite3_value *pVal;
................................................................................
  1139   1205         sqlite3_stmt *pUpdate = 0;
  1140   1206         otaGetUpdateStmt(p, pIter, zMask, &pUpdate);
  1141   1207         if( pUpdate ){
  1142   1208           for(i=0; i<pIter->nCol; i++){
  1143   1209             pVal = sqlite3_column_value(pIter->pSelect, i);
  1144   1210             sqlite3_bind_value(pUpdate, i+1, pVal);
  1145   1211           }
  1146         -        if( pIter->bVtab ){
         1212  +        if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){
         1213  +          /* Bind the ota_rowid value to column _rowid_ */
         1214  +          assertColumnName(pIter->pSelect, pIter->nCol+1, "ota_rowid");
  1147   1215             pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
  1148   1216             sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
  1149   1217           }
  1150   1218           sqlite3_step(pUpdate);
  1151   1219           p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
  1152   1220         }
  1153   1221       }else{
................................................................................
  1191   1259           OtaObjIter *pIter = &p->objiter;
  1192   1260           while( p && p->rc==SQLITE_OK && pIter->zTbl ){
  1193   1261   
  1194   1262             if( pIter->bCleanup ){
  1195   1263               /* Clean up the ota_tmp_xxx table for the previous table. It 
  1196   1264               ** cannot be dropped as there are currently active SQL statements.
  1197   1265               ** But the contents can be deleted.  */
  1198         -            if( pIter->bVtab==0 ){
         1266  +            if( pIter->eType!=OTA_PK_VTAB ){
  1199   1267                 otaMPrintfExec(p, "DELETE FROM ota.'ota_tmp_%q'", pIter->zTbl);
  1200   1268               }
  1201   1269             }else{
  1202   1270               otaObjIterPrepareAll(p, pIter, 0);
  1203   1271   
  1204   1272               /* Advance to the next row to process. */
  1205   1273               if( p->rc==SQLITE_OK ){