]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Allow ALTER TABLE on virtual tables. (CVS 4142)
authordanielk1977 <danielk1977@noemail.net>
Wed, 27 Jun 2007 15:53:34 +0000 (15:53 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Wed, 27 Jun 2007 15:53:34 +0000 (15:53 +0000)
FossilOrigin-Name: 37d1f9f37ea9d2e8a4dbe0ec67c0d6eb7fcc5f3f

manifest
manifest.uuid
src/alter.c
src/sqlite.h.in
src/test8.c
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
test/vtab1.test
test/vtab5.test
test/vtab_alter.test [new file with mode: 0644]

index 76bfe06db7014c3d572f499df26dfc7a5b573261..ca5db471c4df88db690ec840c803d0c008fea91b 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C respect\s$LDFLAGS\sfrom\senv/configure\s(CVS\s4141)
-D 2007-06-27T15:01:46
+C Allow\sALTER\sTABLE\son\svirtual\stables.\s(CVS\s4142)
+D 2007-06-27T15:53:35
 F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -62,7 +62,7 @@ F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
-F src/alter.c 1b1deeb97446ed87f2fa17a3eb6236548841a348
+F src/alter.c 3402b657de80c242b0382f768df273505f8178cc
 F src/analyze.c 8d345472e0f4e44fc88f5cf489c16dcb77904525
 F src/attach.c ba628db0c2b6a362f036d017bf1196cdfe4ebb37
 F src/auth.c 5ea90bc93dfea46e9fe4bf531e14c7cd98219ecb
@@ -107,7 +107,7 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
 F src/select.c e363327d0eba8d758ab00055de962a3bb0bc213e
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c 4b0fc3c76a9f23a1c963e01703c0fbbca1b5c34d
-F src/sqlite.h.in a3c5d9f8566efe43589b428bd4f7f0f77766e9ae
+F src/sqlite.h.in bbcc5481af9f40ce5762c323cf555581a025f3de
 F src/sqlite3ext.h 95575e0d175a0271fe2c3232c0d11e8720ed6887
 F src/sqliteInt.h 81183ae71162818bf60478e738ff68604128bb06
 F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
@@ -120,7 +120,7 @@ F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
 F src/test5.c c40a4cf43266c1c6da7bcb737d294304a177e6cc
 F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94
 F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
-F src/test8.c c3c4aeea4e3d70966306d6eca1b77ce7eee2f059
+F src/test8.c 4f0a8624028588e083731c11927f5b2a07184618
 F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
 F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6
 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
@@ -138,11 +138,11 @@ F src/update.c 6b10becb6235ea314ed245fbfbf8b38755e3166e
 F src/utf.c 01b2aba02b10d12903e9e1ff897215c9faf6b662
 F src/util.c 9e81d417fc60bd2fe156f8f2317aa4845bc6cc90
 F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
-F src/vdbe.c b776b68ad926974c72296145d1282ff6e956b4ff
+F src/vdbe.c 32f39e9cab8a6ef64ad392711396d65ae89fc790
 F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
-F src/vdbeInt.h 7d2bf163d6d4e815724a457f2216dd8e38c3955c
+F src/vdbeInt.h c3514903cad9e36d6b3242be20261351d09db56c
 F src/vdbeapi.c 7930b9a188ab385287ca3eb3840af7225cb43549
-F src/vdbeaux.c c580d3605edc2c24ba9bd26fa7aa8b4fff10daa4
+F src/vdbeaux.c ca1d673fd5e45fe9ba994391b11568c48a7e1b59
 F src/vdbeblob.c bb30b3e387c35ba869949494b2736aff97159470
 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
 F src/vdbemem.c ca4d3994507cb0a9504820293af69f5c778b4abd
@@ -420,16 +420,17 @@ F test/vacuum.test cf839fc3ff24d601057319bbb5c700ce9c8e0fb0
 F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c
 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
 F test/view.test 852bd4101e6d171c46ad682eb5c5faf662b2eba4
-F test/vtab1.test bf129928444f1fe3d992894f6e0b4c6d4a534d49
+F test/vtab1.test e740d4761b9125e6e541c62d199a3822f54614ff
 F test/vtab2.test 94bb3bf691ac10e34cf7dad46b1cf94b861d513c
 F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587
 F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87
-F test/vtab5.test 9fb8f335651afe8f870011e2f68e5b00c5ad03cd
+F test/vtab5.test 26bc7a0a52c5c2bcfa849ba327f8a0d4abccdb23
 F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392
 F test/vtab7.test 5f9ef9fb84733e928d5d0267c821072561b198d5
 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
 F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936
+F test/vtab_alter.test 87617789086fd1767aa071e7805f1af7e1dac144
 F test/vtab_err.test 9eabf98b26838fed8bac4aea986580be0a2bd52e
 F test/vtab_shared.test d631d1f820c38c18939d53aab1fc35db5f0a8094
 F test/where.test 1bcde8984c63747ac6d6bafcacd20fd6e8a223de
@@ -516,7 +517,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 850822e2904bc340afd0b7535ef51fbdf9e1f486
-R 1afeab26f16295155c75ffe8baa66b82
-U vapier
-Z 83aaaa53ff941923277b0d6c2cfa7d3d
+P 9c13fc0f4bf22c8e05b11ef5feaaf07d8a8b3f01
+R 53f2a209b5d25f95ed550b0d365211d1
+U danielk1977
+Z ba48bbb530071e692ea4d7c53d55d66a
index 9c8528d181e2b8c485154e65f17462eeaee38448..94cfb98e2cd9a860054325deb71e78f8bd3abac0 100644 (file)
@@ -1 +1 @@
-9c13fc0f4bf22c8e05b11ef5feaaf07d8a8b3f01
\ No newline at end of file
+37d1f9f37ea9d2e8a4dbe0ec67c0d6eb7fcc5f3f
\ No newline at end of file
index ddcedddcbb07bc5858e95b5beac582bff407e422..d93da8f299b40a98bbc13c8ac8219b6a54c4c2f6 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that used to generate VDBE code
 ** that implements the ALTER TABLE command.
 **
-** $Id: alter.c,v 1.25 2007/05/15 14:34:32 drh Exp $
+** $Id: alter.c,v 1.26 2007/06/27 15:53:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -53,7 +53,7 @@ static void renameTableFunc(
 
   /* The principle used to locate the table name in the CREATE TABLE 
   ** statement is that the table name is the first token that is immediatedly
-  ** followed by a left parenthesis - TK_LP.
+  ** followed by a left parenthesis - TK_LP - or "USING" TK_USING.
   */
   if( zSql ){
     do {
@@ -74,7 +74,7 @@ static void renameTableFunc(
         len = sqlite3GetToken(zCsr, &token);
       } while( token==TK_SPACE );
       assert( len>0 );
-    } while( token!=TK_LP );
+    } while( token!=TK_LP && token!=TK_USING );
 
     zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, 
        zTableName, tname.z+tname.n);
@@ -279,18 +279,13 @@ void sqlite3AlterRenameTable(
 #ifndef SQLITE_OMIT_TRIGGER
   char *zWhere = 0;         /* Where clause to locate temp triggers */
 #endif
+  int isVirtualRename = 0;  /* True if this is a v-table with an xRename() */
   
   if( sqlite3MallocFailed() ) goto exit_rename_table;
   assert( pSrc->nSrc==1 );
 
   pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
   if( !pTab ) goto exit_rename_table;
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-  if( IsVirtual(pTab) ){
-    sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
-    goto exit_rename_table;
-  }
-#endif
   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
   zDb = db->aDb[iDb].zName;
 
@@ -325,17 +320,36 @@ void sqlite3AlterRenameTable(
   }
 #endif
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){
+    isVirtualRename = 1;
+  }
+#endif
+
   /* Begin a transaction and code the VerifyCookie for database iDb. 
   ** Then modify the schema cookie (since the ALTER TABLE modifies the
-  ** schema).
+  ** schema). Open a statement transaction if the table is a virtual
+  ** table.
   */
   v = sqlite3GetVdbe(pParse);
   if( v==0 ){
     goto exit_rename_table;
   }
-  sqlite3BeginWriteOperation(pParse, 0, iDb);
+  sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
   sqlite3ChangeCookie(db, v, iDb);
 
+  /* If this is a virtual table, invoke the xRename() function if
+  ** one is defined. The xRename() callback will modify the names
+  ** of any resources used by the v-table implementation (including other
+  ** SQLite tables) that are identified by the name of the virtual table.
+  */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  if( isVirtualRename ){
+    sqlite3VdbeOp3(v, OP_String8, 0, 0, zName, 0);
+    sqlite3VdbeOp3(v, OP_VRename, 0, 0, (const char*)pTab->pVtab, P3_VTAB);
+  }
+#endif
+
   /* figure out how many UTF-8 characters are in zName */
   zTabName = pTab->zName;
   nTabName = sqlite3Utf8CharLen(zTabName, -1);
index f8e02c5dc81b34271e3bcf4cc7ed5ab6b962fef4..7bc4feb61bc050792448754a1b6d97172481644e 100644 (file)
@@ -30,7 +30,7 @@
 ** the version number) and changes its name to "sqlite3.h" as
 ** part of the build process.
 **
