/ Check-in [9780829a]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix further REUSE_SCHEMA issues.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema1
Files: files | file ages | folders
SHA3-256: 9780829a77a49b199a55e56d21a51d33fee50321621337afabe5a6f977a65eee
User & Date: dan 2018-11-16 17:04:58
Context
2018-11-17
18:11
Fix further problems with the feature on this branch. check-in: 6d7a7e5f user: dan tags: reuse-schema1
2018-11-16
17:04
Fix further REUSE_SCHEMA issues. check-in: 9780829a user: dan tags: reuse-schema1
2018-11-15
21:20
Fix some problems with the feature on this branch. Many problems remain. check-in: 31b6aee7 user: dan tags: reuse-schema1
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/alter.c.

   102    102     savedDbFlags = db->mDbFlags;  
   103    103     if( NEVER(db->mallocFailed) ) goto exit_rename_table;
   104    104     assert( pSrc->nSrc==1 );
   105    105     assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
   106    106   
   107    107     pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
   108    108     if( !pTab ) goto exit_rename_table;
   109         -  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
          109  +  iDb = sqlite3SchemaToIndex2(pParse->db, pTab->pSchema, 0);
   110    110     zDb = db->aDb[iDb].zDbSName;
   111    111     db->mDbFlags |= DBFLAG_PreferBuiltin;
   112    112   
   113    113     /* Get a NULL terminated version of the new table name. */
   114    114     zName = sqlite3NameFromToken(db, pName);
   115    115     if( !zName ) goto exit_rename_table;
   116    116   
................................................................................
   272    272   
   273    273     db = pParse->db;
   274    274     if( pParse->nErr || db->mallocFailed ) return;
   275    275     pNew = pParse->pNewTable;
   276    276     assert( pNew );
   277    277   
   278    278     assert( sqlite3BtreeHoldsAllMutexes(db) );
   279         -  iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
          279  +  iDb = sqlite3SchemaToIndex2(db, pNew->pSchema, 0);
   280    280     zDb = db->aDb[iDb].zDbSName;
   281    281     zTab = &pNew->zName[16];  /* Skip the "sqlite_altertab_" prefix on the name */
   282    282     pCol = &pNew->aCol[pNew->nCol-1];
   283    283     pDflt = pCol->pDflt;
   284    284     pTab = sqlite3FindTable(db, zTab, zDb);
   285    285     assert( pTab );
   286    286   
................................................................................
   425    425       goto exit_begin_add_column;
   426    426     }
   427    427     if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
   428    428       goto exit_begin_add_column;
   429    429     }
   430    430   
   431    431     assert( pTab->addColOffset>0 );
   432         -  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
          432  +  iDb = sqlite3SchemaToIndex2(db, pTab->pSchema, 0);
   433    433   
   434    434     /* Put a copy of the Table struct in Parse.pNewTable for the
   435    435     ** sqlite3AddColumn() function and friends to modify.  But modify
   436    436     ** the name by adding an "sqlite_altertab_" prefix.  By adding this
   437    437     ** prefix, we insure that the name will not collide with an existing
   438    438     ** table because user table are not allowed to have the "sqlite_"
   439    439     ** prefix on their name.
................................................................................
   526    526     if( !pTab ) goto exit_rename_column;
   527    527   
   528    528     /* Cannot alter a system table */
   529    529     if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
   530    530     if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
   531    531   
   532    532     /* Which schema holds the table to be altered */  
   533         -  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
          533  +  iSchema = sqlite3SchemaToIndex2(db, pTab->pSchema, 0);
   534    534     assert( iSchema>=0 );
   535    535     zDb = db->aDb[iSchema].zDbSName;
   536    536   
   537    537   #ifndef SQLITE_OMIT_AUTHORIZATION
   538    538     /* Invoke the authorization callback. */
   539    539     if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
   540    540       goto exit_rename_column;
................................................................................
  1054   1054     NameContext sNC;
  1055   1055     int rc = SQLITE_OK;
  1056   1056   
  1057   1057     memset(&sNC, 0, sizeof(sNC));
  1058   1058     sNC.pParse = pParse;
  1059   1059     assert( pNew->pTabSchema );
  1060   1060     pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, 
  1061         -      db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
         1061  +      db->aDb[sqlite3SchemaToIndex2(db, pNew->pTabSchema, 0)].zDbSName
  1062   1062     );
  1063   1063     pParse->eTriggerOp = pNew->op;
  1064   1064     /* ALWAYS() because if the table of the trigger does not exist, the
  1065   1065     ** error would have been hit before this point */
  1066   1066     if( ALWAYS(pParse->pTriggerTab) ){
  1067   1067       rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
  1068   1068     }
