/ Check-in [01398fb7]
Login

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

Overview
Comment:Fix problems with TEMP indices that lead to corrupt databases. These problems were discovered while working on ticket #317. No sure yet if that ticket is fixed. (CVS 981)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 01398fb78bab7e5c6f439f2b743f26e82118468a
User & Date: drh 2003-05-17 17:35:11
Context
2003-05-17
17:38
Bump the version number and update the change log. We are rushing out release 2.8.2 because of the database corruption problem fixed by the previous check-in. (CVS 982) check-in: e134459d user: drh tags: trunk
17:35
Fix problems with TEMP indices that lead to corrupt databases. These problems were discovered while working on ticket #317. No sure yet if that ticket is fixed. (CVS 981) check-in: 01398fb7 user: drh tags: trunk
02:44
Version 2.8.1 (CVS 980) check-in: 590f963b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.92 2003/04/25 15:37:58 drh Exp $
           12  +** $Id: btree.c,v 1.93 2003/05/17 17:35:11 drh Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
  3225   3225         checkAppendMsg(pCheck, zContext, zMsg);
  3226   3226         break;
  3227   3227       }
  3228   3228       if( isFreeList ){
  3229   3229         FreelistInfo *pInfo = (FreelistInfo*)pOvfl->aPayload;
  3230   3230         int n = SWAB32(pCheck->pBt, pInfo->nFree);
  3231   3231         for(i=0; i<n; i++){
  3232         -        checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zMsg);
         3232  +        checkRef(pCheck, SWAB32(pCheck->pBt, pInfo->aFree[i]), zContext);
  3233   3233         }
  3234   3234         N -= n;
  3235   3235       }
  3236   3236       iPage = SWAB32(pCheck->pBt, pOvfl->iNext);
  3237   3237       sqlitepager_unref(pOvfl);
  3238   3238     }
  3239   3239   }

Changes to src/btree_rb.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree_rb.c,v 1.9 2003/04/25 13:22:53 drh Exp $
           12  +** $Id: btree_rb.c,v 1.10 2003/05/17 17:35:11 drh Exp $
    13     13   **
    14     14   ** This file implements an in-core database using Red-Black balanced
    15     15   ** binary trees.
    16     16   **
    17     17   ** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
    18     18   */
    19     19   #include "btree.h"
................................................................................
    27     27   */
    28     28   #ifndef SQLITE_OMIT_INMEMORYDB
    29     29   
    30     30   
    31     31   typedef struct BtRbTree BtRbTree;
    32     32   typedef struct BtRbNode BtRbNode;
    33     33   typedef struct BtRollbackOp BtRollbackOp;
           34  +typedef struct Rbtree Rbtree;
           35  +typedef struct RbtCursor RbtCursor;
    34     36   
    35     37   /* Forward declarations */
    36         -static BtOps sqliteBtreeOps;
    37         -static BtCursorOps sqliteBtreeCursorOps;
           38  +static BtOps sqliteRbtreeOps;
           39  +static BtCursorOps sqliteRbtreeCursorOps;
    38     40   
    39     41   /*
    40     42    * During each transaction (or checkpoint), a linked-list of
    41     43    * "rollback-operations" is accumulated. If the transaction is rolled back,
    42     44    * then the list of operations must be executed (to restore the database to
    43     45    * it's state before the transaction started). If the transaction is to be
    44     46    * committed, just delete the list.
................................................................................
    64     66   ** Legal values for BtRollbackOp.eOp:
    65     67   */
    66     68   #define ROLLBACK_INSERT 1 /* Insert a record */
    67     69   #define ROLLBACK_DELETE 2 /* Delete a record */
    68     70   #define ROLLBACK_CREATE 3 /* Create a table */
    69     71   #define ROLLBACK_DROP   4 /* Drop a table */
    70     72   
    71         -struct Btree {
           73  +struct Rbtree {
    72     74     BtOps *pOps;    /* Function table */
    73     75     int aMetaData[SQLITE_N_BTREE_META];
    74     76   
    75     77     int next_idx;   /* next available table index */
    76     78     Hash tblHash;   /* All created tables, by index */
    77         -  u8 isAnonymous; /* True if this Btree is to be deleted when closed */
    78         -  u8 eTransState; /* State of this Btree wrt transactions */
           79  +  u8 isAnonymous; /* True if this Rbtree is to be deleted when closed */
           80  +  u8 eTransState; /* State of this Rbtree wrt transactions */
    79     81   
    80     82     BtRollbackOp *pTransRollback; 
    81     83     BtRollbackOp *pCheckRollback;
    82     84     BtRollbackOp *pCheckRollbackTail;
    83     85   };
    84     86   
    85     87   /*
    86         -** Legal values for Btree.eTransState.
           88  +** Legal values for Rbtree.eTransState.
    87     89   */
    88     90   #define TRANS_NONE           0  /* No transaction is in progress */
    89     91   #define TRANS_INTRANSACTION  1  /* A transaction is in progress */
    90     92   #define TRANS_INCHECKPOINT   2  /* A checkpoint is in progress  */
    91     93   #define TRANS_ROLLBACK       3  /* We are currently rolling back a checkpoint or
    92     94                                    * transaction. */
    93     95   
    94         -struct BtCursor {
           96  +struct RbtCursor {
    95     97     BtCursorOps *pOps;        /* Function table */
    96         -  Btree    *pBtree;
           98  +  Rbtree    *pRbtree;
    97     99     BtRbTree *pTree;
    98         -  int       iTree;          /* Index of pTree in pBtree */
          100  +  int       iTree;          /* Index of pTree in pRbtree */
    99    101     BtRbNode *pNode;
   100    102     u8 eSkip;                 /* Determines if next step operation is a no-op */
   101    103   };
   102    104   
   103    105   /*
   104         -** Legal values for BtCursor.eSkip.
          106  +** Legal values for RbtCursor.eSkip.
   105    107   */
   106    108   #define SKIP_NONE     0   /* Always step the cursor */
   107         -#define SKIP_NEXT     1   /* The next sqliteBtreeNext() is a no-op */
   108         -#define SKIP_PREV     2   /* The next sqliteBtreePrevious() is a no-op */
          109  +#define SKIP_NEXT     1   /* The next sqliteRbtreeNext() is a no-op */
          110  +#define SKIP_PREV     2   /* The next sqliteRbtreePrevious() is a no-op */
   109    111   #define SKIP_INVALID  3   /* Calls to Next() and Previous() are invalid */
   110    112   
   111    113   struct BtRbTree {
   112    114     BtRbNode *pHead;   /* Head of the tree, or NULL */
   113    115   };
   114    116   
   115    117   struct BtRbNode {
................................................................................
   122    124     BtRbNode *pLeft;   /* Nodes left child, or NULL */
   123    125     BtRbNode *pRight;  /* Nodes right child, or NULL */
   124    126   
   125    127     int nBlackHeight;  /* Only used during the red-black integrity check */
   126    128   };
   127    129   
   128    130   /* Forward declarations */
   129         -static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey,int *pRes);
   130         -static int memBtreeClearTable(Btree* tree, int n);
   131         -static int memBtreeNext(BtCursor* pCur, int *pRes);
   132         -static int memBtreeLast(BtCursor* pCur, int *pRes);
   133         -static int memBtreePrevious(BtCursor* pCur, int *pRes);
          131  +static int memRbtreeMoveto(
          132  +  RbtCursor* pCur,
          133  +  const void *pKey,
          134  +  int nKey,
          135  +  int *pRes
          136  +);
          137  +static int memRbtreeClearTable(Rbtree* tree, int n);
          138  +static int memRbtreeNext(RbtCursor* pCur, int *pRes);
          139  +static int memRbtreeLast(RbtCursor* pCur, int *pRes);
          140  +static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
   134    141   
   135    142   /*
   136    143    * The key-compare function for the red-black trees. Returns as follows:
   137    144    *
   138    145    * (key1 < key2)             -1
   139    146    * (key1 == key2)             0 
   140    147    * (key1 > key2)              1
................................................................................
   355    362           break;
   356    363         default: assert(0);
   357    364       }
   358    365     }
   359    366   } 
   360    367   
   361    368   /*
   362         - * Node pX has just been inserted into pTree (by code in sqliteBtreeInsert()).
          369  + * Node pX has just been inserted into pTree (by code in sqliteRbtreeInsert()).
   363    370    * It is possible that pX is a red node with a red parent, which is a violation
   364    371    * of the red-black tree properties. This function performs rotations and 
   365    372    * color changes to rebalance the tree
   366    373    */
   367    374   static void do_insert_balancing(BtRbTree *pTree, BtRbNode *pX)
   368    375   {
   369    376     /* In the first iteration of this loop, pX points to the red node just
................................................................................
   536    543       }
   537    544       pParent = pX->pParent;
   538    545     }
   539    546     if( pX ) pX->isBlack = 1;
   540    547   }
   541    548   
   542    549   /*
   543         - * Create table n in tree pBtree. Table n must not exist.
          550  + * Create table n in tree pRbtree. Table n must not exist.
   544    551    */
   545         -static void btreeCreateTable(Btree* pBtree, int n)
          552  +static void btreeCreateTable(Rbtree* pRbtree, int n)
   546    553   {
   547    554     BtRbTree *pNewTbl = sqliteMalloc(sizeof(BtRbTree));
   548         -  sqliteHashInsert(&pBtree->tblHash, 0, n, pNewTbl);
          555  +  sqliteHashInsert(&pRbtree->tblHash, 0, n, pNewTbl);
   549    556   }
   550    557   
   551    558   /*
   552         - * Log a single "rollback-op" for the given Btree. See comments for struct
          559  + * Log a single "rollback-op" for the given Rbtree. See comments for struct
   553    560    * BtRollbackOp.
   554    561    */
   555         -static void btreeLogRollbackOp(Btree* pBtree, BtRollbackOp *pRollbackOp)
   556         -{
   557         -  assert( pBtree->eTransState == TRANS_INCHECKPOINT ||
   558         -      pBtree->eTransState == TRANS_INTRANSACTION );
   559         -  if( pBtree->eTransState == TRANS_INTRANSACTION ){
   560         -    pRollbackOp->pNext = pBtree->pTransRollback;
   561         -    pBtree->pTransRollback = pRollbackOp;
   562         -  }
   563         -  if( pBtree->eTransState == TRANS_INCHECKPOINT ){
   564         -    if( !pBtree->pCheckRollback ){
   565         -      pBtree->pCheckRollbackTail = pRollbackOp;
   566         -    }
   567         -    pRollbackOp->pNext = pBtree->pCheckRollback;
   568         -    pBtree->pCheckRollback = pRollbackOp;
   569         -  }
   570         -}
   571         -
   572         -int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree)
   573         -{
   574         -  *ppBtree = (Btree *)sqliteMalloc(sizeof(Btree));
   575         -  sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0);
          562  +static void btreeLogRollbackOp(Rbtree* pRbtree, BtRollbackOp *pRollbackOp)
          563  +{
          564  +  assert( pRbtree->eTransState == TRANS_INCHECKPOINT ||
          565  +      pRbtree->eTransState == TRANS_INTRANSACTION );
          566  +  if( pRbtree->eTransState == TRANS_INTRANSACTION ){
          567  +    pRollbackOp->pNext = pRbtree->pTransRollback;
          568  +    pRbtree->pTransRollback = pRollbackOp;
          569  +  }
          570  +  if( pRbtree->eTransState == TRANS_INCHECKPOINT ){
          571  +    if( !pRbtree->pCheckRollback ){
          572  +      pRbtree->pCheckRollbackTail = pRollbackOp;
          573  +    }
          574  +    pRollbackOp->pNext = pRbtree->pCheckRollback;
          575  +    pRbtree->pCheckRollback = pRollbackOp;
          576  +  }
          577  +}
          578  +
          579  +int sqliteRbtreeOpen(
          580  +  const char *zFilename,
          581  +  int mode,
          582  +  int nPg,
          583  +  Rbtree **ppRbtree
          584  +){
          585  +  *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree));
          586  +  sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0);
   576    587   
   577    588     /* Create a binary tree for the SQLITE_MASTER table at location 2 */
   578         -  btreeCreateTable(*ppBtree, 2);
   579         -  (*ppBtree)->next_idx = 3;
   580         -  (*ppBtree)->pOps = &sqliteBtreeOps;
          589  +  btreeCreateTable(*ppRbtree, 2);
          590  +  (*ppRbtree)->next_idx = 3;
          591  +  (*ppRbtree)->pOps = &sqliteRbtreeOps;
   581    592     /* Set file type to 4; this is so that "attach ':memory:' as ...."  does not
   582    593     ** think that the database in uninitialised and refuse to attach
   583    594     */
   584         -  (*ppBtree)->aMetaData[2] = 4;
          595  +  (*ppRbtree)->aMetaData[2] = 4;
   585    596     
   586    597     return SQLITE_OK;
   587    598   }
   588    599   
   589    600   /*
   590         - * Create a new table in the supplied Btree. Set *n to the new table number.
          601  + * Create a new table in the supplied Rbtree. Set *n to the new table number.
   591    602    * Return SQLITE_OK if the operation is a success.
   592    603    */
   593         -static int memBtreeCreateTable(Btree* tree, int* n)
          604  +static int memRbtreeCreateTable(Rbtree* tree, int* n)
   594    605   {
   595    606     assert( tree->eTransState != TRANS_NONE );
   596    607   
   597    608     *n = tree->next_idx++;
   598    609     btreeCreateTable(tree, *n);
   599    610   
   600    611     /* Set up the rollback structure (if we are not doing this as part of a
................................................................................
   606    617       btreeLogRollbackOp(tree, pRollbackOp);
   607    618     }
   608    619   
   609    620     return SQLITE_OK;
   610    621   }
   611    622   
   612    623   /*
   613         - * Delete table n from the supplied Btree. 
          624  + * Delete table n from the supplied Rbtree. 
   614    625    */
   615         -static int memBtreeDropTable(Btree* tree, int n)
          626  +static int memRbtreeDropTable(Rbtree* tree, int n)
   616    627   {
   617    628     BtRbTree *pTree;
   618    629     assert( tree->eTransState != TRANS_NONE );
   619    630   
   620         -  memBtreeClearTable(tree, n);
          631  +  memRbtreeClearTable(tree, n);
   621    632     pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
   622    633     assert(pTree);
   623    634     sqliteFree(pTree);
   624    635   
   625    636     if( tree->eTransState != TRANS_ROLLBACK ){
   626    637       BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp));
   627    638       pRollbackOp->eOp = ROLLBACK_CREATE;
................................................................................
   628    639       pRollbackOp->iTab = n;
   629    640       btreeLogRollbackOp(tree, pRollbackOp);
   630    641     }
   631    642   
   632    643     return SQLITE_OK;
   633    644   }
   634    645   
   635         -static int memBtreeKeyCompare(BtCursor* pCur, const void *pKey, int nKey,
          646  +static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey,
   636    647                                    int nIgnore, int *pRes)
   637    648   {
   638    649     assert(pCur);
   639    650   
   640    651     if( !pCur->pNode ) {
   641    652       *pRes = -1;
   642    653     } else {
................................................................................
   647    658             pKey, nKey);
   648    659       }
   649    660     }
   650    661     return SQLITE_OK;
   651    662   }
   652    663   
   653    664   /*
   654         - * Get a new cursor for table iTable of the supplied Btree. The wrFlag
          665  + * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
   655    666    * parameter is ignored, all cursors are capable of write-operations. 
   656    667    *
   657         - * Note that BtCursor.eSkip and BtCursor.pNode both initialize to 0.
          668  + * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
   658    669    */
   659         -static int memBtreeCursor(Btree* tree, int iTable, int wrFlag, BtCursor **ppCur)
   660         -{
          670  +static int memRbtreeCursor(
          671  +  Rbtree* tree,
          672  +  int iTable,
          673  +  int wrFlag,
          674  +  RbtCursor **ppCur
          675  +){
   661    676     assert(tree);
   662         -  *ppCur = sqliteMalloc(sizeof(BtCursor));
          677  +  *ppCur = sqliteMalloc(sizeof(RbtCursor));
   663    678     (*ppCur)->pTree  = sqliteHashFind(&tree->tblHash, 0, iTable);
   664         -  (*ppCur)->pBtree = tree;
          679  +  (*ppCur)->pRbtree = tree;
   665    680     (*ppCur)->iTree  = iTable;
   666         -  (*ppCur)->pOps = &sqliteBtreeCursorOps;
          681  +  (*ppCur)->pOps = &sqliteRbtreeCursorOps;
   667    682   
   668    683     assert( (*ppCur)->pTree );
   669    684     return SQLITE_OK;
   670    685   }
   671    686   
   672    687   /*
   673         - * Insert a new record into the Btree.  The key is given by (pKey,nKey)
          688  + * Insert a new record into the Rbtree.  The key is given by (pKey,nKey)
   674    689    * and the data is given by (pData,nData).  The cursor is used only to
   675    690    * define what database the record should be inserted into.  The cursor
   676    691    * is left pointing at the new record.
   677    692    *
   678    693    * If the key exists already in the tree, just replace the data. 
   679    694    */
   680         -static int memBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
   681         -                             const void *pDataInput, int nData)
   682         -{
          695  +static int memRbtreeInsert(
          696  +  RbtCursor* pCur,
          697  +  const void *pKey,
          698  +  int nKey,
          699  +  const void *pDataInput,
          700  +  int nData
          701  +){
   683    702     void * pData;
   684    703     int match;
   685    704   
   686         -  /* It is illegal to call sqliteBtreeInsert() if we are not in a transaction */
   687         -  assert( pCur->pBtree->eTransState != TRANS_NONE );
          705  +  /* It is illegal to call sqliteRbtreeInsert() if we are
          706  +  ** not in a transaction */
          707  +  assert( pCur->pRbtree->eTransState != TRANS_NONE );
   688    708   
   689    709     /* Take a copy of the input data now, in case we need it for the 
   690    710      * replace case */
   691    711     pData = sqliteMalloc(nData);
   692    712     memcpy(pData, pDataInput, nData);
   693    713   
   694    714     /* Move the cursor to a node near the key to be inserted. If the key already
................................................................................
   698    718      * If there is no exact match, then the cursor points at what would be either
   699    719      * the predecessor (match == -1) or successor (match == 1) of the
   700    720      * searched-for key, were it to be inserted. The new node becomes a child of
   701    721      * this node.
   702    722      * 
   703    723      * The new node is initially red.
   704    724      */
   705         -  memBtreeMoveto( pCur, pKey, nKey, &match);
          725  +  memRbtreeMoveto( pCur, pKey, nKey, &match);
   706    726     if( match ){
   707    727       BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode));
   708    728       pNode->nKey = nKey;
   709    729       pNode->pKey = sqliteMalloc(nKey);
   710    730       memcpy(pNode->pKey, pKey, nKey);
   711    731       pNode->nData = nData;
   712    732       pNode->pData = pData; 
................................................................................
   732    752       /* Point the cursor at the node just inserted, as per SQLite requirements */
   733    753       pCur->pNode = pNode;
   734    754   
   735    755       /* A new node has just been inserted, so run the balancing code */
   736    756       do_insert_balancing(pCur->pTree, pNode);
   737    757   
   738    758       /* Set up a rollback-op in case we have to roll this operation back */
   739         -    if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){
          759  +    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
   740    760         BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
   741    761         pOp->eOp = ROLLBACK_DELETE;
   742    762         pOp->iTab = pCur->iTree;
   743    763         pOp->nKey = pNode->nKey;
   744    764         pOp->pKey = sqliteMalloc( pOp->nKey );
   745    765         memcpy( pOp->pKey, pNode->pKey, pOp->nKey );
   746         -      btreeLogRollbackOp(pCur->pBtree, pOp);
          766  +      btreeLogRollbackOp(pCur->pRbtree, pOp);
   747    767       }
   748    768   
   749    769     }else{ 
   750    770       /* No need to insert a new node in the tree, as the key already exists.
   751    771        * Just clobber the current nodes data. */
   752    772   
   753    773       /* Set up a rollback-op in case we have to roll this operation back */
   754         -    if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){
          774  +    if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
   755    775         BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
   756    776         pOp->iTab = pCur->iTree;
   757    777         pOp->nKey = pCur->pNode->nKey;
   758    778         pOp->pKey = sqliteMalloc( pOp->nKey );
   759    779         memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey );
   760    780         pOp->nData = pCur->pNode->nData;
   761    781         pOp->pData = pCur->pNode->pData;
   762    782         pOp->eOp = ROLLBACK_INSERT;
   763         -      btreeLogRollbackOp(pCur->pBtree, pOp);
          783  +      btreeLogRollbackOp(pCur->pRbtree, pOp);
   764    784       }else{
   765    785         sqliteFree( pCur->pNode->pData );
   766    786       }
   767    787   
   768    788       /* Actually clobber the nodes data */
   769    789       pCur->pNode->pData = pData;
   770    790       pCur->pNode->nData = nData;
