-C Speed\simprovement\son\sthe\sLIKE\scommand.\s(CVS\s2110)
-D 2004-11-18T13:49:26
+C Handle\striggers\scorrectly\sin\sALTER\sTABLE.\s(CVS\s2111)
+D 2004-11-18T15:44:29
F Makefile.in e747bb5ba34ccbdd81f79dcf1b2b33c02817c21d
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
F src/btree.c 49b09718cd988d1c7c981b03e94679bc10b5f711
F src/btree.h 861e40b759a195ba63819740e484390012cf81ab
-F src/build.c a95eb1181247368b0ffe2eed121a43735976a964
+F src/build.c f295d8326f72252681b5376dbd0c33b11f8133cc
F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
F src/delete.c be9d039b819f4a5d0fdfaeceace139ba189ef819
F src/expr.c 4ee3e47358c92a919062255b14057a7a8f641e01
-F src/func.c 1a5e23e206ecb81b73e4b97ef1a9654775b53f1e
+F src/func.c 4f16eba1a7a0d0b3c617acf781607a03719490a2
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
F src/insert.c 9524a6c3e86cbdbae3313f6a083bb9a3e7a2462b
F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0
F src/where.c 4d28167e450255372b45abf1bc8cd5f0e9264d7b
F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c
-F test/alter.test ea6b104fa83da6970b1ce61885827817bdaced3a
+F test/alter.test 45d30922605898392d1619265b8a157a43ba010d
F test/attach.test e305dd59a375e37c658c6d401f19f8a95880bf9a
F test/attach2.test 399128a7b3b209a339a8dbf53ca2ed42eb982d1a
F test/attach3.test 8a0309e284cf9aa1d7d6cc444989031881f7a21c
F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
-P c93a9e18d2bf53690f577a901e0defd8a449d56a
-R 41f63229808e62aecab58ec2f7d5cad7
-U drh
-Z 1e586546872d49a1225e64744cd9ac4a
+P 85d56beb7494ce63e70ab1ffc3797c2ee4c36749
+R 4f62fbea632b577ecd5796892a048619
+U danielk1977
+Z 1e8c5296540a3d2d7fecb9700f01ff06
-85d56beb7494ce63e70ab1ffc3797c2ee4c36749
\ No newline at end of file
+c61b7de107cea76b561d0d6cd90c752b62c5df95
\ No newline at end of file
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.279 2004/11/13 03:48:07 drh Exp $
+** $Id: build.c,v 1.280 2004/11/18 15:44:29 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
/* Modify the sqlite_master table to use the new table name. */
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET "
+#ifdef SQLITE_OMIT_TRIGGER
"sql = sqlite_alter_table(sql, %Q), "
+#else
+ "sql = CASE "
+ "WHEN type = 'trigger' THEN sqlite_alter_trigger(sql, %Q)"
+ "ELSE sqlite_alter_table(sql, %Q) END, "
+#endif
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
"WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name, %d+18,10) "
"ELSE name END "
- "WHERE tbl_name=%Q AND type IN ('table', 'index');",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, zName, zName,
+ "WHERE tbl_name=%Q AND type IN ('table', 'index', 'trigger');",
+ db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, zName, zName, zName,
zName, strlen(pTab->zName), pTab->zName
);
** renamed and load the new versions from the database.
*/
if( pParse->nErr==0 ){
+#ifndef SQLITE_OMIT_TRIGGER
+ Trigger *pTrig;
+ for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){
+ sqlite3VdbeOp3(v, OP_DropTrigger, 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);
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.89 2004/11/18 13:49:26 drh Exp $
+** $Id: func.c,v 1.90 2004/11/18 15:44:29 danielk1977 Exp $
*/
#include <ctype.h>
#include <math.h>
}
#endif
+#ifndef SQLITE_OMIT_ALTERTABLE
+#ifndef SQLITE_OMIT_TRIGGER
+/* This function is used by SQL generated to implement the ALTER TABLE
+** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
+** statement. The second is a table name. The table name in the CREATE
+** TRIGGER statement is replaced with the second argument and the result
+** returned. This is analagous to altertableFunc() above, except for CREATE
+** TRIGGER, not CREATE INDEX and CREATE TABLE.
+*/
+static void altertriggerFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned char const *zSql = sqlite3_value_text(argv[0]);
+ unsigned char const *zTableName = sqlite3_value_text(argv[1]);
+
+ int token;
+ Token tname;
+ int dist = 3;
+ char const *zCsr = zSql;
+ int len = 0;
+ char *zRet;
+
+ /* The principle used to locate the table name in the CREATE TRIGGER
+ ** statement is that the table name is the first token that is immediatedly
+ ** 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. */
+ tname.z = zCsr;
+ tname.n = len;
+
+ /* 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 );
+
+ /* Variable 'dist' stores the number of tokens read since the most
+ ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
+ ** token is read and 'dist' equals 2, the condition stated above
+ ** to be met.
+ **
+ ** Note that ON cannot be a database, table or column name, so
+ ** there is no need to worry about syntax like
+ ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
+ */
+ dist++;
+ if( token==TK_DOT || token==TK_ON ){
+ dist = 0;
+ }
+ } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
+
+ /* Variable tname now contains the token that is the old table-name
+ ** in the CREATE TRIGGER statement.
+ */
+ zRet = sqlite3MPrintf("%.*s%Q%s", tname.z - zSql, zSql,
+ zTableName, tname.z+tname.n);
+ sqlite3_result_text(context, zRet, -1, SQLITE_TRANSIENT);
+ sqliteFree(zRet);
+ }
+}
+#endif /* !SQLITE_OMIT_TRIGGER */
+#endif /* !SQLITE_OMIT_ALTERTABLE */
+
/*
** EXPERIMENTAL - This is not an official function. The interface may
** change. This function may disappear. Do not write code that depends
{ "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
#ifndef SQLITE_OMIT_ALTERTABLE
{ "sqlite_alter_table", 2, 0, SQLITE_UTF8, 0, altertableFunc},
+#ifndef SQLITE_OMIT_TRIGGER
+ { "sqlite_alter_trigger", 2, 0, SQLITE_UTF8, 0, altertriggerFunc},
+#endif
#endif
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
# This file implements regression tests for SQLite library. The
# focus of this script is testing the ALTER TABLE statement.
#
-# $Id: alter.test,v 1.2 2004/11/12 15:53:37 danielk1977 Exp $
+# $Id: alter.test,v 1.3 2004/11/18 15:44:30 danielk1977 Exp $
#
set testdir [file dirname $argv0]
}
} {1 {there is already another table or index with this name: i3}}
+# If this compilation does not include triggers, omit the remainder
+# of this file.
+ifcapable !trigger {
+ finish_test
+ return
+}
+
+# An SQL user-function for triggers to fire, so that we know they
+# are working.
+proc trigfunc {args} {
+ set ::TRIGGER $args
+}
+db func trigfunc trigfunc
+
+do_test alter-3.1.0 {
+ execsql {
+ CREATE TABLE t6(a, b, c);
+ CREATE TRIGGER trig1 AFTER INSERT ON t6 BEGIN
+ SELECT trigfunc('trig1', new.a, new.b, new.c);
+ END;
+ }
+} {}
+do_test alter-3.1.1 {
+ execsql {
+ INSERT INTO t6 VALUES(1, 2, 3);
+ }
+ set ::TRIGGER
+} {trig1 1 2 3}
+do_test alter-3.1.2 {
+ execsql {
+ ALTER TABLE t6 RENAME TO t7;
+ INSERT INTO t7 VALUES(4, 5, 6);
+ }
+ set ::TRIGGER
+} {trig1 4 5 6}
+do_test alter-3.1.3 {
+ execsql {
+ DROP TRIGGER trig1;
+ }
+} {}
+do_test alter-3.1.4 {
+ execsql {
+ CREATE TRIGGER trig2 AFTER INSERT ON main.t7 BEGIN
+ SELECT trigfunc('trig2', new.a, new.b, new.c);
+ END;
+ INSERT INTO t7 VALUES(1, 2, 3);
+ }
+ set ::TRIGGER
+} {trig2 1 2 3}
+do_test alter-3.1.5 {
+ execsql {
+ ALTER TABLE t7 RENAME TO t8;
+ INSERT INTO t8 VALUES(4, 5, 6);
+ }
+ set ::TRIGGER
+} {trig2 4 5 6}
+do_test alter-3.1.6 {
+ execsql {
+ DROP TRIGGER trig2;
+ }
+} {}
+do_test alter-3.1.7 {
+ execsql {
+ CREATE TRIGGER trig3 AFTER INSERT ON main.'t8'BEGIN
+ SELECT trigfunc('trig3', new.a, new.b, new.c);
+ END;
+ INSERT INTO t8 VALUES(1, 2, 3);
+ }
+ set ::TRIGGER
+} {trig3 1 2 3}
+do_test alter-3.1.8 {
+ execsql {
+ ALTER TABLE t8 RENAME TO t9;
+ INSERT INTO t9 VALUES(4, 5, 6);
+ }
+ set ::TRIGGER
+} {trig3 4 5 6}
+# Make sure "ON" cannot be used as a database, table or column name without
+# quoting. Otherwise the sqlite_alter_trigger() function might not work.
+file delete -force test3.db
+file delete -force test3.db-journal
+do_test alter-3.2.1 {
+ catchsql {
+ ATTACH 'test3.db' AS ON;
+ }
+} {1 {near "ON": syntax error}}
+do_test alter-3.2.2 {
+ catchsql {
+ ATTACH 'test3.db' AS 'ON';
+ }
+} {0 {}}
+do_test alter-3.2.3 {
+ catchsql {
+ CREATE TABLE ON.t1(a, b, c);
+ }
+} {1 {near "ON": syntax error}}
+do_test alter-3.2.4 {
+ catchsql {
+ CREATE TABLE 'ON'.t1(a, b, c);
+ }
+} {0 {}}
+do_test alter-3.2.4 {
+ catchsql {
+ CREATE TABLE 'ON'.ON(a, b, c);
+ }
+} {1 {near "ON": syntax error}}
+do_test alter-3.2.5 {
+ catchsql {
+ CREATE TABLE 'ON'.'ON'(a, b, c);
+ }
+} {0 {}}
+do_test alter-3.2.6 {
+ catchsql {
+ CREATE TABLE t10(a, ON, c);
+ }
+} {1 {near "ON": syntax error}}
+do_test alter-3.2.7 {
+ catchsql {
+ CREATE TABLE t10(a, 'ON', c);
+ }
+} {0 {}}
+do_test alter-3.2.8 {
+ catchsql {
+ CREATE TRIGGER trig4 AFTER INSERT ON ON BEGIN SELECT 1; END;
+ }
+} {1 {near "ON": syntax error}}
+do_test alter-3.2.9 {
+ catchsql {
+ CREATE TRIGGER 'on'.trig4 AFTER INSERT ON 'ON' BEGIN SELECT 1; END;
+ }
+} {0 {}}
finish_test
+