aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2002-08-24 18:24:51 +0000
committerdrh <drh@noemail.net>2002-08-24 18:24:51 +0000
commit4b59ab5e643009b42d6d3efb57c463c8d1123ad6 (patch)
tree8220ecb6868d936e28a34344e6760aac8bc43411 /src
parent79983d03e83d845a7a35367ffdf97d3c6b8167e5 (diff)
downloadsqlite-4b59ab5e643009b42d6d3efb57c463c8d1123ad6.tar.gz
sqlite-4b59ab5e643009b42d6d3efb57c463c8d1123ad6.zip
Change the way token memory is allocated in an effort to fix ticket #136.
There is now a memory leak when using views of views. (CVS 725) FossilOrigin-Name: 22d8726e61eec0e53893f492cb2163824b87a23e
Diffstat (limited to 'src')
-rw-r--r--src/build.c31
-rw-r--r--src/expr.c234
-rw-r--r--src/main.c12
-rw-r--r--src/parse.y92
-rw-r--r--src/select.c50
-rw-r--r--src/sqliteInt.h39
-rw-r--r--src/tokenize.c4
-rw-r--r--src/trigger.c117
8 files changed, 340 insertions, 239 deletions
diff --git a/src/build.c b/src/build.c
index f1073d531..4caad2d34 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.109 2002/08/18 20:28:07 drh Exp $
+** $Id: build.c,v 1.110 2002/08/24 18:24:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -844,10 +844,10 @@ void sqliteCreateView(
Select *pSelect, /* A SELECT statement that will become the new view */
int isTemp /* TRUE for a TEMPORARY view */
){
- Token sEnd;
Table *p;
+ int n;
const char *z;
- int n, offset;
+ Token sEnd;
sqliteStartTable(pParse, pBegin, pName, isTemp);
p = pParse->pNewTable;
@@ -860,12 +860,20 @@ void sqliteCreateView(
sqliteExprListDelete(pSelect->pOrderBy);
pSelect->pOrderBy = 0;
}
- p->pSelect = pSelect;
+ /* Make a copy of the entire SELECT statement that defines the view.
+ ** This will force all the Expr.token.z values to be dynamically
+ ** allocated rather than point to the input string - which means that
+ ** they will persist after the current sqlite_exec() call returns.
+ */
+ p->pSelect = sqliteSelectDup(pSelect);
+ sqliteSelectDelete(pSelect);
if( !pParse->initFlag ){
- if( sqliteViewGetColumnNames(pParse, p) ){
- return;
- }
+ sqliteViewGetColumnNames(pParse, p);
}
+
+ /* Locate the end of the CREATE VIEW statement. Make sEnd point to
+ ** the end.
+ */
sEnd = pParse->sLastToken;
if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
sEnd.z += sEnd.n;
@@ -876,12 +884,9 @@ void sqliteCreateView(
while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; }
sEnd.z = &z[n-1];
sEnd.n = 1;
- z = p->pSelect->zSelect = sqliteStrNDup(z, n);
- if( z ){
- offset = ((int)z) - (int)pBegin->z;
- sqliteSelectMoveStrings(p->pSelect, offset);
- sqliteEndTable(pParse, &sEnd, 0);
- }
+
+ /* Use sqliteEndTable() to add the view to the SQLITE_MASTER table */
+ sqliteEndTable(pParse, &sEnd, 0);
return;
}
diff --git a/src/expr.c b/src/expr.c
index 43b4f7ee0..9a358c9fb 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.79 2002/07/18 00:34:12 drh Exp $
+** $Id: expr.c,v 1.80 2002/08/24 18:24:54 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -34,16 +34,17 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
pNew->pLeft = pLeft;
pNew->pRight = pRight;
if( pToken ){
+ assert( pToken->dyn==0 );
pNew->token = *pToken;
+ pNew->token.base = 1;
+ }else if( pLeft && pRight ){
+ sqliteExprSpan(pNew, &pLeft->token, &pRight->token);
}else{
+ pNew->token.dyn = 0;
+ pNew->token.base = 1;
pNew->token.z = 0;
pNew->token.n = 0;
}
- if( pLeft && pRight ){
- sqliteExprSpan(pNew, &pLeft->span, &pRight->span);
- }else{
- pNew->span = pNew->token;
- }
return pNew;
}
@@ -53,8 +54,17 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
*/
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
if( pExpr ){
- pExpr->span.z = pLeft->z;
- pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
+ assert( pExpr->token.dyn==0 );
+ if( pLeft->dyn==0 && pRight->dyn==0 ){
+ pExpr->token.z = pLeft->z;
+ pExpr->token.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
+ pExpr->token.base = 0;
+ }else{
+ pExpr->token.z = 0;
+ pExpr->token.n = 0;
+ pExpr->token.dyn = 0;
+ pExpr->token.base = 0;
+ }
}
}
@@ -71,8 +81,18 @@ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
+
+ /* Expr.token.n is the length of the entire function
+ ** call, including the function arguments. The parser
+ ** will extend token.n to cover the either length of the string.
+ ** Expr.nFuncName is the length of just the function name.
+ */
+ pNew->token.dyn = 0;
+ pNew->token.base = 1;
if( pToken ){
+ assert( pToken->dyn==0 );
pNew->token = *pToken;
+ pNew->nFuncName = pToken->n>255 ? 255 : pToken->n;
}else{
pNew->token.z = 0;
pNew->token.n = 0;
@@ -85,6 +105,7 @@ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
*/
void sqliteExprDelete(Expr *p){
if( p==0 ) return;
+ if( p->token.dyn && p->token.z ) sqliteFree((char*)p->token.z);
if( p->pLeft ) sqliteExprDelete(p->pLeft);
if( p->pRight ) sqliteExprDelete(p->pRight);
if( p->pList ) sqliteExprListDelete(p->pList);
@@ -92,69 +113,6 @@ void sqliteExprDelete(Expr *p){
sqliteFree(p);
}
-/*
-** The following group of functions are used to translate the string
-** pointers of tokens in expression from one buffer to another.
-**
-** Normally, the Expr.token.z and Expr.span.z fields point into the
-** original input buffer of an SQL statement. This is usually OK
-** since the SQL statement is executed and the expression is deleted
-** before the input buffer is freed. Making the tokens point to the
-** original input buffer saves many calls to malloc() and thus helps
-** the library to run faster.
-**
-** But sometimes we need an expression to persist past the time when
-** the input buffer is freed. (Example: The SELECT clause of a
-** CREATE VIEW statement contains expressions that must persist for
-** the life of the view.) When that happens we have to make a
-** persistent copy of the input buffer and translate the Expr.token.z
-** and Expr.span.z fields to point to the copy rather than the
-** original input buffer. The following group of routines handle that
-** translation.
-**
-** The "offset" parameter is the distance from the original input buffer
-** to the persistent copy. These routines recursively walk the entire
-** expression tree and shift all tokens by "offset" amount.
-**
-** The work of figuring out the appropriate "offset" and making the
-** presistent copy of the input buffer is done by the calling routine.
-*/
-void sqliteExprMoveStrings(Expr *p, int offset){
- if( p==0 ) return;
- if( !p->staticToken ){
- if( p->token.z ) p->token.z += offset;
- if( p->span.z ) p->span.z += offset;
- }
- if( p->pLeft ) sqliteExprMoveStrings(p->pLeft, offset);
- if( p->pRight ) sqliteExprMoveStrings(p->pRight, offset);
- if( p->pList ) sqliteExprListMoveStrings(p->pList, offset);
- if( p->pSelect ) sqliteSelectMoveStrings(p->pSelect, offset);
-}
-void sqliteExprListMoveStrings(ExprList *pList, int offset){
- int i;
- if( pList==0 ) return;
- for(i=0; i<pList->nExpr; i++){
- sqliteExprMoveStrings(pList->a[i].pExpr, offset);
- }
-}
-static void sqliteSrcListMoveStrings(SrcList *pSrc, int offset){
- int i;
- if( pSrc==0 ) return;
- for(i=0; i<pSrc->nSrc; i++){
- sqliteSelectMoveStrings(pSrc->a[i].pSelect, offset);
- sqliteExprMoveStrings(pSrc->a[i].pOn, offset);
- }
-}
-void sqliteSelectMoveStrings(Select *pSelect, int offset){
- if( pSelect==0 ) return;
- sqliteExprListMoveStrings(pSelect->pEList, offset);
- sqliteSrcListMoveStrings(pSelect->pSrc, offset);
- sqliteExprMoveStrings(pSelect->pWhere, offset);
- sqliteExprListMoveStrings(pSelect->pGroupBy, offset);
- sqliteExprMoveStrings(pSelect->pHaving, offset);
- sqliteExprListMoveStrings(pSelect->pOrderBy, offset);
- sqliteSelectMoveStrings(pSelect->pPrior, offset);
-}
/*
** The following group of routines make deep copies of expressions,
@@ -162,10 +120,6 @@ void sqliteSelectMoveStrings(Select *pSelect, int offset){
** be deleted (by being passed to their respective ...Delete() routines)
** without effecting the originals.
**
-** Note, however, that the Expr.token.z and Expr.span.z fields point to
-** string space that is allocated separately from the expression tree
-** itself. These routines do NOT duplicate that string space.
-**
** The expression list, ID, and source lists return by sqliteExprListDup(),
** sqliteIdListDup(), and sqliteSrcListDup() can not be further expanded
** by subsequent calls to sqlite*ListAppend() routines.
@@ -178,12 +132,38 @@ Expr *sqliteExprDup(Expr *p){
pNew = sqliteMalloc( sizeof(*p) );
if( pNew==0 ) return 0;
memcpy(pNew, p, sizeof(*pNew));
+ /* Only make a copy of the token if it is a base token (meaning that
+ ** it covers a single term of an expression - not two or more terms)
+ ** or if it is already dynamically allocated. So, for example, in
+ ** a complex expression like "a+b+c", the token "b" would be duplicated
+ ** but "a+b" would not be. */
+ if( p->token.z!=0 && (p->token.base || p->token.dyn) ){
+ pNew->token.z = sqliteStrDup(p->token.z);
+ pNew->token.dyn = 1;
+ }else{
+ pNew->token.z = 0;
+ pNew->token.n = 0;
+ pNew->token.dyn = 0;
+ }
pNew->pLeft = sqliteExprDup(p->pLeft);
pNew->pRight = sqliteExprDup(p->pRight);
pNew->pList = sqliteExprListDup(p->pList);
pNew->pSelect = sqliteSelectDup(p->pSelect);
return pNew;
}
+void sqliteTokenCopy(Token *pTo, Token *pFrom){
+ if( pTo->dyn ) sqliteFree((char*)pTo->z);
+ pTo->base = pFrom->base;
+ if( pFrom->z ){
+ pTo->n = pFrom->n;
+ pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
+ pTo->dyn = 1;
+ }else{
+ pTo->n = 0;
+ pTo->z = 0;
+ pTo->dyn = 0;
+ }
+}
ExprList *sqliteExprListDup(ExprList *p){
ExprList *pNew;
int i;
@@ -194,7 +174,14 @@ ExprList *sqliteExprListDup(ExprList *p){
pNew->a = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
if( pNew->a==0 ) return 0;
for(i=0; i<p->nExpr; i++){
- pNew->a[i].pExpr = sqliteExprDup(p->a[i].pExpr);
+ Expr *pNewExpr, *pOldExpr;
+ pNew->a[i].pExpr = pNewExpr = sqliteExprDup(pOldExpr = p->a[i].pExpr);
+ if( pOldExpr->token.z!=0 && pNewExpr && pNewExpr->token.z==0 ){
+ /* Always make a copy of the token for top-level expressions in the
+ ** expression list. The logic in SELECT processing that determines
+ ** the names of columns in the result set needs this information */
+ sqliteTokenCopy(&pNew->a[i].pExpr->token, &p->a[i].pExpr->token);
+ }
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
pNew->a[i].sortOrder = p->a[i].sortOrder;
pNew->a[i].isAgg = p->a[i].isAgg;
@@ -363,6 +350,9 @@ int sqliteExprIsInteger(Expr *p, int *pValue){
}
break;
}
+ case TK_UPLUS: {
+ return sqliteExprIsInteger(p->pLeft, pValue);
+ }
case TK_UMINUS: {
int v;
if( sqliteExprIsInteger(p->pLeft, &v) ){
@@ -713,6 +703,39 @@ int sqliteExprResolveIds(
}
/*
+** pExpr is a node that defines a function of some kind. It might
+** be a syntactic function like "count(x)" or it might be a function
+** that implements an operator, like "a LIKE b".
+**
+** This routine makes *pzName point to the name of the function and
+** *pnName hold the number of characters in the function name.
+*/
+static void getFunctionName(Expr *pExpr, const char **pzName, int *pnName){
+ switch( pExpr->op ){
+ case TK_FUNCTION: {
+ *pzName = pExpr->token.z;
+ *pnName = pExpr->nFuncName;
+ break;
+ }
+ case TK_LIKE: {
+ *pzName = "like";
+ *pnName = 4;
+ break;
+ }
+ case TK_GLOB: {
+ *pzName = "glob";
+ *pnName = 4;
+ break;
+ }
+ default: {
+ *pzName = "can't happen";
+ *pnName = 12;
+ break;
+ }
+ }
+}
+
+/*
** Error check the functions in an expression. Make sure all
** function names are recognized and all functions have the correct
** number of arguments. Leave an error message in pParse->zErrMsg
@@ -725,6 +748,8 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
int nErr = 0;
if( pExpr==0 ) return 0;
switch( pExpr->op ){
+ case TK_GLOB:
+ case TK_LIKE:
case TK_FUNCTION: {
int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
@@ -732,16 +757,16 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i;
+ int nId; /* Number of characters in function name */
+ const char *zId; /* The function name. */
FuncDef *pDef;
- pDef = sqliteFindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n, n, 0);
+ getFunctionName(pExpr, &zId, &nId);
+ pDef = sqliteFindFunction(pParse->db, zId, nId, n, 0);
if( pDef==0 ){
- pDef = sqliteFindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n, -1, 0);
+ pDef = sqliteFindFunction(pParse->db, zId, nId, -1, 0);
if( pDef==0 ){
- if( n==1 && pExpr->token.n==6
- && sqliteStrNICmp(pExpr->token.z, "typeof", 6)==0 ){
+ if( n==1 && nId==6 && sqliteStrNICmp(zId, "typeof", 6)==0 ){
is_type_of = 1;
}else {
no_such_func = 1;
@@ -754,19 +779,17 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
}
if( is_agg && !allowAgg ){
sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1,
- pExpr->token.z, pExpr->token.n, "()", 2, 0);
+ zId, nId, "()", 2, 0);
pParse->nErr++;
nErr++;
is_agg = 0;
}else if( no_such_func ){
- sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1,
- pExpr->token.z, pExpr->token.n, 0);
+ sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1, zId,nId,0);
pParse->nErr++;
nErr++;
}else if( wrong_num_args ){
sqliteSetNString(&pParse->zErrMsg,
- "wrong number of arguments to function ",-1,
- pExpr->token.z, pExpr->token.n, "()", 2, 0);
+ "wrong number of arguments to function ", -1, zId, nId, "()", 2, 0);
pParse->nErr++;
nErr++;
}
@@ -849,6 +872,7 @@ int sqliteExprType(Expr *p){
case TK_NOTNULL:
case TK_NOT:
case TK_UMINUS:
+ case TK_UPLUS:
case TK_BITAND:
case TK_BITOR:
case TK_BITNOT:
@@ -859,6 +883,8 @@ int sqliteExprType(Expr *p){
case TK_FLOAT:
case TK_IN:
case TK_BETWEEN:
+ case TK_GLOB:
+ case TK_LIKE:
return SQLITE_SO_NUM;
case TK_STRING:
@@ -1031,6 +1057,19 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Concat, 2, 0);
break;
}
+ case TK_UPLUS: {
+ Expr *pLeft = pExpr->pLeft;
+ if( pLeft && pLeft->op==TK_INTEGER ){
+ sqliteVdbeAddOp(v, OP_Integer, atoi(pLeft->token.z), 0);
+ sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n);
+ }else if( pLeft && pLeft->op==TK_FLOAT ){
+ sqliteVdbeAddOp(v, OP_String, 0, 0);
+ sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n);
+ }else{
+ sqliteExprCode(pParse, pExpr->pLeft);
+ }
+ break;
+ }
case TK_UMINUS: {
assert( pExpr->pLeft );
if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
@@ -1068,13 +1107,17 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
break;
}
+ case TK_GLOB:
+ case TK_LIKE:
case TK_FUNCTION: {
int i;
ExprList *pList = pExpr->pList;
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
- pDef = sqliteFindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n, nExpr, 0);
+ int nId;
+ const char *zId;
+ getFunctionName(pExpr, &zId, &nId);
+ pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0);
assert( pDef!=0 );
for(i=0; i<nExpr; i++){
sqliteExprCode(pParse, pList->a[i].pExpr);
@@ -1402,9 +1445,16 @@ int sqliteExprCompare(Expr *pA, Expr *pB){
if( pA->pSelect || pB->pSelect ) return 0;
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
if( pA->token.z ){
+ int n;
if( pB->token.z==0 ) return 0;
- if( pB->token.n!=pA->token.n ) return 0;
- if( sqliteStrNICmp(pA->token.z, pB->token.z, pA->token.n)!=0 ) return 0;
+ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
+ n = pA->nFuncName;
+ if( pB->nFuncName!=n ) return 0;
+ }else{
+ n = pA->token.n;
+ if( pB->token.n!=n ) return 0;
+ }
+ if( sqliteStrNICmp(pA->token.z, pB->token.z, n)!=0 ) return 0;
}
return 1;
}
@@ -1475,7 +1525,7 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
pParse->aAgg[i].isAgg = 1;
pParse->aAgg[i].pExpr = pExpr;
pParse->aAgg[i].pFunc = sqliteFindFunction(pParse->db,
- pExpr->token.z, pExpr->token.n,
+ pExpr->token.z, pExpr->nFuncName,
pExpr->pList ? pExpr->pList->nExpr : 0, 0);
}
pExpr->iAgg = i;
diff --git a/src/main.c b/src/main.c
index 1924c8e16..bef414436 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.97 2002/08/13 23:02:57 drh Exp $
+** $Id: main.c,v 1.98 2002/08/24 18:24:54 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -795,8 +795,11 @@ int sqlite_create_function(
void *pUserData /* User data */
){
FuncDef *p;
+ int nName;
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
- p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
+ nName = strlen(zName);
+ if( nName>255 ) return 1;
+ p = sqliteFindFunction(db, zName, nName, nArg, 1);
if( p==0 ) return 1;
p->xFunc = xFunc;
p->xStep = 0;
@@ -813,8 +816,11 @@ int sqlite_create_aggregate(
void *pUserData /* User data */
){
FuncDef *p;
+ int nName;
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
- p = sqliteFindFunction(db, zName, strlen(zName), nArg, 1);
+ nName = strlen(zName);
+ if( nName>255 ) return 1;
+ p = sqliteFindFunction(db, zName, nName, nArg, 1);
if( p==0 ) return 1;
p->xFunc = 0;
p->xStep = xStep;
diff --git a/src/parse.y b/src/parse.y
index 801f5f3f1..061d16587 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.81 2002/08/18 22:41:22 drh Exp $
+** @(#) $Id: parse.y,v 1.82 2002/08/24 18:24:54 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -486,7 +486,7 @@ inscollist(A) ::= nm(Y). {A = sqliteIdListAppend(0,&Y);}
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
-%right UMINUS BITNOT.
+%right UMINUS UPLUS BITNOT.
%type expr {Expr*}
%destructor expr {sqliteExprDelete($$);}
@@ -506,10 +506,12 @@ expr(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);}
expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
A = sqliteExprFunction(Y, &X);
sqliteExprSpan(A,&X,&E);
+ if( A ) A->token.base = 1;
}
expr(A) ::= ID(X) LP STAR RP(E). {
A = sqliteExprFunction(0, &X);
sqliteExprSpan(A,&X,&E);
+ if( A ) A->token.base = 1;
}
expr(A) ::= expr(X) AND expr(Y). {A = sqliteExpr(TK_AND, X, Y, 0);}
expr(A) ::= expr(X) OR expr(Y). {A = sqliteExpr(TK_OR, X, Y, 0);}
@@ -526,18 +528,21 @@ expr(A) ::= expr(X) RSHIFT expr(Y). {A = sqliteExpr(TK_RSHIFT, X, Y, 0);}
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE] {
ExprList *pList = sqliteExprListAppend(0, Y, 0);
pList = sqliteExprListAppend(pList, X, 0);
- A = sqliteExprFunction(pList, &OP);
- sqliteExprSpan(A, &X->span, &Y->span);
+ A = sqliteExprFunction(pList, 0);
+ if( A ) A->op = OP;
+ sqliteExprSpan(A, &X->token, &Y->token);
}
expr(A) ::= expr(X) NOT likeop(OP) expr(Y). [LIKE] {
ExprList *pList = sqliteExprListAppend(0, Y, 0);
pList = sqliteExprListAppend(pList, X, 0);
- A = sqliteExprFunction(pList, &OP);
+ A = sqliteExprFunction(pList, 0);
+ if( A ) A->op = OP;
A = sqliteExpr(TK_NOT, A, 0, 0);
- sqliteExprSpan(A,&X->span,&Y->span);
+ sqliteExprSpan(A,&X->token,&Y->token);
}
-likeop(A) ::= LIKE(X). {A = X;}
-likeop(A) ::= GLOB(X). {A = X;}
+%type likeop {int}
+likeop(A) ::= LIKE. {A = TK_LIKE;}
+likeop(A) ::= GLOB. {A = TK_GLOB;}
expr(A) ::= expr(X) PLUS expr(Y). {A = sqliteExpr(TK_PLUS, X, Y, 0);}
expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
expr(A) ::= expr(X) STAR expr(Y). {A = sqliteExpr(TK_STAR, X, Y, 0);}
@@ -546,39 +551,39 @@ expr(A) ::= expr(X) REM expr(Y). {A = sqliteExpr(TK_REM, X, Y, 0);}
expr(A) ::= expr(X) CONCAT expr(Y). {A = sqliteExpr(TK_CONCAT, X, Y, 0);}
expr(A) ::= expr(X) ISNULL(E). {
A = sqliteExpr(TK_ISNULL, X, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) IS NULL(E). {
A = sqliteExpr(TK_ISNULL, X, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) NOTNULL(E). {
A = sqliteExpr(TK_NOTNULL, X, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) NOT NULL(E). {
A = sqliteExpr(TK_NOTNULL, X, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) IS NOT NULL(E). {
A = sqliteExpr(TK_NOTNULL, X, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= NOT(B) expr(X). {
A = sqliteExpr(TK_NOT, X, 0, 0);
- sqliteExprSpan(A,&B,&X->span);
+ sqliteExprSpan(A,&B,&X->token);
}
expr(A) ::= BITNOT(B) expr(X). {
A = sqliteExpr(TK_BITNOT, X, 0, 0);
- sqliteExprSpan(A,&B,&X->span);
+ sqliteExprSpan(A,&B,&X->token);
}
expr(A) ::= MINUS(B) expr(X). [UMINUS] {
A = sqliteExpr(TK_UMINUS, X, 0, 0);
- sqliteExprSpan(A,&B,&X->span);
+ sqliteExprSpan(A,&B,&X->token);
}
-expr(A) ::= PLUS(B) expr(X). [UMINUS] {
- A = X;
- sqliteExprSpan(A,&B,&X->span);
+expr(A) ::= PLUS(B) expr(X). [UPLUS] {
+ A = sqliteExpr(TK_UPLUS, X, 0, 0);
+ sqliteExprSpan(A,&B,&X->token);
}
expr(A) ::= LP(B) select(X) RP(E). {
A = sqliteExpr(TK_SELECT, 0, 0, 0);
@@ -590,7 +595,7 @@ expr(A) ::= expr(W) BETWEEN expr(X) AND expr(Y). {
pList = sqliteExprListAppend(pList, Y, 0);
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
if( A ) A->pList = pList;
- sqliteExprSpan(A,&W->span,&Y->span);
+ sqliteExprSpan(A,&W->token,&Y->token);
}
expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
ExprList *pList = sqliteExprListAppend(0, X, 0);
@@ -598,29 +603,29 @@ expr(A) ::= expr(W) NOT BETWEEN expr(X) AND expr(Y). {
A = sqliteExpr(TK_BETWEEN, W, 0, 0);
if( A ) A->pList = pList;
A = sqliteExpr(TK_NOT, A, 0, 0);
- sqliteExprSpan(A,&W->span,&Y->span);
+ sqliteExprSpan(A,&W->token,&Y->token);
}
expr(A) ::= expr(X) IN LP exprlist(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pList = Y;
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) IN LP select(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y;
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) NOT IN LP exprlist(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pList = Y;
A = sqliteExpr(TK_NOT, A, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). {
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pSelect = Y;
A = sqliteExpr(TK_NOT, A, 0, 0);
- sqliteExprSpan(A,&X->span,&E);
+ sqliteExprSpan(A,&X->token,&E);
}
/* CASE expressions */
@@ -717,8 +722,10 @@ plus_opt ::= .
cmd ::= CREATE(A) TRIGGER nm(B) trigger_time(C) trigger_event(D) ON nm(E)
foreach_clause(F) when_clause(G)
BEGIN trigger_cmd_list(S) END(Z). {
- sqliteCreateTrigger(pParse, &B, C, D.a, D.b, &E, F, G, S,
- A.z, (int)(Z.z - A.z) + Z.n );
+ Token all;
+ all.z = A.z;
+ all.n = (Z.z - A.z) + Z.n;
+ sqliteCreateTrigger(pParse, &B, C, D.a, D.b, &E, F, G, S, &all);
}
%type trigger_time {int}
@@ -769,17 +776,26 @@ trigger_cmd(A) ::= DELETE FROM nm(X) where_opt(Y).
trigger_cmd(A) ::= select(X). {A = sqliteTriggerSelectStep(X); }
// The special RAISE expression that may occur in trigger programs
-expr(A) ::= RAISE(X) LP IGNORE RP(Y). { A = sqliteExpr(TK_RAISE, 0, 0, 0);
- A->iColumn = OE_Ignore; sqliteExprSpan(A, &X, &Y);}
-expr(A) ::= RAISE(X) LP ROLLBACK COMMA nm(Z) RP(Y).
-{ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
- A->iColumn = OE_Rollback; sqliteExprSpan(A, &X, &Y);}
-expr(A) ::= RAISE(X) LP ABORT COMMA nm(Z) RP(Y).
-{ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
- A->iColumn = OE_Abort; sqliteExprSpan(A, &X, &Y);}
-expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y).
-{ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
- A->iColumn = OE_Fail; sqliteExprSpan(A, &X, &Y);}
+expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
+ A = sqliteExpr(TK_RAISE, 0, 0, 0);
+ A->iColumn = OE_Ignore;
+ /* sqliteExprSpan(A, &X, &Y); */
+}
+expr(A) ::= RAISE(X) LP ROLLBACK COMMA nm(Z) RP(Y). {
+ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
+ A->iColumn = OE_Rollback;
+ /* sqliteExprSpan(A, &X, &Y); */
+}
+expr(A) ::= RAISE(X) LP ABORT COMMA nm(Z) RP(Y). {
+ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
+ A->iColumn = OE_Abort;
+ /* sqliteExprSpan(A, &X, &Y); */
+}
+expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y). {
+ A = sqliteExpr(TK_RAISE, 0, 0, &Z);
+ A->iColumn = OE_Fail;
+ /* sqliteExprSpan(A, &X, &Y); */
+}
//////////////////////// DROP TRIGGER statement //////////////////////////////
cmd ::= DROP TRIGGER nm(X). {
diff --git a/src/select.c b/src/select.c
index 0bb456af7..2171ead1b 100644
--- a/src/select.c
+++ b/src/select.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.107 2002/08/04 00:52:38 drh Exp $
+** $Id: select.c,v 1.108 2002/08/24 18:24:54 drh Exp $
*/
#include "sqliteInt.h"
@@ -156,18 +156,16 @@ static void addWhereTerm(
dummy.z = zCol;
dummy.n = strlen(zCol);
+ dummy.base = 1;
+ dummy.dyn = 0;
pE1a = sqliteExpr(TK_ID, 0, 0, &dummy);
- pE1a->staticToken = 1;
pE2a = sqliteExpr(TK_ID, 0, 0, &dummy);
- pE2a->staticToken = 1;
dummy.z = pTab1->zName;
dummy.n = strlen(dummy.z);
pE1b = sqliteExpr(TK_ID, 0, 0, &dummy);
- pE1b->staticToken = 1;
dummy.z = pTab2->zName;
dummy.n = strlen(dummy.z);
pE2b = sqliteExpr(TK_ID, 0, 0, &dummy);
- pE2b->staticToken = 1;
pE1c = sqliteExpr(TK_DOT, pE1b, pE1a, 0);
pE2c = sqliteExpr(TK_DOT, pE2b, pE2a, 0);
pE = sqliteExpr(TK_EQ, pE1c, pE2c, 0);
@@ -643,9 +641,9 @@ static void generateColumnNames(
zCol = pTab->aCol[iCol].zName;
zType = pTab->aCol[iCol].zType;
}
- if( p->span.z && p->span.z[0] && !showFullNames ){
+ if( p->token.z && p->token.z[0] && !showFullNames ){
int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
+ sqliteVdbeChangeP3(v, -1, p->token.z, p->token.n);
sqliteVdbeCompressSpace(v, addr);
}else if( pTabList->nSrc>1 || showFullNames ){
char *zName = 0;
@@ -661,13 +659,13 @@ static void generateColumnNames(
sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, zCol, 0);
}
- }else if( p->span.z && p->span.z[0] && !showFullNames ){
+ }else if( p->token.z && p->token.z[0] && !showFullNames ){
int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
+ sqliteVdbeChangeP3(v, -1, p->token.z, p->token.n);
sqliteVdbeCompressSpace(v, addr);
- }else if( p->span.z && p->span.z[0] ){
+ }else if( p->token.z && p->token.z[0] ){
int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
+ sqliteVdbeChangeP3(v, -1, p->token.z, p->token.n);
sqliteVdbeCompressSpace(v, addr);
}else{
char zName[30];
@@ -730,8 +728,8 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
Expr *p;
if( pEList->a[i].zName ){
pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
- }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
- sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
+ }else if( (p=pEList->a[i].pExpr)->token.z && p->token.z[0] ){
+ sqliteSetNString(&pTab->aCol[i].zName, p->token.z, p->token.n, 0);
}else if( p->op==TK_DOT && p->pRight && p->pRight->token.z &&
p->pRight->token.z[0] ){
sqliteSetNString(&pTab->aCol[i].zName,
@@ -895,16 +893,22 @@ static int fillInColumnList(Parse *pParse, Select *p){
if( pRight==0 ) break;
pRight->token.z = zName;
pRight->token.n = strlen(zName);
- if( zTabName ){
+ pRight->token.dyn = 0;
+ pRight->token.base = 1;
+ if( zTabName && pTabList->nSrc>1 ){
pLeft = sqliteExpr(TK_ID, 0, 0, 0);
- if( pLeft==0 ) break;
- pLeft->token.z = zTabName;
- pLeft->token.n = strlen(zTabName);
pExpr = sqliteExpr(TK_DOT, pLeft, pRight, 0);
if( pExpr==0 ) break;
+ pLeft->token.z = zTabName;
+ pLeft->token.n = strlen(zTabName);
+ pLeft->token.dyn = 0;
+ pLeft->token.base = 1;
+ sqliteSetString((char**)&pExpr->token.z, zTabName, ".", zName, 0);
+ pExpr->token.n = strlen(pExpr->token.z);
+ pExpr->token.base = 0;
+ pExpr->token.dyn = 1;
}else{
pExpr = pRight;
- pExpr->span = pExpr->token;
}
pNew = sqliteExprListAppend(pNew, pExpr, 0);
}
@@ -945,8 +949,10 @@ void sqliteSelectUnbind(Select *p){
if( (pTab = pSrc->a[i].pTab)!=0 ){
if( pTab->isTransient ){
sqliteDeleteTable(0, pTab);
+#if 0
sqliteSelectDelete(pSrc->a[i].pSelect);
pSrc->a[i].pSelect = 0;
+#endif
}
pSrc->a[i].pTab = 0;
if( pSrc->a[i].pSelect ){
@@ -1309,7 +1315,8 @@ static void substExpr(Expr *pExpr, int iTable, ExprList *pEList, int iSub){
pExpr->iTable = pNew->iTable;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
- pExpr->token = pNew->token;
+ pExpr->nFuncName = pNew->nFuncName;
+ sqliteTokenCopy(&pExpr->token, &pNew->token);
if( iSub!=iTable ){
changeTables(pExpr, iSub, iTable);
}
@@ -1428,7 +1435,8 @@ int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
for(i=0; i<pList->nExpr; i++){
if( pList->a[i].zName==0 ){
Expr *pExpr = pList->a[i].pExpr;
- pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n);
+ assert( pExpr->token.z!=0 );
+ pList->a[i].zName = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
}
}
if( isAgg ){
@@ -1535,7 +1543,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0;
- if( pExpr->token.n!=3 ) return 0;
+ if( pExpr->nFuncName!=3 ) return 0;
if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){
seekOp = OP_Rewind;
}else if( sqliteStrNICmp(pExpr->token.z,"max",3)==0 ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index e69579532..912ef83e4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.142 2002/08/02 10:36:10 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.143 2002/08/24 18:24:55 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@@ -391,11 +391,19 @@ struct Index {
/*
** Each token coming out of the lexer is an instance of
-** this structure.
+** this structure. Tokens are also used as part of an expression.
+**
+** A "base" token is a real single token such as would come out of the
+** lexer. There are also compound tokens which are aggregates of one
+** or more base tokens. Compound tokens are used to name columns in the
+** result set of a SELECT statement. In the expression "a+b+c", "b"
+** is a base token but "a+b" is a compound token.
*/
struct Token {
const char *z; /* Text of the token. Not NULL-terminated! */
- int n; /* Number of characters in this token */
+ unsigned dyn : 1; /* True for malloced memory, false for static */
+ unsigned base : 1; /* True for a base token, false for compounds */
+ unsigned n : 30; /* Number of characters in this token */
};
/*
@@ -411,10 +419,10 @@ struct Token {
** Expr.pRight and Expr.pLeft are subexpressions. Expr.pList is a list
** of argument if the expression is a function.
**
-** Expr.token is the operator token for this node. Expr.span is the complete
-** subexpression represented by this node and all its decendents. These
-** fields are used for error reporting and for reconstructing the text of
-** an expression to use as the column name in a SELECT statement.
+** Expr.token is the operator token for this node. For some expressions
+** that have subexpressions, Expr.token can be the complete text that gave
+** rise to the Expr. In the latter case, the token is marked as being
+** a compound token.
**
** An expression of the form ID or ID.ID refers to a column in a table.
** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is
@@ -435,13 +443,12 @@ struct Token {
struct Expr {
u8 op; /* Operation performed by this node */
u8 dataType; /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */
- u8 isJoinExpr; /* Origina is the ON or USING phrase of a join */
- u8 staticToken; /* Expr.token.z points to static memory */
+ u8 isJoinExpr; /* Origin is the ON or USING phrase of a join */
+ u8 nFuncName; /* Number of characters in a function name */
Expr *pLeft, *pRight; /* Left and right subnodes */
ExprList *pList; /* A list of expressions used as function arguments
** or in "<expr> IN (<expr-list)" */
Token token; /* An operand token */
- Token span; /* Complete text of the expression */
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** iColumn-th field of the iTable-th table. */
int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
@@ -677,11 +684,6 @@ struct Parse {
* linked list is stored as the "pTrigger" member of the associated
* struct Table.
*
- * The "strings" member of struct Trigger contains a pointer to the memory
- * referenced by the various Token structures referenced indirectly by the
- * "pWhen", "pColumns" and "step_list" members. (ie. the memory allocated for
- * use in conjunction with the sqliteExprMoveStrings() etc. interface).
- *
* The "step_list" member points to the first element of a linked list
* containing the SQL statements specified as the trigger program.
*
@@ -708,7 +710,6 @@ struct Trigger {
int foreach; /* One of TK_ROW or TK_STATEMENT */
TriggerStep *step_list; /* Link list of trigger program steps */
- char *strings; /* pointer to allocation of Token strings */
Trigger *pNext; /* Next trigger associated with the table */
};
@@ -920,10 +921,8 @@ void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
void sqliteBeginWriteOperation(Parse*, int);
void sqliteEndWriteOperation(Parse*);
-void sqliteExprMoveStrings(Expr*, int);
-void sqliteExprListMoveStrings(ExprList*, int);
-void sqliteSelectMoveStrings(Select*, int);
Expr *sqliteExprDup(Expr*);
+void sqliteTokenCopy(Token*, Token*);
ExprList *sqliteExprListDup(ExprList*);
SrcList *sqliteSrcListDup(SrcList*);
IdList *sqliteIdListDup(IdList*);
@@ -935,7 +934,7 @@ int sqliteSafetyOff(sqlite*);
int sqliteSafetyCheck(sqlite*);
void sqliteChangeCookie(sqlite*, Vdbe*);
void sqliteCreateTrigger(Parse*, Token*, int, int, IdList*, Token*,
- int, Expr*, TriggerStep*, char const*,int);
+ int, Expr*, TriggerStep*, Token*);
void sqliteDropTrigger(Parse*, Token*, int);
int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
diff --git a/src/tokenize.c b/src/tokenize.c
index ed2329c04..46f6aa864 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
-** $Id: tokenize.c,v 1.47 2002/07/01 12:27:09 drh Exp $
+** $Id: tokenize.c,v 1.48 2002/08/24 18:24:56 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -418,6 +418,8 @@ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
break;
}
pParse->sLastToken.z = &zSql[i];
+ pParse->sLastToken.base = 1;
+ pParse->sLastToken.dyn = 0;
pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType);
i += pParse->sLastToken.n;
if( once ){
diff --git a/src/trigger.c b/src/trigger.c
index 53eff0c41..24bd74888 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -13,6 +13,24 @@
#include "sqliteInt.h"
/*
+** Delete a linked list of TriggerStep structures.
+*/
+static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
+ while( pTriggerStep ){
+ TriggerStep * pTmp = pTriggerStep;
+ pTriggerStep = pTriggerStep->pNext;
+
+ if( pTmp->target.dyn ) sqliteFree(pTmp->target.z);
+ sqliteExprDelete(pTmp->pWhere);
+ sqliteExprListDelete(pTmp->pExprList);
+ sqliteSelectDelete(pTmp->pSelect);
+ sqliteIdListDelete(pTmp->pIdList);
+
+ sqliteFree(pTmp);
+ }
+}
+
+/*
** This is called by the parser when it sees a CREATE TRIGGER statement. See
** comments surrounding struct Trigger in sqliteInt.h for a description of
** how triggers are stored.
@@ -27,13 +45,10 @@ void sqliteCreateTrigger(
int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */
TriggerStep *pStepList, /* The triggered program */
- char const *zData, /* The string data to make persistent */
- int zDataLen
+ Token *pAll /* Token that describes the complete CREATE TRIGGER */
){
Trigger *nt;
Table *tab;
- int offset;
- TriggerStep *ss;
/* Check that:
** 1. the trigger name does not already exist.
@@ -98,28 +113,15 @@ void sqliteCreateTrigger(
if( nt==0 ) goto trigger_cleanup;
nt->name = sqliteStrNDup(pName->z, pName->n);
nt->table = sqliteStrNDup(pTableName->z, pTableName->n);
- nt->strings = sqliteStrNDup(zData, zDataLen);
if( sqlite_malloc_failed ) goto trigger_cleanup;
nt->op = op;
nt->tr_tm = tr_tm;
- nt->pWhen = pWhen;
- nt->pColumns = pColumns;
+ nt->pWhen = sqliteExprDup(pWhen);
+ sqliteExprDelete(pWhen);
+ nt->pColumns = sqliteIdListDup(pColumns);
+ sqliteIdListDelete(pColumns);
nt->foreach = foreach;
nt->step_list = pStepList;
- offset = (int)(nt->strings - zData);
- sqliteExprMoveStrings(nt->pWhen, offset);
-
- ss = nt->step_list;
- while( ss ){
- sqliteSelectMoveStrings(ss->pSelect, offset);
- if( ss->target.z ){
- ss->target.z += offset;
- }
- sqliteExprMoveStrings(ss->pWhere, offset);
- sqliteExprListMoveStrings(ss->pExprList, offset);
-
- ss = ss->pNext;
- }
/* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry
@@ -148,7 +150,7 @@ void sqliteCreateTrigger(
P3_STATIC);
sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
- sqliteVdbeChangeP3(v, addr+5, nt->strings, 0);
+ sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
if( !tab->isTemp ){
sqliteChangeCookie(pParse->db, v);
}
@@ -165,7 +167,6 @@ void sqliteCreateTrigger(
tab->pTrigger = nt;
return;
}else{
- sqliteFree(nt->strings);
sqliteFree(nt->name);
sqliteFree(nt->table);
sqliteFree(nt);
@@ -175,20 +176,43 @@ trigger_cleanup:
sqliteIdListDelete(pColumns);
sqliteExprDelete(pWhen);
- {
- TriggerStep * pp;
- TriggerStep * nn;
-
- pp = pStepList;
- while( pp ){
- nn = pp->pNext;
- sqliteExprDelete(pp->pWhere);
- sqliteExprListDelete(pp->pExprList);
- sqliteSelectDelete(pp->pSelect);
- sqliteIdListDelete(pp->pIdList);
- sqliteFree(pp);
- pp = nn;
- }
+ sqliteDeleteTriggerStep(pStepList);
+}
+
+/*
+** Make a copy of all components of the given trigger step. This has
+** the effect of copying all Expr.token.z values into memory obtained
+** from sqliteMalloc(). As initially created, the Expr.token.z values
+** all point to the input string that was fed to the parser. But that
+** string is ephemeral - it will go away as soon as the sqlite_exec()
+** call that started the parser exits. This routine makes a persistent
+** copy of all the Expr.token.z strings so that the TriggerStep structure
+** will be valid even after the sqlite_exec() call returns.
+*/
+static void sqlitePersistTriggerStep(TriggerStep *p){
+ if( p->target.z ){
+ p->target.z = sqliteStrNDup(p->target.z, p->target.n);
+ p->target.dyn = 1;
+ }
+ if( p->pSelect ){
+ Select *pNew = sqliteSelectDup(p->pSelect);
+ sqliteSelectDelete(p->pSelect);
+ p->pSelect = pNew;
+ }
+ if( p->pWhere ){
+ Expr *pNew = sqliteExprDup(p->pWhere);
+ sqliteExprDelete(p->pWhere);
+ p->pWhere = pNew;
+ }
+ if( p->pExprList ){
+ ExprList *pNew = sqliteExprListDup(p->pExprList);
+ sqliteExprListDelete(p->pExprList);
+ p->pExprList = pNew;
+ }
+ if( p->pIdList ){
+ IdList *pNew = sqliteIdListDup(p->pIdList);
+ sqliteIdListDelete(p->pIdList);
+ p->pIdList = pNew;
}
}
@@ -206,6 +230,7 @@ TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
+ sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
@@ -236,6 +261,7 @@ TriggerStep *sqliteTriggerInsertStep(
pTriggerStep->pIdList = pColumn;
pTriggerStep->pExprList = pEList;
pTriggerStep->orconf = orconf;
+ sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
@@ -259,6 +285,7 @@ TriggerStep *sqliteTriggerUpdateStep(
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = orconf;
+ sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
@@ -276,6 +303,7 @@ TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
pTriggerStep->target = *pTableName;
pTriggerStep->pWhere = pWhere;
pTriggerStep->orconf = OE_Default;
+ sqlitePersistTriggerStep(pTriggerStep);
return pTriggerStep;
}
@@ -286,24 +314,11 @@ TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
void sqliteDeleteTrigger(Trigger *pTrigger){
TriggerStep *pTriggerStep;
- pTriggerStep = pTrigger->step_list;
- while( pTriggerStep ){
- TriggerStep * pTmp = pTriggerStep;
- pTriggerStep = pTriggerStep->pNext;
-
- sqliteExprDelete(pTmp->pWhere);
- sqliteExprListDelete(pTmp->pExprList);
- sqliteSelectDelete(pTmp->pSelect);
- sqliteIdListDelete(pTmp->pIdList);
-
- sqliteFree(pTmp);
- }
-
+ sqliteDeleteTriggerStep(pTrigger->step_list);
sqliteFree(pTrigger->name);
sqliteFree(pTrigger->table);
sqliteExprDelete(pTrigger->pWhen);
sqliteIdListDelete(pTrigger->pColumns);
- sqliteFree(pTrigger->strings);
sqliteFree(pTrigger);
}