diff options
author | drh <drh@noemail.net> | 2002-08-24 18:24:51 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2002-08-24 18:24:51 +0000 |
commit | 4b59ab5e643009b42d6d3efb57c463c8d1123ad6 (patch) | |
tree | 8220ecb6868d936e28a34344e6760aac8bc43411 /src | |
parent | 79983d03e83d845a7a35367ffdf97d3c6b8167e5 (diff) | |
download | sqlite-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.c | 31 | ||||
-rw-r--r-- | src/expr.c | 234 | ||||
-rw-r--r-- | src/main.c | 12 | ||||
-rw-r--r-- | src/parse.y | 92 | ||||
-rw-r--r-- | src/select.c | 50 | ||||
-rw-r--r-- | src/sqliteInt.h | 39 | ||||
-rw-r--r-- | src/tokenize.c | 4 | ||||
-rw-r--r-- | src/trigger.c | 117 |
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); } |