................................................................................
  1571   1571         }
  1572   1572   
  1573   1573         else if( sParse.pNewTrigger ){
  1574   1574           if( isLegacy==0 ){
  1575   1575             rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
  1576   1576           }
  1577   1577           if( rc==SQLITE_OK ){
  1578         -          int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
         1578  +          int i1 = sqlite3SchemaToIndex2(db, sParse.pNewTrigger->pTabSchema, 0);
  1579   1579             int i2 = sqlite3FindDbName(db, zDb);
  1580   1580             if( i1==i2 ) sqlite3_result_int(context, 1);
  1581   1581           }
  1582   1582         }
  1583   1583       }
  1584   1584   
  1585   1585       if( rc!=SQLITE_OK ){

Changes to src/analyze.c.

   975    975   
   976    976   /*
   977    977   ** Generate code to do an analysis of all indices associated with
   978    978   ** a single table.
   979    979   */
   980    980   static void analyzeOneTable(
   981    981     Parse *pParse,   /* Parser context */
          982  +  int iDb,         /* Database that contains table pTab */
   982    983     Table *pTab,     /* Table whose indices are to be analyzed */
   983    984     Index *pOnlyIdx, /* If not NULL, only analyze this one index */
   984    985     int iStatCur,    /* Index of VdbeCursor that writes the sqlite_stat1 table */
   985    986     int iMem,        /* Available memory locations begin here */
   986    987     int iTab         /* Next available cursor */
   987    988   ){
   988    989     sqlite3 *db = pParse->db;    /* Database handle */
   989    990     Index *pIdx;                 /* An index to being analyzed */
   990    991     int iIdxCur;                 /* Cursor open on index being analyzed */
   991    992     int iTabCur;                 /* Table cursor */
   992    993     Vdbe *v;                     /* The virtual machine being built up */
   993    994     int i;                       /* Loop counter */
   994    995     int jZeroRows = -1;          /* Jump from here if number of rows is zero */
   995         -  int iDb;                     /* Index of database containing pTab */
   996    996     u8 needTableCnt = 1;         /* True to count the table */
   997    997     int regNewRowid = iMem++;    /* Rowid for the inserted record */
   998    998     int regStat4 = iMem++;       /* Register to hold Stat4Accum object */
   999    999     int regChng = iMem++;        /* Index of changed index field */
  1000   1000   #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  1001   1001     int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
  1002   1002   #endif
................................................................................
  1019   1019       return;
  1020   1020     }
  1021   1021     if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){
  1022   1022       /* Do not gather statistics on system tables */
  1023   1023       return;
  1024   1024     }
  1025   1025     assert( sqlite3BtreeHoldsAllMutexes(db) );
  1026         -  iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
  1027   1026     assert( iDb>=0 );
  1028   1027     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  1029   1028   #ifndef SQLITE_OMIT_AUTHORIZATION
  1030   1029     if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
  1031   1030         db->aDb[iDb].zDbSName ) ){
  1032   1031       return;
  1033   1032     }
