1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-10-24 09:53:10 +03:00

Handle triggers correctly in ALTER TABLE. (CVS 2111)

FossilOrigin-Name: c61b7de107cea76b561d0d6cd90c752b62c5df95
This commit is contained in:
danielk1977
2004-11-18 15:44:29 +00:00
parent 20fc0887f5
commit d641d646ff
5 changed files with 234 additions and 15 deletions

View File

@@ -16,7 +16,7 @@
** 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>
@@ -576,6 +576,78 @@ static void altertableFunc(
}
#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
@@ -1028,6 +1100,9 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "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},