Merge recent enhancements from trunk.
FossilOrigin-Name: 6251e438f2a76170fd1e95aa512a46086ed88ab93b9b97a1dba97c4558689305
This commit is contained in:
+16
-12
@@ -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);
|
||||
|
||||
+3
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -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
|
||||
|
||||
+17
-15
@@ -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 */
|
||||
|
||||
@@ -627,6 +627,19 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
||||
return zNew;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
|
||||
+177
-247
@@ -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 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 id(X). {
|
||||
ExprSpan v;
|
||||
spanExpr(&v, pParse, TK_STRING, X);
|
||||
sqlite3AddDefaultValue(pParse,&v);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
%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];
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
A = sqlite3PExpr(pParse,TK_ISNOT,A,Y);
|
||||
binaryToUnaryIfNull(pParse, Y, A, 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 ::= .
|
||||
|
||||
+6
-6
@@ -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 ){
|
||||
|
||||
+187
-6
@@ -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
|
||||
*/
|
||||
@@ -2249,6 +2265,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
|
||||
@@ -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 ){
|
||||
|
||||
+10
-9
@@ -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
|
||||
|
||||
+18
-22
@@ -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 */
|
||||
@@ -2505,17 +2504,6 @@ struct ExprList {
|
||||
} a[1]; /* One slot for each expression in the list */
|
||||
};
|
||||
|
||||
/*
|
||||
** 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
|
||||
|
||||
+10
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-11
@@ -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);
|
||||
}
|
||||
@@ -339,6 +340,17 @@ triggerfinish_cleanup:
|
||||
sqlite3DeleteTriggerStep(db, pStepList);
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
@@ -346,7 +358,12 @@ triggerfinish_cleanup:
|
||||
** 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
|
||||
|
||||
+20
-6
@@ -320,6 +320,24 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
|
||||
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
|
||||
}
|
||||
|
||||
/*
|
||||
** 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{
|
||||
|
||||
+12
-2
@@ -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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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++){
|
||||
|
||||
+34
-32
@@ -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 */
|
||||
|
||||
+1
-1
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user