aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2018-01-04 19:54:55 +0000
committerdrh <drh@noemail.net>2018-01-04 19:54:55 +0000
commitc76ed3d57dfbe7b1080f362a7a59ea6ee25e6bb2 (patch)
tree111c4a7f9be0604bb90f3fba54f2a71faded8a4b /src
parent0cde0c62b1e53c01d72a9a9227010e6afc4032dc (diff)
parent35100fb194cfbaf75b31b504e7bf7d4480900c26 (diff)
downloadsqlite-c76ed3d57dfbe7b1080f362a7a59ea6ee25e6bb2.tar.gz
sqlite-c76ed3d57dfbe7b1080f362a7a59ea6ee25e6bb2.zip
Merge in all recent trunk enhancements.
FossilOrigin-Name: 406f79183736b6ad360169b837172afef2c82a4312f5787db08c54167a44b15e
Diffstat (limited to 'src')
-rw-r--r--src/btree.c14
-rw-r--r--src/btree.h3
-rw-r--r--src/build.c21
-rw-r--r--src/expr.c25
-rw-r--r--src/func.c4
-rw-r--r--src/insert.c2
-rw-r--r--src/main.c16
-rw-r--r--src/malloc.c13
-rw-r--r--src/pager.c2
-rw-r--r--src/parse.y426
-rw-r--r--src/shell.c.in214
-rw-r--r--src/sqlite.h.in11
-rw-r--r--src/sqliteInt.h33
-rw-r--r--src/test_config.c6
-rw-r--r--src/trigger.c59
-rw-r--r--src/util.c26
-rw-r--r--src/vdbe.c44
-rw-r--r--src/where.c6
18 files changed, 557 insertions, 368 deletions
diff --git a/src/btree.c b/src/btree.c
index 0fa00a2e1..8cd5ee673 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -4432,6 +4432,20 @@ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
return pCur->info.nKey;
}
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/*
+** Return the offset into the database file for the start of the
+** payload to which the cursor is pointing.
+*/
+i64 sqlite3BtreeOffset(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ assert( pCur->eState==CURSOR_VALID );
+ getCellInfo(pCur);
+ return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
+ (i64)(pCur->info.pPayload - pCur->pPage->aData);
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
/*
** Return the number of bytes of payload for the entry that pCur is
** currently pointing to. For table btrees, this will be the amount
diff --git a/src/btree.h b/src/btree.h
index e2c271cdc..e8e114bd2 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -291,6 +291,9 @@ int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+i64 sqlite3BtreeOffset(BtCursor*);
+#endif
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
diff --git a/src/build.c b/src/build.c
index 01d897241..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,6 +1968,7 @@ void sqlite3EndTable(
pParse->nTab = 2;
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
+ if( pParse->nErr ) return;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
if( pSelTab==0 ) return;
assert( p->aCol==0 );
@@ -1975,6 +1979,7 @@ void sqlite3EndTable(
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);
diff --git a/src/expr.c b/src/expr.c
index 524e53934..32cc4423f 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);
}
}
@@ -3871,9 +3870,21 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
- constMask, r1, target, (char*)pDef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nFarg);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
+ Expr *pArg = pFarg->a[0].pExpr;
+ if( pArg->op==TK_COLUMN ){
+ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ }
+ }else
+#endif
+ {
+ sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0,
+ constMask, r1, target, (char*)pDef, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nFarg);
+ }
if( nFarg && constMask==0 ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
diff --git a/src/func.c b/src/func.c
index 7528fa8b4..1076b9716 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1799,6 +1799,10 @@ void sqlite3RegisterBuiltinFunctions(void){
#ifdef SQLITE_DEBUG
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
#endif
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
+ SQLITE_FUNC_TYPEOF),
+#endif
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
diff --git a/src/insert.c b/src/insert.c
index f0af0fbd1..e1514692c 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -1571,6 +1571,7 @@ void sqlite3GenerateConstraintChecks(
}
/* Check to see if the new index entry will be unique */
+ sqlite3ExprCachePush(pParse);
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
@@ -1659,6 +1660,7 @@ void sqlite3GenerateConstraintChecks(
}
}
sqlite3VdbeResolveLabel(v, addrUniqueOk);
+ sqlite3ExprCachePop(pParse);
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
if( ipkTop ){
diff --git a/src/main.c b/src/main.c
index 32ce1889f..3c8035c12 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3911,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/pager.c b/src/pager.c
index dbb7636ca..295cbe04c 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -5579,7 +5579,7 @@ static int getPageMMap(
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
- }else{
+ }else{
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
}
if( pPg ){
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/shell.c.in b/src/shell.c.in
index f7edb53f0..6f1c92e00 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -730,6 +730,71 @@ static char quoteChar(const char *zName){
}
/*
+** Construct a fake object name and column list to describe the structure
+** of the view, virtual table, or table valued function zSchema.zName.
+*/
+static char *shellFakeSchema(
+ sqlite3 *db, /* The database connection containing the vtab */
+ const char *zSchema, /* Schema of the database holding the vtab */
+ const char *zName /* The name of the virtual table */
+){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ ShellText s;
+ char cQuote;
+ char *zDiv = "(";
+ int nRow = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
+ zSchema ? zSchema : "main", zName);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ initText(&s);
+ if( zSchema ){
+ cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
+ appendText(&s, zSchema, cQuote);
+ appendText(&s, ".", 0);
+ }
+ cQuote = quoteChar(zName);
+ appendText(&s, zName, cQuote);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
+ nRow++;
+ appendText(&s, zDiv, 0);
+ zDiv = ",";
+ cQuote = quoteChar(zCol);
+ appendText(&s, zCol, cQuote);
+ }
+ appendText(&s, ")", 0);
+ sqlite3_finalize(pStmt);
+ if( nRow==0 ){
+ freeText(&s);
+ s.z = 0;
+ }
+ return s.z;
+}
+
+/*
+** SQL function: shell_module_schema(X)
+**
+** Return a fake schema for the table-valued function or eponymous virtual
+** table X.
+*/
+static void shellModuleSchema(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ const char *zName = (const char*)sqlite3_value_text(apVal[0]);
+ char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
+ if( zFake ){
+ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %z */", zFake),
+ -1, sqlite3_free);
+ }
+}
+
+/*
** SQL function: shell_add_schema(S,X)
**
** Add the schema name X to the CREATE statement in S and return the result.
@@ -764,20 +829,36 @@ static void shellAddSchemaName(
int i = 0;
const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
- assert( nVal==2 );
+ const char *zName = (const char*)sqlite3_value_text(apVal[2]);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
int n = strlen30(aPrefix[i]);
if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
- char cQuote = quoteChar(zSchema);
- char *z;
- if( cQuote ){
- z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
- }else{
- z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ char *z = 0;
+ char *zFake = 0;
+ if( zSchema ){
+ char cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
+ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
+ }else{
+ z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ }
+ }
+ if( zName
+ && aPrefix[i][0]=='V'
+ && (zFake = shellFakeSchema(db, zSchema, zName))!=0
+ ){
+ if( z==0 ){
+ z = sqlite3_mprintf("%s\n/* %z */", zIn, zFake);
+ }else{
+ z = sqlite3_mprintf("%z\n/* %z */", z, zFake);
+ }
+ }
+ if( z ){
+ sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ return;
}
- sqlite3_result_text(pCtx, z, -1, sqlite3_free);
- return;
}
}
}
@@ -3006,8 +3087,10 @@ static void open_db(ShellState *p, int keepAlive){
sqlite3_zipfile_init(p->db, 0, 0);
sqlite3_sqlar_init(p->db, 0, 0);
#endif
- sqlite3_create_function(p->db, "shell_add_schema", 2, SQLITE_UTF8, 0,
+ sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
shellAddSchemaName, 0, 0);
+ sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
+ shellModuleSchema, 0, 0);
}
}
@@ -6073,59 +6156,48 @@ static int do_meta_command(char *zLine, ShellState *p){
ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
- const char *zDiv = 0;
+ const char *zDiv = "(";
+ const char *zName = 0;
int iSchema = 0;
+ int bDebug = 0;
+ int ii;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
initText(&sSelect);
- if( nArg>=2 && optionMatch(azArg[1], "indent") ){
- data.cMode = data.mode = MODE_Pretty;
- nArg--;
- if( nArg==2 ) azArg[1] = azArg[2];
+ for(ii=1; ii<nArg; ii++){
+ if( optionMatch(azArg[ii],"indent") ){
+ data.cMode = data.mode = MODE_Pretty;
+ }else if( optionMatch(azArg[ii],"debug") ){
+ bDebug = 1;
+ }else if( zName==0 ){
+ zName = azArg[ii];
+ }else{
+ raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
}
- if( nArg==2 && azArg[1][0]!='-' ){
- int i;
- for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
- if( strcmp(azArg[1],"sqlite_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TABLE sqlite_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+ if( zName!=0 ){
+ int isMaster = sqlite3_strlike(zName, "sqlite_master", 0)==0;
+ if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master",0)==0 ){
char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+ new_argv[0] = sqlite3_mprintf(
+ "CREATE TABLE %s (\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
- ")";
+ ")", isMaster ? "sqlite_master" : "sqlite_temp_master");
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else{
- zDiv = "(";
+ sqlite3_free(new_argv[0]);
}
- }else if( nArg==1 ){
- zDiv = "(";
- }else{
- raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
}
if( zDiv ){
sqlite3_stmt *pStmt = 0;
@@ -6145,39 +6217,48 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
appendText(&sSelect, zDiv, 0);
zDiv = " UNION ALL ";
- if( strcmp(zDb, "main")!=0 ){
- appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
- appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ") AS sql, type, tbl_name, name, rowid,", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, ", 0);
- appendText(&sSelect, zDb, '\'');
- appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ if( sqlite3_stricmp(zDb, "main")!=0 ){
appendText(&sSelect, zDb, '"');
- appendText(&sSelect, ".sqlite_master", 0);
}else{
- appendText(&sSelect, "SELECT sql, type, tbl_name, name, rowid, ", 0);
- appendText(&sSelect, zScNum, 0);
- appendText(&sSelect, " AS snum, 'main' AS sname FROM sqlite_master",0);
+ appendText(&sSelect, "NULL", 0);
}
+ appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, '"');
+ appendText(&sSelect, ".sqlite_master", 0);
}
sqlite3_finalize(pStmt);
+#ifdef SQLITE_INTROSPECTION_PRAGMAS
+ if( zName ){
+ appendText(&sSelect,
+ " UNION ALL SELECT shell_module_schema(name),"
+ " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", 0);
+ }
+#endif
appendText(&sSelect, ") WHERE ", 0);
- if( nArg>1 ){
- char *zQarg = sqlite3_mprintf("%Q", azArg[1]);
- if( strchr(azArg[1], '.') ){
+ if( zName ){
+ char *zQarg = sqlite3_mprintf("%Q", zName);
+ if( strchr(zName, '.') ){
appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
}else{
appendText(&sSelect, "lower(tbl_name)", 0);
}
- appendText(&sSelect, strchr(azArg[1], '*') ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, strchr(zName, '*') ? " GLOB " : " LIKE ", 0);
appendText(&sSelect, zQarg, 0);
appendText(&sSelect, " AND ", 0);
sqlite3_free(zQarg);
}
appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
" ORDER BY snum, rowid", 0);
- rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ if( bDebug ){
+ utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
+ }else{
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
+ }
freeText(&sSelect);
}
if( zErrMsg ){
@@ -6863,6 +6944,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, "" },
@@ -6988,6 +7072,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 ){
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f161eea6f..f63b02931 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -6971,9 +6971,9 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
** a pointer to the underlying [sqlite3_file] object to be written into
-** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
+** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
** case is a short-circuit path which does not actually invoke the
** underlying sqlite3_io_methods.xFileControl method.
**
@@ -6985,7 +6985,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** an incorrect zDbName and an SQLITE_ERROR return from the underlying
** xFileControl method.
**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
+** See also: [file control opcodes]
*/
int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
@@ -7042,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 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
+#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */
/*
** CAPI3REF: SQLite Runtime Status
@@ -8300,7 +8301,7 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
-** method of a [virtual table implementation].
+** method of a [virtual table].
**
** The first argument must be the sqlite3_index_info object that is the
** first parameter to the xBestIndex() method. The second argument must be
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b0c4711b0..8e7913320 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;
@@ -1630,6 +1629,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
+#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -2505,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:
**
@@ -3215,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 */
};
@@ -3525,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);
@@ -3663,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**);
@@ -3693,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*,
@@ -3914,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);
@@ -4348,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/test_config.c b/src/test_config.c
index 24a7287da..ad63016ba 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -160,6 +160,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mem5", "0", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","1",TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","0",TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "1", TCL_GLOBAL_ONLY);
#else
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 cfe18a9d1..4d643d726 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2349,6 +2349,36 @@ case OP_IfNullRow: { /* jump */
break;
}
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/* Opcode: Offset P1 P2 P3 * *
+** Synopsis: r[P3] = sqlite_offset(P1)
+**
+** Store in register r[P3] the byte offset into the database file that is the
+** start of the payload for the record at which that cursor P1 is currently
+** pointing.
+**
+** P2 is the column number for the argument to the sqlite_offset() function.
+** This opcode does not use P2 itself, but the P2 value is used by the
+** code generator. The P1, P2, and P3 operands to this opcode are the
+** as as for OP_Column.
+**
+** This opcode is only available if SQLite is compiled with the
+** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option.
+*/
+case OP_Offset: { /* out3 */
+ VdbeCursor *pC; /* The VDBE cursor */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ pOut = &p->aMem[pOp->p3];
+ if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
+ sqlite3VdbeMemSetNull(pOut);
+ }else{
+ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
+ }
+ break;
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX
**
@@ -7016,7 +7046,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
**
@@ -7035,6 +7071,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;
@@ -7049,7 +7086,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
@@ -7092,6 +7131,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/where.c b/src/where.c
index d3aec354b..ec5352794 100644
--- a/src/where.c
+++ b/src/where.c
@@ -5146,7 +5146,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
- if( pOp->opcode==OP_Column ){
+ if( pOp->opcode==OP_Column
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ || pOp->opcode==OP_Offset
+#endif
+ ){
int x = pOp->p2;
assert( pIdx->pTable==pTab );
if( !HasRowid(pTab) ){