From 3780be115a461f5da136079e5b9002dc70cbf25e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 31 Jul 2013 19:05:22 +0000 Subject: Resolve names in CREATE INDEX WHERE clauses and detect errors. Disallow expressions that contain variables, subqueries, or functions. The expression is still not used for anything, however. still unused. FossilOrigin-Name: f2aa7842c8b9df24294f09e2bde27b3f08c455c7 --- src/resolve.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 10 deletions(-) (limited to 'src/resolve.c') diff --git a/src/resolve.c b/src/resolve.c index 91efcaa1a..239e0eb2a 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -522,6 +522,39 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ return p; } +/* +** Report an error that an expression is not valid for a partial index WHERE +** clause. +*/ +static void notValidPartIdxWhere( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg /* Type of error */ +){ + if( (pNC->ncFlags & NC_PartIdx)!=0 ){ + sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses", + zMsg); + } +} + +#ifndef SQLITE_OMIT_CHECK +/* +** Report an error that an expression is not valid for a CHECK constraint. +*/ +static void notValidCheckConstraint( + Parse *pParse, /* Leave error message here */ + NameContext *pNC, /* The name context */ + const char *zMsg /* Type of error */ +){ + if( (pNC->ncFlags & NC_IsCheck)!=0 ){ + sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg); + } +} +#else +# define notValidCheckConstraint(P,N,M) +#endif + + /* ** This routine is callback for sqlite3WalkExpr(). ** @@ -621,6 +654,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_CONST_FUNC ); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); + notValidPartIdxWhere(pParse, pNC, "functions"); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); @@ -686,11 +720,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; -#ifndef SQLITE_OMIT_CHECK - if( (pNC->ncFlags & NC_IsCheck)!=0 ){ - sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); - } -#endif + notValidCheckConstraint(pParse, pNC, "subqueries"); + notValidPartIdxWhere(pParse, pNC, "subqueries"); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ @@ -699,14 +730,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } break; } -#ifndef SQLITE_OMIT_CHECK case TK_VARIABLE: { - if( (pNC->ncFlags & NC_IsCheck)!=0 ){ - sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); - } + notValidCheckConstraint(pParse, pNC, "parameters"); + notValidPartIdxWhere(pParse, pNC, "parameters"); break; } -#endif } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } @@ -1331,3 +1359,45 @@ void sqlite3ResolveSelectNames( w.u.pNC = pOuterNC; sqlite3WalkSelect(&w, p); } + +/* +** Resolve names in expressions that can only reference a single table: +** +** * CHECK constraints +** * WHERE clauses on partial indices +** +** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression +** is set to -1 and the Expr.iColumn value is set to the column number. +** +** Any errors cause an error message to be set in pParse. +*/ +void sqlite3ResolveSelfReference( + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table being referenced */ + int type, /* NC_IsCheck or NC_PartIdx */ + Expr *pExpr, /* Expression to resolve. May be NULL. */ + ExprList *pList /* Expression list to resolve. May be NUL. */ +){ + SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + NameContext sNC; /* Name context for pParse->pNewTable */ + int i; /* Loop counter */ + + assert( type==NC_IsCheck || type==NC_PartIdx ); + memset(&sNC, 0, sizeof(sNC)); + memset(&sSrc, 0, sizeof(sSrc)); + sSrc.nSrc = 1; + sSrc.a[0].zName = pTab->zName; + sSrc.a[0].pTab = pTab; + sSrc.a[0].iCursor = -1; + sNC.pParse = pParse; + sNC.pSrcList = &sSrc; + sNC.ncFlags = type; + if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; + if( pList ){ + for(i=0; inExpr; i++){ + if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){ + return; + } + } + } +} -- cgit v1.2.3 From 619a1305e77cc6382013fb1e9c406d8fb88ca600 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 1 Aug 2013 13:04:46 +0000 Subject: Fill out an initial implementation of the sqlite3ExprImpliesExpr() function. FossilOrigin-Name: 8e07aa2ad5579aeb82174ce5bd432ddb9c058bc1 --- src/resolve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/resolve.c') diff --git a/src/resolve.c b/src/resolve.c index 239e0eb2a..f288ed930 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -825,7 +825,7 @@ static int resolveOrderByTermToExprList( ** result-set entry. */ for(i=0; inExpr; i++){ - if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){ + if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){ return i+1; } } @@ -1053,7 +1053,7 @@ static int resolveOrderGroupBy( return 1; } for(j=0; jpEList->nExpr; j++){ - if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr)==0 ){ + if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){ pItem->iOrderByCol = j+1; } } -- cgit v1.2.3 From 1e7d43c97718ba62d2afe9caeac65bbfa6b056e5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 2 Aug 2013 14:18:18 +0000 Subject: Silently ignore database name qualifiers in CHECK constraints and in partial index WHERE clauses. FossilOrigin-Name: 2e8c845eb5011a2743dace333aa38383588f2080 --- src/resolve.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src/resolve.c') diff --git a/src/resolve.c b/src/resolve.c index f288ed930..a194a2655 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -240,11 +240,20 @@ static int lookupName( ** resulting in an appropriate error message toward the end of this routine */ if( zDb ){ - for(i=0; inDb; i++){ - assert( db->aDb[i].zName ); - if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ - pSchema = db->aDb[i].pSchema; - break; + testcase( pNC->ncFlags & NC_PartIdx ); + testcase( pNC->ncFlags & NC_IsCheck ); + if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){ + /* Silently ignore database qualifiers inside CHECK constraints and partial + ** indices. Do not raise errors because that might break legacy and + ** because it does not hurt anything to just ignore the database name. */ + zDb = 0; + }else{ + for(i=0; inDb; i++){ + assert( db->aDb[i].zName ); + if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ + pSchema = db->aDb[i].pSchema; + break; + } } } } -- cgit v1.2.3