................................................................................
  1114   1113       /* Make sure there are enough memory cells allocated to accommodate 
  1115   1114       ** the regPrev array and a trailing rowid (the rowid slot is required
  1116   1115       ** when building a record to insert into the sample column of 
  1117   1116       ** the sqlite_stat4 table.  */
  1118   1117       pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
  1119   1118   
  1120   1119       /* Open a read-only cursor on the index being analyzed. */
  1121         -    assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
         1120  +    assert( db->aDb[iDb].pSchema==pIdx->pSchema );
  1122   1121       sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
  1123   1122       sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  1124   1123       VdbeComment((v, "%s", pIdx->zName));
  1125   1124   
  1126   1125       /* Invoke the stat_init() function. The arguments are:
  1127   1126       ** 
  1128   1127       **    (1) the number of columns in the index including the rowid
................................................................................
  1335   1334     sqlite3 *db = pParse->db;
  1336   1335     Schema *pSchema = db->aDb[iDb].pSchema;    /* Schema of database iDb */
  1337   1336     HashElem *k;
  1338   1337     int iStatCur;
  1339   1338     int iMem;
  1340   1339     int iTab;
  1341   1340   
  1342         -  sqlite3SchemaWritable(pParse, iDb);
  1343   1341     sqlite3BeginWriteOperation(pParse, 0, iDb);
  1344   1342     iStatCur = pParse->nTab;
  1345   1343     pParse->nTab += 3;
  1346   1344     openStatTable(pParse, iDb, iStatCur, 0, 0);
  1347   1345     iMem = pParse->nMem+1;
  1348   1346     iTab = pParse->nTab;
  1349   1347     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  1350   1348     for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
  1351   1349       Table *pTab = (Table*)sqliteHashData(k);
  1352         -    analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
         1350  +    analyzeOneTable(pParse, iDb, pTab, 0, iStatCur, iMem, iTab);
  1353   1351     }
  1354   1352     loadAnalysis(pParse, iDb);
  1355   1353   }
  1356   1354   
  1357   1355   /*
  1358   1356   ** Generate code that will do an analysis of a single table in
  1359   1357   ** a database.  If pOnlyIdx is not NULL then it is a single index
  1360   1358   ** in pTab that should be analyzed.
  1361   1359   */
  1362         -static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
  1363         -  int iDb;
         1360  +static void analyzeTable(Parse *pParse, int iDb, Table *pTab, Index *pOnlyIdx){
  1364   1361     int iStatCur;
  1365   1362   
  1366   1363     assert( pTab!=0 );
  1367   1364     assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
  1368         -  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
  1369   1365     sqlite3BeginWriteOperation(pParse, 0, iDb);
  1370   1366     iStatCur = pParse->nTab;
  1371   1367     pParse->nTab += 3;
  1372   1368     if( pOnlyIdx ){
  1373   1369       openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx");
  1374   1370     }else{
  1375   1371       openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
  1376   1372     }
  1377         -  analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab);
         1373  +  analyzeOneTable(pParse, iDb, pTab, 
         1374  +      pOnlyIdx, iStatCur, pParse->nMem+1, pParse->nTab
         1375  +  );
  1378   1376     loadAnalysis(pParse, iDb);
  1379   1377   }
  1380   1378   
  1381   1379   /*
  1382   1380   ** Generate code for the ANALYZE command.  The parser calls this routine
  1383   1381   ** when it recognizes an ANALYZE command.
  1384   1382   **
................................................................................
  1421   1419       /* Form 3: Analyze the table or index named as an argument */
  1422   1420       iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
  1423   1421       if( iDb>=0 ){
  1424   1422         zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
  1425   1423         z = sqlite3NameFromToken(db, pTableName);
  1426   1424         if( z ){
  1427   1425           if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
  1428         -          analyzeTable(pParse, pIdx->pTable, pIdx);
         1426  +          analyzeTable(pParse, iDb, pIdx->pTable, pIdx);
  1429   1427           }else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
  1430         -          analyzeTable(pParse, pTab, 0);
         1428  +          analyzeTable(pParse, iDb, pTab, 0);
  1431   1429           }
  1432   1430           sqlite3DbFree(db, z);
  1433   1431         }
  1434   1432       }
  1435   1433     }
  1436   1434     if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
  1437   1435       sqlite3VdbeAddOp0(v, OP_Expire);

