aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest52
-rw-r--r--manifest.uuid2
-rw-r--r--src/alter.c2
-rw-r--r--src/attach.c6
-rw-r--r--src/build.c14
-rw-r--r--src/delete.c2
-rw-r--r--src/expr.c238
-rw-r--r--src/func.c5
-rw-r--r--src/parse.y2
-rw-r--r--src/pragma.c2
-rw-r--r--src/resolve.c34
-rw-r--r--src/select.c26
-rw-r--r--src/sqliteInt.h29
-rw-r--r--src/tokenize.c2
-rw-r--r--src/trigger.c36
-rw-r--r--src/update.c2
-rw-r--r--src/util.c2
-rw-r--r--src/vdbemem.c19
-rw-r--r--src/walker.c2
-rw-r--r--src/where.c12
-rw-r--r--test/attach.test2
-rw-r--r--test/select1.test2
-rw-r--r--test/tkt3508.test2
23 files changed, 297 insertions, 198 deletions
diff --git a/manifest b/manifest
index c2c460feb..b2ca6dc2d 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Simplifications\sto\sthe\sExpr\sobject:\s\sRemove\sExpr.span\scompletely\sand\sconvert\nExpr.token\sinto\sa\schar*\sExpr.zToken.\s\sAlso\ssimplify\sthe\sToken\sobject\sby\nremoving\sthe\sToken.dyn\sand\sToken.quoted\sfields.\s(CVS\s6681)
-D 2009-05-27T10:31:29
+C Additional\srefinements\sto\sExpr\shandling.\s\sRestore\scompression\sof\strigger\nexpressions.\s\sChange\sExpr.zToken\sto\sExpr.u.zToken\sand\sadded\sExpr.u.iValue.\nRemove\san\sunnecessary\sExprDup\sfrom\sCHECK\sconstraint\sprocessing.\s\sAnd\sso\sforth.\s(CVS\s6682)
+D 2009-05-28T01:00:55
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -99,9 +99,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
-F src/alter.c accb3c77ef20903e16ec44a04f5ee5ff1bfcf7e4
+F src/alter.c 88b8cc66c09853b5723f66cfd0103dbebb62c562
F src/analyze.c e239496cfb5394ac8867f1c112905ddab8d01cd9
-F src/attach.c 92517f52fb53037c0584c0ecac922ec83e5d9d42
+F src/attach.c ad7eeae19c0844d3b329781c5a35ccda0a2010d2
F src/auth.c 98db07c2088455797678eb1031f42d4d94d18a71
F src/backup.c 437efc2c3371b52bbb943b8c9dfabba774adcf86
F src/bitvec.c ef370407e03440b0852d05024fb016b14a471d3d
@@ -109,14 +109,14 @@ F src/btmutex.c 9b899c0d8df3bd68f527b0afe03088321b696d3c
F src/btree.c 7c4b02afea7efb561361f20408414fec68df898c
F src/btree.h 58d876d3ed944a8f4f1fd0e67024b385243fc9dd
F src/btreeInt.h df64030d632f8c8ac217ed52e8b6b3eacacb33a5
-F src/build.c 028255aa488ee3941ee77e16ae078ad5e03fe6d8
+F src/build.c 567574f5756e9e462cf50c5da1895dc43672bafe
F src/callback.c 57359fa93de47c341b6b8ee504a88ff276397686
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
-F src/delete.c 59da0e52380d7626e98d84082b72f431fafe2799
-F src/expr.c cdddb81c68a0d222e03a4b92a7821d370c298a8e
+F src/delete.c cb791855c7948cecc96def9d97989879ca26f257
+F src/expr.c 2f8b6e5c3c867fa421189ad5692b1ff60ecc59c4
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
-F src/func.c be5067593d9c8971e1af803bb503b91ef1541e8d
+F src/func.c 9d7b47729c337c5e4b78d795922ed34eec4aef67
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
@@ -148,21 +148,21 @@ F src/os_unix.c e55d977c516ed880a2f83f0610b019efd9f8bc06
F src/os_win.c 725c38a524d168ce280446ad8761d731bc516405
F src/pager.c 8bf62fefc7afefc065d37611ebfd1fe0e1c2eb39
F src/pager.h 73f481a308a873ccd626d97331c081db3b53e2e5
-F src/parse.y 6b55e52fb3362ad84130013f861c21f4b3ba5005
+F src/parse.y 07690df997d50b3fdb5e5121e5a27f1a080db13d
F src/pcache.c 395f752a13574120bd7513a400ba02a265aaa76d
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
F src/pcache1.c bed75f157283e7c666f323df0c874c6a2515f76e
-F src/pragma.c cf9adc601f5d0e6de6f3a3ffb8fa5dfef8217d13
+F src/pragma.c d4a6fd74fd1dba0f22c8930791f7fbbe80d2ef26
F src/prepare.c f46d1a029760edee5447e27164fb3ae10e2a6839
F src/printf.c 3f4dca207a88258d37af5a7a03e800a825fe6456
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
-F src/resolve.c 0c9faa469e4e71ff84efd7fa60613036e88498d6
+F src/resolve.c 64e7ac825a887eb5e33262f0b355514734b24ccd
F src/rowset.c c64dafba1f9fd876836c8db8682966b9d197eb1f
-F src/select.c 18c296d45cc8cad8dc4b862d2df000a4681d7883
+F src/select.c fd1737a667bab296f50049a841b3aba5ec89418e
F src/shell.c 7eacd0bdaa887931f5ff205c9defc3e8df95a2dd
F src/sqlite.h.in 79210c4d8905cfb4b038486dde5f36fabb796a86
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 28a5b5c0bfb0efbb735dc0dedc3f076f7de95c57
+F src/sqliteInt.h 97f9125229c14cd3afa6c4fed4b419a1899be476
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
@@ -197,11 +197,11 @@ F src/test_server.c f0a403b5f699c09bd2b1236b6f69830fd6221f6b
F src/test_tclvar.c 9e42fa59d3d2f064b7ab8628e7ab2dc8a9fe93d4
F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
-F src/tokenize.c ef5e56bae212d08ff3a334ff059bc5292322251d
-F src/trigger.c 6d233d6d737a229e31f810012f38ecac7dd89021
-F src/update.c 3aec63a3a85754d16f7571ec80eb928e2fcf6c2e
+F src/tokenize.c 75367c7e4d2aee39a3b0496911284b73de5b4363
+F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b
+F src/update.c 6ae6c26adff8dc34532d578f66e6cfde04b5d177
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
-F src/util.c f3ee188f05921d450ee2a2ff236e455d3131f9ce
+F src/util.c bb2bdd6dd0b51d13301dfb5bfba7abf070aef1dd
F src/vacuum.c e8d178004377e97500c7ea87c8a3542976e3ea45
F src/vdbe.c b859cb274024e5755aa03625251ff859e3e95158
F src/vdbe.h 35a648bc3279a120da24f34d9a25213ec15daf8a
@@ -209,10 +209,10 @@ F src/vdbeInt.h 43183a2a18654fa570219ab65e53a608057c48ae
F src/vdbeapi.c 86aa27a5f3493aaffb8ac051782aa3b22670d7ed
F src/vdbeaux.c 1a07329bdf51cc3687f88d9f5b2bd3f1d47cc5a8
F src/vdbeblob.c 5c5abe9af28316772e7829359f6f9cda2c737ebd
-F src/vdbemem.c 4d1a9b01ad47a8699b767bfc364168c61510b3d1
+F src/vdbemem.c 9f4224911176f27b80d6e8f70f0e909aead5091b
F src/vtab.c b0216337ae7d27708dedd56d220e6f4fecda92f1
-F src/walker.c b28cc618f5dc739bc5fb77389b6a42bc1be679ab
-F src/where.c 145bb0d0590b36603a38f0fe17887fde06c3ed53
+F src/walker.c ec4b9742a4077ef80346e2f9aaf0f44c2d95087a
+F src/where.c 1a21128db4905a29c287086acd7962cbba1c6f7b
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
@@ -226,7 +226,7 @@ F test/async.test c042ff6d2a29f65e05d498a52448229d25bb5d9d
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
F test/async4.test bdb997924394a2034ff3df1d839ff95b2e602ed4
-F test/attach.test 27635c34453504c2df8630730a5eab6e98c59eb9
+F test/attach.test e710d543769305942e9354cee5aba8cfcbe89577
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
F test/attach3.test 7b92dc8e40c1ebca9732ca6f2d3fefbd46f196df
F test/attachmalloc.test cf8cf17d183de357b1147a9baacbdfc85b940b61
@@ -521,7 +521,7 @@ F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test e28f7d8ab8a389d4e5bd1dc08bf2c3312754cc67
F test/schema.test deafe5472099ab5bc65748059dc5182fc8ebad74
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
-F test/select1.test 313078d5fca7a6fe1fb83e5f2e5b3e317beb8fac
+F test/select1.test f67ca2dfc05df41c7b86eb32ca409b427a5f43b0
F test/select2.test 9735da20ccd41e42bf2b4c19fd939141b591adae
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17
@@ -629,7 +629,7 @@ F test/tkt3457.test e9ca2b90f0eb1fb8be73a30d29aacb2e3abedeb9
F test/tkt3461.test f79d027198b7e2bcf3d2d1a5501b6efef52096ee
F test/tkt3472.test 98c7e54b8fef2b1266a552a66c8e5d88a6908d1d
F test/tkt3493.test 8472b3464e49a27ff7271308eec46154209e667b
-F test/tkt3508.test 26dbc10515145627fde6ad8905c842cec18e6f87
+F test/tkt3508.test d75704db9501625c7f7deec119fcaf1696aefb7d
F test/tkt3522.test 22ce2ebbcb04a6be56c0977d405c207967318fd6
F test/tkt3527.test ee4af96183579565987e58873a7490bc04934ffb
F test/tkt3541.test 5dc257bde9bc833ab9cc6844bf170b998dbb950a
@@ -731,7 +731,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 086206e1f51e22ce7b9f45865b370088db126cd2
-R 7a6811accc43c94a2230cdb121b78704
+P 7cb1c3ba0759539cb035978fdaff6316775986f3
+R fbcf886b0709cb6861bc0baa12580b58
U drh
-Z 55c79ac1dc5e1ab2bd7febb8a2417351
+Z 0ccb491a6522821e67071949c3a88c54
diff --git a/manifest.uuid b/manifest.uuid
index 8182fe564..c70ec0db5 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7cb1c3ba0759539cb035978fdaff6316775986f3 \ No newline at end of file
+4ac2bdfbb4230b6ceaae87e738fa61036bbe03cb \ No newline at end of file
diff --git a/src/alter.c b/src/alter.c
index 0c3e00e51..ac185f2da 100644
--- a/src/alter.c
+++ b/src/alter.c
@@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
-** $Id: alter.c,v 1.59 2009/05/27 10:31:29 drh Exp $
+** $Id: alter.c,v 1.60 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
diff --git a/src/attach.c b/src/attach.c
index 2b5ddb589..9af765973 100644
--- a/src/attach.c
+++ b/src/attach.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
-** $Id: attach.c,v 1.91 2009/05/27 10:31:29 drh Exp $
+** $Id: attach.c,v 1.92 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -41,7 +41,7 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
if( pExpr->op!=TK_ID ){
rc = sqlite3ResolveExprNames(pName, pExpr);
if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){
- sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->zToken);
+ sqlite3ErrorMsg(pName->pParse, "invalid name: \"%s\"", pExpr->u.zToken);
return SQLITE_ERROR;
}
}else{
@@ -312,7 +312,7 @@ static void codeAttach(
#ifndef SQLITE_OMIT_AUTHORIZATION
if( pAuthArg ){
- char *zAuthArg = pAuthArg->zToken;
+ char *zAuthArg = pAuthArg->u.zToken;
if( zAuthArg==0 ){
goto attach_end;
}
diff --git a/src/build.c b/src/build.c
index 66f932e6e..ce8385992 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
-** $Id: build.c,v 1.545 2009/05/27 10:31:29 drh Exp $
+** $Id: build.c,v 1.546 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -1181,14 +1181,12 @@ void sqlite3AddCheckConstraint(
#ifndef SQLITE_OMIT_CHECK
Table *pTab = pParse->pNewTable;
if( pTab && !IN_DECLARE_VTAB ){
- /* The CHECK expression must be duplicated so that tokens refer
- ** to malloced space and not the (ephemeral) text of the CREATE TABLE
- ** statement */
- pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck,
- sqlite3ExprDup(db, pCheckExpr, 0));
- }
+ pTab->pCheck = sqlite3ExprAnd(db, pTab->pCheck, pCheckExpr);
+ }else
#endif
- sqlite3ExprDelete(db, pCheckExpr);
+ {
+ sqlite3ExprDelete(db, pCheckExpr);
+ }
}
/*
diff --git a/src/delete.c b/src/delete.c
index e5177819c..95ef3cef7 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements.
**
-** $Id: delete.c,v 1.202 2009/05/27 10:31:29 drh Exp $
+** $Id: delete.c,v 1.203 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
diff --git a/src/expr.c b/src/expr.c
index 6fe400d1e..a94b825eb 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.437 2009/05/27 10:31:29 drh Exp $
+** $Id: expr.c,v 1.438 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -40,7 +40,8 @@ char sqlite3ExprAffinity(Expr *pExpr){
}
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
- return sqlite3AffinityType(pExpr->zToken);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ return sqlite3AffinityType(pExpr->u.zToken);
}
#endif
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
@@ -388,6 +389,12 @@ int sqlite3SelectExprHeight(Select *p){
** parameter is ignored if pToken is NULL or if the token does not
** appear to be quoted. If the quotes were of the form "..." (double-quotes)
** then the EP_DblQuoted flag is set on the expression node.
+**
+** Special case: If op==TK_INTEGER and pToken points to a string that
+** can be translated into a 32-bit integer, then the token is not
+** stored in u.zToken. Instead, the integer values is written
+** into u.iValue and the EP_IntValue flag is set. No extra storage
+** is allocated to hold the integer text and the dequote flag is ignored.
*/
Expr *sqlite3ExprAlloc(
sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */
@@ -396,26 +403,33 @@ Expr *sqlite3ExprAlloc(
int dequote /* True to dequote */
){
Expr *pNew;
- int nExtra;
+ int nExtra = 0;
+ int iValue;
if( pToken ){
- nExtra = pToken->n+1;
- }else{
- nExtra = 0;
+ if( op!=TK_INTEGER || pToken->z==0
+ || sqlite3GetInt32(pToken->z, &iValue)==0 ){
+ nExtra = pToken->n+1;
+ }
}
pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
if( pNew ){
pNew->op = (u8)op;
pNew->iAgg = -1;
if( pToken ){
- int c;
- pNew->zToken = (char*)&pNew[1];
- memcpy(pNew->zToken, pToken->z, pToken->n);
- pNew->zToken[pToken->n] = 0;
- if( dequote && nExtra>=3
- && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
- sqlite3Dequote(pNew->zToken);
- if( c=='"' ) pNew->flags |= EP_DblQuoted;
+ if( nExtra==0 ){
+ pNew->flags |= EP_IntValue;
+ pNew->u.iValue = iValue;
+ }else{
+ int c;
+ pNew->u.zToken = (char*)&pNew[1];
+ memcpy(pNew->u.zToken, pToken->z, pToken->n);
+ pNew->u.zToken[pToken->n] = 0;
+ if( dequote && nExtra>=3
+ && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
+ sqlite3Dequote(pNew->u.zToken);
+ if( c=='"' ) pNew->flags |= EP_DblQuoted;
+ }
}
}
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -550,7 +564,8 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
const char *z;
if( pExpr==0 ) return;
- z = pExpr->zToken;
+ assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
+ z = pExpr->u.zToken;
assert( z!=0 );
assert( z[0]!=0 );
if( z[1]==0 ){
@@ -584,7 +599,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
for(i=0; i<pParse->nVarExpr; i++){
Expr *pE = pParse->apVarExpr[i];
assert( pE!=0 );
- if( memcmp(pE->zToken, z, n)==0 && pE->zToken[n]==0 ){
+ if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){
pExpr->iTable = pE->iTable;
break;
}
@@ -616,19 +631,13 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
** Substructure is deleted.
*/
void sqlite3ExprClear(sqlite3 *db, Expr *p){
+ assert( p!=0 );
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
- if( ExprHasProperty(p, EP_Reduced) ){
- /* Subtrees are part of the same memory allocation when EP_Reduced set */
- if( p->pLeft ) sqlite3ExprClear(db, p->pLeft);
- if( p->pRight ) sqlite3ExprClear(db, p->pRight);
- }else{
- /* Subtrees are separate allocations when EP_Reduced is clear */
- sqlite3ExprDelete(db, p->pLeft);
- sqlite3ExprDelete(db, p->pRight);
- /* Sometimes the zToken is allocated separately */
- if( p->flags2 & EP2_FreeToken ) sqlite3DbFree(db, p->zToken);
+ sqlite3ExprDelete(db, p->pLeft);
+ sqlite3ExprDelete(db, p->pRight);
+ if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
+ sqlite3DbFree(db, p->u.zToken);
}
- /* x.pSelect and x.pList are always separately allocated */
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
@@ -643,7 +652,9 @@ void sqlite3ExprClear(sqlite3 *db, Expr *p){
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p==0 ) return;
sqlite3ExprClear(db, p);
- sqlite3DbFree(db, p);
+ if( !ExprHasProperty(p, EP_Static) ){
+ sqlite3DbFree(db, p);
+ }
}
/*
@@ -658,34 +669,67 @@ static int exprStructSize(Expr *p){
}
/*
-** sqlite3ExprDup() has been called to create a copy of expression p with
-** the EXPRDUP_XXX flags passed as the second argument. This function
-** returns the space required for the copy of the Expr structure only.
-** This is always one of EXPR_FULLSIZE, EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
+** The dupedExpr*Size() routines each return the number of bytes required
+** to store a copy of an expression or expression tree. They differ in
+** how much of the tree is measured.
+**
+** dupedExprStructSize() Size of only the Expr structure
+** dupedExprNodeSize() Size of Expr + space for token
+** dupedExprSize() Expr + token + subtree components
+**
+***************************************************************************
+**
+** The dupedExprStructSize() function returns two values OR-ed together:
+** (1) the space required for a copy of the Expr structure only and
+** (2) the EP_xxx flags that indicate what the structure size should be.
+** The return values is always one of:
+**
+** EXPR_FULLSIZE
+** EXPR_REDUCEDSIZE | EP_Reduced
+** EXPR_TOKENONLYSIZE | EP_TokenOnly
+**
+** The size of the structure can be found by masking the return value
+** of this routine with 0xfff. The flags can be found by masking the
+** return value with EP_Reduced|EP_TokenOnly.
+**
+** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size
+** (unreduced) Expr objects as they or originally constructed by the parser.
+** During expression analysis, extra information is computed and moved into
+** later parts of teh Expr object and that extra information might get chopped
+** off if the expression is reduced. Note also that it does not work to
+** make a EXPRDUP_REDUCE copy of a reduced expression. It is only legal
+** to reduce a pristine expression tree from the parser. The implementation
+** of dupedExprStructSize() contain multiple assert() statements that attempt
+** to enforce this constraint.
*/
static int dupedExprStructSize(Expr *p, int flags){
int nSize;
+ assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
if( 0==(flags&EXPRDUP_REDUCE) ){
nSize = EXPR_FULLSIZE;
- }else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
- nSize = EXPR_REDUCEDSIZE;
}else{
- nSize = EXPR_TOKENONLYSIZE;
+ assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
+ assert( !ExprHasProperty(p, EP_FromJoin) );
+ assert( (p->flags2 & EP2_MallocedToken)==0 );
+ assert( (p->flags2 & EP2_Irreducible)==0 );
+ if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
+ nSize = EXPR_REDUCEDSIZE | EP_Reduced;
+ }else{
+ nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
+ }
}
return nSize;
}
/*
-** sqlite3ExprDup() has been called to create a copy of expression p with
-** the EXPRDUP_XXX passed as the second argument. This function returns
-** the space in bytes required to store the copy of the Expr structure
-** and the copies of the Expr.zToken (if applicable)
-** string buffers.
+** This function returns the space in bytes required to store the copy
+** of the Expr structure and a copy of the Expr.u.zToken string (if that
+** string is defined.)
*/
static int dupedExprNodeSize(Expr *p, int flags){
- int nByte = dupedExprStructSize(p, flags);
- if( p->zToken ){
- nByte += sqlite3Strlen30(p->zToken)+1;
+ int nByte = dupedExprStructSize(p, flags) & 0xfff;
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nByte += sqlite3Strlen30(p->u.zToken)+1;
}
return ROUND8(nByte);
}
@@ -696,7 +740,7 @@ static int dupedExprNodeSize(Expr *p, int flags){
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
-** itself and the buffer referred to by Expr.zToken, if any.
+** itself and the buffer referred to by Expr.u.zToken, if any.
**
** If the EXPRDUP_REDUCE flag is set, then the return value includes
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
@@ -717,7 +761,7 @@ static int dupedExprSize(Expr *p, int flags){
/*
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
-** to store the copy of expression p, the copies of p->zToken
+** to store the copy of expression p, the copies of p->u.zToken
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte passed the
** portion of the buffer copied into by this function.
@@ -727,12 +771,14 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
if( p ){
const int isReduced = (flags&EXPRDUP_REDUCE);
u8 *zAlloc;
+ u32 staticFlag = 0;
assert( pzBuffer==0 || isReduced );
/* Figure out where to write the new Expr structure. */
if( pzBuffer ){
zAlloc = *pzBuffer;
+ staticFlag = EP_Static;
}else{
zAlloc = sqlite3DbMallocRaw(db, dupedExprSize(p, flags));
}
@@ -742,10 +788,16 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
/* Set nNewSize to the size allocated for the structure pointed to
** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
- ** by the copy of the p->zToken string (if any).
+ ** by the copy of the p->u.zToken string (if any).
*/
- const int nNewSize = dupedExprStructSize(p, flags);
- const int nToken = (p->zToken ? sqlite3Strlen30(p->zToken) + 1 : 0);
+ const unsigned nStructSize = dupedExprStructSize(p, flags);
+ const int nNewSize = nStructSize & 0xfff;
+ int nToken;
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
if( isReduced ){
assert( ExprHasProperty(p, EP_Reduced)==0 );
memcpy(zAlloc, p, nNewSize);
@@ -755,17 +807,15 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
- /* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly);
- switch( nNewSize ){
- case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
- case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
- }
+ /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
+ pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
+ pNew->flags |= staticFlag;
- /* Copy the p->zToken string, if any. */
+ /* Copy the p->u.zToken string, if any. */
if( nToken ){
- char *zToken = pNew->zToken = (char*)&zAlloc[nNewSize];
- memcpy(zToken, p->zToken, nToken);
+ char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ memcpy(zToken, p->u.zToken, nToken);
}
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
@@ -1180,12 +1230,13 @@ int sqlite3ExprIsConstantOrFunction(Expr *p){
int sqlite3ExprIsInteger(Expr *p, int *pValue){
int rc = 0;
if( p->flags & EP_IntValue ){
- *pValue = p->iTable;
+ *pValue = p->u.iValue;
return 1;
}
switch( p->op ){
case TK_INTEGER: {
- rc = sqlite3GetInt32(p->zToken, pValue);
+ rc = sqlite3GetInt32(p->u.zToken, pValue);
+ assert( rc==0 );
break;
}
case TK_UPLUS: {
@@ -1203,9 +1254,11 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){
default: break;
}
if( rc ){
+ assert( ExprHasAnyProperty(p, EP_Reduced|EP_TokenOnly)
+ || (p->flags2 & EP2_MallocedToken)==0 );
p->op = TK_INTEGER;
p->flags |= EP_IntValue;
- p->iTable = *pValue;
+ p->u.iValue = *pValue;
}
return rc;
}
@@ -1602,6 +1655,7 @@ void sqlite3CodeSubselect(
return;
}
pExpr->iColumn = dest.iParm;
+ ExprSetIrreducible(pExpr);
break;
}
}
@@ -1662,12 +1716,12 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){
const char *z;
if( pExpr->flags & EP_IntValue ){
- int i = pExpr->iTable;
+ int i = pExpr->u.iValue;
if( negFlag ) i = -i;
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
- }else if( (z = pExpr->zToken)!=0 ){
+ }else if( (z = pExpr->u.zToken)!=0 ){
int i;
- int n = sqlite3Strlen30(pExpr->zToken);
+ int n = sqlite3Strlen30(pExpr->u.zToken);
assert( !sqlite3Isdigit(z[n]) );
if( sqlite3GetInt32(z, &i) ){
if( negFlag ) i = -i;
@@ -2078,11 +2132,13 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
case TK_FLOAT: {
- codeReal(v, pExpr->zToken, 0, target);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ codeReal(v, pExpr->u.zToken, 0, target);
break;
}
case TK_STRING: {
- sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->zToken, 0);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
break;
}
case TK_NULL: {
@@ -2094,9 +2150,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int n;
const char *z;
char *zBlob;
- assert( pExpr->zToken[0]=='x' || pExpr->zToken[0]=='X' );
- assert( pExpr->zToken[1]=='\'' );
- z = &pExpr->zToken[2];
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
+ assert( pExpr->u.zToken[1]=='\'' );
+ z = &pExpr->u.zToken[2];
n = sqlite3Strlen30(z) - 1;
assert( z[n]=='\'' );
zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
@@ -2107,9 +2164,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_VARIABLE: {
int iPrior;
VdbeOp *pOp;
- assert( pExpr->zToken!=0 );
- assert( pExpr->zToken[0]!=0 );
- if( pExpr->zToken[1]==0
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ assert( pExpr->u.zToken!=0 );
+ assert( pExpr->u.zToken[0]!=0 );
+ if( pExpr->u.zToken[1]==0
&& (iPrior = sqlite3VdbeCurrentAddr(v)-1)>=0
&& (pOp = sqlite3VdbeGetOp(v, iPrior))->opcode==OP_Variable
&& pOp->p1+pOp->p3==pExpr->iTable
@@ -2124,8 +2182,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
pOp->p3++;
}else{
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iTable, target, 1);
- if( pExpr->zToken[1]!=0 ){
- sqlite3VdbeChangeP4(v, -1, pExpr->zToken, 0);
+ if( pExpr->u.zToken[1]!=0 ){
+ sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
}
}
break;
@@ -2143,7 +2201,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
/* Expressions of the form: CAST(pLeft AS token) */
int aff, to_op;
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- aff = sqlite3AffinityType(pExpr->zToken);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ aff = sqlite3AffinityType(pExpr->u.zToken);
to_op = aff - SQLITE_AFF_TEXT + OP_ToText;
assert( to_op==OP_ToText || aff!=SQLITE_AFF_TEXT );
assert( to_op==OP_ToBlob || aff!=SQLITE_AFF_NONE );
@@ -2236,7 +2295,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
Expr *pLeft = pExpr->pLeft;
assert( pLeft );
if( pLeft->op==TK_FLOAT ){
- codeReal(v, pLeft->zToken, 1, target);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ codeReal(v, pLeft->u.zToken, 1, target);
}else if( pLeft->op==TK_INTEGER ){
codeInteger(v, pLeft, 1, target);
}else{
@@ -2279,7 +2339,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
if( pInfo==0 ){
- sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->zToken);
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
}else{
inReg = pInfo->aFunc[pExpr->iAgg].iMem;
}
@@ -2306,7 +2367,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
pFarg = pExpr->x.pList;
}
nFarg = pFarg ? pFarg->nExpr : 0;
- zId = pExpr->zToken;
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
assert( pDef!=0 );
@@ -2589,8 +2651,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
assert( pExpr->affinity==OE_Rollback ||
pExpr->affinity == OE_Abort ||
pExpr->affinity == OE_Fail );
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->affinity, 0,
- pExpr->zToken, 0);
+ pExpr->u.zToken, 0);
} else {
assert( pExpr->affinity == OE_Ignore );
sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
@@ -3115,6 +3178,8 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA==0||pB==0 ){
return pB==pA;
}
+ assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
+ assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
return 0;
}
@@ -3135,9 +3200,13 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
}
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
- if( pA->op!=TK_COLUMN && pA->zToken ){
- if( pB->zToken==0 ) return 0;
- if( sqlite3StrICmp(pA->zToken,pB->zToken)!=0 ){
+ if( ExprHasProperty(pA, EP_IntValue) ){
+ if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
+ return 0;
+ }
+ }else if( pA->op!=TK_COLUMN && pA->u.zToken ){
+ if( ExprHasProperty(pB, EP_IntValue) || pB->u.zToken==0 ) return 0;
+ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){
return 0;
}
}
@@ -3204,6 +3273,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
struct SrcList_item *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
struct AggInfo_col *pCol;
+ assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
** that is in the FROM clause of the aggregate query.
@@ -3252,6 +3322,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
** Convert the pExpr to be a TK_AGG_COLUMN referring to that
** pAggInfo->aCol[] entry.
*/
+ ExprSetIrreducible(pExpr);
pExpr->pAggInfo = pAggInfo;
pExpr->op = TK_AGG_COLUMN;
pExpr->iAgg = k;
@@ -3284,8 +3355,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pItem = &pAggInfo->aFunc[i];
pItem->pExpr = pExpr;
pItem->iMem = ++pParse->nMem;
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->zToken, sqlite3Strlen30(pExpr->zToken),
+ pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
@@ -3296,6 +3368,8 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
*/
+ assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
+ ExprSetIrreducible(pExpr);
pExpr->iAgg = i;
pExpr->pAggInfo = pAggInfo;
return WRC_Prune;
diff --git a/src/func.c b/src/func.c
index 3792d9efb..893406ceb 100644
--- a/src/func.c
+++ b/src/func.c
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.235 2009/05/27 10:31:29 drh Exp $
+** $Id: func.c,v 1.236 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -1368,7 +1368,8 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->zToken, sqlite3Strlen30(pExpr->zToken),
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken,
+ sqlite3Strlen30(pExpr->u.zToken),
2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
return 0;
diff --git a/src/parse.y b/src/parse.y
index 848ebaebc..d30f89f26 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.277 2009/05/27 10:31:29 drh Exp $
+** @(#) $Id: parse.y,v 1.278 2009/05/28 01:00:55 drh Exp $
*/
// All token codes are small integers with #defines that begin with "TK_"
diff --git a/src/pragma.c b/src/pragma.c
index 6fca256d0..ae5ca7508 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.210 2009/05/27 10:31:29 drh Exp $
+** $Id: pragma.c,v 1.211 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
diff --git a/src/resolve.c b/src/resolve.c
index b9c7face3..015fe4bf7 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -14,7 +14,7 @@
** resolve all identifiers by associating them with a particular
** table and column.
**
-** $Id: resolve.c,v 1.23 2009/05/27 10:31:29 drh Exp $
+** $Id: resolve.c,v 1.24 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@@ -72,15 +72,15 @@ static void resolveAlias(
}
pDup->iTable = pEList->a[iCol].iAlias;
}else{
- char *zToken = pOrig->zToken;
- pOrig->zToken = 0;
+ char *zToken = pOrig->u.zToken;
+ pOrig->u.zToken = 0;
pDup = sqlite3ExprDup(db, pOrig, 0);
- pOrig->zToken = zToken;
+ pOrig->u.zToken = zToken;
if( pDup==0 ) return;
if( zToken ){
assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 );
- pDup->flags2 |= EP2_FreeToken;
- pDup->zToken = sqlite3DbStrDup(db, zToken);
+ pDup->flags2 |= EP2_MallocedToken;
+ pDup->u.zToken = sqlite3DbStrDup(db, zToken);
}
}
if( pExpr->flags & EP_ExpCollate ){
@@ -138,10 +138,12 @@ static int lookupName(
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
+ assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
pExpr->iTable = -1;
pExpr->pTab = 0;
+ ExprSetIrreducible(pExpr);
/* Start at the inner-most context and move outward until a match is found */
while( pNC && cnt==0 ){
@@ -439,7 +441,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* A lone identifier is the name of a column.
*/
case TK_ID: {
- lookupName(pParse, 0, 0, pExpr->zToken, pNC, pExpr);
+ lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
return WRC_Prune;
}
@@ -456,13 +458,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
- zTable = pExpr->pLeft->zToken;
- zColumn = pRight->zToken;
+ zTable = pExpr->pLeft->u.zToken;
+ zColumn = pRight->u.zToken;
}else{
assert( pRight->op==TK_DOT );
- zDb = pExpr->pLeft->zToken;
- zTable = pRight->pLeft->zToken;
- zColumn = pRight->pRight->zToken;
+ zDb = pExpr->pLeft->u.zToken;
+ zTable = pRight->pLeft->u.zToken;
+ zColumn = pRight->pRight->u.zToken;
}
lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
return WRC_Prune;
@@ -484,7 +486,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- zId = pExpr->zToken;
+ zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
if( pDef==0 ){
@@ -586,8 +588,8 @@ static int resolveAsName(
){
int i; /* Loop counter */
- if( pE->op==TK_ID || (pE->op==TK_STRING && pE->zToken[0]!='\'') ){
- char *zCol = pE->zToken;
+ if( pE->op==TK_ID || (pE->op==TK_STRING && pE->u.zToken[0]!='\'') ){
+ char *zCol = pE->u.zToken;
for(i=0; i<pEList->nExpr; i++){
char *zAs = pEList->a[i].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@@ -748,7 +750,7 @@ static int resolveCompoundOrderBy(
if( pE==0 ) return 1;
pE->pColl = pColl;
pE->flags |= EP_IntValue | flags;
- pE->iTable = iCol;
+ pE->u.iValue = iCol;
pItem->iCol = (u16)iCol;
pItem->done = 1;
}else{
diff --git a/src/select.c b/src/select.c
index 2f91ba9c5..54a42ab29 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.519 2009/05/27 10:31:29 drh Exp $
+** $Id: select.c,v 1.520 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -232,6 +232,8 @@ static void addWhereTerm(
pE = sqlite3PExpr(pParse, TK_EQ, pE1c, pE2c, 0);
if( pE && isOuterJoin ){
ExprSetProperty(pE, EP_FromJoin);
+ assert( !ExprHasAnyProperty(pE, EP_TokenOnly|EP_Reduced) );
+ ExprSetIrreducible(pE);
pE->iRightJoinTable = iRightJoinTable;
}
*ppExpr = sqlite3ExprAnd(pParse->db,*ppExpr, pE);
@@ -266,6 +268,8 @@ static void addWhereTerm(
static void setJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
+ assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
+ ExprSetIrreducible(p);
p->iRightJoinTable = iTable;
setJoinExpr(p->pLeft, iTable);
p = p->pRight;
@@ -1127,7 +1131,8 @@ static int selectColumnsFromExprList(
/* Get an appropriate name for the column
*/
p = pEList->a[i].pExpr;
- assert( p->pRight==0 || p->pRight->zToken==0 || p->pRight->zToken[0]!=0 );
+ assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
+ || p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
if( (zName = pEList->a[i].zName)!=0 ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
zName = sqlite3DbStrDup(db, zName);
@@ -1143,7 +1148,8 @@ static int selectColumnsFromExprList(
zName = sqlite3MPrintf(db, "%s",
iCol>=0 ? pTab->aCol[iCol].zName : "rowid");
}else if( pColExpr->op==TK_ID ){
- zName = sqlite3MPrintf(db, "%s", pColExpr->zToken);
+ assert( !ExprHasProperty(pColExpr, EP_IntValue) );
+ zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken);
}else{
/* Use the original text of the column expression as its name */
zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan);
@@ -2048,7 +2054,7 @@ static int multiSelectOrderBy(
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM;
pNew->flags |= EP_IntValue;
- pNew->iTable = i;
+ pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
pOrderBy->a[nOrderBy++].iCol = (u16)i;
}
@@ -2896,9 +2902,10 @@ static u8 minMaxQuery(Select *p){
pEList = pExpr->x.pList;
if( pEList==0 || pEList->nExpr!=1 ) return 0;
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
- if( sqlite3StrICmp(pExpr->zToken,"min")==0 ){
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){
return WHERE_ORDERBY_MIN;
- }else if( sqlite3StrICmp(pExpr->zToken,"max")==0 ){
+ }else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){
return WHERE_ORDERBY_MAX;
}
return WHERE_ORDERBY_NORMAL;
@@ -3119,7 +3126,8 @@ static int selectExpander(Walker *pWalker, Select *p){
char *zTName; /* text of name of TABLE */
if( pE->op==TK_DOT ){
assert( pE->pLeft!=0 );
- zTName = pE->pLeft->zToken;
+ assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
+ zTName = pE->pLeft->u.zToken;
}else{
zTName = 0;
}
@@ -4143,8 +4151,8 @@ select_end:
** or from temporary "printf" statements inserted for debugging.
*/
void sqlite3PrintExpr(Expr *p){
- if( p->zToken ){
- sqlite3DebugPrintf("(%s", p->zToken);
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ sqlite3DebugPrintf("(%s", p->u.zToken);
}else{
sqlite3DebugPrintf("(%d", p->op);
}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 3c0a525dd..97de27667 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.876 2009/05/27 10:31:29 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.877 2009/05/28 01:00:55 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1464,7 +1464,7 @@ struct AggInfo {
** help reduce memory requirements, sometimes an Expr object will be
** truncated. And to reduce the number of memory allocations, sometimes
** two or more Expr objects will be stored in a single memory allocation,
-** together with Expr.token strings.
+** together with Expr.zToken strings.
**
** If the EP_Reduced and EP_TokenOnly flags are set when
** an Expr object is truncated. When EP_Reduced is set, then all
@@ -1477,7 +1477,10 @@ struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
u16 flags; /* Various flags. EP_* See below */
- char *zToken; /* Token value. Zero terminated and dequoted */
+ union {
+ char *zToken; /* Token value. Zero terminated and dequoted */
+ int iValue; /* Integer value if EP_IntValue */
+ } u;
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
@@ -1498,8 +1501,7 @@ struct Expr {
*********************************************************************/
int iTable; /* TK_COLUMN: cursor number of table holding column
- ** TK_REGISTER: register number
- ** EP_IntValue: integer value */
+ ** TK_REGISTER: register number */
i16 iColumn; /* TK_COLUMN: column index. -1 for rowid */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
@@ -1525,7 +1527,7 @@ struct Expr {
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
#define EP_AnyAff 0x0200 /* Can take a cached column of any affinity */
#define EP_FixedDest 0x0400 /* Result needed in a specific register */
-#define EP_IntValue 0x0800 /* Integer value contained in iTable */
+#define EP_IntValue 0x0800 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x1000 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
@@ -1535,7 +1537,20 @@ struct Expr {
/*
** The following are the meanings of bits in the Expr.flags2 field.
*/
-#define EP2_FreeToken 0x0001 /* Need to call sqlite3DbFree() on Expr.zToken */
+#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */
+#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */
+
+/*
+** The pseudo-routine sqlite3ExprSetIrreducible sets the EP2_Irreducible
+** flag on an expression structure. This flag is used for VV&A only. The
+** routine is implemented as a macro that only works when in debugging mode,
+** so as not to burden production code.
+*/
+#ifdef SQLITE_DEBUG
+# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible
+#else
+# define ExprSetIrreducible(X)
+#endif
/*
** These macros can be used to test, set, or clear bits in the
diff --git a/src/tokenize.c b/src/tokenize.c
index 3e6c98c97..8bfda9bfd 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.157 2009/05/27 10:31:29 drh Exp $
+** $Id: tokenize.c,v 1.158 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
diff --git a/src/trigger.c b/src/trigger.c
index 718e46e11..ab94f246a 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -10,7 +10,7 @@
*************************************************************************
**
**
-** $Id: trigger.c,v 1.140 2009/05/27 10:31:29 drh Exp $
+** $Id: trigger.c,v 1.141 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -375,15 +375,15 @@ TriggerStep *sqlite3TriggerInsertStep(
pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
if( pTriggerStep ){
- pTriggerStep->pSelect = pSelect;
+ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
pTriggerStep->pIdList = pColumn;
- pTriggerStep->pExprList = pEList;
+ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->orconf = orconf;
}else{
sqlite3IdListDelete(db, pColumn);
- sqlite3ExprListDelete(db, pEList);
- sqlite3SelectDelete(db, pSelect);
}
+ sqlite3ExprListDelete(db, pEList);
+ sqlite3SelectDelete(db, pSelect);
return pTriggerStep;
}
@@ -403,14 +403,13 @@ TriggerStep *sqlite3TriggerUpdateStep(
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
- if( pTriggerStep==0 ){
- sqlite3ExprListDelete(db, pEList);
- sqlite3ExprDelete(db, pWhere);
- return 0;
- }
- pTriggerStep->pExprList = pEList;
- pTriggerStep->pWhere = pWhere;
- pTriggerStep->orconf = orconf;
+ if( pTriggerStep ){
+ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
+ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ pTriggerStep->orconf = orconf;
+ }
+ sqlite3ExprListDelete(db, pEList);
+ sqlite3ExprDelete(db, pWhere);
return pTriggerStep;
}
@@ -427,13 +426,11 @@ TriggerStep *sqlite3TriggerDeleteStep(
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
- if( pTriggerStep==0 ){
- sqlite3ExprDelete(db, pWhere);
- return 0;
+ if( pTriggerStep ){
+ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ pTriggerStep->orconf = OE_Default;
}
- pTriggerStep->pWhere = pWhere;
- pTriggerStep->orconf = OE_Default;
-
+ sqlite3ExprDelete(db, pWhere);
return pTriggerStep;
}
@@ -640,7 +637,6 @@ static SrcList *targetSrcList(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
- Token sDb; /* Dummy database name token */
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
diff --git a/src/update.c b/src/update.c
index e72a6354a..6eb92fb61 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.201 2009/05/27 10:31:29 drh Exp $
+** $Id: update.c,v 1.202 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
diff --git a/src/util.c b/src/util.c
index 76a8848db..00d13dd0c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -14,7 +14,7 @@
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
-** $Id: util.c,v 1.255 2009/05/27 10:31:29 drh Exp $
+** $Id: util.c,v 1.256 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 004ea367f..f5120c86b 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -15,7 +15,7 @@
** only within the VDBE. Interface routines refer to a Mem using the
** name sqlite_value
**
-** $Id: vdbemem.c,v 1.145 2009/05/27 10:31:29 drh Exp $
+** $Id: vdbemem.c,v 1.146 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -974,10 +974,15 @@ int sqlite3ValueFromExpr(
op = pExpr->op;
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
- zVal = sqlite3DbStrDup(db, pExpr->zToken);
pVal = sqlite3ValueNew(db);
- if( !zVal || !pVal ) goto no_mem;
- sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ if( pVal==0 ) goto no_mem;
+ if( ExprHasProperty(pExpr, EP_IntValue) ){
+ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
+ }else{
+ zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
+ if( zVal==0 ) goto no_mem;
+ sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
+ }
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
}else{
@@ -996,11 +1001,11 @@ int sqlite3ValueFromExpr(
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
int nVal;
- assert( pExpr->zToken[0]=='x' || pExpr->zToken[0]=='X' );
- assert( pExpr->zToken[1]=='\'' );
+ assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
+ assert( pExpr->u.zToken[1]=='\'' );
pVal = sqlite3ValueNew(db);
if( !pVal ) goto no_mem;
- zVal = &pExpr->zToken[2];
+ zVal = &pExpr->u.zToken[2];
nVal = sqlite3Strlen30(zVal)-1;
assert( zVal[nVal]=='\'' );
sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2,
diff --git a/src/walker.c b/src/walker.c
index 7be9e252f..f565bc55f 100644
--- a/src/walker.c
+++ b/src/walker.c
@@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
-** $Id: walker.c,v 1.5 2009/05/27 10:31:29 drh Exp $
+** $Id: walker.c,v 1.6 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
diff --git a/src/where.c b/src/where.c
index 7396bf198..48651ceb9 100644
--- a/src/where.c
+++ b/src/where.c
@@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
-** $Id: where.c,v 1.398 2009/05/27 10:31:29 drh Exp $
+** $Id: where.c,v 1.399 2009/05/28 01:00:55 drh Exp $
*/
#include "sqliteInt.h"
@@ -658,7 +658,7 @@ static int isLikeOrGlob(
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
return 0;
}
- z = pRight->zToken;
+ z = pRight->u.zToken;
cnt = 0;
if( z ){
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
@@ -691,7 +691,7 @@ static int isMatchOfColumn(
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
- if( sqlite3StrICmp(pExpr->zToken,"match")!=0 ){
+ if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){
return 0;
}
pList = pExpr->x.pList;
@@ -1161,12 +1161,12 @@ static void exprAnalyze(
pLeft = pExpr->x.pList->a[1].pExpr;
pRight = pExpr->x.pList->a[0].pExpr;
- pStr1 = sqlite3Expr(db, TK_STRING, pRight->zToken);
- if( pStr1 ) pStr1->zToken[nPattern] = 0;
+ pStr1 = sqlite3Expr(db, TK_STRING, pRight->u.zToken);
+ if( pStr1 ) pStr1->u.zToken[nPattern] = 0;
pStr2 = sqlite3ExprDup(db, pStr1, 0);
if( !db->mallocFailed ){
u8 c, *pC;
- pC = (u8*)&pStr2->zToken[nPattern-1];
+ pC = (u8*)&pStr2->u.zToken[nPattern-1];
c = *pC;
if( noCase ){
if( c=='@' ) isComplete = 0;
diff --git a/test/attach.test b/test/attach.test
index 8c4552687..8dda7f2a8 100644
--- a/test/attach.test
+++ b/test/attach.test
@@ -12,7 +12,7 @@
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
-# $Id: attach.test,v 1.50 2009/05/27 10:31:30 drh Exp $
+# $Id: attach.test,v 1.51 2009/05/28 01:00:56 drh Exp $
#
set testdir [file dirname $argv0]
diff --git a/test/select1.test b/test/select1.test
index face8e4cf..73b0e40fe 100644
--- a/test/select1.test
+++ b/test/select1.test
@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this file is testing the SELECT statement.
#
-# $Id: select1.test,v 1.69 2009/05/27 10:31:30 drh Exp $
+# $Id: select1.test,v 1.70 2009/05/28 01:00:56 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
diff --git a/test/tkt3508.test b/test/tkt3508.test
index d4efdc3f6..8275d6998 100644
--- a/test/tkt3508.test
+++ b/test/tkt3508.test
@@ -10,7 +10,7 @@
#***********************************************************************
# This file implements regression tests for SQLite library.
#
-# $Id: tkt3508.test,v 1.4 2009/05/27 10:31:30 drh Exp $
+# $Id: tkt3508.test,v 1.5 2009/05/28 01:00:56 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl