/ Check-in [43fe7fc1]
Login

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

Overview
Comment:When an automatic re-prepare occurs, take care not to reset the internal schema symbol table. Ticket #2156. This change also includes some debugging enhancements. (CVS 3578)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 43fe7fc1c38f8d9b3c1346cb1d890c2e25cefe15
User & Date: drh 2007-01-09 14:01:13
Context
2007-01-09
14:37
Do not use the symbol "interrupt" since that is a reserved word in OpenWatcom. Ticket #2159. (CVS 3579) check-in: 9960ba57 user: drh tags: trunk
14:01
When an automatic re-prepare occurs, take care not to reset the internal schema symbol table. Ticket #2156. This change also includes some debugging enhancements. (CVS 3578) check-in: 43fe7fc1 user: drh tags: trunk
2007-01-08
22:40
Additional tests of sqlite3_prepare_v2. (CVS 3577) check-in: b0650aa6 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/prepare.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains the implementation of the sqlite3_prepare()
    13     13   ** interface, and routines that contribute to loading the database schema
    14     14   ** from disk.
    15     15   **
    16         -** $Id: prepare.c,v 1.42 2007/01/08 21:07:18 drh Exp $
           16  +** $Id: prepare.c,v 1.43 2007/01/09 14:01:13 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "os.h"
    20     20   #include <ctype.h>
    21     21   
    22     22   /*
    23     23   ** Fill the InitData structure with an error message that indicates
................................................................................
   573    573       assert( pNew==0 );
   574    574       return 0;
   575    575     }else{
   576    576       assert( pNew!=0 );
   577    577     }
   578    578     sqlite3VdbeSwap(pNew, p);
   579    579     sqlite3_transfer_bindings((sqlite3_stmt*)pNew, (sqlite3_stmt*)p);
   580         -  sqlite3_finalize((sqlite3_stmt*)pNew);
          580  +  sqlite3VdbeResetStepResult(pNew);
          581  +  sqlite3VdbeFinalize(pNew);
   581    582     return 1;
   582    583   }
   583    584   
   584    585   
   585    586   /*
   586    587   ** Two versions of the official API.  Legacy and new use.  In the legacy
   587    588   ** version, the original SQL text is not saved in the prepared statement

Changes to src/test1.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing all sorts of SQLite interfaces.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16         -** $Id: test1.c,v 1.226 2007/01/03 23:37:28 drh Exp $
           16  +** $Id: test1.c,v 1.227 2007/01/09 14:01:13 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "tcl.h"
    20     20   #include "os.h"
    21     21   #include <stdlib.h>
    22     22   #include <string.h>
    23     23   
................................................................................
   755    755       sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
   756    756           countStep,countFinalize);
   757    757     }
   758    758     if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
   759    759     return TCL_OK;
   760    760   }
   761    761   
          762  +
          763  +/*
          764  +** Usage:  printf TEXT
          765  +**
          766  +** Send output to printf.  Use this rather than puts to merge the output
          767  +** in the correct sequence with debugging printfs inserted into C code.
          768  +** Puts uses a separate buffer and debugging statements will be out of
          769  +** sequence if it is used.
          770  +*/
          771  +static int test_printf(
          772  +  void *NotUsed,
          773  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
          774  +  int argc,              /* Number of arguments */
          775  +  char **argv            /* Text of each argument */
          776  +){
          777  +  if( argc!=2 ){
          778  +    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
          779  +       " TEXT\"", 0);
          780  +    return TCL_ERROR;
          781  +  }
          782  +  printf("%s\n", argv[1]);
          783  +  return TCL_OK;
          784  +}
          785  +
   762    786   
   763    787   
   764    788   /*
   765    789   ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
   766    790   **
   767    791   ** Call mprintf with three integer arguments
   768    792   */