................................................................................
   782    802   **
   783    803   **     *pRes==0     The cursor is left pointing at an entry that
   784    804   **                  exactly matches pKey.
   785    805   **
   786    806   **     *pRes>0      The cursor is left pointing at an entry that
   787    807   **                  is larger than pKey.
   788    808   */
   789         -static int memBtreeMoveto(BtCursor* pCur, const void *pKey, int nKey, int *pRes)
   790         -{
          809  +static int memRbtreeMoveto(
          810  +  RbtCursor* pCur,
          811  +  const void *pKey,
          812  +  int nKey,
          813  +  int *pRes
          814  +){
   791    815     BtRbNode *pTmp = 0;
   792    816   
   793    817     pCur->pNode = pCur->pTree->pHead;
   794    818     *pRes = -1;
   795    819     while( pCur->pNode && *pRes ) {
   796    820       *pRes = key_compare(pCur->pNode->pKey, pCur->pNode->nKey, pKey, nKey);
   797    821       pTmp = pCur->pNode;
................................................................................
   819    843   
   820    844   /*
   821    845   ** Delete the entry that the cursor is pointing to.
   822    846   **
   823    847   ** The cursor is left pointing at either the next or the previous
   824    848   ** entry.  If the cursor is left pointing to the next entry, then 
   825    849   ** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to 
   826         -** sqliteBtreeNext() to be a no-op.  That way, you can always call
   827         -** sqliteBtreeNext() after a delete and the cursor will be left
          850  +** sqliteRbtreeNext() to be a no-op.  That way, you can always call
          851  +** sqliteRbtreeNext() after a delete and the cursor will be left
   828    852   ** pointing to the first entry after the deleted entry.  Similarly,
   829    853   ** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
   830    854   ** the entry prior to the deleted entry so that a subsequent call to
   831         -** sqliteBtreePrevious() will always leave the cursor pointing at the
          855  +** sqliteRbtreePrevious() will always leave the cursor pointing at the
   832    856   ** entry immediately before the one that was deleted.
   833    857   */
   834         -static int memBtreeDelete(BtCursor* pCur)
          858  +static int memRbtreeDelete(RbtCursor* pCur)
   835    859   {
   836    860     BtRbNode *pZ;      /* The one being deleted */
   837    861     BtRbNode *pChild;  /* The child of the spliced out node */
   838    862   
   839         -  /* It is illegal to call sqliteBtreeDelete() if we are not in a transaction */
   840         -  assert( pCur->pBtree->eTransState != TRANS_NONE );
          863  +  /* It is illegal to call sqliteRbtreeDelete() if we are
          864  +  ** not in a transaction */
          865  +  assert( pCur->pRbtree->eTransState != TRANS_NONE );
   841    866   
   842    867     pZ = pCur->pNode;
   843    868     if( !pZ ){
   844    869       return SQLITE_OK;
   845    870     }
   846    871   
   847    872     /* If we are not currently doing a rollback, set up a rollback op for this 
   848    873      * deletion */
   849         -  if( pCur->pBtree->eTransState != TRANS_ROLLBACK ){
          874  +  if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){
   850    875       BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) );
   851    876       pOp->iTab = pCur->iTree;
   852    877       pOp->nKey = pZ->nKey;
   853    878       pOp->pKey = pZ->pKey;
   854    879       pOp->nData = pZ->nData;
   855    880       pOp->pData = pZ->pData;
   856    881       pOp->eOp = ROLLBACK_INSERT;
   857         -    btreeLogRollbackOp(pCur->pBtree, pOp);
          882  +    btreeLogRollbackOp(pCur->pRbtree, pOp);
   858    883     }
   859    884   
   860    885     /* First do a standard binary-tree delete (node pZ is to be deleted). How
   861    886      * to do this depends on how many children pZ has:
   862    887      *
   863    888      * If pZ has no children or one child, then splice out pZ.  If pZ has two
   864    889      * children, splice out the successor of pZ and replace the key and data of
   865    890      * pZ with the key and data of the spliced out successor.  */
   866    891     if( pZ->pLeft && pZ->pRight ){
   867    892       BtRbNode *pTmp;
   868    893       int dummy;
   869    894       pCur->eSkip = SKIP_NONE;
   870         -    memBtreeNext(pCur, &dummy);
          895  +    memRbtreeNext(pCur, &dummy);
   871    896       assert( dummy == 0 );
   872         -    if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){
          897  +    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
   873    898         sqliteFree(pZ->pKey);
   874    899         sqliteFree(pZ->pData);
   875    900       }
   876    901       pZ->pData = pCur->pNode->pData;
   877    902       pZ->nData = pCur->pNode->nData;
   878    903       pZ->pKey = pCur->pNode->pKey;
   879    904       pZ->nKey = pCur->pNode->nKey;
................................................................................
   880    905       pTmp = pZ;
   881    906       pZ = pCur->pNode;
   882    907       pCur->pNode = pTmp;
   883    908       pCur->eSkip = SKIP_NEXT;
   884    909     }else{
   885    910       int res;
   886    911       pCur->eSkip = SKIP_NONE;
   887         -    memBtreeNext(pCur, &res);
          912  +    memRbtreeNext(pCur, &res);
   888    913       pCur->eSkip = SKIP_NEXT;
   889    914       if( res ){
   890         -      memBtreeLast(pCur, &res);
   891         -      memBtreePrevious(pCur, &res);
          915  +      memRbtreeLast(pCur, &res);
          916  +      memRbtreePrevious(pCur, &res);
   892    917         pCur->eSkip = SKIP_PREV;
   893    918       }
   894         -    if( pCur->pBtree->eTransState == TRANS_ROLLBACK ){
          919  +    if( pCur->pRbtree->eTransState == TRANS_ROLLBACK ){
   895    920           sqliteFree(pZ->pKey);
   896    921           sqliteFree(pZ->pData);
   897    922       }
   898    923     }
   899    924   
   900    925     /* pZ now points at the node to be spliced out. This block does the 
   901    926      * splicing. */
................................................................................
   924    949     }
   925    950   
   926    951     sqliteFree(pZ);
   927    952     return SQLITE_OK;
   928    953   }
   929    954   
   930    955   /*
   931         - * Empty table n of the Btree.
          956  + * Empty table n of the Rbtree.
   932    957    */
   933         -static int memBtreeClearTable(Btree* tree, int n)
          958  +static int memRbtreeClearTable(Rbtree* tree, int n)
   934    959   {
   935    960     BtRbTree *pTree;
   936    961     BtRbNode *pNode;
   937    962   
   938    963     pTree = sqliteHashFind(&tree->tblHash, 0, n);
   939    964     assert(pTree);
   940    965   
................................................................................
   970    995       }
   971    996     }
   972    997   
   973    998     pTree->pHead = 0;
   974    999     return SQLITE_OK;
   975   1000   }
   976   1001   
   977         -static int memBtreeFirst(BtCursor* pCur, int *pRes)
         1002  +static int memRbtreeFirst(RbtCursor* pCur, int *pRes)
   978   1003   {
   979   1004     if( pCur->pTree->pHead ){
   980   1005       pCur->pNode = pCur->pTree->pHead;
   981   1006       while( pCur->pNode->pLeft ){
   982   1007         pCur->pNode = pCur->pNode->pLeft;
   983   1008       }
   984   1009     }
................................................................................
   987   1012     }else{
   988   1013       *pRes = 1;
   989   1014     }
   990   1015     pCur->eSkip = SKIP_NONE;
   991   1016     return SQLITE_OK;
   992   1017   }
   993   1018   
   994         -static int memBtreeLast(BtCursor* pCur, int *pRes)
         1019  +static int memRbtreeLast(RbtCursor* pCur, int *pRes)
   995   1020   {
   996   1021     if( pCur->pTree->pHead ){
   997   1022       pCur->pNode = pCur->pTree->pHead;
   998   1023       while( pCur->pNode->pRight ){
   999   1024         pCur->pNode = pCur->pNode->pRight;
  1000   1025       }
  1001   1026     }
................................................................................
  1010   1035   
  1011   1036   /*
  1012   1037   ** Advance the cursor to the next entry in the database.  If
  1013   1038   ** successful then set *pRes=0.  If the cursor
  1014   1039   ** was already pointing to the last entry in the database before
  1015   1040   ** this routine was called, then set *pRes=1.
  1016   1041   */
  1017         -static int memBtreeNext(BtCursor* pCur, int *pRes)
         1042  +static int memRbtreeNext(RbtCursor* pCur, int *pRes)
  1018   1043   {
  1019   1044     if( pCur->pNode && pCur->eSkip != SKIP_NEXT ){
  1020   1045       if( pCur->pNode->pRight ){
  1021   1046         pCur->pNode = pCur->pNode->pRight;
  1022   1047         while( pCur->pNode->pLeft )
  1023   1048           pCur->pNode = pCur->pNode->pLeft;
  1024   1049       }else{
................................................................................
  1037   1062     }else{
  1038   1063       *pRes = 0;
  1039   1064     }
  1040   1065   
  1041   1066     return SQLITE_OK;
  1042   1067   }
  1043   1068   
  1044         -static int memBtreePrevious(BtCursor* pCur, int *pRes)
         1069  +static int memRbtreePrevious(RbtCursor* pCur, int *pRes)
  1045   1070   {
  1046   1071     if( pCur->pNode && pCur->eSkip != SKIP_PREV ){
  1047   1072       if( pCur->pNode->pLeft ){
  1048   1073         pCur->pNode = pCur->pNode->pLeft;
  1049   1074         while( pCur->pNode->pRight )
  1050   1075           pCur->pNode = pCur->pNode->pRight;
  1051   1076       }else{
................................................................................
  1064   1089     }else{
  1065   1090       *pRes = 0;
  1066   1091     }
  1067   1092   
  1068   1093     return SQLITE_OK;
  1069   1094   }
  1070   1095   
  1071         -static int memBtreeKeySize(BtCursor* pCur, int *pSize)
         1096  +static int memRbtreeKeySize(RbtCursor* pCur, int *pSize)
  1072   1097   {
  1073   1098     if( pCur->pNode ){
  1074   1099       *pSize = pCur->pNode->nKey;
  1075   1100     }else{
  1076   1101       *pSize = 0;
  1077   1102     }
  1078   1103     return SQLITE_OK;
  1079   1104   }
  1080   1105   
  1081         -static int memBtreeKey(BtCursor* pCur, int offset, int amt, char *zBuf)
         1106  +static int memRbtreeKey(RbtCursor* pCur, int offset, int amt, char *zBuf)
  1082   1107   {
  1083   1108     if( !pCur->pNode ) return 0;
  1084   1109     if( !pCur->pNode->pKey || ((amt + offset) <= pCur->pNode->nKey) ){
  1085   1110       memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, amt);
  1086   1111       return amt;
  1087   1112     }else{
  1088   1113       memcpy(zBuf, ((char*)pCur->pNode->pKey)+offset, pCur->pNode->nKey-offset);
  1089   1114       return pCur->pNode->nKey-offset;
  1090   1115     }
  1091   1116     assert(0);
  1092   1117   }
  1093   1118   
  1094         -static int memBtreeDataSize(BtCursor* pCur, int *pSize)
         1119  +static int memRbtreeDataSize(RbtCursor* pCur, int *pSize)
  1095   1120   {
  1096   1121     if( pCur->pNode ){
  1097   1122       *pSize = pCur->pNode->nData;
  1098   1123     }else{
  1099   1124       *pSize = 0;
  1100   1125     }
  1101   1126     return SQLITE_OK;
  1102   1127   }
  1103   1128   
  1104         -static int memBtreeData(BtCursor *pCur, int offset, int amt, char *zBuf)
         1129  +static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf)
  1105   1130   {
  1106   1131     if( !pCur->pNode ) return 0;
  1107   1132     if( (amt + offset) <= pCur->pNode->nData ){
  1108   1133       memcpy(zBuf, ((char*)pCur->pNode->pData)+offset, amt);
  1109   1134       return amt;
  1110   1135     }else{
  1111   1136       memcpy(zBuf, ((char*)pCur->pNode->pData)+offset ,pCur->pNode->nData-offset);
  1112   1137       return pCur->pNode->nData-offset;
  1113   1138     }
  1114   1139     assert(0);
  1115   1140   }
  1116   1141   
  1117         -static int memBtreeCloseCursor(BtCursor* pCur)
         1142  +static int memRbtreeCloseCursor(RbtCursor* pCur)
  1118   1143   {
  1119   1144     sqliteFree(pCur);
  1120   1145     return SQLITE_OK;
  1121   1146   }
  1122   1147   
  1123         -static int memBtreeGetMeta(Btree* tree, int* aMeta)
         1148  +static int memRbtreeGetMeta(Rbtree* tree, int* aMeta)
  1124   1149   {
  1125   1150     memcpy( aMeta, tree->aMetaData, sizeof(int) * SQLITE_N_BTREE_META );
  1126   1151     return SQLITE_OK;
  1127   1152   }
  1128   1153   
  1129         -static int memBtreeUpdateMeta(Btree* tree, int* aMeta)
         1154  +static int memRbtreeUpdateMeta(Rbtree* tree, int* aMeta)
  1130   1155   {
  1131   1156     memcpy( tree->aMetaData, aMeta, sizeof(int) * SQLITE_N_BTREE_META );
  1132   1157     return SQLITE_OK;
  1133   1158   }
  1134   1159   
  1135   1160   /*
  1136         - * Check that each table in the Btree meets the requirements for a red-black
         1161  + * Check that each table in the Rbtree meets the requirements for a red-black
  1137   1162    * binary tree. If an error is found, return an explanation of the problem in 
  1138   1163    * memory obtained from sqliteMalloc(). Parameters aRoot and nRoot are ignored. 
  1139   1164    */
  1140         -static char *memBtreeIntegrityCheck(Btree* tree, int* aRoot, int nRoot)
         1165  +static char *memRbtreeIntegrityCheck(Rbtree* tree, int* aRoot, int nRoot)
  1141   1166   {
  1142   1167     char * msg = 0;
  1143   1168     HashElem *p;
  1144   1169   
  1145   1170     for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
  1146   1171       BtRbTree *pTree = sqliteHashData(p);
  1147   1172       check_redblack_tree(pTree, &msg);
  1148   1173     }
  1149   1174   
  1150   1175     return msg;
  1151   1176   }
  1152   1177   
  1153   1178   /*
  1154         - * Close the supplied Btree. Delete everything associated with it.
         1179  + * Close the supplied Rbtree. Delete everything associated with it.
  1155   1180    */
  1156         -static int memBtreeClose(Btree* tree)
         1181  +static int memRbtreeClose(Rbtree* tree)
  1157   1182   {
  1158   1183     HashElem *p;
  1159   1184     while( (p=sqliteHashFirst(&tree->tblHash))!=0 ){
  1160   1185       tree->eTransState = TRANS_ROLLBACK;
  1161         -    memBtreeDropTable(tree, sqliteHashKeysize(p));
         1186  +    memRbtreeDropTable(tree, sqliteHashKeysize(p));
  1162   1187     }
  1163   1188     sqliteHashClear(&tree->tblHash);
  1164   1189     sqliteFree(tree);
  1165   1190     return SQLITE_OK;
  1166   1191   }
  1167   1192   
  1168         -static int memBtreeSetCacheSize(Btree* tree, int sz)
         1193  +static int memRbtreeSetCacheSize(Rbtree* tree, int sz)
  1169   1194   {
  1170   1195     return SQLITE_OK;
  1171   1196   }
  1172   1197   
  1173         -static int memBtreeSetSafetyLevel(Btree *pBt, int level){
         1198  +static int memRbtreeSetSafetyLevel(Rbtree *pBt, int level){
  1174   1199     return SQLITE_OK;
  1175   1200   }
  1176   1201   
  1177         -static int memBtreeBeginTrans(Btree* tree)
         1202  +static int memRbtreeBeginTrans(Rbtree* tree)
  1178   1203   {
  1179   1204     if( tree->eTransState != TRANS_NONE ) 
  1180   1205       return SQLITE_ERROR;
  1181   1206   
  1182   1207     assert( tree->pTransRollback == 0 );
  1183   1208     tree->eTransState = TRANS_INTRANSACTION;
  1184   1209     return SQLITE_OK;
................................................................................
  1193   1218       sqliteFree(pOp->pData);
  1194   1219       sqliteFree(pOp->pKey);
  1195   1220       sqliteFree(pOp);
  1196   1221       pOp = pTmp;
  1197   1222     }
  1198   1223   }
  1199   1224   
  1200         -static int memBtreeCommit(Btree* tree){
         1225  +static int memRbtreeCommit(Rbtree* tree){
  1201   1226     /* Just delete pTransRollback and pCheckRollback */
  1202   1227     deleteRollbackList(tree->pCheckRollback);
  1203   1228     deleteRollbackList(tree->pTransRollback);
  1204   1229     tree->pTransRollback = 0;
  1205   1230     tree->pCheckRollback = 0;
  1206   1231     tree->pCheckRollbackTail = 0;
  1207   1232     tree->eTransState = TRANS_NONE;
  1208   1233     return SQLITE_OK;
  1209   1234   }
  1210   1235   
  1211   1236   /*
  1212         - * Execute and delete the supplied rollback-list on pBtree.
         1237  + * Execute and delete the supplied rollback-list on pRbtree.
  1213   1238    */
  1214         -static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList)
         1239  +static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList)
  1215   1240   {
  1216   1241     BtRollbackOp *pTmp;
  1217         -  BtCursor cur;
         1242  +  RbtCursor cur;
  1218   1243     int res;
  1219   1244   
  1220         -  cur.pBtree = pBtree;
         1245  +  cur.pRbtree = pRbtree;
  1221   1246     while( pList ){
  1222   1247       switch( pList->eOp ){
  1223   1248         case ROLLBACK_INSERT:
  1224         -        cur.pTree  = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
         1249  +        cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
  1225   1250           assert(cur.pTree);
  1226   1251           cur.iTree  = pList->iTab;
  1227   1252           cur.eSkip  = SKIP_NONE;
  1228         -        memBtreeInsert( &cur, pList->pKey,
         1253  +        memRbtreeInsert( &cur, pList->pKey,
  1229   1254               pList->nKey, pList->pData, pList->nData );
  1230   1255           break;
  1231   1256         case ROLLBACK_DELETE:
  1232         -        cur.pTree  = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
         1257  +        cur.pTree  = sqliteHashFind( &pRbtree->tblHash, 0, pList->iTab );
  1233   1258           assert(cur.pTree);
  1234   1259           cur.iTree  = pList->iTab;
  1235   1260           cur.eSkip  = SKIP_NONE;
  1236         -        memBtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
         1261  +        memRbtreeMoveto(&cur, pList->pKey, pList->nKey, &res);
  1237   1262           assert(res == 0);
  1238         -        memBtreeDelete( &cur );
         1263  +        memRbtreeDelete( &cur );
  1239   1264           break;
  1240   1265         case ROLLBACK_CREATE:
  1241         -        btreeCreateTable(pBtree, pList->iTab);
         1266  +        btreeCreateTable(pRbtree, pList->iTab);
  1242   1267           break;
  1243   1268         case ROLLBACK_DROP:
  1244         -        memBtreeDropTable(pBtree, pList->iTab);
         1269  +        memRbtreeDropTable(pRbtree, pList->iTab);
  1245   1270           break;
  1246   1271         default:
  1247   1272           assert(0);
  1248   1273       }
  1249   1274       sqliteFree(pList->pKey);
  1250   1275       sqliteFree(pList->pData);
  1251   1276       pTmp = pList->pNext;
  1252   1277       sqliteFree(pList);
  1253   1278       pList = pTmp;
  1254   1279     }
  1255   1280   }
  1256   1281   
  1257         -static int memBtreeRollback(Btree* tree)
         1282  +static int memRbtreeRollback(Rbtree* tree)
  1258   1283   {
  1259   1284     tree->eTransState = TRANS_ROLLBACK;
  1260   1285     execute_rollback_list(tree, tree->pCheckRollback);
  1261   1286     execute_rollback_list(tree, tree->pTransRollback);
  1262   1287     tree->pTransRollback = 0;
  1263   1288     tree->pCheckRollback = 0;
  1264   1289     tree->pCheckRollbackTail = 0;
  1265   1290     tree->eTransState = TRANS_NONE;
  1266   1291     return SQLITE_OK;
  1267   1292   }
  1268   1293   
  1269         -static int memBtreeBeginCkpt(Btree* tree)
         1294  +static int memRbtreeBeginCkpt(Rbtree* tree)
  1270   1295   {
  1271   1296     if( tree->eTransState != TRANS_INTRANSACTION ) 
  1272   1297       return SQLITE_ERROR;
  1273   1298   
  1274   1299     assert( tree->pCheckRollback == 0 );
  1275   1300     assert( tree->pCheckRollbackTail == 0 );
  1276   1301     tree->eTransState = TRANS_INCHECKPOINT;
  1277   1302     return SQLITE_OK;
  1278   1303   }
  1279   1304   
  1280         -static int memBtreeCommitCkpt(Btree* tree)
         1305  +static int memRbtreeCommitCkpt(Rbtree* tree)
  1281   1306   {
  1282   1307     if( tree->eTransState == TRANS_INCHECKPOINT ){ 
  1283   1308       if( tree->pCheckRollback ){
  1284   1309         tree->pCheckRollbackTail->pNext = tree->pTransRollback;
  1285   1310         tree->pTransRollback = tree->pCheckRollback;
  1286   1311         tree->pCheckRollback = 0;
  1287   1312         tree->pCheckRollbackTail = 0;
  1288   1313       }
  1289   1314       tree->eTransState = TRANS_INTRANSACTION;
  1290   1315     }
  1291   1316     return SQLITE_OK;
  1292   1317   }
  1293   1318   
  1294         -static int memBtreeRollbackCkpt(Btree* tree)
         1319  +static int memRbtreeRollbackCkpt(Rbtree* tree)
  1295   1320   {
  1296   1321     if( tree->eTransState != TRANS_INCHECKPOINT ) return SQLITE_OK;
  1297   1322     tree->eTransState = TRANS_ROLLBACK;
  1298   1323     execute_rollback_list(tree, tree->pCheckRollback);
  1299   1324     tree->pCheckRollback = 0;
  1300   1325     tree->pCheckRollbackTail = 0;
  1301   1326     tree->eTransState = TRANS_INTRANSACTION;
  1302   1327     return SQLITE_OK;
  1303   1328     return SQLITE_OK;
  1304   1329   }
  1305   1330   
  1306   1331   #ifdef SQLITE_TEST
  1307         -static int memBtreePageDump(Btree* tree, int pgno, int rec)
         1332  +static int memRbtreePageDump(Rbtree* tree, int pgno, int rec)
  1308   1333   {
  1309         -  assert(!"Cannot call sqliteBtreePageDump");
         1334  +  assert(!"Cannot call sqliteRbtreePageDump");
  1310   1335     return SQLITE_OK;
  1311   1336   }
  1312   1337   
  1313         -static int memBtreeCursorDump(BtCursor* pCur, int* aRes)
         1338  +static int memRbtreeCursorDump(RbtCursor* pCur, int* aRes)
  1314   1339   {
  1315         -  assert(!"Cannot call sqliteBtreeCursorDump");
         1340  +  assert(!"Cannot call sqliteRbtreeCursorDump");
  1316   1341     return SQLITE_OK;
  1317   1342   }
  1318   1343   
  1319         -static struct Pager *memBtreePager(Btree* tree)
         1344  +static struct Pager *memRbtreePager(Rbtree* tree)
  1320   1345   {
  1321         -  assert(!"Cannot call sqliteBtreePager");
         1346  +  assert(!"Cannot call sqliteRbtreePager");
  1322   1347     return SQLITE_OK;
  1323   1348   }
  1324   1349   #endif
  1325   1350   
  1326   1351   /*
  1327   1352   ** Return the full pathname of the underlying database file.
  1328   1353   */
  1329         -static const char *memBtreeGetFilename(Btree *pBt){
         1354  +static const char *memRbtreeGetFilename(Rbtree *pBt){
  1330   1355     return 0;  /* A NULL return indicates there is no underlying file */
  1331   1356   }
  1332   1357   
  1333   1358   /*
  1334   1359   ** The copy file function is not implemented for the in-memory database
  1335   1360   */
  1336         -static int memBtreeCopyFile(Btree *pBt, Btree *pBt2){
         1361  +static int memRbtreeCopyFile(Rbtree *pBt, Rbtree *pBt2){
  1337   1362     return SQLITE_INTERNAL;  /* Not implemented */
  1338   1363   }
  1339   1364   
  1340         -static BtOps sqliteBtreeOps = {
  1341         -    memBtreeClose,
  1342         -    memBtreeSetCacheSize,
  1343         -    memBtreeSetSafetyLevel,
  1344         -    memBtreeBeginTrans,
  1345         -    memBtreeCommit,
  1346         -    memBtreeRollback,
  1347         -    memBtreeBeginCkpt,
  1348         -    memBtreeCommitCkpt,
  1349         -    memBtreeRollbackCkpt,
  1350         -    memBtreeCreateTable,
  1351         -    memBtreeCreateTable,
  1352         -    memBtreeDropTable,
  1353         -    memBtreeClearTable,
  1354         -    memBtreeCursor,
  1355         -    memBtreeGetMeta,
  1356         -    memBtreeUpdateMeta,
  1357         -    memBtreeIntegrityCheck,
  1358         -    memBtreeGetFilename,
  1359         -    memBtreeCopyFile,
         1365  +static BtOps sqliteRbtreeOps = {
         1366  +    (int(*)(Btree*)) memRbtreeClose,
         1367  +    (int(*)(Btree*,int)) memRbtreeSetCacheSize,
         1368  +    (int(*)(Btree*,int)) memRbtreeSetSafetyLevel,
         1369  +    (int(*)(Btree*)) memRbtreeBeginTrans,
         1370  +    (int(*)(Btree*)) memRbtreeCommit,
         1371  +    (int(*)(Btree*)) memRbtreeRollback,
         1372  +    (int(*)(Btree*)) memRbtreeBeginCkpt,
         1373  +    (int(*)(Btree*)) memRbtreeCommitCkpt,
         1374  +    (int(*)(Btree*)) memRbtreeRollbackCkpt,
         1375  +    (int(*)(Btree*,int*)) memRbtreeCreateTable,
         1376  +    (int(*)(Btree*,int*)) memRbtreeCreateTable,
         1377  +    (int(*)(Btree*,int)) memRbtreeDropTable,
         1378  +    (int(*)(Btree*,int)) memRbtreeClearTable,
         1379  +    (int(*)(Btree*,int,int,BtCursor**)) memRbtreeCursor,
         1380  +    (int(*)(Btree*,int*)) memRbtreeGetMeta,
         1381  +    (int(*)(Btree*,int*)) memRbtreeUpdateMeta,
         1382  +    (char*(*)(Btree*,int*,int)) memRbtreeIntegrityCheck,
         1383  +    (const char*(*)(Btree*)) memRbtreeGetFilename,
         1384  +    (int(*)(Btree*,Btree*)) memRbtreeCopyFile,
  1360   1385   
  1361   1386   #ifdef SQLITE_TEST
  1362         -    memBtreePageDump,
  1363         -    memBtreePager
         1387  +    (int(*)(Btree*,int,int)) memRbtreePageDump,
         1388  +    (struct Pager*(*)(Btree*)) memRbtreePager
  1364   1389   #endif
  1365   1390   };
  1366   1391   
  1367         -static BtCursorOps sqliteBtreeCursorOps = {
  1368         -    memBtreeMoveto,
  1369         -    memBtreeDelete,
  1370         -    memBtreeInsert,
  1371         -    memBtreeFirst,
  1372         -    memBtreeLast,
  1373         -    memBtreeNext,
  1374         -    memBtreePrevious,
  1375         -    memBtreeKeySize,
  1376         -    memBtreeKey,
  1377         -    memBtreeKeyCompare,
  1378         -    memBtreeDataSize,
  1379         -    memBtreeData,
  1380         -    memBtreeCloseCursor,
         1392  +static BtCursorOps sqliteRbtreeCursorOps = {
         1393  +    (int(*)(BtCursor*,const void*,int,int*)) memRbtreeMoveto,
         1394  +    (int(*)(BtCursor*)) memRbtreeDelete,
         1395  +    (int(*)(BtCursor*,const void*,int,const void*,int)) memRbtreeInsert,
         1396  +    (int(*)(BtCursor*,int*)) memRbtreeFirst,
         1397  +    (int(*)(BtCursor*,int*)) memRbtreeLast,
         1398  +    (int(*)(BtCursor*,int*)) memRbtreeNext,
         1399  +    (int(*)(BtCursor*,int*)) memRbtreePrevious,
         1400  +    (int(*)(BtCursor*,int*)) memRbtreeKeySize,
         1401  +    (int(*)(BtCursor*,int,int,char*)) memRbtreeKey,
         1402  +    (int(*)(BtCursor*,const void*,int,int,int*)) memRbtreeKeyCompare,
         1403  +    (int(*)(BtCursor*,int*)) memRbtreeDataSize,
         1404  +    (int(*)(BtCursor*,int,int,char*)) memRbtreeData,
         1405  +    (int(*)(BtCursor*)) memRbtreeCloseCursor,
  1381   1406   #ifdef SQLITE_TEST
  1382         -    memBtreeCursorDump,
         1407  +    (int(*)(BtCursor*,int*)) memRbtreeCursorDump,
  1383   1408   #endif
  1384   1409   
  1385   1410   };
  1386   1411   
  1387   1412   #endif /* SQLITE_OMIT_INMEMORYDB */

Changes to src/build.c.

    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **     PRAGMA
    25     25   **
    26         -** $Id: build.c,v 1.152 2003/05/02 14:32:13 drh Exp $
           26  +** $Id: build.c,v 1.153 2003/05/17 17:35:11 drh Exp $
    27     27   */
    28     28   #include "sqliteInt.h"
    29     29   #include <ctype.h>
    30     30   
    31     31   /*
    32     32   ** This routine is called when a new SQL statement is beginning to
    33     33   ** be parsed.  Check to see if the schema for the database needs
    34     34   ** to be read from the SQLITE_MASTER and SQLITE_TEMP_MASTER tables.
    35     35   ** If it does, then read it.
    36     36   */
    37     37   void sqliteBeginParse(Parse *pParse, int explainFlag){
    38     38     sqlite *db = pParse->db;
           39  +  int i;
    39     40     pParse->explain = explainFlag;
    40     41     if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
    41     42       int rc = sqliteInit(db, &pParse->zErrMsg);
    42     43       if( rc!=SQLITE_OK ){
    43     44         pParse->rc = rc;
    44     45         pParse->nErr++;
    45     46       }
           47  +  }
           48  +  for(i=0; i<db->nDb; i++){
           49  +    DbClearProperty(db, i, DB_Locked);
           50  +    if( !db->aDb[i].inTrans ){
           51  +      DbClearProperty(db, i, DB_Cookie);
           52  +    }
    46     53     }
    47     54   }
    48     55   
    49     56   /*
    50     57   ** This is a fake callback procedure used when sqlite_exec() is
    51     58   ** invoked with a NULL callback pointer.  If we pass a NULL callback
    52     59   ** pointer into sqliteVdbeExec() it will return at every OP_Callback,
................................................................................
    92     99         pParse->pVdbe = 0;
    93    100         pParse->rc = rc;
    94    101         if( rc ) pParse->nErr++;
    95    102       }else{
    96    103         pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
    97    104       }
    98    105       pParse->colNamesSet = 0;
    99         -    pParse->schemaVerified = 0;
   100    106     }else if( pParse->useCallback==0 ){
   101    107       pParse->rc = SQLITE_ERROR;
   102    108     }
   103    109     pParse->nTab = 0;
   104    110     pParse->nMem = 0;
   105    111     pParse->nSet = 0;
   106    112     pParse->nAgg = 0;
................................................................................
   259    265       sqliteHashClear(&temp2);
   260    266       sqliteHashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0);
   261    267       for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
   262    268         Table *pTab = sqliteHashData(pElem);
   263    269         sqliteDeleteTable(db, pTab);
   264    270       }
   265    271       sqliteHashClear(&temp1);
   266         -    db->aDb[i].flags &= ~SQLITE_Initialized;
          272  +    DbClearProperty(db, i, DB_SchemaLoaded);
   267    273       if( iDb>0 ) return;
   268    274     }
   269    275     assert( iDb==0 );
   270    276     db->flags &= ~SQLITE_InternChanges;
   271    277   
   272    278     /* If one or more of the auxiliary database files has been closed,
   273    279     ** then remove then from the auxiliary database list.  We take the
................................................................................
   278    284     for(i=j=2; i<db->nDb; i++){
   279    285       if( db->aDb[i].pBt==0 ){
   280    286         sqliteFree(db->aDb[i].zName);
   281    287         db->aDb[i].zName = 0;
   282    288         continue;
   283    289       }
   284    290       if( j<i ){
   285         -      db->aDb[j++] = db->aDb[i];
          291  +      db->aDb[j] = db->aDb[i];
   286    292       }
          293  +    j++;
   287    294     }
   288    295     memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
   289    296     db->nDb = j;
   290    297     if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
   291    298       memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
   292    299       sqliteFree(db->aDb);
   293    300       db->aDb = db->aDbStatic;
................................................................................
  1133   1140     if( pSelTab ){
  1134   1141       assert( pTable->aCol==0 );
  1135   1142       pTable->nCol = pSelTab->nCol;
  1136   1143       pTable->aCol = pSelTab->aCol;
  1137   1144       pSelTab->nCol = 0;
  1138   1145       pSelTab->aCol = 0;
  1139   1146       sqliteDeleteTable(0, pSelTab);
  1140         -    pParse->db->aDb[pTable->iDb].flags |= SQLITE_UnresetViews;
         1147  +    DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews);
  1141   1148     }else{
  1142   1149       pTable->nCol = 0;
  1143   1150       nErr++;
  1144   1151     }
  1145   1152     sqliteSelectUnbind(pSel);
  1146   1153     sqliteExprListDelete(pSel->pEList);
  1147   1154     pSel->pEList = pEList;
................................................................................
  1167   1174     }
  1168   1175     sqliteFree(pTable->aCol);
  1169   1176     pTable->aCol = 0;
  1170   1177     pTable->nCol = 0;
  1171   1178   }
  1172   1179   
  1173   1180   /*
  1174         -** Clear the column names from every VIEW.
         1181  +** Clear the column names from every VIEW in database idx.
  1175   1182   */
  1176   1183   static void sqliteViewResetAll(sqlite *db, int idx){
  1177   1184     HashElem *i;
  1178         -  if( (db->aDb[idx].flags & SQLITE_UnresetViews)==0 ) return;
         1185  +  if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
  1179   1186     for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){
  1180   1187       Table *pTab = sqliteHashData(i);
  1181   1188       if( pTab->pSelect ){
  1182   1189         sqliteViewResetColumnNames(pTab);
  1183   1190       }
  1184   1191     }
  1185         -  db->aDb[idx].flags &= ~SQLITE_UnresetViews;
         1192  +  DbClearProperty(db, idx, DB_UnresetViews);
  1186   1193   }
  1187   1194   
  1188   1195   /*
  1189   1196   ** Given a token, look up a table with that name.  If not found, leave
  1190   1197   ** an error for the parser to find and return NULL.
  1191   1198   */
  1192   1199   Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
................................................................................
  1282   1289         { OP_Ne,         0, ADDR(7),  0},
  1283   1290         { OP_Delete,     0, 0,        0},
  1284   1291         { OP_Next,       0, ADDR(3),  0}, /* 7 */
  1285   1292       };
  1286   1293       Index *pIdx;
  1287   1294       Trigger *pTrigger;
  1288   1295       sqliteBeginWriteOperation(pParse, 0, pTable->iDb);
  1289         -    sqliteOpenMasterTable(v, pTable->iDb);
         1296  +
  1290   1297       /* Drop all triggers associated with the table being dropped */
  1291   1298       pTrigger = pTable->pTrigger;
  1292   1299       while( pTrigger ){
  1293   1300         SrcList *pNm;
  1294         -      assert( pTrigger->iDb==pTable->iDb );
         1301  +      assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 );
  1295   1302         pNm = sqliteSrcListAppend(0, 0, 0);
  1296   1303         pNm->a[0].zName = sqliteStrDup(pTrigger->name);
  1297   1304         pNm->a[0].zDatabase = sqliteStrDup(db->aDb[pTable->iDb].zName);
  1298   1305         sqliteDropTrigger(pParse, pNm, 1);
  1299   1306         if( pParse->explain ){
  1300   1307           pTrigger = pTrigger->pNext;
  1301   1308         }else{
  1302   1309           pTrigger = pTable->pTrigger;
  1303   1310         }
  1304   1311       }
         1312  +
         1313  +    /* Drop all SQLITE_MASTER entries that refer to the table */
         1314  +    sqliteOpenMasterTable(v, pTable->iDb);
  1305   1315       base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
  1306   1316       sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
  1307         -    if( !pTable->iDb ){
         1317  +
         1318  +    /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */
         1319  +    if( pTable->iDb!=1 ){
         1320  +      sqliteOpenMasterTable(v, 1);
         1321  +      base = sqliteVdbeAddOpList(v, ArraySize(dropTable), dropTable);
         1322  +      sqliteVdbeChangeP3(v, base+1, pTable->zName, 0);
         1323  +    }
         1324  +
         1325  +    if( pTable->iDb==0 ){
  1308   1326         sqliteChangeCookie(db, v);
  1309   1327       }
  1310   1328       sqliteVdbeAddOp(v, OP_Close, 0, 0);
  1311   1329       if( !isView ){
  1312   1330         sqliteVdbeAddOp(v, OP_Destroy, pTable->tnum, pTable->iDb);
  1313   1331         for(pIdx=pTable->pIndex; pIdx; pIdx=pIdx->pNext){
  1314         -        sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pTable->iDb);
         1332  +        sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
  1315   1333         }
  1316   1334       }
  1317   1335       sqliteEndWriteOperation(pParse);
  1318   1336     }
  1319   1337   
  1320   1338     /* Delete the in-memory description of the table.
  1321   1339     **
................................................................................
  2113   2131     db->onError = OE_Default;
  2114   2132   }
  2115   2133   
  2116   2134   /*
  2117   2135   ** Generate VDBE code that will verify the schema cookie for all
  2118   2136   ** named database files.
  2119   2137   */
  2120         -void sqliteCodeVerifySchema(Parse *pParse){
  2121         -  int i;
         2138  +void sqliteCodeVerifySchema(Parse *pParse, int iDb){
  2122   2139     sqlite *db = pParse->db;
  2123   2140     Vdbe *v = sqliteGetVdbe(pParse);
  2124         -  for(i=0; i<db->nDb; i++){
  2125         -    if( i==1 || db->aDb[i].pBt==0 ) continue;
  2126         -    sqliteVdbeAddOp(v, OP_VerifyCookie, i, db->aDb[i].schema_cookie);
         2141  +  assert( iDb>=0 && iDb<db->nDb );
         2142  +  assert( db->aDb[iDb].pBt!=0 );
         2143  +  if( iDb!=1 && !DbHasProperty(db, iDb, DB_Cookie) ){
         2144  +    sqliteVdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
         2145  +    DbSetProperty(db, iDb, DB_Cookie);
  2127   2146     }
  2128         -  pParse->schemaVerified = 1;
  2129   2147   }
  2130   2148   
  2131   2149   /*
  2132   2150   ** Generate VDBE code that prepares for doing an operation that
  2133   2151   ** might change the database.
  2134   2152   **
  2135   2153   ** This routine starts a new transaction if we are not already within
................................................................................
  2137   2155   ** is set if the setCheckpoint parameter is true.  A checkpoint should
  2138   2156   ** be set for operations that might fail (due to a constraint) part of
  2139   2157   ** the way through and which will need to undo some writes without having to
  2140   2158   ** rollback the whole transaction.  For operations where all constraints
  2141   2159   ** can be checked before any changes are made to the database, it is never
  2142   2160   ** necessary to undo a write and the checkpoint should not be set.
  2143   2161   **
  2144         -** The tempOnly flag indicates that only temporary tables will be changed
  2145         -** during this write operation.  The primary database table is not
  2146         -** write-locked.  Only the temporary database file gets a write lock.
  2147         -** Other processes can continue to read or write the primary database file.
         2162  +** Only database iDb and the temp database are made writable by this call.
         2163  +** If iDb==0, then the main and temp databases are made writable.   If
         2164  +** iDb==1 then only the temp database is made writable.  If iDb>1 then the
         2165  +** specified auxiliary database and the temp database are made writable.
  2148   2166   */
  2149         -void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){
         2167  +void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int iDb){
  2150   2168     Vdbe *v;
         2169  +  sqlite *db = pParse->db;
         2170  +  if( DbHasProperty(db, iDb, DB_Locked) ) return;
  2151   2171     v = sqliteGetVdbe(pParse);
  2152   2172     if( v==0 ) return;
  2153         -  if( pParse->trigStack ) return; /* if this is in a trigger */
  2154         -  if( (pParse->db->flags & SQLITE_InTrans)==0 ){
  2155         -    sqliteVdbeAddOp(v, OP_Transaction, 1, 0);
  2156         -    if( !tempOnly ){
  2157         -      int i;
  2158         -      sqlite *db = pParse->db;
  2159         -      sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
  2160         -      for(i=2; i<db->nDb; i++){
  2161         -        if( db->aDb[i].pBt==0 ) continue;
  2162         -        sqliteVdbeAddOp(v, OP_Transaction, i, 0);
  2163         -      }
  2164         -      sqliteCodeVerifySchema(pParse);
         2173  +  if( !db->aDb[iDb].inTrans ){
         2174  +    sqliteVdbeAddOp(v, OP_Transaction, iDb, 0);
         2175  +    DbSetProperty(db, iDb, DB_Locked);
         2176  +    sqliteCodeVerifySchema(pParse, iDb);
         2177  +    if( iDb!=1 ){
         2178  +      sqliteBeginWriteOperation(pParse, setCheckpoint, 1);
  2165   2179       }
  2166   2180     }else if( setCheckpoint ){
  2167         -    sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
  2168         -    sqliteVdbeAddOp(v, OP_Checkpoint, 1, 0);
         2181  +    sqliteVdbeAddOp(v, OP_Checkpoint, iDb, 0);
         2182  +    DbSetProperty(db, iDb, DB_Locked);
  2169   2183     }
  2170   2184   }
  2171   2185   
  2172   2186   /*
  2173   2187   ** Generate code that concludes an operation that may have changed
  2174         -** the database.  This is a companion function to BeginWriteOperation().
  2175         -** If a transaction was started, then commit it.  If a checkpoint was
  2176         -** started then commit that.
         2188  +** the database.  If a statement transaction was started, then emit
         2189  +** an OP_Commit that will cause the changes to be committed to disk.
         2190  +**
         2191  +** Note that checkpoints are automatically committed at the end of
         2192  +** a statement.  Note also that there can be multiple calls to 
         2193  +** sqliteBeginWriteOperation() but there should only be a single
         2194  +** call to sqliteEndWriteOperation() at the conclusion of the statement.
  2177   2195   */
  2178   2196   void sqliteEndWriteOperation(Parse *pParse){
  2179   2197     Vdbe *v;
         2198  +  sqlite *db = pParse->db;
  2180   2199     if( pParse->trigStack ) return; /* if this is in a trigger */
  2181   2200     v = sqliteGetVdbe(pParse);
  2182   2201     if( v==0 ) return;
  2183         -  if( pParse->db->flags & SQLITE_InTrans ){
  2184         -    /* Do Nothing */
         2202  +  if( db->flags & SQLITE_InTrans ){
         2203  +    /* A BEGIN has executed.  Do not commit until we see an explicit
         2204  +    ** COMMIT statement. */
  2185   2205     }else{
  2186   2206       sqliteVdbeAddOp(v, OP_Commit, 0, 0);
  2187   2207     }
  2188   2208   }

Changes to src/copy.c.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains code used to implement the COPY command.
    13     13   **
    14         -** $Id: copy.c,v 1.4 2003/04/24 01:45:04 drh Exp $
           14  +** $Id: copy.c,v 1.5 2003/05/17 17:35:11 drh Exp $
    15     15   */
    16     16   #include "sqliteInt.h"
    17     17   
    18     18   /*
    19     19   ** The COPY command is for compatibility with PostgreSQL and specificially
    20     20   ** for the ability to read the output of pg_dump.  The format is as
    21     21   ** follows:
................................................................................
    53     53     zDb = db->aDb[pTab->iDb].zName;
    54     54     if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb)
    55     55         || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){
    56     56       goto copy_cleanup;
    57     57     }
    58     58     v = sqliteGetVdbe(pParse);
    59     59     if( v ){
    60         -    sqliteBeginWriteOperation(pParse, 1, pTab->iDb==1);
           60  +    sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
    61     61       addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
    62     62       sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
    63     63       sqliteVdbeDequoteP3(v, addr);
    64     64       sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
    65     65       sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
    66     66       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
    67     67       for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){

Changes to src/delete.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle DELETE FROM statements.
    14     14   **
    15         -** $Id: delete.c,v 1.56 2003/05/02 14:32:13 drh Exp $
           15  +** $Id: delete.c,v 1.57 2003/05/17 17:35:11 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** Look up every table that is named in pSrc.  If any table is not found,
    21     21   ** add an error message to pParse->zErrMsg and return NULL.  If all tables
    22     22   ** are found, return a pointer to the last table.
................................................................................
   138    138   
   139    139     /* Begin generating code.
   140    140     */
   141    141     v = sqliteGetVdbe(pParse);
   142    142     if( v==0 ){
   143    143       goto delete_from_cleanup;
   144    144     }
   145         -  sqliteBeginWriteOperation(pParse, row_triggers_exist,
   146         -       !row_triggers_exist && pTab->iDb==1);
          145  +  sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
   147    146   
   148    147     /* If we are trying to delete from a view, construct that view into
   149    148     ** a temporary table.
   150    149     */
   151    150     if( isView ){
   152    151       Select *pView = sqliteSelectDup(pTab->pSelect);
   153    152       sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);

Changes to src/insert.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle INSERT statements in SQLite.
    14     14   **
    15         -** $Id: insert.c,v 1.84 2003/05/16 02:30:27 drh Exp $
           15  +** $Id: insert.c,v 1.85 2003/05/17 17:35:12 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** This routine is call to handle SQL of the following forms:
    21     21   **
    22     22   **    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
   155    155       goto insert_cleanup;
   156    156     }
   157    157   
   158    158     /* Allocate a VDBE
   159    159     */
   160    160     v = sqliteGetVdbe(pParse);
   161    161     if( v==0 ) goto insert_cleanup;
   162         -  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist,
   163         -         !row_triggers_exist && pTab->iDb==1);
          162  +  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);
   164    163   
   165    164     /* if there are row triggers, allocate a temp table for new.* references. */
   166    165     if( row_triggers_exist ){
   167    166       newIdx = pParse->nTab++;
   168    167     }
   169    168   
   170    169     /* Figure out how many columns of data are supplied.  If the data

Changes to src/main.c.

    10     10   **
    11     11   *************************************************************************
    12     12   ** Main file for the SQLite library.  The routines in this file
    13     13   ** implement the programmer interface to the library.  Routines in
    14     14   ** other files are for internal use by SQLite and should not be
    15     15   ** accessed by users of the library.
    16     16   **
    17         -** $Id: main.c,v 1.130 2003/05/04 17:58:26 drh Exp $
           17  +** $Id: main.c,v 1.131 2003/05/17 17:35:12 drh Exp $
    18     18   */
    19     19   #include "sqliteInt.h"
    20     20   #include "os.h"
    21     21   #include <ctype.h>
    22     22   
    23     23   /*
    24     24   ** A pointer to this structure is used to communicate information
................................................................................
    25     25   ** from sqliteInit into the sqliteInitCallback.
    26     26   */
    27     27   typedef struct {
    28     28     sqlite *db;         /* The database being initialized */
    29     29     char **pzErrMsg;    /* Error message stored here */
    30     30   } InitData;
    31     31   
           32  +/*
           33  +** Fill the InitData structure with an error message that indicates
           34  +** that the database is corrupt.
           35  +*/
           36  +static void corruptSchema(InitData *pData){
           37  +  sqliteSetString(pData->pzErrMsg, "malformed database schema", 0);
           38  +}
    32     39   
    33     40   /*
    34     41   ** This is the callback routine for the code that initializes the
    35     42   ** database.  See sqliteInit() below for additional information.
    36     43   **
    37     44   ** Each callback contains the following information:
    38     45   **
................................................................................
    46     53   */
    47     54   static
    48     55   int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
    49     56     InitData *pData = (InitData*)pInit;
    50     57     Parse sParse;
    51     58     int nErr = 0;
    52     59   
    53         -  /* TODO: Do some validity checks on all fields.  In particular,
    54         -  ** make sure fields do not contain NULLs. Otherwise we might core
    55         -  ** when attempting to initialize from a corrupt database file. */
    56         -
    57     60     assert( argc==5 );
           61  +  if( argv[0]==0 ){
           62  +    corruptSchema(pData);
           63  +    return 1;
           64  +  }
    58     65     switch( argv[0][0] ){
    59     66       case 'v':
    60     67       case 'i':
    61     68       case 't': {  /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
           69  +      if( argv[2]==0 || argv[4]==0 ){
           70  +        corruptSchema(pData);
           71  +        return 1;
           72  +      }
    62     73         if( argv[3] && argv[3][0] ){
    63     74           /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
    64     75           ** But because sParse.initFlag is set to 1, no VDBE code is generated
    65     76           ** or executed.  All the parser does is build the internal data
    66     77           ** structures that describe the table, index, or view.
    67     78           */
    68     79           memset(&sParse, 0, sizeof(sParse));
................................................................................
   338    349     sqliteBtreeCloseCursor(curMain);
   339    350     if( sqlite_malloc_failed ){
   340    351       sqliteSetString(pzErrMsg, "out of memory", 0);
   341    352       sParse.rc = SQLITE_NOMEM;
   342    353       sqliteResetInternalSchema(db, 0);
   343    354     }
   344    355     if( sParse.rc==SQLITE_OK ){
   345         -    db->aDb[iDb].flags |= SQLITE_Initialized;
          356  +    DbSetProperty(db, iDb, DB_SchemaLoaded);
          357  +    if( iDb==0 ){
          358  +      DbSetProperty(db, 1, DB_SchemaLoaded);
          359  +    }
   346    360     }else{
   347    361       sqliteResetInternalSchema(db, iDb);
   348    362     }
   349    363     return sParse.rc;
   350    364   }
   351    365   
   352    366   /*
................................................................................
   364    378   */
   365    379   int sqliteInit(sqlite *db, char **pzErrMsg){
   366    380     int i, rc;
   367    381     
   368    382     assert( (db->flags & SQLITE_Initialized)==0 );
   369    383     rc = SQLITE_OK;
   370    384     for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
   371         -    if( db->aDb[i].flags & SQLITE_Initialized ) continue;
   372         -    if( i==1 ) continue;  /* Skip the temp database - initialized with 0 */
          385  +    if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
          386  +    assert( i!=1 );  /* Should have been initialized together with 0 */
   373    387       rc = sqliteInitOne(db, i, pzErrMsg);
   374    388     }
   375    389     if( rc==SQLITE_OK ){
   376    390       db->flags |= SQLITE_Initialized;
   377    391       sqliteCommitInternalChanges(db);
   378    392     }else{
   379    393       db->flags &= ~SQLITE_Initialized;
................................................................................
   957    971       } else if (TEMP_STORE == 1 || TEMP_STORE == 2) {
   958    972         /* Switch depending on compile-time and/or runtime settings. */
   959    973         int location = db->temp_store==0 ? TEMP_STORE : db->temp_store;
   960    974   
   961    975         if (location == 1) {
   962    976           return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
   963    977         } else {
   964         -        return sqliteRBtreeOpen(0, 0, 0, ppBtree);
          978  +        return sqliteRbtreeOpen(0, 0, 0, ppBtree);
   965    979         }
   966    980       } else {
   967    981         /* Always use in-core DB */
   968         -      return sqliteRBtreeOpen(0, 0, 0, ppBtree);
          982  +      return sqliteRbtreeOpen(0, 0, 0, ppBtree);
   969    983       }
   970    984     }else if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
   971         -    return sqliteRBtreeOpen(0, 0, 0, ppBtree);
          985  +    return sqliteRbtreeOpen(0, 0, 0, ppBtree);
   972    986     }else
   973    987   #endif
   974    988     {
   975    989       return sqliteBtreeOpen(zFilename, omitJournal, nCache, ppBtree);
   976    990     }
   977    991   }

