mirror of https://github.com/sqlite/sqlite
Fix bugs in ALTER TABLE related to (a) whitespace in table defn, (b) temp triggers. (CVS 2112)
FossilOrigin-Name: 1fd8e835a3656799c23f4ef6ea1311fecf5a15cb
This commit is contained in:
parent
d641d646ff
commit
343e92610e
16
manifest
16
manifest
|
@ -1,5 +1,5 @@
|
|||
C Handle\striggers\scorrectly\sin\sALTER\sTABLE.\s(CVS\s2111)
|
||||
D 2004-11-18T15:44:29
|
||||
C Fix\sbugs\sin\sALTER\sTABLE\srelated\sto\s(a)\swhitespace\sin\stable\sdefn,\s(b)\stemp\striggers.\s(CVS\s2112)
|
||||
D 2004-11-19T05:14:55
|
||||
F Makefile.in e747bb5ba34ccbdd81f79dcf1b2b33c02817c21d
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
|
||||
|
@ -31,11 +31,11 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
|
|||
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
|
||||
F src/btree.c 49b09718cd988d1c7c981b03e94679bc10b5f711
|
||||
F src/btree.h 861e40b759a195ba63819740e484390012cf81ab
|
||||
F src/build.c f295d8326f72252681b5376dbd0c33b11f8133cc
|
||||
F src/build.c 467e940702206e950d810e765586a787ec06dd5b
|
||||
F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
|
||||
F src/delete.c be9d039b819f4a5d0fdfaeceace139ba189ef819
|
||||
F src/expr.c 4ee3e47358c92a919062255b14057a7a8f641e01
|
||||
F src/func.c 4f16eba1a7a0d0b3c617acf781607a03719490a2
|
||||
F src/func.c b668e5ad043176049454c95a6a780367a0e8f6bb
|
||||
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c 9524a6c3e86cbdbae3313f6a083bb9a3e7a2462b
|
||||
|
@ -83,7 +83,7 @@ F src/vdbeaux.c c6da55e0096e141211f918837eca98e0be6400b4
|
|||
F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0
|
||||
F src/where.c 4d28167e450255372b45abf1bc8cd5f0e9264d7b
|
||||
F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c
|
||||
F test/alter.test 45d30922605898392d1619265b8a157a43ba010d
|
||||
F test/alter.test 627f1c24c80b842b02b94ce7416e9b2498a790eb
|
||||
F test/attach.test e305dd59a375e37c658c6d401f19f8a95880bf9a
|
||||
F test/attach2.test 399128a7b3b209a339a8dbf53ca2ed42eb982d1a
|
||||
F test/attach3.test 8a0309e284cf9aa1d7d6cc444989031881f7a21c
|
||||
|
@ -259,7 +259,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
|
|||
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
|
||||
P 85d56beb7494ce63e70ab1ffc3797c2ee4c36749
|
||||
R 4f62fbea632b577ecd5796892a048619
|
||||
P c61b7de107cea76b561d0d6cd90c752b62c5df95
|
||||
R 2dccc389e14622418d8f9c23b5390305
|
||||
U danielk1977
|
||||
Z 1e8c5296540a3d2d7fecb9700f01ff06
|
||||
Z dfa16d84296b817116f68efa4f87c5bd
|
||||
|
|
|
@ -1 +1 @@
|
|||
c61b7de107cea76b561d0d6cd90c752b62c5df95
|
||||
1fd8e835a3656799c23f4ef6ea1311fecf5a15cb
|
48
src/build.c
48
src/build.c
|
@ -22,7 +22,7 @@
|
|||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.280 2004/11/18 15:44:29 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.281 2004/11/19 05:14:55 danielk1977 Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
@ -2931,6 +2931,9 @@ void sqlite3AlterRenameTable(
|
|||
char *zWhere = 0; /* Where clause of schema elements to reparse */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Vdbe *v;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
char *zTempTrig = 0; /* Where clause to locate temp triggers */
|
||||
#endif
|
||||
|
||||
assert( pSrc->nSrc==1 );
|
||||
|
||||
|
@ -2994,6 +2997,39 @@ void sqlite3AlterRenameTable(
|
|||
zName, strlen(pTab->zName), pTab->zName
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* If there are TEMP triggers on this table, modify the sqlite_temp_master
|
||||
** table. Don't do this if the table being ALTERed is itself located in
|
||||
** the temp database.
|
||||
*/
|
||||
if( iDb!=1 ){
|
||||
Trigger *pTrig;
|
||||
char *tmp = 0;
|
||||
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
|
||||
if( pTrig->iDb==1 ){
|
||||
if( !zTempTrig ){
|
||||
zTempTrig =
|
||||
sqlite3MPrintf("type = 'trigger' AND name IN(%Q", pTrig->name);
|
||||
}else{
|
||||
tmp = zTempTrig;
|
||||
zTempTrig = sqlite3MPrintf("%s, %Q", zTempTrig, pTrig->name);
|
||||
sqliteFree(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( zTempTrig ){
|
||||
tmp = zTempTrig;
|
||||
zTempTrig = sqlite3MPrintf("%s)", zTempTrig);
|
||||
sqliteFree(tmp);
|
||||
sqlite3NestedParse(pParse,
|
||||
"UPDATE sqlite_temp_master SET "
|
||||
"sql = sqlite_alter_trigger(sql, %Q), "
|
||||
"tbl_name = %Q "
|
||||
"WHERE %s;", zName, zName, zTempTrig);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Drop the elements of the in-memory schema that refered to the table
|
||||
** renamed and load the new versions from the database.
|
||||
*/
|
||||
|
@ -3001,12 +3037,20 @@ void sqlite3AlterRenameTable(
|
|||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
Trigger *pTrig;
|
||||
for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, iDb, 0, pTrig->name, 0);
|
||||
assert( pTrig->iDb==iDb || pTrig->iDb==1 );
|
||||
sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0);
|
||||
}
|
||||
#endif
|
||||
sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0);
|
||||
zWhere = sqlite3MPrintf("tbl_name=%Q", zName);
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( zTempTrig ){
|
||||
sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zTempTrig, P3_DYNAMIC);
|
||||
}
|
||||
}else{
|
||||
sqliteFree(zTempTrig);
|
||||
#endif
|
||||
}
|
||||
|
||||
sqliteFree(zName);
|
||||
|
|
48
src/func.c
48
src/func.c
|
@ -16,7 +16,7 @@
|
|||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.90 2004/11/18 15:44:29 danielk1977 Exp $
|
||||
** $Id: func.c,v 1.91 2004/11/19 05:14:55 danielk1977 Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
@ -552,26 +552,38 @@ static void altertableFunc(
|
|||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
char const *zSql = sqlite3_value_text(argv[0]);
|
||||
char const *zTableName = sqlite3_value_text(argv[1]);
|
||||
unsigned char const *zSql = sqlite3_value_text(argv[0]);
|
||||
unsigned char const *zTableName = sqlite3_value_text(argv[1]);
|
||||
|
||||
int token;
|
||||
Token tname;
|
||||
char const *zCsr = zSql;
|
||||
char const *zPrev;
|
||||
char *zRet = 0;
|
||||
int tokenType = 0;
|
||||
int len;
|
||||
int len = 0;
|
||||
char *zRet;
|
||||
|
||||
assert( argc==2 );
|
||||
/* 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.
|
||||
*/
|
||||
if( zSql ){
|
||||
while( tokenType!=TK_LP ){
|
||||
zPrev = zCsr-len;
|
||||
len = sqlite3GetToken(zCsr, &tokenType);
|
||||
zCsr += len;
|
||||
}
|
||||
do {
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
tname.z = zCsr;
|
||||
tname.n = len;
|
||||
|
||||
zRet = sqlite3MPrintf("%.*s%Q(%s", zPrev-zSql, zSql, zTableName, zCsr);
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_TRANSIENT);
|
||||
sqliteFree(zRet);
|
||||
/* Advance zCsr to the next token. Store that token type in 'token',
|
||||
** and it's length in 'len' (to be used next iteration of this loop).
|
||||
*/
|
||||
do {
|
||||
zCsr += len;
|
||||
len = sqlite3GetToken(zCsr, &token);
|
||||
} while( token==TK_SPACE );
|
||||
assert( len>0 );
|
||||
} while( token!=TK_LP );
|
||||
|
||||
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -605,7 +617,6 @@ static void altertriggerFunc(
|
|||
** preceded by either TK_ON or TK_DOT and immediatedly followed by one
|
||||
** of TK_WHEN, TK_BEGIN or TK_FOR.
|
||||
*/
|
||||
assert( argc==2 );
|
||||
if( zSql ){
|
||||
do {
|
||||
/* Store the token that zCsr points to in tname. */
|
||||
|
@ -641,8 +652,7 @@ static void altertriggerFunc(
|
|||
*/
|
||||
zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
|
||||
zTableName, tname.z+tname.n);
|
||||
sqlite3_result_text(context, zRet, -1, SQLITE_TRANSIENT);
|
||||
sqliteFree(zRet);
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3FreeX);
|
||||
}
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_TRIGGER */
|
||||
|
|
106
test/alter.test
106
test/alter.test
|
@ -8,7 +8,7 @@
|
|||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the ALTER TABLE statement.
|
||||
#
|
||||
# $Id: alter.test,v 1.3 2004/11/18 15:44:30 danielk1977 Exp $
|
||||
# $Id: alter.test,v 1.4 2004/11/19 05:14:56 danielk1977 Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
|
@ -20,6 +20,21 @@ ifcapable !altertable {
|
|||
return
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Test organization:
|
||||
#
|
||||
# alter-1.1.* - alter-1.7.*: Basic tests of ALTER TABLE, including tables
|
||||
# with implicit and explicit indices. These tests came from an earlier
|
||||
# fork of SQLite that also supported ALTER TABLE.
|
||||
# alter-1.8.*: Tests for ALTER TABLE when the table resides in an
|
||||
# attached database.
|
||||
# alter-1.9.*: Tests for ALTER TABLE when their is whitespace between the
|
||||
# table name and left parenthesis token. i.e:
|
||||
# "CREATE TABLE abc (a, b, c);"
|
||||
# alter-2.*: Test error conditions and messages.
|
||||
# alter-3.*: Test ALTER TABLE on tables that have TRIGGERs attached to them.
|
||||
#
|
||||
|
||||
# Create some tables to rename. Be sure to include some TEMP tables
|
||||
# and some tables with odd names.
|
||||
#
|
||||
|
@ -196,6 +211,29 @@ do_test alter-1.8.7 {
|
|||
}
|
||||
} {aux aux aux}
|
||||
|
||||
do_test alter-1.9.1 {
|
||||
execsql {
|
||||
CREATE TABLE tbl1 (a, b, c);
|
||||
INSERT INTO tbl1 VALUES(1, 2, 3);
|
||||
}
|
||||
} {}
|
||||
do_test alter-1.9.2 {
|
||||
execsql {
|
||||
SELECT * FROM tbl1;
|
||||
}
|
||||
} {1 2 3}
|
||||
do_test alter-1.9.3 {
|
||||
execsql {
|
||||
ALTER TABLE tbl1 RENAME TO tbl2;
|
||||
SELECT * FROM tbl2;
|
||||
}
|
||||
} {1 2 3}
|
||||
do_test alter-1.9.4 {
|
||||
execsql {
|
||||
DROP TABLE tbl2;
|
||||
}
|
||||
} {}
|
||||
|
||||
# Test error messages
|
||||
#
|
||||
do_test alter-2.1 {
|
||||
|
@ -224,6 +262,17 @@ ifcapable !trigger {
|
|||
return
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Tests alter-3.* test ALTER TABLE on tables that have triggers.
|
||||
#
|
||||
# alter-3.1.*: ALTER TABLE with triggers.
|
||||
# alter-3.2.*: Test that the ON keyword cannot be used as a database,
|
||||
# table or column name unquoted. This is done because part of the
|
||||
# ALTER TABLE code (specifically the implementation of SQL function
|
||||
# "sqlite_alter_trigger") will break in this case.
|
||||
# alter-3.3.*: ALTER TABLE with TEMP triggers (todo).
|
||||
#
|
||||
|
||||
# An SQL user-function for triggers to fire, so that we know they
|
||||
# are working.
|
||||
proc trigfunc {args} {
|
||||
|
@ -349,5 +398,58 @@ do_test alter-3.2.9 {
|
|||
CREATE TRIGGER 'on'.trig4 AFTER INSERT ON 'ON' BEGIN SELECT 1; END;
|
||||
}
|
||||
} {0 {}}
|
||||
finish_test
|
||||
do_test alter-3.2.10 {
|
||||
execsql {
|
||||
DROP TABLE t10;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test alter-3.3.1 {
|
||||
execsql {
|
||||
CREATE TABLE tbl1(a, b, c);
|
||||
CREATE TEMP TRIGGER trig1 AFTER INSERT ON tbl1 BEGIN
|
||||
SELECT trigfunc('trig1', new.a, new.b, new.c);
|
||||
END;
|
||||
}
|
||||
} {}
|
||||
do_test alter-3.3.2 {
|
||||
execsql {
|
||||
INSERT INTO tbl1 VALUES('a', 'b', 'c');
|
||||
}
|
||||
set ::TRIGGER
|
||||
} {trig1 a b c}
|
||||
do_test alter-3.3.3 {
|
||||
execsql {
|
||||
ALTER TABLE tbl1 RENAME TO tbl2;
|
||||
INSERT INTO tbl2 VALUES('d', 'e', 'f');
|
||||
}
|
||||
set ::TRIGGER
|
||||
} {trig1 d e f}
|
||||
do_test alter-3.3.4 {
|
||||
execsql {
|
||||
CREATE TEMP TRIGGER trig2 AFTER UPDATE ON tbl2 BEGIN
|
||||
SELECT trigfunc('trig2', new.a, new.b, new.c);
|
||||
END;
|
||||
}
|
||||
} {}
|
||||
do_test alter-3.3.5 {
|
||||
execsql {
|
||||
ALTER TABLE tbl2 RENAME TO tbl3;
|
||||
INSERT INTO tbl3 VALUES('g', 'h', 'i');
|
||||
}
|
||||
set ::TRIGGER
|
||||
} {trig1 g h i}
|
||||
do_test alter-3.3.6 {
|
||||
execsql {
|
||||
UPDATE tbl3 SET a = 'G' where a = 'g';
|
||||
}
|
||||
set ::TRIGGER
|
||||
} {trig2 G h i}
|
||||
do_test alter-3.3.7 {
|
||||
execsql {
|
||||
DROP TABLE tbl3;
|
||||
SELECT * FROM sqlite_temp_master WHERE type = 'trigger';
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
|
Loading…
Reference in New Issue