1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Allow ALTER TABLE on virtual tables. (CVS 4142)

FossilOrigin-Name: 37d1f9f37ea9d2e8a4dbe0ec67c0d6eb7fcc5f3f
This commit is contained in:
danielk1977
2007-06-27 15:53:34 +00:00
parent c3d56d1509
commit 182c4ba979
11 changed files with 317 additions and 52 deletions

View File

@@ -1,5 +1,5 @@
C respect\s$LDFLAGS\sfrom\senv/configure\s(CVS\s4141) C Allow\sALTER\sTABLE\son\svirtual\stables.\s(CVS\s4142)
D 2007-06-27T15:01:46 D 2007-06-27T15:53:35
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -62,7 +62,7 @@ F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
F src/alter.c 1b1deeb97446ed87f2fa17a3eb6236548841a348 F src/alter.c 3402b657de80c242b0382f768df273505f8178cc
F src/analyze.c 8d345472e0f4e44fc88f5cf489c16dcb77904525 F src/analyze.c 8d345472e0f4e44fc88f5cf489c16dcb77904525
F src/attach.c ba628db0c2b6a362f036d017bf1196cdfe4ebb37 F src/attach.c ba628db0c2b6a362f036d017bf1196cdfe4ebb37
F src/auth.c 5ea90bc93dfea46e9fe4bf531e14c7cd98219ecb F src/auth.c 5ea90bc93dfea46e9fe4bf531e14c7cd98219ecb
@@ -107,7 +107,7 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
F src/select.c e363327d0eba8d758ab00055de962a3bb0bc213e F src/select.c e363327d0eba8d758ab00055de962a3bb0bc213e
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c 4b0fc3c76a9f23a1c963e01703c0fbbca1b5c34d F src/shell.c 4b0fc3c76a9f23a1c963e01703c0fbbca1b5c34d
F src/sqlite.h.in a3c5d9f8566efe43589b428bd4f7f0f77766e9ae F src/sqlite.h.in bbcc5481af9f40ce5762c323cf555581a025f3de
F src/sqlite3ext.h 95575e0d175a0271fe2c3232c0d11e8720ed6887 F src/sqlite3ext.h 95575e0d175a0271fe2c3232c0d11e8720ed6887
F src/sqliteInt.h 81183ae71162818bf60478e738ff68604128bb06 F src/sqliteInt.h 81183ae71162818bf60478e738ff68604128bb06
F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
@@ -120,7 +120,7 @@ F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
F src/test5.c c40a4cf43266c1c6da7bcb737d294304a177e6cc F src/test5.c c40a4cf43266c1c6da7bcb737d294304a177e6cc
F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94 F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94
F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3 F src/test7.c 03fa8d787f6aebc6d1f72504d52f33013ad2c8e3
F src/test8.c c3c4aeea4e3d70966306d6eca1b77ce7eee2f059 F src/test8.c 4f0a8624028588e083731c11927f5b2a07184618
F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6 F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6
F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
@@ -138,11 +138,11 @@ F src/update.c 6b10becb6235ea314ed245fbfbf8b38755e3166e
F src/utf.c 01b2aba02b10d12903e9e1ff897215c9faf6b662 F src/utf.c 01b2aba02b10d12903e9e1ff897215c9faf6b662
F src/util.c 9e81d417fc60bd2fe156f8f2317aa4845bc6cc90 F src/util.c 9e81d417fc60bd2fe156f8f2317aa4845bc6cc90
F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
F src/vdbe.c b776b68ad926974c72296145d1282ff6e956b4ff F src/vdbe.c 32f39e9cab8a6ef64ad392711396d65ae89fc790
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3 F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
F src/vdbeInt.h 7d2bf163d6d4e815724a457f2216dd8e38c3955c F src/vdbeInt.h c3514903cad9e36d6b3242be20261351d09db56c
F src/vdbeapi.c 7930b9a188ab385287ca3eb3840af7225cb43549 F src/vdbeapi.c 7930b9a188ab385287ca3eb3840af7225cb43549
F src/vdbeaux.c c580d3605edc2c24ba9bd26fa7aa8b4fff10daa4 F src/vdbeaux.c ca1d673fd5e45fe9ba994391b11568c48a7e1b59
F src/vdbeblob.c bb30b3e387c35ba869949494b2736aff97159470 F src/vdbeblob.c bb30b3e387c35ba869949494b2736aff97159470
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c ca4d3994507cb0a9504820293af69f5c778b4abd F src/vdbemem.c ca4d3994507cb0a9504820293af69f5c778b4abd
@@ -420,16 +420,17 @@ F test/vacuum.test cf839fc3ff24d601057319bbb5c700ce9c8e0fb0
F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c F test/vacuum2.test 5aea8c88a65cb29f7d175296e7c819c6158d838c
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/view.test 852bd4101e6d171c46ad682eb5c5faf662b2eba4 F test/view.test 852bd4101e6d171c46ad682eb5c5faf662b2eba4
F test/vtab1.test bf129928444f1fe3d992894f6e0b4c6d4a534d49 F test/vtab1.test e740d4761b9125e6e541c62d199a3822f54614ff
F test/vtab2.test 94bb3bf691ac10e34cf7dad46b1cf94b861d513c F test/vtab2.test 94bb3bf691ac10e34cf7dad46b1cf94b861d513c
F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587 F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587
F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87 F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87
F test/vtab5.test 9fb8f335651afe8f870011e2f68e5b00c5ad03cd F test/vtab5.test 26bc7a0a52c5c2bcfa849ba327f8a0d4abccdb23
F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392 F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392
F test/vtab7.test 5f9ef9fb84733e928d5d0267c821072561b198d5 F test/vtab7.test 5f9ef9fb84733e928d5d0267c821072561b198d5
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936 F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936
F test/vtab_alter.test 87617789086fd1767aa071e7805f1af7e1dac144
F test/vtab_err.test 9eabf98b26838fed8bac4aea986580be0a2bd52e F test/vtab_err.test 9eabf98b26838fed8bac4aea986580be0a2bd52e
F test/vtab_shared.test d631d1f820c38c18939d53aab1fc35db5f0a8094 F test/vtab_shared.test d631d1f820c38c18939d53aab1fc35db5f0a8094
F test/where.test 1bcde8984c63747ac6d6bafcacd20fd6e8a223de F test/where.test 1bcde8984c63747ac6d6bafcacd20fd6e8a223de
@@ -516,7 +517,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 850822e2904bc340afd0b7535ef51fbdf9e1f486 P 9c13fc0f4bf22c8e05b11ef5feaaf07d8a8b3f01
R 1afeab26f16295155c75ffe8baa66b82 R 53f2a209b5d25f95ed550b0d365211d1
U vapier U danielk1977
Z 83aaaa53ff941923277b0d6c2cfa7d3d Z ba48bbb530071e692ea4d7c53d55d66a