................................................................................
  4031   4055        { "sqlite_set_magic",              (Tcl_CmdProc*)sqlite_set_magic      },
  4032   4056        { "sqlite3_interrupt",             (Tcl_CmdProc*)test_interrupt        },
  4033   4057        { "sqlite_delete_function",        (Tcl_CmdProc*)delete_function       },
  4034   4058        { "sqlite_delete_collation",       (Tcl_CmdProc*)delete_collation      },
  4035   4059        { "sqlite3_get_autocommit",        (Tcl_CmdProc*)get_autocommit        },
  4036   4060        { "sqlite3_stack_used",            (Tcl_CmdProc*)test_stack_used       },
  4037   4061        { "sqlite3_busy_timeout",          (Tcl_CmdProc*)test_busy_timeout     },
         4062  +     { "printf",                        (Tcl_CmdProc*)test_printf           },
  4038   4063     };
  4039   4064     static struct {
  4040   4065        char *zName;
  4041   4066        Tcl_ObjCmdProc *xProc;
  4042   4067        void *clientData;
  4043   4068     } aObjCmd[] = {
  4044   4069        { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.584 2007/01/05 16:39:43 drh Exp $
           46  +** $Id: vdbe.c,v 1.585 2007/01/09 14:01:14 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
   450    450     if( p->popStack ){
   451    451       popStack(&pTos, p->popStack);
   452    452       p->popStack = 0;
   453    453     }
   454    454     p->resOnStack = 0;
   455    455     db->busyHandler.nBusy = 0;
   456    456     CHECK_FOR_INTERRUPT;
          457  +#ifdef SQLITE_DEBUG
          458  +  if( (p->db->flags & SQLITE_VdbeListing)!=0
          459  +    || sqlite3OsFileExists("vdbe_explain")
          460  +  ){
          461  +    int i;
          462  +    printf("VDBE Program Listing:\n");
          463  +    sqlite3VdbePrintSql(p);
          464  +    for(i=0; i<p->nOp; i++){
          465  +      sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
          466  +    }
          467  +  }
          468  +  if( sqlite3OsFileExists("vdbe_trace") ){
          469  +    p->trace = stdout;
          470  +  }
          471  +#endif
   457    472     for(pc=p->pc; rc==SQLITE_OK; pc++){
   458    473       assert( pc>=0 && pc<p->nOp );
   459    474       assert( pTos<=&p->aStack[pc] );
   460    475       if( sqlite3MallocFailed() ) goto no_mem;
   461    476   #ifdef VDBE_PROFILE
   462    477       origPc = pc;
   463    478       start = hwtime();
................................................................................
  4000   4015       pTos->flags = MEM_Int;
  4001   4016     }else{
  4002   4017       pTos->flags = MEM_Null;
  4003   4018     }
  4004   4019     break;
  4005   4020   }
  4006   4021   
  4007         -/* Opcode: ParseSchema P1 * P3
         4022  +/* Opcode: ParseSchema P1 P2 P3
  4008   4023   **
  4009   4024   ** Read and parse all entries from the SQLITE_MASTER table of database P1
  4010         -** that match the WHERE clause P3.
         4025  +** that match the WHERE clause P3.  P2 is the "force" flag.   Always do
         4026  +** the parsing if P2 is true.  If P2 is false, then this routine is a
         4027  +** no-op if the schema is not currently loaded.  In other words, if P2
         4028  +** is false, the SQLITE_MASTER table is only parsed if the rest of the
         4029  +** schema is already loaded into the symbol table.
  4011   4030   **
  4012   4031   ** This opcode invokes the parser to create a new virtual machine,
  4013   4032   ** then runs the new virtual machine.  It is thus a reentrant opcode.
  4014   4033   */
  4015   4034   case OP_ParseSchema: {        /* no-push */
  4016   4035     char *zSql;
  4017   4036     int iDb = pOp->p1;
  4018   4037     const char *zMaster;
  4019   4038     InitData initData;
  4020   4039   
  4021   4040     assert( iDb>=0 && iDb<db->nDb );
  4022         -  if( !DbHasProperty(db, iDb, DB_SchemaLoaded) ) break;
         4041  +  if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
         4042  +    break;
         4043  +  }
  4023   4044     zMaster = SCHEMA_TABLE(iDb);
  4024   4045     initData.db = db;
  4025   4046     initData.iDb = pOp->p1;
  4026   4047     initData.pzErrMsg = &p->zErrMsg;
  4027   4048     zSql = sqlite3MPrintf(
  4028   4049        "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
  4029   4050        db->aDb[iDb].zName, zMaster, pOp->p3);

Changes to src/vdbe.h.

    11     11   *************************************************************************
    12     12   ** Header file for the Virtual DataBase Engine (VDBE)
    13     13   **
    14     14   ** This header defines the interface to the virtual database engine
    15     15   ** or VDBE.  The VDBE implements an abstract machine that runs a
    16     16   ** simple program to access and modify the underlying database.
    17     17   **
    18         -** $Id: vdbe.h,v 1.107 2007/01/08 21:07:18 drh Exp $
           18  +** $Id: vdbe.h,v 1.108 2007/01/09 14:01:14 drh Exp $
    19     19   */
    20     20   #ifndef _SQLITE_VDBE_H_
    21     21   #define _SQLITE_VDBE_H_
    22     22   #include <stdio.h>
    23     23   
    24     24   /*
    25     25   ** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
   125    125   int sqlite3VdbeMakeLabel(Vdbe*);
   126    126   void sqlite3VdbeDelete(Vdbe*);
   127    127   void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
   128    128   int sqlite3VdbeFinalize(Vdbe*);
   129    129   void sqlite3VdbeResolveLabel(Vdbe*, int);
   130    130   int sqlite3VdbeCurrentAddr(Vdbe*);
   131    131   void sqlite3VdbeTrace(Vdbe*,FILE*);
          132  +void sqlite3VdbeResetStepResult(Vdbe*);
   132    133   int sqlite3VdbeReset(Vdbe*);
   133    134   int sqliteVdbeSetVariables(Vdbe*,int,const char**);
   134    135   void sqlite3VdbeSetNumCols(Vdbe*,int);
   135    136   int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
   136    137   void sqlite3VdbeCountChanges(Vdbe*);
   137    138   sqlite3 *sqlite3VdbeDb(Vdbe*);
   138    139   void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);

Changes to src/vdbeaux.c.

   848    848         }
   849    849       }
   850    850     }
   851    851     for(n=0; n<p->nMem; n++){
   852    852       p->aMem[n].flags = MEM_Null;
   853    853     }
   854    854   
   855         -#ifdef SQLITE_DEBUG
   856         -  if( (p->db->flags & SQLITE_VdbeListing)!=0
   857         -    || sqlite3OsFileExists("vdbe_explain")
   858         -  ){
   859         -    int i;
   860         -    printf("VDBE Program Listing:\n");
   861         -    sqlite3VdbePrintSql(p);
   862         -    for(i=0; i<p->nOp; i++){
   863         -      sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
   864         -    }
   865         -  }
   866         -  if( sqlite3OsFileExists("vdbe_trace") ){
   867         -    p->trace = stdout;
   868         -  }
   869         -#endif
   870    855     p->pTos = &p->aStack[-1];
   871    856     p->pc = -1;
   872    857     p->rc = SQLITE_OK;
   873    858     p->uniqueCnt = 0;
   874    859     p->returnDepth = 0;
   875    860     p->errorAction = OE_Abort;
   876    861     p->popStack =  0;
................................................................................
  1459   1444       db->activeVdbeCnt--;
  1460   1445     }
  1461   1446     p->magic = VDBE_MAGIC_HALT;
  1462   1447     checkActiveVdbeCnt(db);
  1463   1448   
  1464   1449     return SQLITE_OK;
  1465   1450   }
         1451  +
         1452  +/*
         1453  +** Each VDBE holds the result of the most recent sqlite3_step() call
         1454  +** in p->rc.  This routine sets that result back to SQLITE_OK.
         1455  +*/
         1456  +void sqlite3VdbeResetStepResult(Vdbe *p){
         1457  +  p->rc = SQLITE_OK;
         1458  +}
  1466   1459   
  1467   1460   /*
  1468   1461   ** Clean up a VDBE after execution but do not delete the VDBE just yet.
  1469   1462   ** Write any error messages into *pzErrMsg.  Return the result code.
  1470   1463   **
  1471   1464   ** After this routine is run, the VDBE should be ready to be executed
  1472   1465   ** again.

Changes to src/vtab.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 help implement virtual tables.
    13     13   **
    14         -** $Id: vtab.c,v 1.38 2007/01/05 14:41:07 drh Exp $
           14  +** $Id: vtab.c,v 1.39 2007/01/09 14:01:14 drh Exp $
    15     15   */
    16     16   #ifndef SQLITE_OMIT_VIRTUALTABLE
    17     17   #include "sqliteInt.h"
    18     18   
    19     19   /*
    20     20   ** External API function used to create a new virtual-table module.
    21     21   */
................................................................................
   226    226       );
   227    227       sqliteFree(zStmt);
   228    228       v = sqlite3GetVdbe(pParse);
   229    229       sqlite3ChangeCookie(db, v, iDb);
   230    230   
   231    231       sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
   232    232       zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
   233         -    sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
          233  +    sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
   234    234       sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
   235    235     }
   236    236   
   237    237     /* If we are rereading the sqlite_master table create the in-memory
   238    238     ** record of the table. If the module has already been registered,
   239    239     ** also call the xConnect method here.
   240    240     */