Changes to src/select.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle SELECT statements in SQLite.
    14     14   **
    15         -** $Id: select.c,v 1.138 2003/05/06 20:35:16 drh Exp $
           15  +** $Id: select.c,v 1.139 2003/05/17 17:35:12 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   
    20     20   /*
    21     21   ** Allocate a new Select structure and return a pointer to that
    22     22   ** structure.
................................................................................
  1841   1841     }
  1842   1842   
  1843   1843     /* Generating code to find the min or the max.  Basically all we have
  1844   1844     ** to do is find the first or the last entry in the chosen index.  If
  1845   1845     ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
  1846   1846     ** or last entry in the main table.
  1847   1847     */
  1848         -  if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
  1849         -    sqliteCodeVerifySchema(pParse);
  1850         -  }
         1848  +  sqliteCodeVerifySchema(pParse, pTab->iDb);
  1851   1849     base = p->pSrc->a[0].iCursor;
  1852   1850     sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
  1853   1851     sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
  1854   1852     sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
  1855   1853     cont = sqliteVdbeMakeLabel(v);
  1856   1854     if( pIdx==0 ){
  1857   1855       sqliteVdbeAddOp(v, seekOp, base, 0);

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.184 2003/05/10 03:04:34 jplyon Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.185 2003/05/17 17:35:12 drh Exp $
    15     15   */
    16     16   #include "config.h"
    17     17   #include "sqlite.h"
    18     18   #include "hash.h"
    19     19   #include "vdbe.h"
    20     20   #include "parse.h"
    21     21   #include "btree.h"
................................................................................
   235    235     Hash tblHash;        /* All tables indexed by name */
   236    236     Hash idxHash;        /* All (named) indices indexed by name */
   237    237     Hash trigHash;       /* All triggers indexed by name */
   238    238     Hash aFKey;          /* Foreign keys indexed by to-table */
   239    239     u8 inTrans;          /* True if a transaction is underway for this backend */
   240    240     u16 flags;           /* Flags associated with this database */
   241    241   };
          242  +
          243  +/*
          244  +** These macros can be used to test, set, or clear bits in the 
          245  +** Db.flags field.
          246  +*/
          247  +#define DbHasProperty(D,I,P)     (((D)->aDb[I].flags&(P))==(P))
          248  +#define DbHasAnyProperty(D,I,P)  (((D)->aDb[I].flags&(P))!=0)
          249  +#define DbSetProperty(D,I,P)     (D)->aDb[I].flags|=(P)
          250  +#define DbClearProperty(D,I,P)   (D)->aDb[I].flags&=~(P)
          251  +
          252  +/*
          253  +** Allowed values for the DB.flags field.
          254  +**
          255  +** The DB_Locked flag is set when the first OP_Transaction or OP_Checkpoint
          256  +** opcode is emitted for a database.  This prevents multiple occurances
          257  +** of those opcodes for the same database in the same program.  Similarly,
          258  +** the DB_Cookie flag is set when the OP_VerifyCookie opcode is emitted,
          259  +** and prevents duplicate OP_VerifyCookies from taking up space and slowing
          260  +** down execution.
          261  +**
          262  +** The DB_SchemaLoaded flag is set after the database schema has been
          263  +** read into internal hash tables.
          264  +**
          265  +** DB_UnresetViews means that one or more views have column names that
          266  +** have been filled out.  If the schema changes, these column names might
          267  +** changes and so the view will need to be reset.
          268  +*/
          269  +#define DB_Locked          0x0001  /* OP_Transaction opcode has been emitted */
          270  +#define DB_Cookie          0x0002  /* OP_VerifyCookie opcode has been emiited */
          271  +#define DB_SchemaLoaded    0x0004  /* The schema has been loaded */
          272  +#define DB_UnresetViews    0x0008  /* Some views have defined column names */
          273  +
   242    274   
   243    275   /*
   244    276   ** Each database is an instance of the following structure.
   245    277   **
   246    278   ** The sqlite.file_format is initialized by the database file
   247    279   ** and helps determines how the data in the database file is
   248    280   ** represented.  This field allows newer versions of the library
................................................................................
   289    321     int (*xAuth)(void*,int,const char*,const char*,const char*,const char*);
   290    322                                   /* Access authorization function */
   291    323     void *pAuthArg;               /* 1st argument to the access auth function */
   292    324   #endif
   293    325   };
   294    326   
   295    327   /*
   296         -** Possible values for the sqlite.flags.
          328  +** Possible values for the sqlite.flags and or Db.flags fields.
          329  +**
          330  +** On sqlite.flags, the SQLITE_InTrans value means that we have
          331  +** executed a BEGIN.  On Db.flags, SQLITE_InTrans means a statement
          332  +** transaction is active on that particular database file.
   297    333   */
   298    334   #define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
   299    335   #define SQLITE_Initialized    0x00000002  /* True after initialization */
   300    336   #define SQLITE_Interrupt      0x00000004  /* Cancel current operation */
   301    337   #define SQLITE_InTrans        0x00000008  /* True if in a transaction */
   302    338   #define SQLITE_InternChanges  0x00000010  /* Uncommitted Hash table changes */
   303    339   #define SQLITE_FullColNames   0x00000020  /* Show full column names on SELECT */
   304    340   #define SQLITE_CountRows      0x00000040  /* Count rows changed by INSERT, */
   305    341                                             /*   DELETE, or UPDATE and return */
   306    342                                             /*   the count using a callback. */
   307    343   #define SQLITE_NullCallback   0x00000080  /* Invoke the callback once if the */
   308    344                                             /*   result set is empty */
   309         -/*#define SQLITE_ResultDetails  0x00000100 * (UNUSED -- flag free for reuse) */
   310         -#define SQLITE_UnresetViews   0x00000200  /* True if one or more views have */
   311         -                                          /*   defined column names */
   312         -#define SQLITE_ReportTypes    0x00000400  /* Include information on datatypes */
          345  +#define SQLITE_ReportTypes    0x00000200  /* Include information on datatypes */
   313    346                                             /*   in 4th argument of callback */
   314    347   
   315    348   /*
   316    349   ** Possible values for the sqlite.magic field.
   317    350   ** The numbers are obtained at random and have no special meaning, other
   318    351   ** than being distinct from one another.
   319    352   */