View File

@@ -1 +1 @@
9c13fc0f4bf22c8e05b11ef5feaaf07d8a8b3f01 37d1f9f37ea9d2e8a4dbe0ec67c0d6eb7fcc5f3f

View File

@@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code ** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -53,7 +53,7 @@ static void renameTableFunc(
/* The principle used to locate the table name in the CREATE TABLE /* 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 ** 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 ){ if( zSql ){
do { do {
@@ -74,7 +74,7 @@ static void renameTableFunc(
len = sqlite3GetToken(zCsr, &token); len = sqlite3GetToken(zCsr, &token);
} while( token==TK_SPACE ); } while( token==TK_SPACE );
assert( len>0 ); assert( len>0 );
} while( token!=TK_LP ); } while( token!=TK_LP && token!=TK_USING );
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql, zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
zTableName, tname.z+tname.n); zTableName, tname.z+tname.n);
@@ -279,18 +279,13 @@ void sqlite3AlterRenameTable(
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
char *zWhere = 0; /* Where clause to locate temp triggers */ char *zWhere = 0; /* Where clause to locate temp triggers */
#endif #endif
int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
if( sqlite3MallocFailed() ) goto exit_rename_table; if( sqlite3MallocFailed() ) goto exit_rename_table;
assert( pSrc->nSrc==1 ); assert( pSrc->nSrc==1 );
pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase);
if( !pTab ) goto exit_rename_table; 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); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName; zDb = db->aDb[iDb].zName;
@@ -325,17 +320,36 @@ void sqlite3AlterRenameTable(
} }
#endif #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. /* Begin a transaction and code the VerifyCookie for database iDb.
** Then modify the schema cookie (since the ALTER TABLE modifies the ** 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); v = sqlite3GetVdbe(pParse);
if( v==0 ){ if( v==0 ){
goto exit_rename_table; goto exit_rename_table;
} }
sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
sqlite3ChangeCookie(db, v, 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 */ /* figure out how many UTF-8 characters are in zName */
zTabName = pTab->zName; zTabName = pTab->zName;
nTabName = sqlite3Utf8CharLen(zTabName, -1); nTabName = sqlite3Utf8CharLen(zTabName, -1);

View File

@@ -30,7 +30,7 @@
** the version number) and changes its name to "sqlite3.h" as ** the version number) and changes its name to "sqlite3.h" as
** part of the build process. ** 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_ #ifndef _SQLITE3_H_
#define _SQLITE3_H_ #define _SQLITE3_H_
@@ -2403,6 +2403,8 @@ struct sqlite3_module {
int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg); void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
}; };
/* /*

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -61,6 +61,8 @@ struct echo_vtab {
Tcl_Interp *interp; /* Tcl interpreter containing debug variables */ Tcl_Interp *interp; /* Tcl interpreter containing debug variables */
sqlite3 *db; /* Database connection */ sqlite3 *db; /* Database connection */
int isPattern;
char *zThis; /* Name of the echo table */
char *zTableName; /* Name of the real table */ char *zTableName; /* Name of the real table */
char *zLogName; /* Name of the log table */ char *zLogName; /* Name of the log table */
int nCol; /* Number of columns in the real table */ int nCol; /* Number of columns in the real table */
@@ -74,6 +76,46 @@ struct echo_cursor {
sqlite3_stmt *pStmt; 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 ** Retrieve the column names for the table named zTab via database
** connection db. SQLITE_OK is returned on success, or an sqlite error ** 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( static int echoDeclareVtab(
echo_vtab *pVtab, echo_vtab *pVtab,
sqlite3 *db, sqlite3 *db
int argc,
const char *const*argv
){ ){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( argc>=4 ){ if( pVtab->zTableName ){
sqlite3_stmt *pStmt = 0; sqlite3_stmt *pStmt = 0;
sqlite3_prepare(db, sqlite3_prepare(db,
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?", "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
-1, &pStmt, 0); -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 ){ if( sqlite3_step(pStmt)==SQLITE_ROW ){
int rc2; int rc2;
const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0); const char *zCreateTable = (const char *)sqlite3_column_text(pStmt, 0);
@@ -282,12 +322,11 @@ static int echoDeclareVtab(
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
} }
if( rc==SQLITE_OK ){ 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 ){ 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; echo_vtab *p = (echo_vtab*)pVtab;
sqliteFree(p->aIndex); sqliteFree(p->aIndex);
sqliteFree(p->aCol); sqliteFree(p->aCol);
sqliteFree(p->zThis);
sqliteFree(p->zTableName); sqliteFree(p->zTableName);
sqliteFree(p->zLogName); sqliteFree(p->zLogName);
sqliteFree(p); sqliteFree(p);
@@ -331,12 +371,28 @@ static int echoConstructor(
pVtab->interp = (Tcl_Interp *)pAux; pVtab->interp = (Tcl_Interp *)pAux;
pVtab->db = db; pVtab->db = db;
/* Allocate echo_vtab.zThis */
pVtab->zThis = sqlite3MPrintf("%s", argv[2]);
if( !pVtab->zThis ){
echoDestructor((sqlite3_vtab *)pVtab);
return SQLITE_NOMEM;
}
/* Allocate echo_vtab.zTableName */ /* Allocate echo_vtab.zTableName */
if( argc>3 ){
pVtab->zTableName = sqlite3MPrintf("%s", argv[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 ){ if( !pVtab->zTableName ){
echoDestructor((sqlite3_vtab *)pVtab); echoDestructor((sqlite3_vtab *)pVtab);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
}
/* Log the arguments to this function to Tcl var ::echo_module */ /* Log the arguments to this function to Tcl var ::echo_module */
for(i=0; i<argc; i++){ for(i=0; i<argc; i++){
@@ -347,7 +403,7 @@ static int echoConstructor(
** structure. If an error occurs, delete the sqlite3_vtab structure and ** structure. If an error occurs, delete the sqlite3_vtab structure and
** return an error code. ** return an error code.
*/ */
if( echoDeclareVtab(pVtab, db, argc, argv) ){ if( echoDeclareVtab(pVtab, db) ){
echoDestructor((sqlite3_vtab *)pVtab); echoDestructor((sqlite3_vtab *)pVtab);
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@@ -975,6 +1031,21 @@ static int echoFindFunction(
return 1; 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 ** A virtual table module that merely "echos" the contents of another
** table (like an SQL VIEW). ** table (like an SQL VIEW).
@@ -999,6 +1070,7 @@ static sqlite3_module echoModule = {
echoCommit, /* xCommit - commit transaction */ echoCommit, /* xCommit - commit transaction */
echoRollback, /* xRollback - rollback transaction */ echoRollback, /* xRollback - rollback transaction */
echoFindFunction, /* xFindFunction - function overloading */ echoFindFunction, /* xFindFunction - function overloading */
echoRename, /* xRename - rename the table */
}; };
/* /*

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -2408,6 +2408,7 @@ case OP_Statement: { /* no-push */
assert( sqlite3BtreeIsInTrans(pBt) ); assert( sqlite3BtreeIsInTrans(pBt) );
if( !sqlite3BtreeIsInStmt(pBt) ){ if( !sqlite3BtreeIsInStmt(pBt) ){
rc = sqlite3BtreeBeginStmt(pBt); rc = sqlite3BtreeBeginStmt(pBt);
p->openedStatement = 1;
} }
} }
break; break;
@@ -4999,6 +5000,30 @@ case OP_VNext: { /* no-push */
} }
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #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 #ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VUpdate P1 P2 P3 /* Opcode: VUpdate P1 P2 P3

View File

@@ -343,6 +343,7 @@ struct Vdbe {
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
FILE *trace; /* Write an execution trace here, if not NULL */ FILE *trace; /* Write an execution trace here, if not NULL */
#endif #endif
int openedStatement; /* True if this VM has opened a statement journal */
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */ int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */ int lru; /* Counter used for LRU cache replacement */

View File

@@ -299,18 +299,23 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
#endif #endif
){ ){
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; 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 ){ if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
doesStatementRollback = 1; doesStatementRollback = 1;
} }
}else if( opcode==OP_Statement ){ }else if( opcode==OP_Statement ){
hasStatementBegin = 1; hasStatementBegin = 1;
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( opcode==OP_VUpdate || opcode==OP_VRename ){
doesStatementRollback = 1;
}else if( opcode==OP_VFilter ){ }else if( opcode==OP_VFilter ){
int n; int n;
assert( p->nOp - i >= 3 ); assert( p->nOp - i >= 3 );
assert( pOp[-2].opcode==OP_Integer ); assert( pOp[-2].opcode==OP_Integer );
n = pOp[-2].p1; n = pOp[-2].p1;
if( n>nMaxArgs ) nMaxArgs = n; if( n>nMaxArgs ) nMaxArgs = n;
#endif
} }
if( opcodeNoPush(opcode) ){ if( opcodeNoPush(opcode) ){
nMaxStack--; nMaxStack--;
@@ -898,6 +903,7 @@ void sqlite3VdbeMakeReady(
p->nChange = 0; p->nChange = 0;
p->cacheCtr = 1; p->cacheCtr = 1;
p->minWriteFileFormat = 255; p->minWriteFileFormat = 255;
p->openedStatement = 0;
#ifdef VDBE_PROFILE #ifdef VDBE_PROFILE
{ {
int i; int i;
@@ -1447,7 +1453,9 @@ int sqlite3VdbeHalt(Vdbe *p){
} }
}else if( !xFunc ){ }else if( !xFunc ){
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){ if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
if( p->openedStatement ){
xFunc = sqlite3BtreeCommitStmt; xFunc = sqlite3BtreeCommitStmt;
}
}else if( p->errorAction==OE_Abort ){ }else if( p->errorAction==OE_Abort ){
xFunc = sqlite3BtreeRollbackStmt; xFunc = sqlite3BtreeRollbackStmt;
}else{ }else{

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this file is creating and dropping virtual tables. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -243,7 +243,6 @@ do_test vtab1-2.4 {
# echo module has not been registered with this database connection. # echo module has not been registered with this database connection.
# #
do_test vtab1.2.6 { do_test vtab1.2.6 {
breakpoint
catchsql { PRAGMA table_info(t1); } catchsql { PRAGMA table_info(t1); }
} {1 {no such module: echo}} } {1 {no such module: echo}}
@@ -890,6 +889,44 @@ do_test vtab1.11-5 {
} }
} {{2 1} {2 2}} } {{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 unset -nocomplain echo_module_begin_fail
finish_test finish_test

View File

@@ -10,7 +10,7 @@
#*********************************************************************** #***********************************************************************
# This file implements regression tests for SQLite library. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -140,13 +140,14 @@ do_test vtab5.4.2 {
} }
} {1 {virtual tables may not be altered}} } {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 { # do_test vtab5.4.3 {
catchsql { # catchsql {
ALTER TABLE echo_strings RENAME TO echo_strings2; # ALTER TABLE echo_strings RENAME TO echo_strings2;
} # }
} {1 {virtual tables may not be altered}} # } {1 {virtual tables may not be altered}}
finish_test finish_test

104
test/vtab_alter.test Normal file
View File

@@ -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