Changes to test/vtab1.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is creating and dropping virtual tables.
    13     13   #
    14         -# $Id: vtab1.test,v 1.38 2006/09/16 21:45:14 drh Exp $
           14  +# $Id: vtab1.test,v 1.39 2007/01/09 14:01:14 drh Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   ifcapable !vtab||!schema_pragmas {
    20     20     finish_test
    21     21     return
................................................................................
    91     91     }
    92     92   } {1 {vtable constructor failed: t1}}
    93     93   do_test vtab1-1.6 {
    94     94     execsql {
    95     95       SELECT name FROM sqlite_master ORDER BY 1
    96     96     }
    97     97   } {}
           98  +
           99  +# Ticket #2156.  Using the sqlite3_prepare_v2() API, make sure that
          100  +# a CREATE VIRTUAL TABLE statement can be used multiple times.
          101  +#
          102  +do_test vtab1-1.2152.1 {
          103  +  set DB [sqlite3_connection_pointer db]
          104  +  set sql {CREATE VIRTUAL TABLE t2152a USING echo(t2152b)}
          105  +  set STMT [sqlite3_prepare_v2 $DB $sql -1 TAIL]
          106  +  sqlite3_step $STMT
          107  +} SQLITE_ERROR
          108  +do_test vtab-1.2152.2 {
          109  +  sqlite3_reset $STMT
          110  +  sqlite3_step $STMT
          111  +} SQLITE_ERROR
          112  +do_test vtab-1.2152.3 {
          113  +  sqlite3_reset $STMT
          114  +  db eval {CREATE TABLE t2152b(x,y)}
          115  +  sqlite3_step $STMT
          116  +} SQLITE_DONE
          117  +do_test vtab-1.2152.4 {
          118  +  sqlite3_finalize $STMT
          119  +  db eval {DROP TABLE t2152a; DROP TABLE t2152b}
          120  +} {}
    98    121   
    99    122   # Test to make sure nothing goes wrong and no memory is leaked if we 
   100    123   # select an illegal table-name (i.e a reserved name or the name of a
   101    124   # table that already exists).
   102    125   #
   103    126   do_test vtab1-1.7 {
   104    127     catchsql {