-** @(#) $Id: sqlite.h.in,v 1.216 2007/06/27 10:21:39 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.217 2007/06/27 15:53:35 danielk1977 Exp $
 */
 #ifndef _SQLITE3_H_
 #define _SQLITE3_H_
@@ -2403,6 +2403,8 @@ struct sqlite3_module {
   int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
                        void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
                        void **ppArg);
+
+  int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
 };
 
 /*
index 1267a1ec581baf712ffce61d6e419a72a696efde..1c19c563cd672cbd525f8425604c0f315d5e8e4c 100644 (file)
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test8.c,v 1.46 2007/04/18 17:04:01 danielk1977 Exp $
+** $Id: test8.c,v 1.47 2007/06/27 15:53:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -61,6 +61,8 @@ struct echo_vtab {
   Tcl_Interp *interp;     /* Tcl interpreter containing debug variables */
   sqlite3 *db;            /* Database connection */
 
+  int isPattern;
+  char *zThis;            /* Name of the echo table */
   char *zTableName;       /* Name of the real table */
   char *zLogName;         /* Name of the log table */
   int nCol;               /* Number of columns in the real table */
@@ -74,6 +76,46 @@ struct echo_cursor {
   sqlite3_stmt *pStmt;
 };
 
+/*
+** Convert an SQL-style quoted string into a normal string by removing
+** the quote characters.  The conversion is done in-place.  If the
+** input does not begin with a quote character, then this routine
+** is a no-op.
+**
+** Examples:
+**
+**     "abc"   becomes   abc
+**     'xyz'   becomes   xyz
+**     [pqr]   becomes   pqr
+**     `mno`   becomes   mno
+*/
+static void dequoteString(char *z){
+  int quote;
+  int i, j;
+  if( z==0 ) return;
+  quote = z[0];
+  switch( quote ){
+    case '\'':  break;
+    case '"':   break;
+    case '`':   break;                /* For MySQL compatibility */
+    case '[':   quote = ']';  break;  /* For MS SqlServer compatibility */
+    default:    return;
+  }
+  for(i=1, j=0; z[i]; i++){
+    if( z[i]==quote ){
+      if( z[i+1]==quote ){
+        z[j++] = quote;
+        i++;
+      }else{
+        z[j++] = 0;
+        break;
+      }
+    }else{
+      z[j++] = z[i];
+    }
+  }
+}
+
 /*
 ** Retrieve the column names for the table named zTab via database
 ** connection db. SQLITE_OK is returned on success, or an sqlite error
@@ -256,18 +298,16 @@ static void appendToEchoModule(Tcl_Interp *interp, const char *zArg){
 */
 static int echoDeclareVtab(
   echo_vtab *pVtab, 
-  sqlite3 *db, 
-  int argc, 
-  const char *const*argv
+  sqlite3 *db 
 ){
   int rc = SQLITE_OK;
 
-  if( argc>=4 ){
+  if( pVtab->zTableName ){
     sqlite3_stmt *pStmt = 0;
     sqlite3_prepare(db, 
         "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
         -1, &pStmt, 0);
-    sqlite3_bind_text(pStmt, 1, argv[3], -1, 0);
+    sqlite3_bind_text(pStmt, 1, pVtab->zTableName, -1, 0);
     if( sqlite3_step(pStmt)==SQLITE_ROW ){
       int rc2;
       const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0);
@@ -282,12 +322,11 @@ static int echoDeclareVtab(
         rc = SQLITE_ERROR;
       }
     }
-
     if( rc==SQLITE_OK ){
-      rc = getColumnNames(db, argv[3], &pVtab->aCol, &pVtab->nCol);
+      rc = getColumnNames(db, pVtab->zTableName, &pVtab->aCol, &pVtab->nCol);
     }
     if( rc==SQLITE_OK ){
-      rc = getIndexArray(db, argv[3], pVtab->nCol, &pVtab->aIndex);
+      rc = getIndexArray(db, pVtab->zTableName, pVtab->nCol, &pVtab->aIndex);
     }
   }
 
@@ -302,6 +341,7 @@ static int echoDestructor(sqlite3_vtab *pVtab){
   echo_vtab *p = (echo_vtab*)pVtab;
   sqliteFree(p->aIndex);
   sqliteFree(p->aCol);
+  sqliteFree(p->zThis);
   sqliteFree(p->zTableName);
   sqliteFree(p->zLogName);
   sqliteFree(p);
@@ -331,13 +371,29 @@ static int echoConstructor(
   pVtab->interp = (Tcl_Interp *)pAux;
   pVtab->db = db;
 
-  /* Allocate echo_vtab.zTableName */
-  pVtab->zTableName = sqlite3MPrintf("%s", argv[3]);
-  if( !pVtab->zTableName ){
+  /* Allocate echo_vtab.zThis */
+  pVtab->zThis = sqlite3MPrintf("%s", argv[2]);
+  if( !pVtab->zThis ){
     echoDestructor((sqlite3_vtab *)pVtab);
     return SQLITE_NOMEM;
   }
 
+  /* Allocate echo_vtab.zTableName */
+  if( argc>3 ){
+    pVtab->zTableName = sqlite3MPrintf("%s", argv[3]);
+    dequoteString(pVtab->zTableName);
+    if( pVtab->zTableName && pVtab->zTableName[0]=='*' ){
+      char *z = sqlite3MPrintf("%s%s", argv[2], &(pVtab->zTableName[1]));
+      sqliteFree(pVtab->zTableName);
+      pVtab->zTableName = z;
+      pVtab->isPattern = 1;
+    }
+    if( !pVtab->zTableName ){
+      echoDestructor((sqlite3_vtab *)pVtab);
+      return SQLITE_NOMEM;
+    }
+  }
+
   /* Log the arguments to this function to Tcl var ::echo_module */
   for(i=0; i<argc; i++){
     appendToEchoModule(pVtab->interp, argv[i]);
@@ -347,7 +403,7 @@ static int echoConstructor(
   ** structure. If an error occurs, delete the sqlite3_vtab structure and
   ** return an error code.
   */
-  if( echoDeclareVtab(pVtab, db, argc, argv) ){
+  if( echoDeclareVtab(pVtab, db) ){
     echoDestructor((sqlite3_vtab *)pVtab);
     return SQLITE_ERROR;
   }
@@ -975,6 +1031,21 @@ static int echoFindFunction(
   return 1;
 }
 
+static int echoRename(sqlite3_vtab *vtab, const char *zNewName){
+  int rc = SQLITE_OK;
+  echo_vtab *p = (echo_vtab *)vtab;
+
+  if( p->isPattern ){
+    int nThis = strlen(p->zThis);
+    char *zSql = sqlite3MPrintf("ALTER TABLE %s RENAME TO %s%s", 
+        p->zTableName, zNewName, &p->zTableName[nThis]
+    );
+    rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
+  }
+
+  return rc;
+}
+
 /*
 ** A virtual table module that merely "echos" the contents of another
 ** table (like an SQL VIEW).
@@ -999,6 +1070,7 @@ static sqlite3_module echoModule = {
   echoCommit,                /* xCommit - commit transaction */
   echoRollback,              /* xRollback - rollback transaction */
   echoFindFunction,          /* xFindFunction - function overloading */
+  echoRename,                /* xRename - rename the table */
 };
 
 /*
index 688dcd7761f30fe5c0248d9e28eefc013a769b11..a090b22eba56a506760e30f2c4c5048e2973d7a2 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.634 2007/06/26 12:52:34 danielk1977 Exp $
+** $Id: vdbe.c,v 1.635 2007/06/27 15:53:35 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -2408,6 +2408,7 @@ case OP_Statement: {       /* no-push */
     assert( sqlite3BtreeIsInTrans(pBt) );
     if( !sqlite3BtreeIsInStmt(pBt) ){
       rc = sqlite3BtreeBeginStmt(pBt);
+      p->openedStatement = 1;
     }
   }
   break;
@@ -4999,6 +5000,30 @@ case OP_VNext: {   /* no-push */
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VRename * * P3
+**
+** P3 is a pointer to a virtual table object, an sqlite3_vtab structure.
+** This opcode invokes the corresponding xRename method. The value
+** on the top of the stack is popped and passed as the zName argument
+** to the xRename method.
+*/
+case OP_VRename: {   /* no-push */
+  sqlite3_vtab *pVtab = (sqlite3_vtab *)(pOp->p3);
+  assert( pVtab->pModule->xRename );
+
+  Stringify(pTos, encoding);
+
+  if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+  sqlite3VtabLock(pVtab);
+  rc = pVtab->pModule->xRename(pVtab, pTos->z);
+  sqlite3VtabUnlock(db, pVtab);
+  if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
+
+  popStack(&pTos, 1);
+  break;
+}
+#endif
 
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 /* Opcode: VUpdate P1 P2 P3
index 472ce743a7d9434aee12db06a633e8b71020725f..78550c434731f97a8fce725d5fed634fffed6300 100644 (file)
@@ -343,6 +343,7 @@ struct Vdbe {
 #ifdef SQLITE_DEBUG
   FILE *trace;        /* Write an execution trace here, if not NULL */
 #endif
+  int openedStatement;  /* True if this VM has opened a statement journal */
 #ifdef SQLITE_SSE
   int fetchId;          /* Statement number used by sqlite3_fetch_statement */
   int lru;              /* Counter used for LRU cache replacement */
index 1bef9976bac7b8e17322dbb00f182a27e678f765..b3d92c427640ca208c8eedfdbef268ce372697d4 100644 (file)
@@ -299,18 +299,23 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
 #endif
     ){
       if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
-    }else if( opcode==OP_Halt ){
+    }
+    if( opcode==OP_Halt ){
       if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
         doesStatementRollback = 1;
       }
     }else if( opcode==OP_Statement ){
       hasStatementBegin = 1;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+    }else if( opcode==OP_VUpdate || opcode==OP_VRename ){
+      doesStatementRollback = 1;
     }else if( opcode==OP_VFilter ){
       int n;
       assert( p->nOp - i >= 3 );
       assert( pOp[-2].opcode==OP_Integer );
       n = pOp[-2].p1;
       if( n>nMaxArgs ) nMaxArgs = n;
+#endif
     }
     if( opcodeNoPush(opcode) ){
       nMaxStack--;
@@ -898,6 +903,7 @@ void sqlite3VdbeMakeReady(
   p->nChange = 0;
   p->cacheCtr = 1;
   p->minWriteFileFormat = 255;
+  p->openedStatement = 0;
 #ifdef VDBE_PROFILE
   {
     int i;
@@ -1447,7 +1453,9 @@ int sqlite3VdbeHalt(Vdbe *p){
       }
     }else if( !xFunc ){
       if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
-        xFunc = sqlite3BtreeCommitStmt;
+        if( p->openedStatement ){
+          xFunc = sqlite3BtreeCommitStmt;
+        } 
       }else if( p->errorAction==OE_Abort ){
         xFunc = sqlite3BtreeRollbackStmt;
       }else{
index b0eb78365b7e4ef5f4c760b6fea42da499850619..98d5625fab08d6134f68cd23fd7cc62c093761e6 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is creating and dropping virtual tables.
 #
-# $Id: vtab1.test,v 1.42 2007/03/30 14:56:35 danielk1977 Exp $
+# $Id: vtab1.test,v 1.43 2007/06/27 15:53:35 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -243,7 +243,6 @@ do_test vtab1-2.4 {
 # echo module has not been registered with this database connection.
 #
 do_test vtab1.2.6 {
-breakpoint
   catchsql { PRAGMA table_info(t1); }
 } {1 {no such module: echo}}
 
@@ -890,6 +889,44 @@ do_test vtab1.11-5 {
   }
 } {{2 1} {2 2}}
  
+#----------------------------------------------------------------------
+# Test the outcome if a constraint is encountered half-way through
+# a multi-row INSERT that is inside a transaction
+#
+do_test vtab1.12-1 {
+  execsql {
+    CREATE TABLE b(a, b, c);
+    CREATE TABLE c(a UNIQUE, b, c);
+    INSERT INTO b VALUES(1, 'A', 'B');
+    INSERT INTO b VALUES(2, 'C', 'D');
+    INSERT INTO b VALUES(3, 'E', 'F');
+    INSERT INTO c VALUES(3, 'G', 'H');
+    CREATE VIRTUAL TABLE echo_c USING echo(c);
+  }
+} {}
+
+# First test outside of a transaction.
+do_test vtab1.12-2 {
+  catchsql { INSERT INTO echo_c SELECT * FROM b; }
+} {1 {constraint failed}}
+do_test vtab1.12-3 {
+  execsql { SELECT * FROM c }
+} {3 G H}
+
+breakpoint
+
+# Now the real test - wrapped in a transaction.
+do_test vtab1.12-4 {
+  execsql  {BEGIN}
+  catchsql { INSERT INTO echo_c SELECT * FROM b; }
+} {1 {constraint failed}}
+do_test vtab1.12-5 {
+  execsql { SELECT * FROM c }
+} {3 G H}
+do_test vtab1.12-6 {
+  execsql { COMMIT }
+  execsql { SELECT * FROM c }
+} {3 G H}
 
 unset -nocomplain echo_module_begin_fail
 finish_test
index 36dad9bb56e02e71329182ab2a2e8f71506cd8e0..4fd678c0524c164e44712d90590b89aa86b64b81 100644 (file)
@@ -10,7 +10,7 @@
 #***********************************************************************
 # This file implements regression tests for SQLite library.
 #
-# $Id: vtab5.test,v 1.6 2006/06/21 12:36:26 danielk1977 Exp $
+# $Id: vtab5.test,v 1.7 2007/06/27 15:53:35 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -140,13 +140,14 @@ do_test vtab5.4.2 {
   }
 } {1 {virtual tables may not be altered}}
 
-# Test that it is impossible to add a column to a virtual table.
+# Test that it is impossible to rename a virtual table.
+# UPDATE: It is now possible.
 #
-do_test vtab5.4.3 {
-  catchsql {
-    ALTER TABLE echo_strings RENAME TO echo_strings2;
-  }
-} {1 {virtual tables may not be altered}}
+do_test vtab5.4.3 {
+  catchsql {
+    ALTER TABLE echo_strings RENAME TO echo_strings2;
+  }
+} {1 {virtual tables may not be altered}}
 
 finish_test
 
diff --git a/test/vtab_alter.test b/test/vtab_alter.test
new file mode 100644 (file)
index 0000000..fddd76f
--- /dev/null
@@ -0,0 +1,104 @@
+# 2007 June 26
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the ALTER TABLE ... RENAME TO
+# command on virtual tables.
+#
+# $Id: vtab_alter.test,v 1.1 2007/06/27 15:53:35 danielk1977 Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !vtab {
+  finish_test
+  return
+}
+
+# Register the echo module.
+#
+# This test uses a special feature of the echo module. If the name
+# of the virtual table is a prefix of the name of the underlying
+# real table (for example if the v-table is "tbl" and the real table
+# is "tbl_base"), then the name of the real table is modified
+# when an "ALTER TABLE ... RENAME TO" is executed on the v-table.
+# For example:
+#
+#   sqlite> CREATE TABLE t1_base(a, b, c); 
+#   sqlite> CREATE VIRTUAL TABLE t1 USING(t1_base);
+#   sqlite> ALTER TABLE t1 RENAME TO t2;
+#   sqlite> SELECT tbl_name FROM sqlite_master;
+#   t2_base
+#   t2
+#
+register_echo_module [sqlite3_connection_pointer db]
+
+
+# Try to rename an echo table. Make sure nothing terrible happens.
+#
+do_test vtab_alter-1.1 {
+  execsql { CREATE TABLE t1(a, b VARCHAR, c INTEGER) }
+} {}
+do_test vtab_alter-1.2 {
+  execsql { CREATE VIRTUAL TABLE t1echo USING echo(t1) }
+} {}
+do_test vtab_alter-1.3 {
+  catchsql { SELECT * FROM t1echo }
+} {0 {}}
+do_test vtab_alter-1.4 {
+  execsql { ALTER TABLE t1echo RENAME TO new }
+} {}
+do_test vtab_alter-1.5 {
+  catchsql { SELECT * FROM t1echo }
+} {1 {no such table: t1echo}}
+do_test vtab_alter-1.6 {
+  catchsql { SELECT * FROM new }
+} {0 {}}
+
+# Try to rename an echo table that renames it's base table. Make 
+# sure nothing terrible happens.
+#
+do_test vtab_alter-2.1 {
+  execsql { 
+    DROP TABLE new;
+    DROP TABLE t1;
+    CREATE TABLE t1_base(a, b, c);
+    CREATE VIRTUAL TABLE t1 USING echo('*_base');
+  }
+} {}
+do_test vtab_alter-2.2 {
+  execsql { 
+    INSERT INTO t1_base VALUES(1, 2, 3);
+    SELECT * FROM t1;
+  }
+} {1 2 3}
+do_test vtab_alter-2.3 {
+  execsql { ALTER TABLE t1 RENAME TO x }
+} {}
+do_test vtab_alter-2.4 {
+  execsql { SELECT * FROM x; }
+} {1 2 3}
+do_test vtab_alter-2.5 {
+  execsql { SELECT * FROM x_base; }
+} {1 2 3}
+
+# Cause an error to occur when the echo module renames it's
+# backing store table.
+#
+do_test vtab_alter-3.1 {
+  execsql  { CREATE TABLE y_base(a, b, c) }
+  catchsql { ALTER TABLE x RENAME TO y }
+} {1 {SQL logic error or missing database}}
+do_test vtab_alter-3.2 {
+  execsql  { SELECT * FROM x }
+} {1 2 3}
+
+finish_test
+