................................................................................
   813    846     Vdbe *pVdbe;         /* An engine for executing database bytecode */
   814    847     u8 colNamesSet;      /* TRUE after OP_ColumnName has been issued to pVdbe */
   815    848     u8 explain;          /* True if the EXPLAIN flag is found on the query */
   816    849     u8 initFlag;         /* True if reparsing CREATE TABLEs */
   817    850     u8 nameClash;        /* A permanent table name clashes with temp table name */
   818    851     u8 useAgg;           /* If true, extract field values from the aggregator
   819    852                          ** while generating expressions.  Normally false */
   820         -  u8 schemaVerified;   /* True if an OP_VerifySchema has been coded someplace
   821         -                       ** other than after an OP_Transaction */
   822    853     u8 iDb;              /* Index of database whose schema is being parsed */
   823    854     u8 useCallback;      /* True if callbacks should be used to report results */
   824    855     int useDb;           /* Restrict references to tables in this database */
   825    856     int newTnum;         /* Table number to use when reparsing CREATE TABLEs */
   826    857     int nErr;            /* Number of errors seen */
   827    858     int nTab;            /* Number of previously allocated VDBE cursors */
   828    859     int nMem;            /* Number of memory cells used so far */
................................................................................
  1073   1104   int sqliteFuncId(Token*);
  1074   1105   int sqliteExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
  1075   1106   int sqliteExprAnalyzeAggregates(Parse*, Expr*);
  1076   1107   Vdbe *sqliteGetVdbe(Parse*);
  1077   1108   int sqliteRandomByte(void);
  1078   1109   int sqliteRandomInteger(void);
  1079   1110   void sqliteRollbackAll(sqlite*);
  1080         -void sqliteCodeVerifySchema(Parse*);
         1111  +void sqliteCodeVerifySchema(Parse*, int);
  1081   1112   void sqliteBeginTransaction(Parse*, int);
  1082   1113   void sqliteCommitTransaction(Parse*);
  1083   1114   void sqliteRollbackTransaction(Parse*);
  1084   1115   int sqliteExprIsConstant(Expr*);
  1085   1116   int sqliteExprIsInteger(Expr*, int*);
  1086   1117   int sqliteIsRowid(const char*);
  1087   1118   void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);

