Minor refactoring of the expression-compaction logic for clarity of

presentation.  New comments added.  The EXPRDUP_DISTINCTSPAN flag is
removed as obsolete. (CVS 6470)

FossilOrigin-Name: 44ded2ea67374f187a111df69c3f51f866735400
This commit is contained in:
drh 2009-04-08 13:51:51 +00:00
parent 0a9aa2253c
commit 12ffee8cb9
7 changed files with 88 additions and 88 deletions

View File

@ -1,5 +1,5 @@
C Do\snot\sattempt\sto\swalk\sa\sTokenOnly\sor\sSpanOnly\sexpression\stree\snode.\nTicket\s#3791.\s(CVS\s6469)
D 2009-04-08T12:21:31
C Minor\srefactoring\sof\sthe\sexpression-compaction\slogic\sfor\sclarity\sof\npresentation.\s\sNew\scomments\sadded.\s\sThe\sEXPRDUP_DISTINCTSPAN\sflag\sis\nremoved\sas\sobsolete.\s(CVS\s6470)
D 2009-04-08T13:51:51
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 583e87706abc3026960ed759aff6371faf84c211
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@ -98,7 +98,7 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c 472c0a4733de40f1d997ff4fd746042b707faf7b
F src/analyze.c 3585d1a4c480ee85b65cf0a676e05d2c29eb6bdb
F src/attach.c d34589d5c85d81e755e4a8fc946d313915a6fa6d
F src/attach.c af80fa85d391ad302c148c4e2524a2cebec64cb2
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
F src/backup.c 0082d0e5a63f04e88faee0dff0a7d63d3e92a78d
F src/bitvec.c ef370407e03440b0852d05024fb016b14a471d3d
@ -106,12 +106,12 @@ F src/btmutex.c 341502bc496dc0840dcb00cde65680fb0e85c3ab
F src/btree.c 0d02176d76c6e202cff0788929e8eee71bf60e88
F src/btree.h 8007018c1753944790c39610280894ab280210b8
F src/btreeInt.h df64030d632f8c8ac217ed52e8b6b3eacacb33a5
F src/build.c 72357fd75ef036d0afbf1756edab6d62c56fcf4b
F src/build.c 2882f22078db1c3f887b1aca77ff460cf9461c62
F src/callback.c 73016376d6848ba987709e8c9048d4f0e0776036
F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c
F src/date.c 3e5c554b2f4f2d798761597c08147d7b15f35bea
F src/delete.c eb1066b2f35489fee46ad765d2b66386fc7d8adf
F src/expr.c b7ce173d17b80e937473147604bfde4bb339a8a0
F src/expr.c ccc5b5fa3bac249a9ab6e5e10629d77ff293c9f8
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
F src/func.c 99ae90d46154952e08282fcdfe72d08e9601e174
F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
@ -159,7 +159,7 @@ F src/select.c 462d9671e91accd983110fa38674be0d2a3daa66
F src/shell.c 0a11f831603f17fea20ca97133c0f64e716af4a7
F src/sqlite.h.in 718a026b4cf3c766fc7ac5ff582faa60324b116c
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 7b341ab7d570b271e8566e7e7ed6993453f84964
F src/sqliteInt.h fcdad0896da9c8b6372db974131e33b7a06606ce
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 332ab0ea691e63862e2a8bdfe2c0617ee61062a3
@ -208,7 +208,7 @@ F src/vdbeaux.c 570aaa5e15ae141115194d22443c73c8beb5032b
F src/vdbeblob.c e67757450ae8581a8b354d9d7e467e41502dfe38
F src/vdbemem.c 9798905787baae83d0b53b62030e32ecf7a0586f
F src/vtab.c f1aba5a6dc1f83b97a39fbbc58ff8cbc76311347
F src/walker.c b32028f411cd4faa4e9e75da6f192f3e6e3dc7af
F src/walker.c 7cdf63223c953d4343c6833e940f110281a378ee
F src/where.c ddf26069d03f9e0c6ef14d537422df02e0c593f0
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
@ -716,7 +716,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P ee5a4a0e595a7b916db7d55d30ddfda0a8d40d90
R 17434378e2db6c8fd2ad9ea648250d41
P 8362d883248f00a8ec7294bf027fd19758aec5f2
R 4b30b803e3cfb8e04c48c3d2b8d2124a
U drh
Z 66c9263486f4e7d1bb93c05e15462035
Z 869480ece5a998deade5da75d4798c3b

