aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c28
-rw-r--r--src/expr.c7
-rw-r--r--src/loadext.c4
-rw-r--r--src/main.c32
-rw-r--r--src/malloc.c13
-rw-r--r--src/parse.y426
-rw-r--r--src/select.c12
-rw-r--r--src/shell.c.in193
-rw-r--r--src/sqlite.h.in19
-rw-r--r--src/sqliteInt.h40
-rw-r--r--src/treeview.c12
-rw-r--r--src/trigger.c59
-rw-r--r--src/util.c26
-rw-r--r--src/vdbe.c14
-rw-r--r--src/vdbeaux.c6
-rw-r--r--src/where.c66
-rw-r--r--src/wherecode.c2
17 files changed, 579 insertions, 380 deletions
diff --git a/src/build.c b/src/build.c
index 9582f136c..26eb0579e 100644
--- a/src/build.c
+++ b/src/build.c
@@ -1221,34 +1221,37 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
** This routine is called by the parser while in the middle of
** parsing a CREATE TABLE statement.
*/
-void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
+void sqlite3AddDefaultValue(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The parsed expression of the default value */
+ const char *zStart, /* Start of the default value text */
+ const char *zEnd /* First character past end of defaut value text */
+){
Table *p;
Column *pCol;
sqlite3 *db = pParse->db;
p = pParse->pNewTable;
if( p!=0 ){
pCol = &(p->aCol[p->nCol-1]);
- if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
+ if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
/* A copy of pExpr is used instead of the original, as pExpr contains
- ** tokens that point to volatile memory. The 'span' of the expression
- ** is required by pragma table_info.
+ ** tokens that point to volatile memory.
*/
Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
memset(&x, 0, sizeof(x));
x.op = TK_SPAN;
- x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
- x.pLeft = pSpan->pExpr;
+ x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
+ x.pLeft = pExpr;
x.flags = EP_Skip;
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
sqlite3DbFree(db, x.u.zToken);
}
}
- sqlite3ExprDelete(db, pSpan->pExpr);
+ sqlite3ExprDelete(db, pExpr);
}
/*
@@ -1965,10 +1968,6 @@ void sqlite3EndTable(
pParse->nTab = 2;
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
- sqlite3Select(pParse, pSelect, &dest);
- sqlite3VdbeEndCoroutine(v, regYield);
- sqlite3VdbeJumpHere(v, addrTop - 1);
if( pParse->nErr ) return;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
if( pSelTab==0 ) return;
@@ -1978,6 +1977,11 @@ void sqlite3EndTable(
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ sqlite3Select(pParse, pSelect, &dest);
+ if( pParse->nErr ) return;
+ sqlite3VdbeEndCoroutine(v, regYield);
+ sqlite3VdbeJumpHere(v, addrTop - 1);
addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
diff --git a/src/expr.c b/src/expr.c
index b7c64d3c1..dbfc1b7ed 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1654,17 +1654,16 @@ void sqlite3ExprListSetName(
void sqlite3ExprListSetSpan(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List to which to add the span. */
- ExprSpan *pSpan /* The span to be added */
+ const char *zStart, /* Start of the span */
+ const char *zEnd /* End of the span */
){
sqlite3 *db = pParse->db;
assert( pList!=0 || db->mallocFailed!=0 );
if( pList ){
struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
assert( pList->nExpr>0 );
- assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr );
sqlite3DbFree(db, pItem->zSpan);
- pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
+ pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd);
}
}
diff --git a/src/loadext.c b/src/loadext.c
index 675142593..abc6b3ff1 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -496,8 +496,10 @@ static int sqlite3LoadExtension(
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
+ int bExists = 0;
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
- handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ sqlite3OsAccess(pVfs, zAltFile, SQLITE_ACCESS_EXISTS, &bExists);
+ if( bExists ) handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
#endif
diff --git a/src/main.c b/src/main.c
index 52d3be953..3c8035c12 100644
--- a/src/main.c
+++ b/src/main.c
@@ -806,21 +806,6 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
- case SQLITE_DBCONFIG_FULL_EQP: {
- int onoff = va_arg(ap, int);
- int *pRes = va_arg(ap, int*);
- if( onoff>0 ){
- db->bFullEQP = 1;
- }else if( onoff==0 ){
- db->bFullEQP = 0;
- }
- sqlite3ExpirePreparedStatements(db);
- if( pRes ){
- *pRes = db->bFullEQP;
- }
- rc = SQLITE_OK;
- break;
- }
default: {
static const struct {
int op; /* The opcode */
@@ -832,6 +817,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
{ SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG },
+ { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -3925,6 +3911,22 @@ int sqlite3_test_control(int op, ...){
sqlite3_mutex_leave(db->mutex);
break;
}
+
+#if defined(YYCOVERAGE)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
+ **
+ ** This test control (only available when SQLite is compiled with
+ ** -DYYCOVERAGE) writes a report onto "out" that shows all
+ ** state/lookahead combinations in the parser state machine
+ ** which are never exercised. If any state is missed, make the
+ ** return code SQLITE_ERROR.
+ */
+ case SQLITE_TESTCTRL_PARSER_COVERAGE: {
+ FILE *out = va_arg(ap, FILE*);
+ if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
+ break;
+ }
+#endif /* defined(YYCOVERAGE) */
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
diff --git a/src/malloc.c b/src/malloc.c
index b750f6e72..ec2d93ac8 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -628,6 +628,19 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
}
/*
+** The text between zStart and zEnd represents a phrase within a larger
+** SQL statement. Make a copy of this phrase in space obtained form
+** sqlite3DbMalloc(). Omit leading and trailing whitespace.
+*/
+char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ int n;
+ while( sqlite3Isspace(zStart[0]) ) zStart++;
+ n = (int)(zEnd - zStart);
+ while( n>0 && sqlite3Isspace(zStart[n-1]) ) n--;
+ return sqlite3DbStrNDup(db, zStart, n);
+}
+
+/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
diff --git a/src/parse.y b/src/parse.y
index 0867d1e0c..e780f8c3a 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -273,26 +273,44 @@ typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);}
signed ::= plus_num.
signed ::= minus_num.
+// The scanpt non-terminal takes a value which is a pointer to the
+// input text just past the last token that has been shifted into
+// the parser. By surrounding some phrase in the grammar with two
+// scanpt non-terminals, we can capture the input text for that phrase.
+// For example:
+//
+// something ::= .... scanpt(A) phrase scanpt(Z).
+//
+// The text that is parsed as "phrase" is a string starting at A
+// and containing (int)(Z-A) characters. There might be some extra
+// whitespace on either end of the text, but that can be removed in
+// post-processing, if needed.
+//
+%type scanpt {const char*}
+scanpt(A) ::= . {
+ assert( yyLookahead!=YYNOCODE );
+ A = yyLookaheadToken.z;
+}
+
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
//
carglist ::= carglist ccons.
carglist ::= .
ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
-ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);}
-ccons ::= DEFAULT MINUS(A) term(X). {
- ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, X.pExpr, 0);
- v.zStart = A.z;
- v.zEnd = X.zEnd;
- sqlite3AddDefaultValue(pParse,&v);
-}
-ccons ::= DEFAULT id(X). {
- ExprSpan v;
- spanExpr(&v, pParse, TK_STRING, X);
- sqlite3AddDefaultValue(pParse,&v);
+ccons ::= DEFAULT scanpt(A) term(X) scanpt(Z).
+ {sqlite3AddDefaultValue(pParse,X,A,Z);}
+ccons ::= DEFAULT LP(A) expr(X) RP(Z).
+ {sqlite3AddDefaultValue(pParse,X,A.z+1,Z.z);}
+ccons ::= DEFAULT PLUS(A) term(X) scanpt(Z).
+ {sqlite3AddDefaultValue(pParse,X,A.z,Z);}
+ccons ::= DEFAULT MINUS(A) term(X) scanpt(Z). {
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0);
+ sqlite3AddDefaultValue(pParse,p,A.z,Z);
+}
+ccons ::= DEFAULT scanpt id(X). {
+ Expr *p = tokenExpr(pParse, TK_STRING, X);
+ sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n);
}
// In addition to the type name, we also care about the primary key and
@@ -304,7 +322,7 @@ ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
-ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
+ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
@@ -355,7 +373,7 @@ tcons ::= UNIQUE LP sortlist(X) RP onconf(R).
{sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
tcons ::= CHECK LP expr(E) RP onconf.
- {sqlite3AddCheckConstraint(pParse,E.pExpr);}
+ {sqlite3AddCheckConstraint(pParse,E);}
tcons ::= FOREIGN KEY LP eidlist(FA) RP
REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). {
sqlite3CreateForeignKey(pParse, FA, &T, TA, R);
@@ -549,16 +567,16 @@ distinct(A) ::= . {A = 0;}
%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);}
sclp(A) ::= selcollist(A) COMMA.
sclp(A) ::= . {A = 0;}
-selcollist(A) ::= sclp(A) expr(X) as(Y). {
- A = sqlite3ExprListAppend(pParse, A, X.pExpr);
+selcollist(A) ::= sclp(A) scanpt(B) expr(X) scanpt(Z) as(Y). {
+ A = sqlite3ExprListAppend(pParse, A, X);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
- sqlite3ExprListSetSpan(pParse,A,&X);
+ sqlite3ExprListSetSpan(pParse,A,B,Z);
}
-selcollist(A) ::= sclp(A) STAR. {
+selcollist(A) ::= sclp(A) scanpt STAR. {
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
A = sqlite3ExprListAppend(pParse, A, p);
}
-selcollist(A) ::= sclp(A) nm(X) DOT STAR. {
+selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR. {
Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
@@ -656,7 +674,7 @@ joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
-on_opt(N) ::= ON expr(E). {N = E.pExpr;}
+on_opt(N) ::= ON expr(E). {N = E;}
on_opt(N) ::= . {N = 0;}
// Note that this block abuses the Token type just a little. If there is
@@ -693,11 +711,11 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,A,Y.pExpr);
+ A = sqlite3ExprListAppend(pParse,A,Y);
sqlite3ExprListSetSortOrder(A,Z);
}
sortlist(A) ::= expr(Y) sortorder(Z). {
- A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/
+ A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/
sqlite3ExprListSetSortOrder(A,Z);
}
@@ -715,7 +733,7 @@ groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);}
having_opt(A) ::= . {A = 0;}
-having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
+having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {Expr*}
@@ -729,11 +747,11 @@ having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
//%destructor limit_opt {sqlite3ExprDelete(pParse->db, $$);}
limit_opt(A) ::= . {A = 0;}
limit_opt(A) ::= LIMIT expr(X).
- {A = sqlite3PExpr(pParse,TK_LIMIT,X.pExpr,0);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,X,0);}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
- {A = sqlite3PExpr(pParse,TK_LIMIT,X.pExpr,Y.pExpr);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,X,Y);}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
- {A = sqlite3PExpr(pParse,TK_LIMIT,Y.pExpr,X.pExpr);}
+ {A = sqlite3PExpr(pParse,TK_LIMIT,Y,X);}
/////////////////////////// The DELETE statement /////////////////////////////
//
@@ -757,7 +775,7 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
-where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
+where_opt(A) ::= WHERE expr(X). {A = X;}
////////////////////////// The UPDATE command ////////////////////////////////
//
@@ -784,18 +802,18 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). {
- A = sqlite3ExprListAppend(pParse, A, Y.pExpr);
+ A = sqlite3ExprListAppend(pParse, A, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= setlist(A) COMMA LP idlist(X) RP EQ expr(Y). {
- A = sqlite3ExprListAppendVector(pParse, A, X, Y.pExpr);
+ A = sqlite3ExprListAppendVector(pParse, A, X, Y);
}
setlist(A) ::= nm(X) EQ expr(Y). {
- A = sqlite3ExprListAppend(pParse, 0, Y.pExpr);
+ A = sqlite3ExprListAppend(pParse, 0, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= LP idlist(X) RP EQ expr(Y). {
- A = sqlite3ExprListAppendVector(pParse, 0, X, Y.pExpr);
+ A = sqlite3ExprListAppendVector(pParse, 0, X, Y);
}
////////////////////////// The INSERT command /////////////////////////////////
@@ -829,26 +847,18 @@ idlist(A) ::= nm(Y).
/////////////////////////// Expression Processing /////////////////////////////
//
-%type expr {ExprSpan}
-%destructor expr {sqlite3ExprDelete(pParse->db, $$.pExpr);}
-%type term {ExprSpan}
-%destructor term {sqlite3ExprDelete(pParse->db, $$.pExpr);}
+%type expr {Expr*}
+%destructor expr {sqlite3ExprDelete(pParse->db, $$);}
+%type term {Expr*}
+%destructor term {sqlite3ExprDelete(pParse->db, $$);}
%include {
- /* This is a utility routine used to set the ExprSpan.zStart and
- ** ExprSpan.zEnd values of pOut so that the span covers the complete
- ** range of text beginning with pStart and going to the end of pEnd.
- */
- static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
- pOut->zStart = pStart->z;
- pOut->zEnd = &pEnd->z[pEnd->n];
- }
/* Construct a new Expr object from a single identifier. Use the
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
- static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
+ static Expr *tokenExpr(Parse *pParse, int op, Token t){
Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
if( p ){
memset(p, 0, sizeof(Expr));
@@ -866,136 +876,98 @@ idlist(A) ::= nm(Y).
p->nHeight = 1;
#endif
}
- pOut->pExpr = p;
- pOut->zStart = t.z;
- pOut->zEnd = &t.z[t.n];
+ return p;
}
}
expr(A) ::= term(A).
-expr(A) ::= LP(B) expr(X) RP(E).
- {spanSet(&A,&B,&E); /*A-overwrites-B*/ A.pExpr = X.pExpr;}
-expr(A) ::= id(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
-expr(A) ::= JOIN_KW(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
+expr(A) ::= LP expr(X) RP. {A = X;}
+expr(A) ::= id(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
+expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1);
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
- spanSet(&A,&X,&Z); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+ A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
-term(A) ::= NULL|FLOAT|BLOB(X). {spanExpr(&A,pParse,@X,X); /*A-overwrites-X*/}
-term(A) ::= STRING(X). {spanExpr(&A,pParse,@X,X); /*A-overwrites-X*/}
+term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
+term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/}
term(A) ::= INTEGER(X). {
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
- A.zStart = X.z;
- A.zEnd = X.z + X.n;
+ A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1);
}
expr(A) ::= VARIABLE(X). {
if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){
u32 n = X.n;
- spanExpr(&A, pParse, TK_VARIABLE, X);
- sqlite3ExprAssignVarNumber(pParse, A.pExpr, n);
+ A = tokenExpr(pParse, TK_VARIABLE, X);
+ sqlite3ExprAssignVarNumber(pParse, A, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
Token t = X; /*A-overwrites-X*/
assert( t.n>=2 );
- spanSet(&A, &t, &t);
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- A.pExpr = 0;
+ A = 0;
}else{
- A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
- if( A.pExpr ) sqlite3GetInt32(&t.z[1], &A.pExpr->iTable);
+ A = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( A ) sqlite3GetInt32(&t.z[1], &A->iTable);
}
}
}
expr(A) ::= expr(A) COLLATE ids(C). {
- A.pExpr = sqlite3ExprAddCollateToken(pParse, A.pExpr, &C, 1);
- A.zEnd = &C.z[C.n];
+ A = sqlite3ExprAddCollateToken(pParse, A, &C, 1);
}
%ifndef SQLITE_OMIT_CAST
-expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1);
- sqlite3ExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0);
+expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. {
+ A = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, A, E, 0);
}
%endif SQLITE_OMIT_CAST
-expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). {
+expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP. {
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
- A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
- spanSet(&A,&X,&E);
- if( D==SF_Distinct && A.pExpr ){
- A.pExpr->flags |= EP_Distinct;
+ A = sqlite3ExprFunction(pParse, Y, &X);
+ if( D==SF_Distinct && A ){
+ A->flags |= EP_Distinct;
}
}
-expr(A) ::= id(X) LP STAR RP(E). {
- A.pExpr = sqlite3ExprFunction(pParse, 0, &X);
- spanSet(&A,&X,&E);
+expr(A) ::= id(X) LP STAR RP. {
+ A = sqlite3ExprFunction(pParse, 0, &X);
}
term(A) ::= CTIME_KW(OP). {
- A.pExpr = sqlite3ExprFunction(pParse, 0, &OP);
- spanSet(&A, &OP, &OP);
+ A = sqlite3ExprFunction(pParse, 0, &OP);
}
-%include {
- /* This routine constructs a binary expression node out of two ExprSpan
- ** objects and uses the result to populate a new ExprSpan object.
- */
- static void spanBinaryExpr(
- Parse *pParse, /* The parsing context. Errors accumulate here */
- int op, /* The binary operation */
- ExprSpan *pLeft, /* The left operand, and output */
- ExprSpan *pRight /* The right operand */
- ){
- pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr);
- pLeft->zEnd = pRight->zEnd;
- }
-
- /* If doNot is true, then add a TK_NOT Expr-node wrapper around the
- ** outside of *ppExpr.
- */
- static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
- if( doNot ){
- pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0);
- }
- }
-}
-
-expr(A) ::= LP(L) nexprlist(X) COMMA expr(Y) RP(R). {
- ExprList *pList = sqlite3ExprListAppend(pParse, X, Y.pExpr);
- A.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = pList;
- spanSet(&A, &L, &R);
+expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. {
+ ExprList *pList = sqlite3ExprListAppend(pParse, X, Y);
+ A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( A ){
+ A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
}
-expr(A) ::= expr(A) AND(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) OR(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+expr(A) ::= expr(A) AND(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) OR(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) LT|GT|GE|LE(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) PLUS|MINUS(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
expr(A) ::= expr(A) STAR|SLASH|REM(OP) expr(Y).
- {spanBinaryExpr(pParse,@OP,&A,&Y);}
-expr(A) ::= expr(A) CONCAT(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
+ {A=sqlite3PExpr(pParse,@OP,A,Y);}
+expr(A) ::= expr(A) CONCAT(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);}
%type likeop {Token}
likeop(A) ::= LIKE_KW|MATCH(A).
likeop(A) ::= NOT LIKE_KW|MATCH(X). {A=X; A.n|=0x80000000; /*A-overwrite-X*/}
@@ -1003,42 +975,26 @@ expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] {
ExprList *pList;
int bNot = OP.n & 0x80000000;
OP.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
- A.pExpr = sqlite3ExprFunction(pParse, pList, &OP);
- exprNot(pParse, bNot, &A);
- A.zEnd = Y.zEnd;
- if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, Y);
+ pList = sqlite3ExprListAppend(pParse,pList, A);
+ A = sqlite3ExprFunction(pParse, pList, &OP);
+ if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
+ if( A ) A->flags |= EP_InfixFunc;
}
expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
ExprList *pList;
int bNot = OP.n & 0x80000000;
OP.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
- A.pExpr = sqlite3ExprFunction(pParse, pList, &OP);
- exprNot(pParse, bNot, &A);
- A.zEnd = E.zEnd;
- if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
-}
-
-%include {
- /* Construct an expression node for a unary postfix operator
- */
- static void spanUnaryPostfix(
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand, and output */
- Token *pPostOp /* The operand token for setting the span */
- ){
- pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
- pOperand->zEnd = &pPostOp->z[pPostOp->n];
- }
+ pList = sqlite3ExprListAppend(pParse,0, Y);
+ pList = sqlite3ExprListAppend(pParse,pList, A);
+ pList = sqlite3ExprListAppend(pParse,pList, E);
+ A = sqlite3ExprFunction(pParse, pList, &OP);
+ if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
+ if( A ) A->flags |= EP_InfixFunc;
}
-expr(A) ::= expr(A) ISNULL|NOTNULL(E). {spanUnaryPostfix(pParse,@E,&A,&E);}
-expr(A) ::= expr(A) NOT NULL(E). {spanUnaryPostfix(pParse,TK_NOTNULL,&A,&E);}
+expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);}
+expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);}
%include {
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
@@ -1060,61 +1016,42 @@ expr(A) ::= expr(A) NOT NULL(E). {spanUnaryPostfix(pParse,TK_NOTNULL,&A,&E);}
// is any other expression, code as TK_IS or TK_ISNOT.
//
expr(A) ::= expr(A) IS expr(Y). {
- spanBinaryExpr(pParse,TK_IS,&A,&Y);
- binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL);
+ A = sqlite3PExpr(pParse,TK_IS,A,Y);
+ binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL);
}
expr(A) ::= expr(A) IS NOT expr(Y). {
- spanBinaryExpr(pParse,TK_ISNOT,&A,&Y);
- binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
-}
-
-%include {
- /* Construct an expression node for a unary prefix operator
- */
- static void spanUnaryPrefix(
- ExprSpan *pOut, /* Write the new expression node here */
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand */
- Token *pPreOp /* The operand token for setting the span */
- ){
- pOut->zStart = pPreOp->z;
- pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
- pOut->zEnd = pOperand->zEnd;
- }
+ A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
+ binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL);
}
-
-
expr(A) ::= NOT(B) expr(X).
- {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
+ {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
expr(A) ::= BITNOT(B) expr(X).
- {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
-expr(A) ::= MINUS(B) expr(X). [BITNOT]
- {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);/*A-overwrites-B*/}
-expr(A) ::= PLUS(B) expr(X). [BITNOT]
- {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);/*A-overwrites-B*/}
+ {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/}
+expr(A) ::= MINUS expr(X). [BITNOT]
+ {A = sqlite3PExpr(pParse, TK_UMINUS, X, 0);}
+expr(A) ::= PLUS expr(X). [BITNOT]
+ {A = sqlite3PExpr(pParse, TK_UPLUS, X, 0);}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
- ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr);
- A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, A.pExpr, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, X);
+ pList = sqlite3ExprListAppend(pParse,pList, Y);
+ A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0);
+ if( A ){
+ A->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- exprNot(pParse, N, &A);
- A.zEnd = Y.zEnd;
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
%ifndef SQLITE_OMIT_SUBQUERY
%type in_op {int}
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
- expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] {
+ expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP. [IN] {
if( Y==0 ){
/* Expressions of the form
**
@@ -1124,8 +1061,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprDelete(pParse->db, A.pExpr);
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1);
+ sqlite3ExprDelete(pParse->db, A);
+ A = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1);
}else if( Y->nExpr==1 ){
/* Expressions of the form:
**
@@ -1152,54 +1089,48 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
- A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A.pExpr, pRHS);
+ A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS);
}else{
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = Y;
- sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ if( A ){
+ A->x.pList = Y;
+ sqlite3ExprSetHeightAndFlags(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
}
- exprNot(pParse, N, &A);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
- A.zEnd = &E.z[E.n];
}
- expr(A) ::= LP(B) select(X) RP(E). {
- spanSet(&A,&B,&E); /*A-overwrites-B*/
- A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, X);
+ expr(A) ::= LP select(X) RP. {
+ A = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, A, X);
}
- expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] {
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, Y);
- exprNot(pParse, N, &A);
- A.zEnd = &E.z[E.n];
+ expr(A) ::= expr(A) in_op(N) LP select(Y) RP. [IN] {
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ sqlite3PExprAddSelect(pParse, A, Y);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E);
- A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0);
- sqlite3PExprAddSelect(pParse, A.pExpr, pSelect);
- exprNot(pParse, N, &A);
- A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
+ A = sqlite3PExpr(pParse, TK_IN, A, 0);
+ sqlite3PExprAddSelect(pParse, A, pSelect);
+ if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0);
}
- expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
+ expr(A) ::= EXISTS LP select(Y) RP. {
Expr *p;
- spanSet(&A,&B,&E); /*A-overwrites-B*/
- p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
sqlite3PExprAddSelect(pParse, p, Y);
}
%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
-expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
- spanSet(&A,&C,&E); /*A-overwrites-C*/
- A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0);
- if( A.pExpr ){
- A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
- sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
+expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. {
+ A = sqlite3PExpr(pParse, TK_CASE, X, 0);
+ if( A ){
+ A->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
+ sqlite3ExprSetHeightAndFlags(pParse, A);
}else{
sqlite3ExprListDelete(pParse->db, Y);
sqlite3ExprDelete(pParse->db, Z);
@@ -1208,20 +1139,20 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(A) WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,A, Y.pExpr);
- A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
+ A = sqlite3ExprListAppend(pParse,A, Y);
+ A = sqlite3ExprListAppend(pParse,A, Z);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
- A = sqlite3ExprListAppend(pParse,0, Y.pExpr);
- A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
+ A = sqlite3ExprListAppend(pParse,0, Y);
+ A = sqlite3ExprListAppend(pParse,A, Z);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete(pParse->db, $$);}
-case_else(A) ::= ELSE expr(X). {A = X.pExpr;}
+case_else(A) ::= ELSE expr(X). {A = X;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
-case_operand(A) ::= expr(X). {A = X.pExpr; /*A-overwrites-X*/}
+case_operand(A) ::= expr(X). {A = X; /*A-overwrites-X*/}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
@@ -1232,9 +1163,9 @@ case_operand(A) ::= . {A = 0;}
exprlist(A) ::= nexprlist(A).
exprlist(A) ::= . {A = 0;}
nexprlist(A) ::= nexprlist(A) COMMA expr(Y).
- {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);}
+ {A = sqlite3ExprListAppend(pParse,A,Y);}
nexprlist(A) ::= expr(Y).
- {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/}
+ {A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/}
%ifndef SQLITE_OMIT_SUBQUERY
/* A paren_exprlist is an optional expression list contained inside
@@ -1388,7 +1319,7 @@ foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete(pParse->db, $$);}
when_clause(A) ::= . { A = 0; }
-when_clause(A) ::= WHEN expr(X). { A = X.pExpr; }
+when_clause(A) ::= WHEN expr(X). { A = X; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
@@ -1437,34 +1368,33 @@ tridxby ::= NOT INDEXED. {
%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);}
// UPDATE
trigger_cmd(A) ::=
- UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z).
- {A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R);}
+ UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E).
+ {A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R, B.z, E);}
// INSERT
-trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S).
- {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);/*A-overwrites-R*/}
+trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO
+ trnm(X) idlist_opt(F) select(S) scanpt(Z).
+ {A = sqlite3TriggerInsertStep(pParse->db,&X,F,S,R,B,Z);/*A-overwrites-R*/}
// DELETE
-trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
- {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
+trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E).
+ {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y, B.z, E);}
// SELECT
-trigger_cmd(A) ::= select(X).
- {A = sqlite3TriggerSelectStep(pParse->db, X); /*A-overwrites-X*/}
+trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E).
+ {A = sqlite3TriggerSelectStep(pParse->db, X, B, E); /*A-overwrites-X*/}
// The special RAISE expression that may occur in trigger programs
-expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
- if( A.pExpr ){
- A.pExpr->affinity = OE_Ignore;
+expr(A) ::= RAISE LP IGNORE RP. {
+ A = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( A ){
+ A->affinity = OE_Ignore;
}
}
-expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
- spanSet(&A,&X,&Y); /*A-overwrites-X*/
- A.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
- if( A.pExpr ) {
- A.pExpr->affinity = (char)T;
+expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. {
+ A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
+ if( A ) {
+ A->affinity = (char)T;
}
}
%endif !SQLITE_OMIT_TRIGGER
@@ -1485,16 +1415,16 @@ cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
%ifndef SQLITE_OMIT_ATTACH
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
- sqlite3Attach(pParse, F.pExpr, D.pExpr, K);
+ sqlite3Attach(pParse, F, D, K);
}
cmd ::= DETACH database_kw_opt expr(D). {
- sqlite3Detach(pParse, D.pExpr);
+ sqlite3Detach(pParse, D);
}
%type key_opt {Expr*}
%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
key_opt(A) ::= . { A = 0; }
-key_opt(A) ::= KEY expr(X). { A = X.pExpr; }
+key_opt(A) ::= KEY expr(X). { A = X; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
diff --git a/src/select.c b/src/select.c
index 97eaf21b4..1a4b0a93a 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1381,8 +1381,9 @@ static const char *columnTypeImpl(
assert( pExpr!=0 );
assert( pNC->pSrcList!=0 );
+ assert( pExpr->op!=TK_AGG_COLUMN ); /* This routine runes before aggregates
+ ** are processed */
switch( pExpr->op ){
- case TK_AGG_COLUMN:
case TK_COLUMN: {
/* The expression is a column. Locate the table the column is being
** extracted from in NameContext.pSrcList. This table may be real
@@ -1391,8 +1392,6 @@ static const char *columnTypeImpl(
Table *pTab = 0; /* Table structure column is extracted from */
Select *pS = 0; /* Select the column is extracted from */
int iCol = pExpr->iColumn; /* Index of column in pTab */
- testcase( pExpr->op==TK_AGG_COLUMN );
- testcase( pExpr->op==TK_COLUMN );
while( pNC && !pTab ){
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
@@ -1596,6 +1595,7 @@ static void generateColumnNames(
if( pParse->colNamesSet || db->mallocFailed ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
+ SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
pTabList = pSelect->pSrc;
pEList = pSelect->pEList;
assert( v!=0 );
@@ -1704,12 +1704,12 @@ int sqlite3ColumnsFromExprList(
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
- if( (pColExpr->op==TK_COLUMN || pColExpr->op==TK_AGG_COLUMN)
- && pColExpr->pTab!=0
- ){
+ assert( pColExpr->op!=TK_AGG_COLUMN );
+ if( pColExpr->op==TK_COLUMN ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
Table *pTab = pColExpr->pTab;
+ assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
}else if( pColExpr->op==TK_ID ){
diff --git a/src/shell.c.in b/src/shell.c.in
index 062f76e47..155ca708a 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -796,6 +796,8 @@ static void shellAddSchemaName(
INCLUDE ../ext/misc/shathree.c
INCLUDE ../ext/misc/fileio.c
INCLUDE ../ext/misc/completion.c
+INCLUDE ../ext/expert/sqlite3expert.h
+INCLUDE ../ext/expert/sqlite3expert.c
#if defined(SQLITE_ENABLE_SESSION)
/*
@@ -822,6 +824,12 @@ struct SavedModeInfo {
int colWidth[100]; /* Column widths prior to ".explain on" */
};
+typedef struct ExpertInfo ExpertInfo;
+struct ExpertInfo {
+ sqlite3expert *pExpert;
+ int bVerbose;
+};
+
/*
** State information about the database connection is contained in an
** instance of the following structure.
@@ -866,8 +874,16 @@ struct ShellState {
int nSession; /* Number of active sessions */
OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
#endif
+ ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
};
+/* Allowed values for ShellState.autoEQP
+*/
+#define AUTOEQP_off 0
+#define AUTOEQP_on 1
+#define AUTOEQP_trigger 2
+#define AUTOEQP_full 3
+
/*
** These are the allowed shellFlgs values
*/
@@ -2250,6 +2266,79 @@ static void exec_prepared_stmt(
}
/*
+** This function is called to process SQL if the previous shell command
+** was ".expert". It passes the SQL in the second argument directly to
+** the sqlite3expert object.
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
+** code. In this case, (*pzErr) may be set to point to a buffer containing
+** an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using sqlite3_free().
+*/
+static int expertHandleSQL(
+ ShellState *pState,
+ const char *zSql,
+ char **pzErr
+){
+ assert( pState->expert.pExpert );
+ assert( pzErr==0 || *pzErr==0 );
+ return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
+}
+
+/*
+** This function is called either to silently clean up the object
+** created by the ".expert" command (if bCancel==1), or to generate a
+** report from it and then clean it up (if bCancel==0).
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
+** code. In this case, (*pzErr) may be set to point to a buffer containing
+** an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using sqlite3_free().
+*/
+static int expertFinish(
+ ShellState *pState,
+ int bCancel,
+ char **pzErr
+){
+ int rc = SQLITE_OK;
+ sqlite3expert *p = pState->expert.pExpert;
+ assert( p );
+ assert( bCancel || pzErr==0 || *pzErr==0 );
+ if( bCancel==0 ){
+ FILE *out = pState->out;
+ int bVerbose = pState->expert.bVerbose;
+
+ rc = sqlite3_expert_analyze(p, pzErr);
+ if( rc==SQLITE_OK ){
+ int nQuery = sqlite3_expert_count(p);
+ int i;
+
+ if( bVerbose ){
+ const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
+ raw_printf(out, "-- Candidates -----------------------------\n");
+ raw_printf(out, "%s\n", zCand);
+ }
+ for(i=0; i<nQuery; i++){
+ const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
+ const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
+ const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
+ if( zIdx==0 ) zIdx = "(no new indexes)\n";
+ if( bVerbose ){
+ raw_printf(out, "-- Query %d --------------------------------\n",i+1);
+ raw_printf(out, "%s\n\n", zSql);
+ }
+ raw_printf(out, "%s\n", zIdx);
+ raw_printf(out, "%s\n", zEQP);
+ }
+ }
+ }
+ sqlite3_expert_destroy(p);
+ pState->expert.pExpert = 0;
+ return rc;
+}
+
+
+/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
@@ -2275,6 +2364,11 @@ static int shell_exec(
*pzErrMsg = NULL;
}
+ if( pArg->expert.pExpert ){
+ rc = expertHandleSQL(pArg, zSql, pzErrMsg);
+ return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
+ }
+
while( zSql[0] && (SQLITE_OK == rc) ){
static const char *zStmtSql;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
@@ -2308,7 +2402,12 @@ static int shell_exec(
if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
sqlite3_stmt *pExplain;
char *zEQP;
+ int triggerEQP = 0;
disable_debug_trace_modes();
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
+ if( pArg->autoEQP>=AUTOEQP_trigger ){
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
+ }
zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
@@ -2321,7 +2420,7 @@ static int shell_exec(
}
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
- if( pArg->autoEQP>=2 ){
+ if( pArg->autoEQP>=AUTOEQP_full ){
/* Also do an EXPLAIN for ".eqp full" mode */
zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
@@ -2334,6 +2433,7 @@ static int shell_exec(
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
}
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, triggerEQP, 0);
restore_debug_trace_modes();
}
@@ -2692,6 +2792,7 @@ static char zHelp[] =
".echo on|off Turn command echo on or off\n"
".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
".exit Exit this program\n"
+ ".expert EXPERIMENTAL. Suggest indexes for specified queries\n"
/* Because explain mode comes on automatically now, the ".explain" mode
** is removed from the help screen. It is still supported for legacy, however */
/*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/
@@ -4068,6 +4169,64 @@ static int lintDotCommand(
return SQLITE_ERROR;
}
+/*
+** Implementation of ".expert" dot command.
+*/
+static int expertDotCommand(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+ int i;
+ int iSample = 0;
+
+ assert( pState->expert.pExpert==0 );
+ memset(&pState->expert, 0, sizeof(ExpertInfo));
+
+ for(i=1; rc==SQLITE_OK && i<nArg; i++){
+ char *z = azArg[i];
+ int n;
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ n = strlen(z);
+ if( n>=2 && 0==strncmp(z, "-verbose", n) ){
+ pState->expert.bVerbose = 1;
+ }
+ else if( n>=2 && 0==strncmp(z, "-sample", n) ){
+ if( i==(nArg-1) ){
+ raw_printf(stderr, "option requires an argument: %s\n", z);
+ rc = SQLITE_ERROR;
+ }else{
+ iSample = (int)integerValue(azArg[++i]);
+ if( iSample<0 || iSample>100 ){
+ raw_printf(stderr, "value out of range: %s\n", azArg[i]);
+ rc = SQLITE_ERROR;
+ }
+ }
+ }
+ else{
+ raw_printf(stderr, "unknown option: %s\n", z);
+ rc = SQLITE_ERROR;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
+ if( pState->expert.pExpert==0 ){
+ raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
+ rc = SQLITE_ERROR;
+ }else{
+ sqlite3_expert_config(
+ pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
+ );
+ }
+ }
+
+ return rc;
+}
+
+
/*
** If an input line begins with "." then invoke this routine to
@@ -4082,6 +4241,10 @@ static int do_meta_command(char *zLine, ShellState *p){
int rc = 0;
char *azArg[50];
+ if( p->expert.pExpert ){
+ expertFinish(p, 1, 0);
+ }
+
/* Parse the input line into tokens.
*/
while( zLine[h] && nArg<ArraySize(azArg) ){
@@ -4397,12 +4560,14 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
if( strcmp(azArg[1],"full")==0 ){
- p->autoEQP = 2;
+ p->autoEQP = AUTOEQP_full;
+ }else if( strcmp(azArg[1],"trigger")==0 ){
+ p->autoEQP = AUTOEQP_trigger;
}else{
p->autoEQP = booleanValue(azArg[1]);
}
}else{
- raw_printf(stderr, "Usage: .eqp on|off|full\n");
+ raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n");
rc = 1;
}
}else
@@ -4436,6 +4601,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
+ open_db(p, 0);
+ expertDotCommand(p, azArg, nArg);
+ }else
+
if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
ShellState data;
char *zErrMsg = 0;
@@ -5750,7 +5920,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
- static const char *azBool[] = { "off", "on", "full", "unk" };
+ static const char *azBool[] = { "off", "on", "trigger", "full"};
int i;
if( nArg!=1 ){
raw_printf(stderr, "Usage: .show\n");
@@ -5938,6 +6108,9 @@ static int do_meta_command(char *zLine, ShellState *p){
{ "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
+#ifdef YYCOVERAGE
+ { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" },
+#endif
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET, "" },
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
@@ -6063,6 +6236,14 @@ static int do_meta_command(char *zLine, ShellState *p){
isOk = 3;
}
break;
+
+#ifdef YYCOVERAGE
+ case SQLITE_TESTCTRL_PARSER_COVERAGE:
+ if( nArg==2 ){
+ sqlite3_test_control(testctrl, p->out);
+ isOk = 3;
+ }
+#endif
}
}
if( isOk==0 && iCtrl>=0 ){
@@ -6902,9 +7083,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( strcmp(z,"-echo")==0 ){
ShellSetFlag(&data, SHFLG_Echo);
}else if( strcmp(z,"-eqp")==0 ){
- data.autoEQP = 1;
+ data.autoEQP = AUTOEQP_on;
}else if( strcmp(z,"-eqpfull")==0 ){
- data.autoEQP = 2;
+ data.autoEQP = AUTOEQP_full;
}else if( strcmp(z,"-stats")==0 ){
data.statsOn = 1;
}else if( strcmp(z,"-scanstats")==0 ){
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f4d44b52f..7e5fccdae 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2070,7 +2070,7 @@ struct sqlite3_mem_methods {
** the QPSG active, SQLite will always use the same query plan in the field as
** was used during testing in the lab.
** </dd>
-** <dt>SQLITE_DBCONFIG_FULL_EQP</dt>
+** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
** include output for any operations performed by trigger programs. This
** option is used to set or clear (the default) a flag that governs this
@@ -2090,7 +2090,8 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */
-#define SQLITE_DBCONFIG_FULL_EQP 1008 /* int int* */
+#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1008 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -7041,7 +7042,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
-#define SQLITE_TESTCTRL_LAST 25
+#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
+#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
/*
** CAPI3REF: SQLite Runtime Status
@@ -8301,15 +8303,14 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** This function may only be called from within a call to the [xBestIndex]
** method of a [virtual table implementation].
**
-** The first argument must be the database handle with which the virtual
-** table is associated (the one passed to the [xConnect] or [xCreate] method
-** to create the sqlite3_vtab object. The second argument must be an index
-** into the aConstraint[] array belonging to the sqlite3_index_info structure
-** passed to xBestIndex. This function returns a pointer to a buffer
+** The first argument must be the sqlite3_index_info object that is the
+** first parameter to the xBestIndex() method. The second argument must be
+** an index into the aConstraint[] array belonging to the sqlite3_index_info
+** structure passed to xBestIndex. This function returns a pointer to a buffer
** containing the name of the collation sequence for the corresponding
** constraint.
*/
-SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3*, int);
+SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
/*
** CAPI3REF: Conflict resolution modes
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index f85682a39..24a36e2c5 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1063,7 +1063,6 @@ typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
-typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
@@ -1356,7 +1355,6 @@ struct sqlite3 {
u8 mTrace; /* zero or more SQLITE_TRACE flags */
u8 skipBtreeMutex; /* True if no shared-cache backends */
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
- u8 bFullEQP; /* Include triggers in EQP output */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -1421,8 +1419,7 @@ struct sqlite3 {
Hash aModule; /* populated by sqlite3_create_module() */
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
- VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
- void *pBestIndexCtx; /* For sqlite3_vtab_collation() */
+ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
@@ -1497,7 +1494,9 @@ struct sqlite3 {
#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */
#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */
#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */
-#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee */
+#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/
+#define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */
+
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */
@@ -2506,17 +2505,6 @@ struct ExprList {
};
/*
-** An instance of this structure is used by the parser to record both
-** the parse tree for an expression and the span of input text for an
-** expression.
-*/
-struct ExprSpan {
- Expr *pExpr; /* The expression parse tree */
- const char *zStart; /* First character of input text */
- const char *zEnd; /* One character past the end of input text */
-};
-
-/*
** An instance of this structure can hold a simple list of identifiers,
** such as the list "a,b,c" in the following statements:
**
@@ -3216,6 +3204,7 @@ struct TriggerStep {
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
ExprList *pExprList; /* SET clause for UPDATE. */
IdList *pIdList; /* Column names for INSERT */
+ char *zSpan; /* Original SQL text of this command */
TriggerStep *pNext; /* Next in the link-list */
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
@@ -3526,6 +3515,7 @@ void *sqlite3DbMallocRaw(sqlite3*, u64);
void *sqlite3DbMallocRawNN(sqlite3*, u64);
char *sqlite3DbStrDup(sqlite3*,const char*);
char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
+char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
void *sqlite3Realloc(void*, u64);
void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
void *sqlite3DbRealloc(sqlite3 *, void *, u64);
@@ -3664,7 +3654,7 @@ ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
void sqlite3ExprListSetSortOrder(ExprList*,int);
void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
-void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
+void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
void sqlite3ExprListDelete(sqlite3*, ExprList*);
u32 sqlite3ExprListFlags(const ExprList*);
int sqlite3Init(sqlite3*, char**);
@@ -3694,7 +3684,7 @@ void sqlite3AddColumn(Parse*,Token*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
-void sqlite3AddDefaultValue(Parse*,ExprSpan*);
+void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
int sqlite3ParseUri(const char*,const char*,unsigned int*,
@@ -3915,11 +3905,14 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
- TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
+ TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
+ const char*,const char*);
TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
- Select*,u8);
- TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
- TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
+ Select*,u8,const char*,const char*);
+ TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
+ const char*,const char*);
+ TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
+ const char*,const char*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
@@ -4349,6 +4342,9 @@ void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_DEBUG
void sqlite3ParserTrace(FILE*, char *);
#endif
+#if defined(YYCOVERAGE)
+ int sqlite3ParserCoverage(FILE*);
+#endif
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
diff --git a/src/treeview.c b/src/treeview.c
index 8d171a473..6dd386ffe 100644
--- a/src/treeview.c
+++ b/src/treeview.c
@@ -507,12 +507,20 @@ void sqlite3TreeViewBareExprList(
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
- if( j ){
+ char *zName = pList->a[i].zName;
+ if( j || zName ){
sqlite3TreeViewPush(pView, 0);
+ }
+ if( zName ){
+ sqlite3TreeViewLine(pView, "AS %s", zName);
+ }
+ if( j ){
sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
}
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
- if( j ) sqlite3TreeViewPop(pView);
+ if( j || zName ){
+ sqlite3TreeViewPop(pView);
+ }
}
}
}
diff --git a/src/trigger.c b/src/trigger.c
index d8aac2cc2..9f7bff505 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -25,6 +25,7 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
+ sqlite3DbFree(db, pTmp->zSpan);
sqlite3DbFree(db, pTmp);
}
@@ -340,13 +341,29 @@ triggerfinish_cleanup:
}
/*
+** Duplicate a range of text from an SQL statement, then convert all
+** whitespace characters into ordinary space characters.
+*/
+static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ char *z = sqlite3DbSpanDup(db, zStart, zEnd);
+ int i;
+ if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
+ return z;
+}
+
+/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
**
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
-TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
+TriggerStep *sqlite3TriggerSelectStep(
+ sqlite3 *db, /* Database connection */
+ Select *pSelect, /* The SELECT statement */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
+){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(db, pSelect);
@@ -355,6 +372,7 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
return pTriggerStep;
}
@@ -367,7 +385,9 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
static TriggerStep *triggerStepAllocate(
sqlite3 *db, /* Database connection */
u8 op, /* Trigger opcode */
- Token *pName /* The target name */
+ Token *pName, /* The target name */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
@@ -378,6 +398,7 @@ static TriggerStep *triggerStepAllocate(
sqlite3Dequote(z);
pTriggerStep->zTarget = z;
pTriggerStep->op = op;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
}
return pTriggerStep;
}
@@ -394,13 +415,15 @@ TriggerStep *sqlite3TriggerInsertStep(
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
Select *pSelect, /* A SELECT statement that supplies values */
- u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
assert(pSelect != 0 || db->mallocFailed);
- pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
pTriggerStep->pIdList = pColumn;
@@ -423,11 +446,13 @@ TriggerStep *sqlite3TriggerUpdateStep(
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
- u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
@@ -446,11 +471,13 @@ TriggerStep *sqlite3TriggerUpdateStep(
TriggerStep *sqlite3TriggerDeleteStep(
sqlite3 *db, /* Database connection */
Token *pTableName, /* The table from which rows are deleted */
- Expr *pWhere /* The WHERE clause */
+ Expr *pWhere, /* The WHERE clause */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
+ pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
if( pTriggerStep ){
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pTriggerStep->orconf = OE_Default;
@@ -705,6 +732,14 @@ static int codeTriggerProgram(
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
assert( pParse->okConstFactor==0 );
+#ifndef SQLITE_OMIT_TRACE
+ if( pStep->zSpan ){
+ sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
+ sqlite3MPrintf(db, "-- %s", pStep->zSpan),
+ P4_DYNAMIC);
+ }
+#endif
+
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
@@ -845,9 +880,11 @@ static TriggerPrg *codeRowTrigger(
pTab->zName
));
#ifndef SQLITE_OMIT_TRACE
- sqlite3VdbeChangeP4(v, -1,
- sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
- );
+ if( pTrigger->zName ){
+ sqlite3VdbeChangeP4(v, -1,
+ sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
+ );
+ }
#endif
/* If one was specified, code the WHEN clause. If it evaluates to false
diff --git a/src/util.c b/src/util.c
index a4dbe8fda..75de4b3b3 100644
--- a/src/util.c
+++ b/src/util.c
@@ -321,6 +321,24 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
}
/*
+** Compute 10 to the E-th power. Examples: E==1 results in 10.
+** E==2 results in 100. E==50 results in 1.0e50.
+**
+** This routine only works for values of E between 1 and 341.
+*/
+static LONGDOUBLE_TYPE sqlite3Pow10(int E){
+ LONGDOUBLE_TYPE x = 10.0;
+ LONGDOUBLE_TYPE r = 1.0;
+ while(1){
+ if( E & 1 ) r *= x;
+ E >>= 1;
+ if( E==0 ) break;
+ x *= x;
+ }
+ return r;
+}
+
+/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
**
@@ -475,11 +493,10 @@ do_atof_calc:
if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
result = (double)s;
}else{
- LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
if( esign<0 ){
result = s / scale;
result /= 1.0e+308;
@@ -499,10 +516,7 @@ do_atof_calc:
}
}
}else{
- /* 1.0e+22 is the largest power of 10 than can be
- ** represented exactly. */
- while( e%22 ) { scale *= 1.0e+1; e -= 1; }
- while( e>0 ) { scale *= 1.0e+22; e -= 22; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
if( esign<0 ){
result = s / scale;
}else{
diff --git a/src/vdbe.c b/src/vdbe.c
index 74cf82c4c..975a09819 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -7036,7 +7036,13 @@ case OP_Function: {
break;
}
-
+/* Opcode: Trace P1 P2 * P4 *
+**
+** Write P4 on the statement trace output if statement tracing is
+** enabled.
+**
+** Operand P1 must be 0x7fffffff and P2 must positive.
+*/
/* Opcode: Init P1 P2 P3 P4 *
** Synopsis: Start at P2
**
@@ -7055,6 +7061,7 @@ case OP_Function: {
** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
** error is encountered.
*/
+case OP_Trace:
case OP_Init: { /* jump */
char *zTrace;
int i;
@@ -7069,7 +7076,9 @@ case OP_Init: { /* jump */
** sqlite3_expanded_sql(P) otherwise.
*/
assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
- assert( pOp==p->aOp ); /* Always instruction 0 */
+
+ /* OP_Init is always instruction 0 */
+ assert( pOp==p->aOp || pOp->opcode==OP_Trace );
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
@@ -7112,6 +7121,7 @@ case OP_Init: { /* jump */
#endif /* SQLITE_OMIT_TRACE */
assert( pOp->p2>0 );
if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
+ if( pOp->opcode==OP_Trace ) break;
for(i=1; i<p->nOp; i++){
if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
}
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 1c354e0be..bc4bbda8e 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1639,7 +1639,7 @@ int sqlite3VdbeList(
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
- int bFull = (p->explain==1 || db->bFullEQP);
+ int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
Op *pOp = 0;
assert( p->explain );
@@ -1668,7 +1668,7 @@ int sqlite3VdbeList(
** encountered, but p->pc will eventually catch up to nRow.
*/
nRow = p->nOp;
- if( bFull ){
+ if( bListSubprogs ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
** to trigger subprograms. The VDBE is guaranteed to have at least 9
@@ -1713,7 +1713,7 @@ int sqlite3VdbeList(
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
** has not already been seen.
*/
- if( bFull && pOp->p4type==P4_SUBPROGRAM ){
+ if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
int nByte = (nSub+1)*sizeof(SubProgram*);
int j;
for(j=0; j<nSub; j++){
diff --git a/src/where.c b/src/where.c
index 0694031a5..d3aec354b 100644
--- a/src/where.c
+++ b/src/where.c
@@ -19,6 +19,21 @@
#include "sqliteInt.h"
#include "whereInt.h"
+/*
+** Extra information appended to the end of sqlite3_index_info but not
+** visible to the xBestIndex function, at least not directly. The
+** sqlite3_vtab_collation() interface knows how to reach it, however.
+**
+** This object is not an API and can be changed from one release to the
+** next. As long as allocateIndexInfo() and sqlite3_vtab_collation()
+** agree on the structure, all will be well.
+*/
+typedef struct HiddenIndexInfo HiddenIndexInfo;
+struct HiddenIndexInfo {
+ WhereClause *pWC; /* The Where clause being analyzed */
+ Parse *pParse; /* The parsing context */
+};
+
/* Forward declaration of methods */
static int whereLoopResize(sqlite3*, WhereLoop*, int);
@@ -841,11 +856,11 @@ end_auto_index_create:
** by passing the pointer returned by this function to sqlite3_free().
*/
static sqlite3_index_info *allocateIndexInfo(
- Parse *pParse,
- WhereClause *pWC,
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause being analyzed */
Bitmask mUnusable, /* Ignore terms with these prereqs */
- struct SrcList_item *pSrc,
- ExprList *pOrderBy,
+ struct SrcList_item *pSrc, /* The FROM clause term that is the vtab */
+ ExprList *pOrderBy, /* The ORDER BY clause */
u16 *pmNoOmit /* Mask of terms not to omit */
){
int i, j;
@@ -853,6 +868,7 @@ static sqlite3_index_info *allocateIndexInfo(
struct sqlite3_index_constraint *pIdxCons;
struct sqlite3_index_orderby *pIdxOrderBy;
struct sqlite3_index_constraint_usage *pUsage;
+ struct HiddenIndexInfo *pHidden;
WhereTerm *pTerm;
int nOrderBy;
sqlite3_index_info *pIdxInfo;
@@ -894,7 +910,7 @@ static sqlite3_index_info *allocateIndexInfo(
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
- + sizeof(*pIdxOrderBy)*nOrderBy );
+ + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
@@ -905,7 +921,8 @@ static sqlite3_index_info *allocateIndexInfo(
** changing them. We have to do some funky casting in order to
** initialize those fields.
*/
- pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
+ pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
+ pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
*(int*)&pIdxInfo->nConstraint = nTerm;
@@ -915,6 +932,8 @@ static sqlite3_index_info *allocateIndexInfo(
*(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
pUsage;
+ pHidden->pWC = pWC;
+ pHidden->pParse = pParse;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
u16 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
@@ -3138,17 +3157,6 @@ static int whereLoopAddVirtualOne(
return rc;
}
-
-/*
-** Context object used to pass information from whereLoopAddVirtual()
-** to sqlite3_vtab_collation().
-*/
-struct BestIndexCtx {
- WhereClause *pWC;
- sqlite3_index_info *pIdxInfo;
- Parse *pParse;
-};
-
/*
** If this function is invoked from within an xBestIndex() callback, it
** returns a pointer to a buffer containing the name of the collation
@@ -3156,13 +3164,16 @@ struct BestIndexCtx {
** array. Or, if iCons is out of range or there is no active xBestIndex
** call, return NULL.
*/
-const char *sqlite3_vtab_collation(sqlite3 *db, int iCons){
- struct BestIndexCtx *p = (struct BestIndexCtx*)db->pBestIndexCtx;
+const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
const char *zRet = 0;
- if( p && iCons>=0 && iCons<p->pIdxInfo->nConstraint ){
- int iTerm = p->pIdxInfo->aConstraint[iCons].iTermOffset;
- Expr *pX = p->pWC->a[iTerm].pExpr;
- CollSeq *pC = sqlite3BinaryCompareCollSeq(p->pParse,pX->pLeft,pX->pRight);
+ if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
+ CollSeq *pC = 0;
+ int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
+ Expr *pX = pHidden->pWC->a[iTerm].pExpr;
+ if( pX->pLeft ){
+ pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
+ }
zRet = (pC ? pC->zName : "BINARY");
}
return zRet;
@@ -3209,8 +3220,6 @@ static int whereLoopAddVirtual(
WhereLoop *pNew;
Bitmask mBest; /* Tables used by best possible plan */
u16 mNoOmit;
- struct BestIndexCtx bic;
- void *pSaved;
assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo;
@@ -3232,12 +3241,6 @@ static int whereLoopAddVirtual(
return SQLITE_NOMEM_BKPT;
}
- bic.pWC = pWC;
- bic.pIdxInfo = p;
- bic.pParse = pParse;
- pSaved = pParse->db->pBestIndexCtx;
- pParse->db->pBestIndexCtx = (void*)&bic;
-
/* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
@@ -3314,7 +3317,6 @@ static int whereLoopAddVirtual(
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
sqlite3DbFreeNN(pParse->db, p);
- pParse->db->pBestIndexCtx = pSaved;
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/src/wherecode.c b/src/wherecode.c
index 3c166a121..32dd2048b 100644
--- a/src/wherecode.c
+++ b/src/wherecode.c
@@ -128,7 +128,7 @@ int sqlite3WhereExplainOneScan(
){
int ret = 0;
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( pParse->explain==2 )
+ if( sqlite3ParseToplevel(pParse)->explain==2 )
#endif
{
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];