Changes to src/update.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains C code routines that are called by the parser
    13     13   ** to handle UPDATE statements.
    14     14   **
    15         -** $Id: update.c,v 1.65 2003/05/02 14:32:14 drh Exp $
           15  +** $Id: update.c,v 1.66 2003/05/17 17:35:12 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** Process an UPDATE statement.
    21     21   **
    22     22   **   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
................................................................................
   199    199       sqliteAuthContextPush(pParse, &sContext, pTab->zName);
   200    200     }
   201    201   
   202    202     /* Begin generating code.
   203    203     */
   204    204     v = sqliteGetVdbe(pParse);
   205    205     if( v==0 ) goto update_cleanup;
   206         -  sqliteBeginWriteOperation(pParse, 1, !row_triggers_exist && pTab->iDb==1);
          206  +  sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
   207    207   
   208    208     /* If we are trying to update a view, construct that view into
   209    209     ** a temporary table.
   210    210     */
   211    211     if( isView ){
   212    212       Select *pView;
   213    213       pView = sqliteSelectDup(pTab->pSelect);

Changes to src/vdbe.c.

    32     32   **
    33     33   ** Various scripts scan this source file in order to generate HTML
    34     34   ** documentation, headers files, or other derived files.  The formatting
    35     35   ** of the code in this file is, therefore, important.  See other comments
    36     36   ** in this file for details.  If in doubt, do not deviate from existing
    37     37   ** commenting and indentation practices when changing or adding code.
    38     38   **
    39         -** $Id: vdbe.c,v 1.222 2003/05/10 03:36:54 drh Exp $
           39  +** $Id: vdbe.c,v 1.223 2003/05/17 17:35:12 drh Exp $
    40     40   */
    41     41   #include "sqliteInt.h"
    42     42   #include <ctype.h>
    43     43   
    44     44   /*
    45     45   ** The makefile scans this source file and creates the following
    46     46   ** array of string constants which are the names of all VDBE opcodes.
................................................................................
  3189   3189   ** transaction is underway.  Starting a transaction also creates a
  3190   3190   ** rollback journal.  A transaction must be started before any changes
  3191   3191   ** can be made to the database.
  3192   3192   */
  3193   3193   case OP_Transaction: {
  3194   3194     int busy = 1;
  3195   3195     int i = pOp->p1;
  3196         -  while( i>=0 && i<db->nDb && db->aDb[i].pBt!=0 && busy ){
         3196  +  assert( i>=0 && i<db->nDb );
         3197  +  if( db->aDb[i].inTrans ) break;
         3198  +  while( db->aDb[i].pBt!=0 && busy ){
  3197   3199       rc = sqliteBtreeBeginTrans(db->aDb[i].pBt);
  3198   3200       switch( rc ){
  3199   3201         case SQLITE_BUSY: {
  3200   3202           if( db->xBusyCallback==0 ){
  3201   3203             p->pc = pc;
  3202   3204             p->undoTransOnError = 1;
  3203   3205             p->rc = SQLITE_BUSY;
................................................................................
  4543   4545   ** The table being destroyed is in the main database file if P2==0.  If
  4544   4546   ** P2==1 then the table to be clear is in the auxiliary database file
  4545   4547   ** that is used to store tables create using CREATE TEMPORARY TABLE.
  4546   4548   **
  4547   4549   ** See also: Clear
  4548   4550   */
  4549   4551   case OP_Destroy: {
  4550         -  sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
         4552  +  rc = sqliteBtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
  4551   4553     break;
  4552   4554   }
  4553   4555   
  4554   4556   /* Opcode: Clear P1 P2 *
  4555   4557   **
  4556   4558   ** Delete all contents of the database table or index whose root page
  4557   4559   ** in the database file is given by P1.  But, unlike Destroy, do not
................................................................................
  4560   4562   ** The table being clear is in the main database file if P2==0.  If
  4561   4563   ** P2==1 then the table to be clear is in the auxiliary database file
  4562   4564   ** that is used to store tables create using CREATE TEMPORARY TABLE.
  4563   4565   **
  4564   4566   ** See also: Destroy
  4565   4567   */
  4566   4568   case OP_Clear: {
  4567         -  sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
         4569  +  rc = sqliteBtreeClearTable(db->aDb[pOp->p2].pBt, pOp->p1);
  4568   4570     break;
  4569   4571   }
  4570   4572   
  4571   4573   /* Opcode: CreateTable * P2 P3
  4572   4574   **
  4573   4575   ** Allocate a new table in the main database file if P2==0 or in the
  4574   4576   ** auxiliary database file if P2==1.  Push the page number

Changes to src/where.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This module contains C code that generates VDBE code used to process
    13     13   ** the WHERE clause of SQL statements.
    14     14   **
    15         -** $Id: where.c,v 1.78 2003/05/02 14:32:14 drh Exp $
           15  +** $Id: where.c,v 1.79 2003/05/17 17:35:13 drh Exp $
    16     16   */
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** The query generator uses an array of instances of this structure to
    21     21   ** help it analyze the subexpressions of the WHERE clause.  Each WHERE
    22     22   ** clause subexpression is separated from the others by an AND operator.
................................................................................
   676    676       Table *pTab;
   677    677   
   678    678       pTab = pTabList->a[i].pTab;
   679    679       if( pTab->isTransient || pTab->pSelect ) continue;
   680    680       sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
   681    681       sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
   682    682       sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
   683         -    if( i==0 && !pParse->schemaVerified &&
   684         -          (pParse->db->flags & SQLITE_InTrans)==0 ){
   685         -      sqliteCodeVerifySchema(pParse);
   686         -    }
          683  +    sqliteCodeVerifySchema(pParse, pTab->iDb);
   687    684       if( pWInfo->a[i].pIdx!=0 ){
   688    685         sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
   689    686         sqliteVdbeAddOp(v, OP_OpenRead,
   690    687                         pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
   691    688         sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
   692    689       }
   693    690     }

Changes to test/attach.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this script is testing the ATTACH and DETACH commands
    13     13   # and related functionality.
    14     14   #
    15         -# $Id: attach.test,v 1.3 2003/04/17 22:57:55 drh Exp $
           15  +# $Id: attach.test,v 1.4 2003/05/17 17:35:13 drh Exp $
    16     16   #
    17     17   
    18     18   set testdir [file dirname $argv0]
    19     19   source $testdir/tester.tcl
    20     20   
    21     21   for {set i 2} {$i<=15} {incr i} {
    22     22     file delete -force test$i.db
................................................................................
   233    233     }
   234    234   } {1 11 x x 2 12 y y 11 21 x x 12 22 y y}
   235    235   do_test attach-2.6 {
   236    236     execsql {
   237    237       SELECT * FROM main.tx;
   238    238     }
   239    239   } {}
          240  +do_test attach-2.7 {
          241  +  execsql {
          242  +    SELECT type, name, tbl_name FROM db2.sqlite_master;
          243  +  }
          244  +} {table t2 t2 table tx tx trigger r1 t2}
          245  +do_test attach-2.8 {
          246  +  execsql {
          247  +    PRAGMA database_list
          248  +  }
          249  +} {0 main 1 temp 2 db2}
          250  +do_test attach-2.9 {
          251  +  execsql {
          252  +    CREATE INDEX i2 ON t2(x);
          253  +    SELECT * FROM t2 WHERE x>5;
          254  +  } db2
          255  +} {21 x 22 y}
          256  +do_test attach-2.10 {
          257  +  execsql {
          258  +    SELECT type, name, tbl_name FROM sqlite_master;
          259  +  } db2
          260  +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
          261  +do_test attach-2.11 {
          262  +  catchsql { pragma vdbe_trace=on;
          263  +    SELECT * FROM t2 WHERE x>5;
          264  +  }
          265  +} {1 {database schema has changed}}
          266  +do_test attach-2.12 {
          267  +  execsql {
          268  +    PRAGMA database_list
          269  +  }
          270  +} {0 main 1 temp 2 db2}
          271  +do_test attach-2.13 {
          272  +  catchsql {
          273  +    SELECT * FROM t2 WHERE x>5;
          274  +  }
          275  +} {0 {21 x 22 y}}
          276  +do_test attach-2.14 {
          277  +  execsql {
          278  +    SELECT type, name, tbl_name FROM sqlite_master;
          279  +  }
          280  +} {table t1 t1 table tx tx}
          281  +do_test attach-2.15 {
          282  +  execsql {
          283  +    SELECT type, name, tbl_name FROM db2.sqlite_master;
          284  +  }
          285  +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
          286  +do_test attach-2.16 {
          287  +  db close
          288  +  sqlite db test.db
          289  +  execsql {
          290  +    ATTACH 'test2.db' AS db2;
          291  +    SELECT type, name, tbl_name FROM db2.sqlite_master;
          292  +  }
          293  +} {table t2 t2 table tx tx trigger r1 t2 index i2 t2}
   240    294   
   241    295   for {set i 2} {$i<=15} {incr i} {
   242    296     catch {db$i close}
   243    297   }
   244    298   
   245    299   
   246    300   finish_test

Changes to test/temptable.test.

     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.
    12     12   #
    13     13   # This file implements tests for temporary tables and indices.
    14     14   #
    15         -# $Id: temptable.test,v 1.9 2003/03/30 00:19:50 drh Exp $
           15  +# $Id: temptable.test,v 1.10 2003/05/17 17:35:13 drh Exp $
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   # Create an alternative connection to the database
    21     21   #
    22     22   do_test temptable-1.0 {
................................................................................
   161    161       SELECT * FROM t2;
   162    162     }
   163    163   } {9 8 7}
   164    164   do_test temptable-4.3 {
   165    165     catchsql {
   166    166       SELECT * FROM t2;
   167    167     } db2
   168         -} {1 {database schema has changed}}
          168  +} {0 {10 20}}
   169    169   do_test temptable-4.4.1 {
   170    170     catchsql {
   171    171       SELECT * FROM temp.t2;
   172    172     } db2
   173    173   } {0 {10 20}}
   174    174   do_test temptable-4.4.2 {
   175    175     catchsql {
   176    176       SELECT * FROM main.t2;
   177    177     } db2
   178         -} {0 {9 8 7}}
          178  +} {1 {no such table: main.t2}}
   179    179   do_test temptable-4.4.3 {
          180  +  catchsql {
          181  +    SELECT name FROM main.sqlite_master WHERE type='table';
          182  +  } db2
          183  +} {1 {database schema has changed}}
          184  +do_test temptable-4.4.4 {
          185  +  catchsql {
          186  +    SELECT name FROM main.sqlite_master WHERE type='table';
          187  +  } db2
          188  +} {0 {t1 t2}}
          189  +do_test temptable-4.4.5 {
          190  +  catchsql {
          191  +    SELECT * FROM main.t2;
          192  +  } db2
          193  +} {0 {9 8 7}}
          194  +do_test temptable-4.4.6 {
   180    195     # TEMP takes precedence over MAIN
   181    196     catchsql {
   182    197       SELECT * FROM t2;
   183    198     } db2
   184    199   } {0 {10 20}}
   185    200   do_test temptable-4.5 {
   186    201     catchsql {
................................................................................
   213    228   do_test temptable-4.9 {
   214    229     execsql {
   215    230       CREATE TABLE t2(x unique, y);
   216    231       INSERT INTO t2 VALUES(3,4);
   217    232       SELECT * FROM t2;
   218    233     }
   219    234   } {3 4}
   220         -do_test temptable-4.10 {
          235  +do_test temptable-4.10.1 {
   221    236     catchsql {
   222    237       SELECT * FROM t2;
   223    238     } db2
          239  +} {0 {1 2}}
          240  +do_test temptable-4.10.2 {
          241  +  catchsql {
          242  +    SELECT name FROM sqlite_master WHERE type='table'
          243  +  } db2
   224    244   } {1 {database schema has changed}}
          245  +do_test temptable-4.10.3 {
          246  +  catchsql {
          247  +    SELECT name FROM sqlite_master WHERE type='table'
          248  +  } db2
          249  +} {0 {t1 t2}}
   225    250   do_test temptable-4.11 {
   226    251     execsql {
   227    252       SELECT * FROM t2;
   228    253     } db2
   229    254   } {1 2}
   230    255   do_test temptable-4.12 {
   231    256     execsql {

Changes to test/trigger2.test.

    48     48   #
    49     49   
    50     50   set testdir [file dirname $argv0]
    51     51   source $testdir/tester.tcl
    52     52   
    53     53   # 1.
    54     54   set ii 0
    55         -foreach tbl_defn [ list \
    56         -	{CREATE TABLE tbl (a, b);} \
    57         -	{CREATE TEMP TABLE tbl (a, b);} \
    58         -	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \
    59         -        {CREATE TABLE tbl (a, b PRIMARY KEY);} \
    60         -	{CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} ] {
           55  +foreach tbl_defn {
           56  +	{CREATE TEMP TABLE tbl (a, b);} 
           57  +	{CREATE TABLE tbl (a, b);} 
           58  +	{CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} 
           59  +	{CREATE TEMPORARY TABLE tbl (a INTEGER PRIMARY KEY, b);} 
           60  +        {CREATE TABLE tbl (a, b PRIMARY KEY);} 
           61  +	{CREATE TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 
           62  +	{CREATE TEMP TABLE tbl (a, b); CREATE INDEX tbl_idx ON tbl(b);} 
           63  +	{CREATE TABLE tbl (a, b); CREATE TEMP INDEX tbl_idx ON tbl(b);} 
           64  +} {
    61     65     incr ii
    62     66     catchsql { DROP INDEX tbl_idx; }
    63     67     catchsql {
    64     68       DROP TABLE rlog;
    65     69       DROP TABLE clog;
    66     70       DROP TABLE tbl;
    67     71       DROP TABLE other_tbl;
................................................................................
    98    102         INSERT INTO clog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM clog), 
    99    103   	  old.a, old.b, 
   100    104   	  (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), 
   101    105   	  new.a, new.b);
   102    106       END;
   103    107     }
   104    108   
   105         -  do_test trigger2-1.1.$ii {
   106         -    execsql {
          109  +  do_test trigger2-1.$ii.1 {
          110  +    execsql { 
   107    111         UPDATE tbl SET a = a * 10, b = b * 10;
   108    112         SELECT * FROM rlog ORDER BY idx;
   109    113         SELECT * FROM clog ORDER BY idx;
   110    114       }
   111    115     } [list 1 1 2  4  6 10 20 \
   112    116             2 1 2 13 24 10 20 \
   113    117   	  3 3 4 13 24 30 40 \
   114    118   	  4 3 4 40 60 30 40 \
   115    119             1 1 2 13 24 10 20 ]
   116         -  
          120  +
   117    121     execsql {
   118    122       DELETE FROM rlog;
   119    123       DELETE FROM tbl;
   120    124       INSERT INTO tbl VALUES (100, 100);
   121    125       INSERT INTO tbl VALUES (300, 200);
   122    126       CREATE TRIGGER delete_before_row BEFORE DELETE ON tbl FOR EACH ROW
   123    127         BEGIN
................................................................................
   131    135         BEGIN
   132    136         INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
   133    137   	  old.a, old.b, 
   134    138   	  (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), 
   135    139   	  0, 0);
   136    140       END;
   137    141     }
   138         -  do_test trigger2-1.2.$ii {
          142  +  do_test trigger2-1.$ii.2 {
   139    143       execsql {
   140    144         DELETE FROM tbl;
   141    145         SELECT * FROM rlog;
   142    146       }
   143    147     } [list 1 100 100 400 300 0 0 \
   144    148             2 100 100 300 200 0 0 \
   145    149             3 300 200 300 200 0 0 \
................................................................................
   159    163         BEGIN
   160    164         INSERT INTO rlog VALUES ( (SELECT coalesce(max(idx),0) + 1 FROM rlog), 
   161    165   	  0, 0,
   162    166   	  (SELECT sum(a) FROM tbl), (SELECT sum(b) FROM tbl), 
   163    167   	  new.a, new.b);
   164    168       END;
   165    169     }
   166         -  do_test trigger2-1.3.$ii {
          170  +  do_test trigger2-1.$ii.3 {
   167    171       execsql {
   168    172   
   169    173         CREATE TABLE other_tbl(a, b);
   170    174         INSERT INTO other_tbl VALUES(1, 2);
   171    175         INSERT INTO other_tbl VALUES(3, 4);
   172    176         -- INSERT INTO tbl SELECT * FROM other_tbl;
   173    177         INSERT INTO tbl VALUES(5, 6);
   174    178         DROP TABLE other_tbl;
   175    179   
   176    180         SELECT * FROM rlog;
   177    181       }
   178    182     } [list 1 0 0 0 0 5 6 \
   179    183             2 0 0 5 6 5 6 ]
          184  +
          185  +  do_test trigger2-1.$ii.4 {
          186  +    execsql {
          187  +      PRAGMA integrity_check;
          188  +    }
          189  +  } {ok ok}
   180    190   }
   181    191   catchsql {
   182    192     DROP TABLE rlog;
   183    193     DROP TABLE clog;
   184    194     DROP TABLE tbl;
   185    195     DROP TABLE other_tbl;
   186    196   }
   187    197   
   188    198   # 2.
   189    199   set ii 0
   190         -foreach tr_program [ list \
   191         -   {UPDATE tbl SET b = old.b;} \
   192         -  {INSERT INTO log VALUES(new.c, 2, 3);} \
   193         -  {DELETE FROM log WHERE a = 1;} \
          200  +foreach tr_program {
          201  +  {UPDATE tbl SET b = old.b;}
          202  +  {INSERT INTO log VALUES(new.c, 2, 3);}
          203  +  {DELETE FROM log WHERE a = 1;}
   194    204     {INSERT INTO tbl VALUES(500, new.b * 10, 700); 
   195    205       UPDATE tbl SET c = old.c; 
   196         -    DELETE FROM log;} \
          206  +    DELETE FROM log;}
   197    207     {INSERT INTO log select * from tbl;} 
   198         -   ] \
   199         -{
          208  +} {
   200    209     foreach test_varset [ list \
   201    210       {
   202    211         set statement {UPDATE tbl SET c = 10 WHERE a = 1;} 
   203    212         set prep      {INSERT INTO tbl VALUES(1, 2, 3);}
   204    213         set newC 10
   205    214         set newB 2
   206    215         set newA 1
................................................................................
   258    267       regsub -all old\.b $tr_program_cooked $oldB tr_program_cooked 
   259    268       regsub -all old\.c $tr_program_cooked $oldC tr_program_cooked 
   260    269   
   261    270       catchsql {
   262    271         DROP TABLE tbl;
   263    272         DROP TABLE log;
   264    273       }
          274  +
   265    275       execsql {
   266    276         CREATE TABLE tbl(a PRIMARY KEY, b, c);
   267    277         CREATE TABLE log(a, b, c);
   268    278       }
   269    279   
   270    280       set query {SELECT * FROM tbl; SELECT * FROM log;}
   271         -    set prep "$prep; INSERT INTO log VALUES(1, 2, 3); INSERT INTO log VALUES(10, 20, 30);"
          281  +    set prep "$prep; INSERT INTO log VALUES(1, 2, 3);\
          282  +             INSERT INTO log VALUES(10, 20, 30);"
   272    283   
   273    284   # Check execution of BEFORE programs:
   274    285   
   275    286       set before_data [ execsql "$prep $tr_program_cooked $statement $query" ]
   276    287   
   277    288       execsql "DELETE FROM tbl; DELETE FROM log; $prep";
   278         -    execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6] ON tbl BEGIN $tr_program_fixed END;"
          289  +    execsql "CREATE TRIGGER the_trigger BEFORE [string range $statement 0 6]\
          290  +             ON tbl BEGIN $tr_program_fixed END;"
   279    291   
   280         -    do_test trigger2-2-$ii-before "execsql {$statement $query}" $before_data
          292  +    do_test trigger2-2.$ii-before "execsql {$statement $query}" $before_data
   281    293   
   282    294       execsql "DROP TRIGGER the_trigger;"
   283    295       execsql "DELETE FROM tbl; DELETE FROM log;"
   284    296   
   285    297   # Check execution of AFTER programs
   286    298       set after_data [ execsql "$prep $statement $tr_program_cooked $query" ]
   287    299   
   288    300       execsql "DELETE FROM tbl; DELETE FROM log; $prep";
          301  +    execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6]\
          302  +             ON tbl BEGIN $tr_program_fixed END;"
   289    303   
   290         -    execsql "CREATE TRIGGER the_trigger AFTER [string range $statement 0 6] ON tbl BEGIN $tr_program_fixed END;"
   291         -
   292         -    do_test trigger2-2-$ii-after "execsql {$statement $query}" $after_data
          304  +    do_test trigger2-2.$ii-after "execsql {$statement $query}" $after_data
   293    305       execsql "DROP TRIGGER the_trigger;"
          306  +
          307  +    do_test trigger2-2.$ii-integrity {
          308  +      execsql {
          309  +        PRAGMA integrity_check;
          310  +      }
          311  +    } {ok ok}
          312  +
   294    313     }
   295    314   }
   296    315   catchsql {
   297    316     DROP TABLE tbl;
   298    317     DROP TABLE log;
   299    318   }
   300    319   
................................................................................
   357    376       UPDATE log SET a = 0;
   358    377     }
   359    378   } {1 0 1}
   360    379   execsql {
   361    380     DROP TABLE tbl;
   362    381     DROP TABLE log;
   363    382   }
          383  +do_test trigger2-3.3 {
          384  +  execsql {
          385  +    PRAGMA integrity_check;
          386  +  }
          387  +} {ok ok}
   364    388   
   365    389   # Simple cascaded trigger
   366    390   execsql {
   367    391     CREATE TABLE tblA(a, b);
   368    392     CREATE TABLE tblB(a, b);
   369    393     CREATE TABLE tblC(a, b);
   370    394   
................................................................................
   581    605   	0, 0, 0, 0, new.a, new.b, new.c, new.d);
   582    606     END;
   583    607      CREATE TRIGGER after_insert INSTEAD OF INSERT ON abcd BEGIN
   584    608       INSERT INTO tlog VALUES(NULL, 
   585    609   	0, 0, 0, 0, new.a, new.b, new.c, new.d);
   586    610      END;
   587    611     }
   588         -} {}
          612  +} {};
   589    613   
   590         -#explain {delete from abcd where a=1;}
   591    614   do_test trigger2-7.2 {
   592    615     execsql {
   593    616       UPDATE abcd SET a = 100, b = 5*5 WHERE a = 1;
   594    617       DELETE FROM abcd WHERE a = 1;
   595    618       INSERT INTO abcd VALUES(10, 20, 30, 40);
   596    619       SELECT * FROM tlog;
   597    620     }
................................................................................
   685    708       END;
   686    709       DELETE FROM v1log;
   687    710       UPDATE v1 SET x=x+100, y=y+200, z=z+300;
   688    711       SELECT * FROM v1log;
   689    712     }
   690    713   } {3 103 5 205 4 304 9 109 11 211 10 310}
   691    714   
          715  +do_test trigger2-9.9 {
          716  +  execsql {PRAGMA integrity_check}
          717  +} {ok ok}
   692    718   
   693    719   finish_test