View File

@ -1 +1 @@
8362d883248f00a8ec7294bf027fd19758aec5f2
44ded2ea67374f187a111df69c3f51f866735400

View File

@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.83 2009/02/19 14:39:25 danielk1977 Exp $
** $Id: attach.c,v 1.84 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -488,7 +488,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ) break;
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanToken) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{

View File

@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.527 2009/03/31 03:41:57 shane Exp $
** $Id: build.c,v 1.528 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -1112,9 +1112,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
** is required by pragma table_info.
*/
sqlite3ExprDelete(db, pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(
db, pExpr, EXPRDUP_REDUCE|EXPRDUP_DISTINCTSPAN
);
pCol->pDflt = sqlite3ExprDup(db, pExpr, EXPRDUP_REDUCE|EXPRDUP_SPAN);
}
}
sqlite3ExprDelete(db, pExpr);

View File

@ -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.425 2009/04/02 17:23:33 danielk1977 Exp $
** $Id: expr.c,v 1.426 2009/04/08 13:51:51 drh Exp $
*/
#include "sqliteInt.h"
@ -629,15 +629,18 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
*/
void sqlite3ExprClear(sqlite3 *db, Expr *p){
if( p->token.dyn ) sqlite3DbFree(db, (char*)p->token.z);
if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanToken) ){
if( p->span.dyn ) sqlite3DbFree(db, (char*)p->span.z);
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);
}
/* x.pSelect and x.pList are always separately allocated */
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
@ -674,7 +677,7 @@ void sqlite3DequoteExpr(Expr *p){
*/
static int exprStructSize(Expr *p){
if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
if( ExprHasProperty(p, EP_SpanOnly) ) return EXPR_SPANONLYSIZE;
if( ExprHasProperty(p, EP_SpanToken) ) return EXPR_SPANTOKENSIZE;
if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
return EXPR_FULLSIZE;
}
@ -691,8 +694,8 @@ static int dupedExprStructSize(Expr *p, int flags){
nSize = EXPR_FULLSIZE;
}else if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
nSize = EXPR_REDUCEDSIZE;
}else if( flags&(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN) ){
nSize = EXPR_SPANONLYSIZE;
}else if( flags&EXPRDUP_SPAN ){
nSize = EXPR_SPANTOKENSIZE;
}else{
nSize = EXPR_TOKENONLYSIZE;
}
@ -708,8 +711,8 @@ static int dupedExprStructSize(Expr *p, int flags){
*/
static int dupedExprNodeSize(Expr *p, int flags){
int nByte = dupedExprStructSize(p, flags) + (p->token.z ? p->token.n + 1 : 0);
if( (flags&EXPRDUP_DISTINCTSPAN)
|| (flags&EXPRDUP_SPAN && (p->token.z!=p->span.z || p->token.n!=p->span.n))
if( (flags&EXPRDUP_SPAN)!=0
&& (p->token.z!=p->span.z || p->token.n!=p->span.n)
){
nByte += p->span.n;
}
@ -736,7 +739,7 @@ static int dupedExprSize(Expr *p, int flags){
if( p ){
nByte = dupedExprNodeSize(p, flags);
if( flags&EXPRDUP_REDUCE ){
int f = flags&(~(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN));
int f = flags&(~EXPRDUP_SPAN);
nByte += dupedExprSize(p->pLeft, f) + dupedExprSize(p->pRight, f);
}
}
@ -754,8 +757,7 @@ static int dupedExprSize(Expr *p, int flags){
static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
Expr *pNew = 0; /* Value to return */
if( p ){
const int isRequireDistinctSpan = (flags&EXPRDUP_DISTINCTSPAN);
const int isRequireSpan = (flags&(EXPRDUP_SPAN|EXPRDUP_DISTINCTSPAN));
const int isRequireSpan = (flags&EXPRDUP_SPAN);
const int isReduced = (flags&EXPRDUP_REDUCE);
u8 *zAlloc;
@ -787,11 +789,11 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
}
/* Set the EP_Reduced and EP_TokenOnly flags appropriately. */
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanOnly);
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_SpanToken);
switch( nNewSize ){
case EXPR_REDUCEDSIZE: pNew->flags |= EP_Reduced; break;
case EXPR_TOKENONLYSIZE: pNew->flags |= EP_TokenOnly; break;
case EXPR_SPANONLYSIZE: pNew->flags |= EP_SpanOnly; break;
case EXPR_SPANTOKENSIZE: pNew->flags |= EP_SpanToken; break;
}
/* Copy the p->token string, if any. */
@ -806,9 +808,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
/* Fill in the pNew->span token, if required. */
if( isRequireSpan ){
if( isRequireDistinctSpan
|| p->token.z!=p->span.z || p->token.n!=p->span.n
){
if( p->token.z!=p->span.z || p->token.n!=p->span.n ){
pNew->span.z = &zAlloc[nNewSize+nToken];
memcpy((char *)pNew->span.z, p->span.z, p->span.n);
pNew->span.dyn = 0;
@ -822,7 +822,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
}
}
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanOnly)) ){
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_SpanToken)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprHasProperty(p, EP_xIsSelect) ){
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
@ -832,7 +832,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
}
/* Fill in pNew->pLeft and pNew->pRight. */
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanOnly) ){
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly|EP_SpanToken) ){
zAlloc += dupedExprNodeSize(p, flags);
if( ExprHasProperty(pNew, EP_Reduced) ){
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
@ -841,7 +841,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
if( pzBuffer ){
*pzBuffer = zAlloc;
}
}else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanOnly) ){
}else if( !ExprHasAnyProperty(p, EP_TokenOnly|EP_SpanToken) ){
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
@ -2205,31 +2205,34 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = (
ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanOnly) ? 0 : pExpr->x.pList
);
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
int nId;
const char *zId;
int constMask = 0;
int i;
u8 enc = ENC(db);
CollSeq *pColl = 0;
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
int constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
u8 enc = ENC(db); /* The text encoding used by this database */
CollSeq *pColl = 0; /* A collating sequence */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
testcase( op==TK_CONST_FUNC );
testcase( op==TK_FUNCTION );
if( ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_SpanToken) ){
pFarg = 0;
}else{
pFarg = pExpr->x.pList;
}
nFarg = pFarg ? pFarg->nExpr : 0;
zId = (char*)pExpr->token.z;
nId = pExpr->token.n;
pDef = sqlite3FindFunction(db, zId, nId, nExpr, enc, 0);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
assert( pDef!=0 );
if( pList ){
nExpr = pList->nExpr;
r1 = sqlite3GetTempRange(pParse, nExpr);
sqlite3ExprCodeExprList(pParse, pList, r1, 1);
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
}else{
nExpr = r1 = 0;
r1 = 0;
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Possibly overload the function if the first argument is
@ -2244,18 +2247,18 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** "glob(B,A). We want to use the A in "A glob B" to test
** for function overloading. But we use the B term in "glob(B,A)".
*/
if( nExpr>=2 && (pExpr->flags & EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[1].pExpr);
}else if( nExpr>0 ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nExpr, pList->a[0].pExpr);
if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr);
}else if( nFarg>0 ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
}
#endif
for(i=0; i<nExpr && i<32; i++){
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
for(i=0; i<nFarg && i<32; i++){
if( sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
constMask |= (1<<i);
}
if( (pDef->flags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
}
}
if( pDef->flags & SQLITE_FUNC_NEEDCOLL ){
@ -2264,11 +2267,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
(char*)pDef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nExpr);
if( nExpr ){
sqlite3ReleaseTempRange(pParse, r1, nExpr);
sqlite3VdbeChangeP5(v, (u8)nFarg);
if( nFarg ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
sqlite3ExprCacheAffinityChange(pParse, r1, nExpr);
sqlite3ExprCacheAffinityChange(pParse, r1, nFarg);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY

View File

@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.853 2009/04/07 22:06:57 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.854 2009/04/08 13:51:51 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@ -1452,19 +1452,18 @@ struct AggInfo {
**
** ALLOCATION NOTES:
**
** Expr structures may be stored as part of the in-memory database schema,
** for example as part of trigger, view or table definitions. In this case,
** the amount of memory consumed by complex expressions may be significant.
** For this reason, less than sizeof(Expr) bytes may be allocated for some
** Expr structs stored as part of the in-memory database schema.
** Expr objects can use a lot of memory space in database schema. To
** 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 and/or Expr.span strings.
**
** If the EP_Reduced flag is set in Expr.flags, then only EXPR_REDUCEDSIZE
** bytes of space are allocated for the expression structure. This is enough
** space to store all fields up to and including the "Token span;" field.
**
** If the EP_TokenOnly flag is set in Expr.flags, then only EXPR_TOKENONLYSIZE
** bytes of space are allocated for the expression structure. This is enough
** space to store all fields up to and including the "Token token;" field.
** If the EP_Reduced, EP_SpanToken, and EP_TokenOnly flags are set when
** an Expr object is truncated. When EP_Reduced is set, then all
** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees
** are contained within the same memory allocation. Note, however, that
** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately
** allocated, regardless of whether or not EP_Reduced is set.
*/
struct Expr {
u8 op; /* Operation performed by this node */
@ -1480,7 +1479,7 @@ struct Expr {
Token span; /* Complete text of the expression */
/* If the EP_SpanOnly flag is set in the Expr.flags mask, then no
/* If the EP_SpanToken flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
** access them will result in a segfault or malfunction.
*********************************************************************/
@ -1528,7 +1527,7 @@ struct Expr {
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_SpanOnly 0x8000 /* Expr struct is EXPR_SPANONLYSIZE bytes only */
#define EP_SpanToken 0x8000 /* Expr size is EXPR_SPANTOKENSIZE bytes */
/*
** The following are the meanings of bits in the Expr.vvaFlags field.
@ -1553,18 +1552,17 @@ struct Expr {
** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr)
#define EXPR_REDUCEDSIZE offsetof(Expr,iTable)
#define EXPR_TOKENONLYSIZE offsetof(Expr,span)
#define EXPR_SPANONLYSIZE offsetof(Expr,pLeft)
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
#define EXPR_REDUCEDSIZE offsetof(Expr,iTable) /* Common features */
#define EXPR_SPANTOKENSIZE offsetof(Expr,pLeft) /* Fewer features */
#define EXPR_TOKENONLYSIZE offsetof(Expr,span) /* Smallest possible */
/*
** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001
#define EXPRDUP_SPAN 0x0002
#define EXPRDUP_DISTINCTSPAN 0x0004
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
#define EXPRDUP_SPAN 0x0002 /* Make a copy of Expr.span */
/*
** A list of expressions. Each expression may optionally have a

View File

@ -12,7 +12,7 @@
** This file contains routines used for walking the parser tree for
** an SQL statement.
**
** $Id: walker.c,v 1.3 2009/04/08 12:21:31 drh Exp $
** $Id: walker.c,v 1.4 2009/04/08 13:51:52 drh Exp $
*/
#include "sqliteInt.h"
#include <stdlib.h>
@ -42,10 +42,11 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
int rc;
if( pExpr==0 ) return WRC_Continue;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_SpanOnly) );
testcase( ExprHasProperty(pExpr, EP_SpanToken) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc==WRC_Continue && !ExprHasAnyProperty(pExpr,EP_TokenOnly|EP_SpanOnly) ){
if( rc==WRC_Continue
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly|EP_SpanToken) ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){