// Return the default collation sequence for the expression pExpr. If there is no default collation type, return 0. internal static CollSeq sqlite3ExprCollSeq(Parse pParse, Expr pExpr) { CollSeq pColl = null; var p = pExpr; while (ALWAYS(p)) { pColl = pExpr.pColl; if (pColl != null) break; var op = p.op; if (p.pTab != null && (op == TK.AGG_COLUMN || op == TK.COLUMN || op == TK.REGISTER || op == TK.TRIGGER)) { // op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally a TK_COLUMN but was previously evaluated and cached in a register var j = p.iColumn; if (j >= 0) { var db = pParse.db; var zColl = p.pTab.aCol[j].zColl; pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); pExpr.pColl = pColl; } break; } if (op != TK.CAST && op != TK.UPLUS) break; p = p.pLeft; } if (sqlite3CheckCollSeq(pParse, pColl) != 0) pColl = null; return pColl; }
// Return the 'affinity' of the expression pExpr if any. // // If pExpr is a column, a reference to a column via an 'AS' alias, // or a sub-select with a column as the return value, then the // affinity of that column is returned. Otherwise, 0x00 is returned, // indicating no affinity for the expression. // // i.e. the WHERE clause expresssions in the following statements all // have an affinity: // // CREATE TABLE t1(a); // SELECT * FROM t1 WHERE a; // SELECT a AS b FROM t1 WHERE b; // SELECT * FROM t1 WHERE (select a from t1); internal static char sqlite3ExprAffinity(Expr pExpr) { var op = pExpr.op; if (op == TK.SELECT) { Debug.Assert((pExpr.flags & Expr.EP_xIsSelect) != 0); return sqlite3ExprAffinity(pExpr.x.pSelect.pEList.a[0].pExpr); } #if !SQLITE_OMIT_CAST if (op == TK.CAST) { Debug.Assert(!Expr.ExprHasProperty(pExpr, Expr.EP_IntValue)); return sqlite3AffinityType(pExpr.u.zToken); } #endif if ((op == TK.AGG_COLUMN || op == TK.COLUMN || op == TK.REGISTER) && pExpr.pTab != null) { // op==TK_REGISTER && pExpr.pTab!=0 happens when pExpr was originally a TK_COLUMN but was previously evaluated and cached in a register var j = pExpr.iColumn; if (j < 0) return SQLITE_AFF_INTEGER; Debug.Assert(pExpr.pTab != null && j < pExpr.pTab.nCol); return pExpr.pTab.aCol[j].affinity; } return pExpr.affinity; }
// Set the collating sequence for expression pExpr to be the collating sequence named by pToken. Return a pointer to the revised expression. // The collating sequence is marked as "explicit" using the EP_ExpCollate flag. An explicit collating sequence will override implicit // collating sequences. internal static Expr sqlite3ExprSetCollByToken(Parse pParse, Expr pExpr, Token pCollName) { var db = pParse.db; var zColl = sqlite3NameFromToken(db, pCollName); // Dequoted name of collation sequence var pColl = sqlite3LocateCollSeq(pParse, zColl); sqlite3ExprSetColl(pExpr, pColl); sqlite3DbFree(db, ref zColl); return pExpr; }
// Set the explicit collating sequence for an expression to the collating sequence supplied in the second argument. internal static Expr sqlite3ExprSetColl(Expr pExpr, CollSeq pColl) { if (pExpr != null && pColl != null) { pExpr.pColl = pColl; pExpr.flags |= Expr.EP_ExpCollate; } return pExpr; }
internal static SrcList sqlite3SrcListAppendFromTerm(Parse pParse, SrcList p, Token pTable, Token pDatabase, Token pAlias, Select pSubquery, Expr pOn, IdList pUsing) { var db = pParse.db; if (null == p && (pOn != null || pUsing != null)) { sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", pOn != null ? "ON" : "USING"); goto append_from_error; } p = sqlite3SrcListAppend(db, p, pTable, pDatabase); var pItem = p.a[p.nSrc - 1]; Debug.Assert(pAlias != null); if (pAlias.n != 0) pItem.zAlias = sqlite3NameFromToken(db, pAlias); pItem.pSelect = pSubquery; pItem.pOn = pOn; pItem.pUsing = pUsing; return p; append_from_error: Debug.Assert(p == null); sqlite3ExprDelete(db, ref pOn); sqlite3IdListDelete(db, ref pUsing); sqlite3SelectDelete(db, ref pSubquery); return null; }
/* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. */ static Expr sqlite3ExprAnd(sqlite3 db, Expr pLeft, Expr pRight) { if (pLeft == null) { return pRight; } else if (pRight == null) { return pLeft; } else { Expr pNew = sqlite3ExprAlloc(db, TK_AND, null, 0); sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); return pNew; } }
/* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is false but execution ** continues straight thru if the expression is true. ** ** If the expression evaluates to NULL (neither true nor false) then ** jump if jumpIfNull is SQLITE_JUMPIFNULL or fall through if jumpIfNull ** is 0. */ static void sqlite3ExprIfFalse(Parse pParse, Expr pExpr, int dest, int jumpIfNull) { Vdbe v = pParse.pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1 = 0, r2 = 0; Debug.Assert(jumpIfNull == SQLITE_JUMPIFNULL || jumpIfNull == 0); if (NEVER(v == null)) return; /* Existance of VDBE checked by caller */ if (pExpr == null) return; /* The value of pExpr.op and op are related as follows: ** ** pExpr.op op ** --------- ---------- ** TK_ISNULL OP_NotNull ** TK_NOTNULL OP_IsNull ** TK_NE OP_Eq ** TK_EQ OP_Ne ** TK_GT OP_Le ** TK_LE OP_Gt ** TK_GE OP_Lt ** TK_LT OP_Ge ** ** For other values of pExpr.op, op is undefined and unused. ** The value of TK_ and OP_ constants are arranged such that we ** can compute the mapping above using the following expression. ** Assert()s verify that the computation is correct. */ op = ((pExpr.op + (TK_ISNULL & 1)) ^ 1) - (TK_ISNULL & 1); /* Verify correct alignment of TK_ and OP_ constants */ Debug.Assert(pExpr.op != TK_ISNULL || op == OP_NotNull); Debug.Assert(pExpr.op != TK_NOTNULL || op == OP_IsNull); Debug.Assert(pExpr.op != TK_NE || op == OP_Eq); Debug.Assert(pExpr.op != TK_EQ || op == OP_Ne); Debug.Assert(pExpr.op != TK_LT || op == OP_Ge); Debug.Assert(pExpr.op != TK_LE || op == OP_Gt); Debug.Assert(pExpr.op != TK_GT || op == OP_Le); Debug.Assert(pExpr.op != TK_GE || op == OP_Lt); switch (pExpr.op) { case TK_AND: { testcase(jumpIfNull == 0); sqlite3ExprIfFalse(pParse, pExpr.pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr.pRight, dest, jumpIfNull); break; } case TK_OR: { int d2 = sqlite3VdbeMakeLabel(v); testcase(jumpIfNull == 0); sqlite3ExprCachePush(pParse); sqlite3ExprIfTrue(pParse, pExpr.pLeft, d2, jumpIfNull ^ SQLITE_JUMPIFNULL); sqlite3ExprIfFalse(pParse, pExpr.pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); sqlite3ExprCachePop(pParse, 1); break; } case TK_NOT: { testcase(jumpIfNull == 0); sqlite3ExprIfTrue(pParse, pExpr.pLeft, dest, jumpIfNull); break; } case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { testcase(op == TK_LT); testcase(op == TK_LE); testcase(op == TK_GT); testcase(op == TK_GE); testcase(op == TK_EQ); testcase(op == TK_NE); testcase(jumpIfNull == 0); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); r2 = sqlite3ExprCodeTemp(pParse, pExpr.pRight, ref regFree2); codeCompare(pParse, pExpr.pLeft, pExpr.pRight, op, r1, r2, dest, jumpIfNull); testcase(regFree1 == 0); testcase(regFree2 == 0); break; } case TK_IS: case TK_ISNOT: { testcase(pExpr.op == TK_IS); testcase(pExpr.op == TK_ISNOT); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); r2 = sqlite3ExprCodeTemp(pParse, pExpr.pRight, ref regFree2); op = (pExpr.op == TK_IS) ? TK_NE : TK_EQ; codeCompare(pParse, pExpr.pLeft, pExpr.pRight, op, r1, r2, dest, SQLITE_NULLEQ); testcase(regFree1 == 0); testcase(regFree2 == 0); break; } case TK_ISNULL: case TK_NOTNULL: { testcase(op == TK_ISNULL); testcase(op == TK_NOTNULL); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase(regFree1 == 0); break; } case TK_BETWEEN: { testcase(jumpIfNull == 0); exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull); break; } #if SQLITE_OMIT_SUBQUERY case TK_IN: { if ( jumpIfNull != 0 ) { sqlite3ExprCodeIN( pParse, pExpr, dest, dest ); } else { int destIfNull = sqlite3VdbeMakeLabel( v ); sqlite3ExprCodeIN( pParse, pExpr, dest, destIfNull ); sqlite3VdbeResolveLabel( v, destIfNull ); } break; } #endif default: { r1 = sqlite3ExprCodeTemp(pParse, pExpr, ref regFree1); sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull != 0 ? 1 : 0); testcase(regFree1 == 0); testcase(jumpIfNull == 0); break; } } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); }
static Expr sqlite3PExpr(Parse pParse, int op, Expr pLeft, Expr pRight, int null_5) { return sqlite3PExpr(pParse, op, pLeft, pRight, null); }
static Expr sqlite3PExpr( Parse pParse, /* Parsing context */ int op, /* Expression opcode */ Expr pLeft, /* Left operand */ Expr pRight, /* Right operand */ Token pToken /* Argument Token */ ) { Expr p = sqlite3ExprAlloc(pParse.db, op, pToken, 1); sqlite3ExprAttachSubtrees(pParse.db, p, pLeft, pRight); if (p != null) { sqlite3ExprCheckHeight(pParse, p.nHeight); } return p; }
/* ** 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->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. */ static Expr exprDup(sqlite3 db, Expr p, int flags, ref Expr pzBuffer) { Expr pNew = null; /* Value to return */ if (p != null) { bool isReduced = (flags & EXPRDUP_REDUCE) != 0; Expr zAlloc = new Expr(); u32 staticFlag = 0; Debug.Assert(pzBuffer == null || isReduced); /* Figure out where to write the new Expr structure. */ //if ( pzBuffer !=null) //{ // zAlloc = pzBuffer; // staticFlag = EP_Static; //} //else //{ ///Expr zAlloc = new Expr();//sqlite3DbMallocRaw( db, dupedExprSize( p, flags ) ); //} // (Expr)zAlloc; //if ( pNew != null ) { /* 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->u.zToken string (if any). */ int nStructSize = dupedExprStructSize(p, flags); int nNewSize = nStructSize & 0xfff; int nToken; if (!ExprHasProperty(p, EP_IntValue) && !String.IsNullOrEmpty(p.u.zToken)) { nToken = sqlite3Strlen30(p.u.zToken); } else { nToken = 0; } if (isReduced) { Debug.Assert(!ExprHasProperty(p, EP_Reduced)); pNew = p.Copy(EXPR_TOKENONLYSIZE);//memcpy( zAlloc, p, nNewSize ); } else { int nSize = exprStructSize(p); //memcpy( zAlloc, p, nSize ); pNew = p.Copy(); //memset( &zAlloc[nSize], 0, EXPR_FULLSIZE - nSize ); } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ unchecked { pNew.flags &= (ushort)(~(EP_Reduced | EP_TokenOnly | EP_Static)); } pNew.flags |= (ushort)(nStructSize & (EP_Reduced | EP_TokenOnly)); pNew.flags |= (ushort)staticFlag; /* Copy the p->u.zToken string, if any. */ if (nToken != 0) { string zToken;// = pNew.u.zToken = (char)&zAlloc[nNewSize]; zToken = p.u.zToken.Substring(0, nToken);// memcpy( zToken, p.u.zToken, nToken ); } if (0 == ((p.flags | pNew.flags) & EP_TokenOnly)) { /* 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 ? 1 : 0); } else { pNew.x.pList = sqlite3ExprListDup(db, p.x.pList, isReduced ? 1 : 0); } } /* Fill in pNew.pLeft and pNew.pRight. */ if (ExprHasAnyProperty(pNew, EP_Reduced | EP_TokenOnly)) { //zAlloc += dupedExprNodeSize( p, flags ); if (ExprHasProperty(pNew, EP_Reduced)) { pNew.pLeft = exprDup(db, p.pLeft, EXPRDUP_REDUCE, ref pzBuffer); pNew.pRight = exprDup(db, p.pRight, EXPRDUP_REDUCE, ref pzBuffer); } //if ( pzBuffer != null ) //{ // pzBuffer = zAlloc; //} } else { pNew.flags2 = 0; if (!ExprHasAnyProperty(p, EP_TokenOnly)) { pNew.pLeft = sqlite3ExprDup(db, p.pLeft, 0); pNew.pRight = sqlite3ExprDup(db, p.pRight, 0); } } } } return pNew; }
/* ** Set the Expr.nHeight variable using the exprSetHeight() function. If ** the height is greater than the maximum allowed expression depth, ** leave an error in pParse. */ static void sqlite3ExprSetHeight(Parse pParse, Expr p) { exprSetHeight(p); sqlite3ExprCheckHeight(pParse, p.nHeight); }
/* ** 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 Debug.Assert() statements that attempt ** to enforce this constraint. */ static int dupedExprStructSize(Expr p, int flags) { int nSize; Debug.Assert(flags == EXPRDUP_REDUCE || flags == 0); /* Only one flag value allowed */ if (0 == (flags & EXPRDUP_REDUCE)) { nSize = EXPR_FULLSIZE; } else { Debug.Assert(!ExprHasAnyProperty(p, EP_TokenOnly | EP_Reduced)); Debug.Assert(!ExprHasProperty(p, EP_FromJoin)); Debug.Assert((p.flags2 & EP2_MallocedToken) == 0); Debug.Assert((p.flags2 & EP2_Irreducible) == 0); if (p.pLeft != null || p.pRight != null || p.pColl != null || p.x.pList != null || p.x.pSelect != null) { nSize = EXPR_REDUCEDSIZE | EP_Reduced; } else { nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly; } } return nSize; }
/* ** Generate code that evalutes the given expression and puts the result ** in register target. ** ** Also make a copy of the expression results into another "cache" register ** and modify the expression so that the next time it is evaluated, ** the result is a copy of the cache register. ** ** This routine is used for expressions that are used multiple ** times. They are evaluated once and the results of the expression ** are reused. */ static int sqlite3ExprCodeAndCache(Parse pParse, Expr pExpr, int target) { Vdbe v = pParse.pVdbe; int inReg; inReg = sqlite3ExprCode(pParse, pExpr, target); Debug.Assert(target > 0); /* This routine is called for terms to INSERT or UPDATE. And the only ** other place where expressions can be converted into TK_REGISTER is ** in WHERE clause processing. So as currently implemented, there is ** no way for a TK_REGISTER to exist here. But it seems prudent to ** keep the ALWAYS() in case the conditions above change with future ** modifications or enhancements. */ if (ALWAYS(pExpr.op != TK_REGISTER)) { int iMem; iMem = ++pParse.nMem; sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); pExpr.iTable = iMem; pExpr.op2 = pExpr.op; pExpr.op = TK_REGISTER; } return inReg; }
/* ** Assign a variable number to an expression that encodes a wildcard ** in the original SQL statement. ** ** Wildcards consisting of a single "?" are assigned the next sequential ** variable number. ** ** Wildcards of the form "?nnn" are assigned the number "nnn". We make ** sure "nnn" is not too be to avoid a denial of service attack when ** the SQL statement comes from an external source. ** ** Wildcards of the form ":aaa", "@aaa" or "$aaa" are assigned the same number ** as the previous instance of the same wildcard. Or if this is the first ** instance of the wildcard, the next sequenial variable number is ** assigned. */ static void sqlite3ExprAssignVarNumber(Parse pParse, Expr pExpr) { sqlite3 db = pParse.db; string z; if (pExpr == null) return; Debug.Assert(!ExprHasAnyProperty(pExpr, EP_IntValue | EP_Reduced | EP_TokenOnly)); z = pExpr.u.zToken; Debug.Assert(z != null); Debug.Assert(z.Length != 0); if (z.Length == 1) { /* Wildcard of the form "?". Assign the next variable number */ Debug.Assert(z[0] == '?'); pExpr.iColumn = (ynVar)(++pParse.nVar); } else { ynVar x = 0; int n = sqlite3Strlen30(z); if (z[0] == '?') { /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ long i = 0; bool bOk = 0 == sqlite3Atoi64(z.Substring(1), ref i, n - 1, SQLITE_UTF8); pExpr.iColumn = x = (ynVar)i; testcase(i == 0); testcase(i == 1); testcase(i == db.aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] - 1); testcase(i == db.aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); if (bOk == false || i < 1 || i > db.aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]) { sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db.aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); x = 0; } if (i > pParse.nVar) { pParse.nVar = (int)i; } } else { /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ** number as the prior appearance of the same name, or if the name ** has never appeared before, reuse the same variable number */ ynVar i; for (i = 0; i < pParse.nzVar; i++) { if (pParse.azVar[i] != null && z.CompareTo(pParse.azVar[i]) == 0) //memcmp(pParse.azVar[i],z,n+1)==0 ) { pExpr.iColumn = x = (ynVar)(i + 1); break; } } if (x == 0) x = pExpr.iColumn = (ynVar)(++pParse.nVar); } if (x > 0) { if (x > pParse.nzVar) { //char **a; //a = sqlite3DbRealloc(db, pParse.azVar, x*sizeof(a[0])); //if( a==0 ) return; /* Error reported through db.mallocFailed */ //pParse.azVar = a; //memset(&a[pParse.nzVar], 0, (x-pParse.nzVar)*sizeof(a[0])); Array.Resize(ref pParse.azVar, x); pParse.nzVar = x; } if (z[0] != '?' || pParse.azVar[x - 1] == null) { //sqlite3DbFree(db, pParse.azVar[x-1]); pParse.azVar[x - 1] = z.Substring(0, n);//sqlite3DbStrNDup( db, z, n ); } } } if (pParse.nErr == 0 && pParse.nVar > db.aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]) { sqlite3ErrorMsg(pParse, "too many SQL variables"); } }
/* ** Return TRUE if pExpr is an constant expression that is appropriate ** for factoring out of a loop. Appropriate expressions are: ** ** * Any expression that evaluates to two or more opcodes. ** ** * Any OP_Integer, OP_Real, OP_String, OP_Blob, OP_Null, ** or OP_Variable that does not need to be placed in a ** specific register. ** ** There is no point in factoring out single-instruction constant ** expressions that need to be placed in a particular register. ** We could factor them out, but then we would end up adding an ** OP_SCopy instruction to move the value into the correct register ** later. We might as well just use the original instruction and ** avoid the OP_SCopy. */ static int isAppropriateForFactoring(Expr p) { if (sqlite3ExprIsConstantNotJoin(p) == 0) { return 0; /* Only constant expressions are appropriate for factoring */ } if ((p.flags & EP_FixedDest) == 0) { return 1; /* Any constant without a fixed destination is appropriate */ } while (p.op == TK_UPLUS) p = p.pLeft; switch (p.op) { #if !SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: #endif case TK_VARIABLE: case TK_INTEGER: case TK_FLOAT: case TK_NULL: case TK_STRING: { testcase(p.op == TK_BLOB); testcase(p.op == TK_VARIABLE); testcase(p.op == TK_INTEGER); testcase(p.op == TK_FLOAT); testcase(p.op == TK_NULL); testcase(p.op == TK_STRING); /* Single-instruction constants with a fixed destination are ** better done in-line. If we factor them, they will just end ** up generating an OP_SCopy to move the value to the destination ** register. */ return 0; } case TK_UMINUS: { if (p.pLeft.op == TK_FLOAT || p.pLeft.op == TK_INTEGER) { return 0; } break; } default: { break; } } return 1; }
//#define exprSetHeight(y) #endif //* SQLITE_MAX_EXPR_DEPTH>0 */ /* ** This routine is the core allocator for Expr nodes. ** ** Construct a new expression node and return a pointer to it. Memory ** for this node and for the pToken argument is a single allocation ** obtained from sqlite3DbMalloc(). The calling function ** is responsible for making sure the node eventually gets freed. ** ** If dequote is true, then the token (if it exists) is dequoted. ** If dequote is false, no dequoting is performance. The deQuote ** 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. */ static Expr sqlite3ExprAlloc( sqlite3 db, /* Handle for sqlite3DbMallocZero() (may be null) */ int op, /* Expression opcode */ Token pToken, /* Token argument. Might be NULL */ int dequote /* True to dequote */ ) { Expr pNew; int nExtra = 0; int iValue = 0; if (pToken != null) { if (op != TK_INTEGER || pToken.z == null || pToken.z.Length == 0 || sqlite3GetInt32(pToken.z.ToString(), ref iValue) == false) { nExtra = pToken.n + 1; Debug.Assert(iValue >= 0); } } pNew = new Expr();//sqlite3DbMallocZero(db, sizeof(Expr)+nExtra); if (pNew != null) { pNew.op = (byte)op; pNew.iAgg = -1; if (pToken != null) { if (nExtra == 0) { pNew.flags |= EP_IntValue; pNew.u.iValue = iValue; } else { int c; //pNew.u.zToken = (char)&pNew[1]; if (pToken.n > 0) pNew.u.zToken = pToken.z.Substring(0, pToken.n);//memcpy(pNew.u.zToken, pToken.z, pToken.n); else if (pToken.n == 0 && pToken.z == "") pNew.u.zToken = ""; //pNew.u.zToken[pToken.n] = 0; if (dequote != 0 && nExtra >= 3 && ((c = pToken.z[0]) == '\'' || c == '"' || c == '[' || c == '`')) { #if DEBUG_CLASS_EXPR || DEBUG_CLASS_ALL sqlite3Dequote(ref pNew.u._zToken); #else sqlite3Dequote(ref pNew.u.zToken); #endif if (c == '"') pNew.flags |= EP_DblQuoted; } } } #if SQLITE_MAX_EXPR_DEPTH//>0 pNew.nHeight = 1; #endif } return pNew; }
/* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is true but execution ** continues straight thru if the expression is false. ** ** If the expression evaluates to NULL (neither true nor false), then ** take the jump if the jumpIfNull flag is SQLITE_JUMPIFNULL. ** ** This code depends on the fact that certain token values (ex: TK_EQ) ** are the same as opcode values (ex: OP_Eq) that implement the corresponding ** operation. Special comments in vdbe.c and the mkopcodeh.awk script in ** the make process cause these values to align. Assert()s in the code ** below verify that the numbers are aligned correctly. */ static void sqlite3ExprIfTrue(Parse pParse, Expr pExpr, int dest, int jumpIfNull) { Vdbe v = pParse.pVdbe; int op = 0; int regFree1 = 0; int regFree2 = 0; int r1 = 0, r2 = 0; Debug.Assert(jumpIfNull == SQLITE_JUMPIFNULL || jumpIfNull == 0); if (NEVER(v == null)) return; /* Existance of VDBE checked by caller */ if (NEVER(pExpr == null)) return; /* No way this can happen */ op = pExpr.op; switch (op) { case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); testcase(jumpIfNull == 0); sqlite3ExprCachePush(pParse); sqlite3ExprIfFalse(pParse, pExpr.pLeft, d2, jumpIfNull ^ SQLITE_JUMPIFNULL); sqlite3ExprIfTrue(pParse, pExpr.pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); sqlite3ExprCachePop(pParse, 1); break; } case TK_OR: { testcase(jumpIfNull == 0); sqlite3ExprIfTrue(pParse, pExpr.pLeft, dest, jumpIfNull); sqlite3ExprIfTrue(pParse, pExpr.pRight, dest, jumpIfNull); break; } case TK_NOT: { testcase(jumpIfNull == 0); sqlite3ExprIfFalse(pParse, pExpr.pLeft, dest, jumpIfNull); break; } case TK_LT: case TK_LE: case TK_GT: case TK_GE: case TK_NE: case TK_EQ: { Debug.Assert(TK_LT == OP_Lt); Debug.Assert(TK_LE == OP_Le); Debug.Assert(TK_GT == OP_Gt); Debug.Assert(TK_GE == OP_Ge); Debug.Assert(TK_EQ == OP_Eq); Debug.Assert(TK_NE == OP_Ne); testcase(op == TK_LT); testcase(op == TK_LE); testcase(op == TK_GT); testcase(op == TK_GE); testcase(op == TK_EQ); testcase(op == TK_NE); testcase(jumpIfNull == 0); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); r2 = sqlite3ExprCodeTemp(pParse, pExpr.pRight, ref regFree2); codeCompare(pParse, pExpr.pLeft, pExpr.pRight, op, r1, r2, dest, jumpIfNull); testcase(regFree1 == 0); testcase(regFree2 == 0); break; } case TK_IS: case TK_ISNOT: { testcase(op == TK_IS); testcase(op == TK_ISNOT); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); r2 = sqlite3ExprCodeTemp(pParse, pExpr.pRight, ref regFree2); op = (op == TK_IS) ? TK_EQ : TK_NE; codeCompare(pParse, pExpr.pLeft, pExpr.pRight, op, r1, r2, dest, SQLITE_NULLEQ); testcase(regFree1 == 0); testcase(regFree2 == 0); break; } case TK_ISNULL: case TK_NOTNULL: { Debug.Assert(TK_ISNULL == OP_IsNull); Debug.Assert(TK_NOTNULL == OP_NotNull); testcase(op == TK_ISNULL); testcase(op == TK_NOTNULL); r1 = sqlite3ExprCodeTemp(pParse, pExpr.pLeft, ref regFree1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase(regFree1 == 0); break; } case TK_BETWEEN: { testcase(jumpIfNull == 0); exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull); break; } #if SQLITE_OMIT_SUBQUERY case TK_IN: { int destIfFalse = sqlite3VdbeMakeLabel( v ); int destIfNull = jumpIfNull != 0 ? dest : destIfFalse; sqlite3ExprCodeIN( pParse, pExpr, destIfFalse, destIfNull ); sqlite3VdbeAddOp2( v, OP_Goto, 0, dest ); sqlite3VdbeResolveLabel( v, destIfFalse ); break; } #endif default: { r1 = sqlite3ExprCodeTemp(pParse, pExpr, ref regFree1); sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull != 0 ? 1 : 0); testcase(regFree1 == 0); testcase(jumpIfNull == 0); break; } } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); }
/* ** Generate code for a BETWEEN operator. ** ** x BETWEEN y AND z ** ** The above is equivalent to ** ** x>=y AND x<=z ** ** Code it as such, taking care to do the common subexpression ** elementation of x. */ static void exprCodeBetween( Parse pParse, /* Parsing and code generating context */ Expr pExpr, /* The BETWEEN expression */ int dest, /* Jump here if the jump is taken */ int jumpIfTrue, /* Take the jump if the BETWEEN is true */ int jumpIfNull /* Take the jump if the BETWEEN is NULL */ ) { Expr exprAnd = new Expr(); /* The AND operator in x>=y AND x<=z */ Expr compLeft = new Expr(); /* The x>=y term */ Expr compRight = new Expr(); /* The x<=z term */ Expr exprX; /* The x subexpression */ int regFree1 = 0; /* Temporary use register */ Debug.Assert(!ExprHasProperty(pExpr, EP_xIsSelect)); exprX = pExpr.pLeft.Copy(); exprAnd.op = TK_AND; exprAnd.pLeft = compLeft; exprAnd.pRight = compRight; compLeft.op = TK_GE; compLeft.pLeft = exprX; compLeft.pRight = pExpr.x.pList.a[0].pExpr; compRight.op = TK_LE; compRight.pLeft = exprX; compRight.pRight = pExpr.x.pList.a[1].pExpr; exprX.iTable = sqlite3ExprCodeTemp(pParse, exprX, ref regFree1); exprX.op = TK_REGISTER; if (jumpIfTrue != 0) { sqlite3ExprIfTrue(pParse, exprAnd, dest, jumpIfNull); } else { sqlite3ExprIfFalse(pParse, exprAnd, dest, jumpIfNull); } sqlite3ReleaseTempReg(pParse, regFree1); /* Ensure adequate test coverage */ testcase(jumpIfTrue == 0 && jumpIfNull == 0 && regFree1 == 0); testcase(jumpIfTrue == 0 && jumpIfNull == 0 && regFree1 != 0); testcase(jumpIfTrue == 0 && jumpIfNull != 0 && regFree1 == 0); testcase(jumpIfTrue == 0 && jumpIfNull != 0 && regFree1 != 0); testcase(jumpIfTrue != 0 && jumpIfNull == 0 && regFree1 == 0); testcase(jumpIfTrue != 0 && jumpIfNull == 0 && regFree1 != 0); testcase(jumpIfTrue != 0 && jumpIfNull != 0 && regFree1 == 0); testcase(jumpIfTrue != 0 && jumpIfNull != 0 && regFree1 != 0); }
/* ** Preevaluate constant subexpressions within pExpr and store the ** results in registers. Modify pExpr so that the constant subexpresions ** are TK_REGISTER opcodes that refer to the precomputed values. ** ** This routine is a no-op if the jump to the cookie-check code has ** already occur. Since the cookie-check jump is generated prior to ** any other serious processing, this check ensures that there is no ** way to accidently bypass the constant initializations. ** ** This routine is also a no-op if the SQLITE_FactorOutConst optimization ** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) ** interface. This allows test logic to verify that the same answer is ** obtained for queries regardless of whether or not constants are ** precomputed into registers or if they are inserted in-line. */ static void sqlite3ExprCodeConstants(Parse pParse, Expr pExpr) { Walker w; if (pParse.cookieGoto != 0) return; if ((pParse.db.flags & SQLITE_FactorOutConst) != 0) return; w = new Walker(); w.xExprCallback = (dxExprCallback)evalConstExpr; w.xSelectCallback = null; w.pParse = pParse; sqlite3WalkExpr(w, ref pExpr); }
/* ** If pExpr is a constant expression that is appropriate for ** factoring out of a loop, then evaluate the expression ** into a register and convert the expression into a TK_REGISTER ** expression. */ static int evalConstExpr(Walker pWalker, ref Expr pExpr) { Parse pParse = pWalker.pParse; switch (pExpr.op) { case TK_IN: case TK_REGISTER: { return WRC_Prune; } case TK_FUNCTION: case TK_AGG_FUNCTION: case TK_CONST_FUNC: { /* The arguments to a function have a fixed destination. ** Mark them this way to avoid generated unneeded OP_SCopy ** instructions. */ ExprList pList = pExpr.x.pList; Debug.Assert(!ExprHasProperty(pExpr, EP_xIsSelect)); if (pList != null) { int i = pList.nExpr; ExprList_item pItem;//= pList.a; for (; i > 0; i--) {//, pItem++){ pItem = pList.a[pList.nExpr - i]; if (ALWAYS(pItem.pExpr != null)) pItem.pExpr.flags |= EP_FixedDest; } } break; } } if (isAppropriateForFactoring(pExpr) != 0) { int r1 = ++pParse.nMem; int r2; r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if (NEVER(r1 != r2)) sqlite3ReleaseTempReg(pParse, r1); pExpr.op2 = pExpr.op; pExpr.op = TK_REGISTER; pExpr.iTable = r2; return WRC_Prune; } return WRC_Continue; }
/* ** Recursively delete an expression tree. */ static void sqlite3ExprDelete(sqlite3 db, ref Expr p) { if (p == null) return; /* Sanity check: Assert that the IntValue is non-negative if it exists */ Debug.Assert(!ExprHasProperty(p, EP_IntValue) || p.u.iValue >= 0); if (!ExprHasAnyProperty(p, EP_TokenOnly)) { sqlite3ExprDelete(db, ref p.pLeft); sqlite3ExprDelete(db, ref p.pRight); if (!ExprHasProperty(p, EP_Reduced) && (p.flags2 & EP2_MallocedToken) != 0) { #if DEBUG_CLASS_EXPR || DEBUG_CLASS_ALL sqlite3DbFree( db, ref p.u._zToken ); #else sqlite3DbFree(db, ref p.u.zToken); #endif } if (ExprHasProperty(p, EP_xIsSelect)) { sqlite3SelectDelete(db, ref p.x.pSelect); } else { sqlite3ExprListDelete(db, ref p.x.pList); } } if (!ExprHasProperty(p, EP_Static)) { sqlite3DbFree(db, ref p); } }
/* ** Do a deep comparison of two expression trees. Return 0 if the two ** expressions are completely identical. Return 1 if they differ only ** by a COLLATE operator at the top level. Return 2 if there are differences ** other than the top-level COLLATE operator. ** ** Sometimes this routine will return 2 even if the two expressions ** really are equivalent. If we cannot prove that the expressions are ** identical, we return 2 just to be safe. So if this routine ** returns 2, then you do not really know for certain if the two ** expressions are the same. But if you get a 0 or 1 return, then you ** can be sure the expressions are the same. In the places where ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. */ static int sqlite3ExprCompare(Expr pA, Expr pB) { if (pA == null || pB == null) { return pB == pA ? 0 : 2; } Debug.Assert(!ExprHasAnyProperty(pA, EP_TokenOnly | EP_Reduced)); Debug.Assert(!ExprHasAnyProperty(pB, EP_TokenOnly | EP_Reduced)); if (ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect)) { return 2; } if ((pA.flags & EP_Distinct) != (pB.flags & EP_Distinct)) return 2; if (pA.op != pB.op) return 2; if (sqlite3ExprCompare(pA.pLeft, pB.pLeft) != 0) return 2; if (sqlite3ExprCompare(pA.pRight, pB.pRight) != 0) return 2; if (sqlite3ExprListCompare(pA.x.pList, pB.x.pList) != 0) return 2; if (pA.iTable != pB.iTable || pA.iColumn != pB.iColumn) return 2; if (ExprHasProperty(pA, EP_IntValue)) { if (!ExprHasProperty(pB, EP_IntValue) || pA.u.iValue != pB.u.iValue) { return 2; } } else if (pA.op != TK_COLUMN && pA.u.zToken != null) { if (ExprHasProperty(pB, EP_IntValue) || NEVER(pB.u.zToken == null)) return 2; if (!pA.u.zToken.Equals(pB.u.zToken, StringComparison.InvariantCultureIgnoreCase)) { return 2; } } if ((pA.flags & EP_ExpCollate) != (pB.flags & EP_ExpCollate)) return 1; if ((pA.flags & EP_ExpCollate) != 0 && pA.pColl != pB.pColl) return 2; return 0; }
/* ** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, ** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE. */ static int exprStructSize(Expr p) { if (ExprHasProperty(p, EP_TokenOnly)) return EXPR_TOKENONLYSIZE; if (ExprHasProperty(p, EP_Reduced)) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; }
/* ** This is the xExprCallback for a tree walker. It is used to ** implement sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates ** for additional information. */ static int analyzeAggregate(Walker pWalker, ref Expr pExpr) { int i; NameContext pNC = pWalker.u.pNC; Parse pParse = pNC.pParse; SrcList pSrcList = pNC.pSrcList; AggInfo pAggInfo = pNC.pAggInfo; switch (pExpr.op) { case TK_AGG_COLUMN: case TK_COLUMN: { testcase(pExpr.op == TK_AGG_COLUMN); testcase(pExpr.op == TK_COLUMN); /* Check to see if the column is in one of the tables in the FROM ** clause of the aggregate query */ if (ALWAYS(pSrcList != null)) { SrcList_item pItem;// = pSrcList.a; for (i = 0; i < pSrcList.nSrc; i++) {//, pItem++){ pItem = pSrcList.a[i]; AggInfo_col pCol; Debug.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. ** ** Make an entry for the column in pAggInfo.aCol[] if there ** is not an entry there already. */ int k; //pCol = pAggInfo.aCol; for (k = 0; k < pAggInfo.nColumn; k++) {//, pCol++){ pCol = pAggInfo.aCol[k]; if (pCol.iTable == pExpr.iTable && pCol.iColumn == pExpr.iColumn) { break; } } if ((k >= pAggInfo.nColumn) && (k = addAggInfoColumn(pParse.db, pAggInfo)) >= 0 ) { pCol = pAggInfo.aCol[k]; pCol.pTab = pExpr.pTab; pCol.iTable = pExpr.iTable; pCol.iColumn = pExpr.iColumn; pCol.iMem = ++pParse.nMem; pCol.iSorterColumn = -1; pCol.pExpr = pExpr; if (pAggInfo.pGroupBy != null) { int j, n; ExprList pGB = pAggInfo.pGroupBy; ExprList_item pTerm;// = pGB.a; n = pGB.nExpr; for (j = 0; j < n; j++) {//, pTerm++){ pTerm = pGB.a[j]; Expr pE = pTerm.pExpr; if (pE.op == TK_COLUMN && pE.iTable == pExpr.iTable && pE.iColumn == pExpr.iColumn) { pCol.iSorterColumn = j; break; } } } if (pCol.iSorterColumn < 0) { pCol.iSorterColumn = pAggInfo.nSortingColumn++; } } /* There is now an entry for pExpr in pAggInfo.aCol[] (either ** because it was there before or because we just created it). ** 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 = (short)k; break; } /* endif pExpr.iTable==pItem.iCursor */ } /* end loop over pSrcList */ } return WRC_Prune; } case TK_AGG_FUNCTION: { /* The pNC.nDepth==0 test causes aggregate functions in subqueries ** to be ignored */ if (pNC.nDepth == 0) { /* Check to see if pExpr is a duplicate of another aggregate ** function that is already in the pAggInfo structure */ AggInfo_func pItem;// = pAggInfo.aFunc; for (i = 0; i < pAggInfo.nFunc; i++) {//, pItem++){ pItem = pAggInfo.aFunc[i]; if (sqlite3ExprCompare(pItem.pExpr, pExpr) == 0) { break; } } if (i >= pAggInfo.nFunc) { /* pExpr is original. Make a new entry in pAggInfo.aFunc[] */ u8 enc = pParse.db.aDbStatic[0].pSchema.enc;// ENC(pParse.db); i = addAggInfoFunc(pParse.db, pAggInfo); if (i >= 0) { Debug.Assert(!ExprHasProperty(pExpr, EP_xIsSelect)); pItem = pAggInfo.aFunc[i]; pItem.pExpr = pExpr; pItem.iMem = ++pParse.nMem; Debug.Assert(!ExprHasProperty(pExpr, EP_IntValue)); pItem.pFunc = sqlite3FindFunction(pParse.db, pExpr.u.zToken, sqlite3Strlen30(pExpr.u.zToken), pExpr.x.pList != null ? pExpr.x.pList.nExpr : 0, enc, 0); if ((pExpr.flags & EP_Distinct) != 0) { pItem.iDistinct = pParse.nTab++; } else { pItem.iDistinct = -1; } } } /* Make pExpr point to the appropriate pAggInfo.aFunc[] entry */ Debug.Assert(!ExprHasAnyProperty(pExpr, EP_TokenOnly | EP_Reduced)); ExprSetIrreducible(pExpr); pExpr.iAgg = (short)i; pExpr.pAggInfo = pAggInfo; return WRC_Prune; } break; } } return WRC_Continue; }
/* ** 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) & 0xfff; if (!ExprHasProperty(p, EP_IntValue) && p.u.zToken != null) { nByte += sqlite3Strlen30(p.u.zToken) + 1; } return ROUND8(nByte); }
/* ** Analyze the given expression looking for aggregate functions and ** for variables that need to be added to the pParse.aAgg[] array. ** Make additional entries to the pParse.aAgg[] array as necessary. ** ** This routine should only be called after the expression has been ** analyzed by sqlite3ResolveExprNames(). */ static void sqlite3ExprAnalyzeAggregates(NameContext pNC, ref Expr pExpr) { Walker w = new Walker(); w.xExprCallback = (dxExprCallback)analyzeAggregate; w.xSelectCallback = (dxSelectCallback)analyzeAggregatesInSelect; w.u.pNC = pNC; Debug.Assert(pNC.pSrcList != null); sqlite3WalkExpr(w, ref pExpr); }
/* ** Return the number of bytes required to create a duplicate of the ** expression passed as the first argument. The second argument is a ** 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.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 ** and Expr.pRight variables (but not for any structures pointed to or ** descended from the Expr.x.pList or Expr.x.pSelect variables). */ static int dupedExprSize(Expr p, int flags) { int nByte = 0; if (p != null) { nByte = dupedExprNodeSize(p, flags); if ((flags & EXPRDUP_REDUCE) != 0) { nByte += dupedExprSize(p.pLeft, flags) + dupedExprSize(p.pRight, flags); } } return nByte; }
/* ** Attach subtrees pLeft and pRight to the Expr node pRoot. ** ** If pRoot==NULL that means that a memory allocation error has occurred. ** In that case, delete the subtrees pLeft and pRight. */ static void sqlite3ExprAttachSubtrees( sqlite3 db, Expr pRoot, Expr pLeft, Expr pRight ) { if (pRoot == null) { //Debug.Assert( db.mallocFailed != 0 ); sqlite3ExprDelete(db, ref pLeft); sqlite3ExprDelete(db, ref pRight); } else { if (pRight != null) { pRoot.pRight = pRight; if ((pRight.flags & EP_ExpCollate) != 0) { pRoot.flags |= EP_ExpCollate; pRoot.pColl = pRight.pColl; } } if (pLeft != null) { pRoot.pLeft = pLeft; if ((pLeft.flags & EP_ExpCollate) != 0) { pRoot.flags |= EP_ExpCollate; pRoot.pColl = pLeft.pColl; } } exprSetHeight(pRoot); } }
/* ** The following group of routines make deep copies of expressions, ** expression lists, ID lists, and select statements. The copies can ** be deleted (by being passed to their respective ...Delete() routines) ** without effecting the originals. ** ** The expression list, ID, and source lists return by sqlite3ExprListDup(), ** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded ** by subsequent calls to sqlite*ListAppend() routines. ** ** Any tables that the SrcList might point to are not duplicated. ** ** The flags parameter contains a combination of the EXPRDUP_XXX flags. ** If the EXPRDUP_REDUCE flag is set, then the structure returned is a ** truncated version of the usual Expr structure that will be stored as ** part of the in-memory representation of the database schema. */ static Expr sqlite3ExprDup(sqlite3 db, Expr p, int flags) { Expr ExprDummy = null; return exprDup(db, p, flags, ref ExprDummy); }
static Expr sqlite3PExpr(Parse pParse, int op, Expr pLeft, int null_4, Token pToken) { return sqlite3PExpr(pParse, op, pLeft, null, pToken); }