Changes to src/build.c.

   262    262     if( zSql==0 ){
   263    263       return;   /* A malloc must have failed */
   264    264     }
   265    265     pParse->nested++;
   266    266     memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
   267    267     memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
   268    268     sqlite3RunParser(pParse, zSql, &zErrMsg);
   269         -  sqlite3DbFree(db, zErrMsg);
          269  +  if( zErrMsg ){
          270  +    sqlite3ErrorMsg(pParse, "%z", zErrMsg);
          271  +  }
   270    272     sqlite3DbFree(db, zSql);
   271    273     memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
   272    274     pParse->nested--;
   273    275   }
   274    276   
   275    277   #if SQLITE_USER_AUTHENTICATION
   276    278   /*
................................................................................
  3531   3533       }
  3532   3534     }
  3533   3535   
  3534   3536     /* When adding an index to the list of indices for a table, make
  3535   3537     ** sure all indices labeled OE_Replace come after all those labeled
  3536   3538     ** OE_Ignore.  This is necessary for the correct constraint check
  3537   3539     ** processing (in sqlite3GenerateConstraintChecks()) as part of
  3538         -  ** UPDATE and INSERT statements.  
         3540  +  ** UPDATE and INSERT statements.
  3539   3541     */
  3540   3542     if( db->init.busy || pTblName==0 ){
  3541   3543       if( onError!=OE_Replace || pTab->pIndex==0
  3542   3544            || pTab->pIndex->onError==OE_Replace){
  3543   3545         pIndex->pNext = pTab->pIndex;
  3544   3546         pTab->pIndex = pIndex;
  3545   3547       }else{

Changes to src/delete.c.

   659    659   **   then it identifies an index cursor (from within array of cursors
   660    660   **   starting at iIdxCur) that already points to the index entry to be deleted.
   661    661   **   Except, this optimization is disabled if there are BEFORE triggers since
   662    662   **   the trigger body might have moved the cursor.
   663    663   */
   664    664   void sqlite3GenerateRowDelete(
   665    665     Parse *pParse,     /* Parsing context */
   666         -  int iDb,
          666  +  int iDb,           /* Database containing pTab */
   667    667     Table *pTab,       /* Table containing the row to be deleted */
   668    668     Trigger *pTrigger, /* List of triggers to (potentially) fire */
   669    669     int iDataCur,      /* Cursor from which column data is extracted */
   670    670     int iIdxCur,       /* First index cursor */
   671    671     int iPk,           /* First memory cell containing the PRIMARY KEY */
   672    672     i16 nPk,           /* Number of PRIMARY KEY memory cells */
   673    673     u8 count,          /* If non-zero, increment the row change counter */

Changes to src/insert.c.

  1033   1033         sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
  1034   1034         sqlite3MayAbort(pParse);
  1035   1035       }else
  1036   1036   #endif
  1037   1037       {
  1038   1038         int isReplace;    /* Set to true if constraints may cause a replace */
  1039   1039         int bUseSeek;     /* True to use OPFLAG_SEEKRESULT */
  1040         -      sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
  1041         -          regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
         1040  +      sqlite3GenerateConstraintChecks(pParse, iDb, pTab, aRegIdx, iDataCur, 
         1041  +          iIdxCur, regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 
         1042  +          0, pUpsert
  1042   1043         );
  1043   1044         sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
  1044   1045   
  1045   1046         /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
  1046   1047         ** constraints or (b) there are no triggers and this table is not a
  1047   1048         ** parent table in a foreign key constraint. It is safe to set the
  1048   1049         ** flag in the second case as if any REPLACE constraint is hit, an
................................................................................
  1270   1271   ** Which action to take is determined by the overrideError parameter.
  1271   1272   ** Or if overrideError==OE_Default, then the pParse->onError parameter
  1272   1273   ** is used.  Or if pParse->onError==OE_Default then the onError value
  1273   1274   ** for the constraint is used.
  1274   1275   */
  1275   1276   void sqlite3GenerateConstraintChecks(
  1276   1277     Parse *pParse,       /* The parser context */
         1278  +  int iDb,             /* Databse that contains pTab */
  1277   1279     Table *pTab,         /* The table being inserted or updated */
  1278   1280     int *aRegIdx,        /* Use register aRegIdx[i] for index i.  0 for unused */
  1279   1281     int iDataCur,        /* Canonical data cursor (main table or PK index) */
  1280   1282     int iIdxCur,         /* First index cursor */
  1281   1283     int regNewData,      /* First register in a range holding values to insert */
  1282   1284     int regOldData,      /* Previous content.  0 for INSERTs */
  1283   1285     u8 pkChng,           /* Non-zero if the rowid or PRIMARY KEY changed */
................................................................................
  1553   1555           */
  1554   1556           Trigger *pTrigger = 0;
  1555   1557           if( db->flags&SQLITE_RecTriggers ){
  1556   1558             pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
  1557   1559           }
  1558   1560           if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
  1559   1561             sqlite3MultiWrite(pParse);
  1560         -          sqlite3GenerateRowDelete(pParse, 0, pTab, pTrigger, iDataCur, iIdxCur,
  1561         -                                   regNewData, 1, 0, OE_Replace, 1, -1);
         1562  +          sqlite3GenerateRowDelete(pParse, iDb, pTab, pTrigger, iDataCur, 
         1563  +                                  iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1);
  1562   1564           }else{
  1563   1565   #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  1564   1566             assert( HasRowid(pTab) );
  1565   1567             /* This OP_Delete opcode fires the pre-update-hook only. It does
  1566   1568             ** not modify the b-tree. It is more efficient to let the coming
  1567   1569             ** OP_Insert replace the existing entry than it is to delete the
  1568   1570             ** existing entry and then insert a new one. */
................................................................................
  1802   1804           assert( onError==OE_Replace );
  1803   1805           if( db->flags&SQLITE_RecTriggers ){
  1804   1806             pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
  1805   1807           }
  1806   1808           if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
  1807   1809             sqlite3MultiWrite(pParse);
  1808   1810           }
  1809         -        sqlite3GenerateRowDelete(pParse, 0, pTab, pTrigger, iDataCur, iIdxCur,
         1811  +        sqlite3GenerateRowDelete(pParse, iDb, pTab, pTrigger, iDataCur, iIdxCur,
  1810   1812               regR, nPkField, 0, OE_Replace,
  1811   1813               (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
  1812   1814           seenReplace = 1;
  1813   1815           break;
  1814   1816         }
  1815   1817       }
  1816   1818       if( pUpIdx==pIdx ){

Changes to src/sqliteInt.h.

  4032   4032   #endif
  4033   4033   void sqlite3GenerateRowDelete(
  4034   4034       Parse*,int,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
  4035   4035   void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
  4036   4036   int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
  4037   4037   void sqlite3ResolvePartIdxLabel(Parse*,int);
  4038   4038   int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int);
  4039         -void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
         4039  +void sqlite3GenerateConstraintChecks(Parse*,int,Table*,int*,int,int,int,int,
  4040   4040                                        u8,u8,int,int*,int*,Upsert*);
  4041   4041   #ifdef SQLITE_ENABLE_NULL_TRIM
  4042   4042     void sqlite3SetMakeRecordP5(Vdbe*,Table*);
  4043   4043   #else
  4044   4044   # define sqlite3SetMakeRecordP5(A,B)
  4045   4045   #endif
  4046   4046   void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);

Changes to src/update.c.

   706    706     }
   707    707   
   708    708     if( !isView ){
   709    709       int addr1 = 0;        /* Address of jump instruction */
   710    710   
   711    711       /* Do constraint checks. */
   712    712       assert( regOldRowid>0 );
   713         -    sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
   714         -        regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
   715         -        aXRef, 0);
          713  +    sqlite3GenerateConstraintChecks(pParse, iDb, pTab, aRegIdx, iDataCur, 
          714  +        iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, 
          715  +        &bReplace, aXRef, 0);
   716    716   
   717    717       /* Do FK constraint checks. */
   718    718       if( hasFK ){
   719    719         sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
   720    720       }
   721    721   
   722    722       /* Delete the index entries associated with the current record.  */

Changes to test/reuse1.test.

   117    117     } {aux1 aux2 aux3}
   118    118   
   119    119     do_execsql_test 2.2 {
   120    120       SELECT * FROM aux.ft_content;
   121    121     } {1 aux1 2 aux2 3 aux3}
   122    122   }
   123    123   
          124  +#-------------------------------------------------------------------------
          125  +#
   124    126   reset_db
   125    127   forcedelete test.db2
   126    128   do_execsql_test 3.0 {
   127    129     CREATE TABLE t1(a PRIMARY KEY, b, c);
   128    130     CREATE VIEW v1 AS SELECT * FROM t1;
   129    131     CREATE TRIGGER v1_ins INSTEAD OF INSERT ON v1 BEGIN
   130    132       INSERT INTO t1 VALUES(new.a, new.b, new.c);
................................................................................
   193    195   do_execsql_test 3.13.2 {
   194    196     INSERT INTO aux.v1 VALUES('x', 'y', 'z');
   195    197   }
   196    198   do_execsql_test 3.13.3 {
   197    199     SELECT * FROM v1;
   198    200   } {1 2 3 x y z}
   199    201   
          202  +#-------------------------------------------------------------------------
          203  +#
          204  +reset_db
          205  +forcedelete test.db2
          206  +do_execsql_test 4.0 {
          207  +  CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
          208  +  CREATE TABLE del(a, b, c);
          209  +  CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
          210  +    INSERT INTO del VALUES(old.a, old.b, old.c);
          211  +  END;
          212  +}
          213  +forcecopy test.db test.db2
          214  +
          215  +db close
          216  +sqlite3 db test.db -reuse-schema 1
          217  +execsql { 
          218  +  ATTACH 'test.db2' AS aux;
          219  +  PRAGMA recursive_triggers = 1;
          220  +}
          221  +
          222  +do_execsql_test 4.1 {
          223  +  INSERT INTO main.t1 VALUES(1, 2, 3);
          224  +  INSERT INTO aux.t1 VALUES(4, 5, 6);
          225  +}
          226  +
          227  +do_execsql_test 4.2.1 {
          228  +  INSERT OR REPLACE INTO aux.t1 VALUES('a', 'b', 6);
          229  +  SELECT * FROM aux.t1;
          230  +} {a b 6}
          231  +do_execsql_test 4.2.2 { SELECT * FROM aux.del  } {4 5 6}
          232  +do_execsql_test 4.2.3 { SELECT * FROM main.del } {}
          233  +
          234  +do_execsql_test 4.3.1 {
          235  +  INSERT INTO aux.t1 VALUES('x', 'y', 'z');
          236  +  UPDATE OR REPLACE aux.t1 SET c='z' WHERE a='a';
          237  +} {}
          238  +do_execsql_test 4.3.2 { SELECT * FROM aux.del  } {4 5 6 x y z}
          239  +do_execsql_test 4.3.3 { SELECT * FROM main.del } {}
          240  +
          241  +#-------------------------------------------------------------------------
          242  +#
          243  +reset_db
          244  +do_execsql_test 5.0 {
          245  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
          246  +  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
          247  +  CREATE INDEX i1 ON t1(b);
          248  +  INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
          249  +  ANALYZE;
          250  +  PRAGMA writable_schema = 1;
          251  +  DELETE FROM sqlite_stat1;
          252  +}
          253  +db close
          254  +forcecopy test.db test.db2
          255  +sqlite3 db test.db -reuse-schema 1
          256  +execsql { ATTACH 'test.db2' AS aux }
          257  +
          258  +foreach {tn sql} {
          259  +  1 { CREATE TABLE t3(x) }
          260  +  2 { DROP TABLE t2 }
          261  +  3 { CREATE INDEX i2 ON t2(b) }
          262  +  4 { DROP INDEX i1 }
          263  +  5 { ALTER TABLE t1 ADD COLUMN d }
          264  +  6 { ALTER TABLE t1 RENAME TO t3 }
          265  +  7 { ALTER TABLE t1 RENAME c TO d }
          266  +} {
          267  +  do_catchsql_test 5.1.$tn $sql {1 {attempt to modify read-only schema}}
          268  +}
          269  +
          270  +do_execsql_test 5.2.1 { ANALYZE aux.t1 } {}
          271  +do_execsql_test 5.2.2 { SELECT * FROM aux.sqlite_stat1  } {t1 i1 {2 1}}
          272  +do_execsql_test 5.2.3 { SELECT * FROM main.sqlite_stat1 } {}
          273  +
          274  +do_test 5.3.0 {
          275  +  sqlite3 db2 test.db2
          276  +  db2 eval { 
          277  +    PRAGMA writable_schema = 1;
          278  +    DELETE FROM sqlite_stat1;
          279  +  }
          280  +} {}
          281  +
          282  +do_execsql_test 5.3.1 { SELECT * FROM aux.sqlite_stat1  } {}
          283  +do_execsql_test 5.3.2 { ANALYZE aux } {}
          284  +do_execsql_test 5.3.3 { SELECT * FROM aux.sqlite_stat1  } {t1 i1 {2 1}}
          285  +do_execsql_test 5.3.4 { SELECT * FROM main.sqlite_stat1 } {}
          286  +
          287  +#-------------------------------------------------------------------------
          288  +# Attempting to run ANALYZE when the required sqlite_statXX functions
          289  +# are missing is an error (because it would modify the database schema).
          290  +#
          291  +reset_db
          292  +do_execsql_test 5.4 {
          293  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
          294  +  CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
          295  +  CREATE INDEX i1 ON t1(b);
          296  +  INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
          297  +}
          298  +db close
          299  +sqlite3 db test.db -reuse-schema 1
          300  +foreach {tn sql} {
          301  +  1 { ANALYZE }
          302  +  2 { ANALYZE t1 }
          303  +  3 { ANALYZE i1 }
          304  +  4 { ANALYZE main }
          305  +  5 { ANALYZE main.t1 }
          306  +  6 { ANALYZE main.i1 }
          307  +} {
          308  +  do_catchsql_test 5.4.$tn $sql {1 {attempt to modify read-only schema}}
          309  +}
          310  +
          311  +
   200    312   
   201    313   finish_test
          314  +
   202    315