aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c65
-rw-r--r--src/resolve.c14
-rw-r--r--src/select.c5
-rw-r--r--src/sqliteInt.h8
4 files changed, 70 insertions, 22 deletions
diff --git a/src/expr.c b/src/expr.c
index 790aa45f3..e2f8b4578 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -3816,22 +3816,35 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
}
/*
-** This is the expression callback for sqlite3FunctionUsesOtherSrc().
-**
-** Determine if an expression references any table other than one of the
-** tables in pWalker->u.pSrcList and abort if it does.
+** An instance of the following structure is used by the tree walker
+** to count references to table columns in the arguments of an
+** aggregate function, in order to implement the sqlite3FunctionUsesOtherSrc()
+** and sqlite3FunctionThisSrc() routines.
*/
-static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
+struct SrcCount {
+ SrcList *pSrc; /* One particular FROM clause in a nested query */
+ int nThis; /* Number of references to columns in pSrcList */
+ int nOther; /* Number of references to columns in other FROM clauses */
+};
+
+/*
+** Count the number of references to columns.
+*/
+static int exprSrcCount(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
int i;
- SrcList *pSrc = pWalker->u.pSrcList;
+ struct SrcCount *p = pWalker->u.pSrcCount;
+ SrcList *pSrc = p->pSrc;
for(i=0; i<pSrc->nSrc; i++){
- if( pExpr->iTable==pSrc->a[i].iCursor ) return WRC_Continue;
+ if( pExpr->iTable==pSrc->a[i].iCursor ) break;
+ }
+ if( i<pSrc->nSrc ){
+ p->nThis++;
+ }else{
+ p->nOther++;
}
- return WRC_Abort;
- }else{
- return WRC_Continue;
}
+ return WRC_Continue;
}
/*
@@ -3842,12 +3855,36 @@ static int exprUsesOtherSrc(Walker *pWalker, Expr *pExpr){
*/
static int sqlite3FunctionUsesOtherSrc(Expr *pExpr, SrcList *pSrcList){
Walker w;
+ struct SrcCount cnt;
assert( pExpr->op==TK_AGG_FUNCTION );
memset(&w, 0, sizeof(w));
- w.xExprCallback = exprUsesOtherSrc;
- w.u.pSrcList = pSrcList;
- if( sqlite3WalkExprList(&w, pExpr->x.pList)!=WRC_Continue ) return 1;
- return 0;
+ w.xExprCallback = exprSrcCount;
+ w.u.pSrcCount = &cnt;
+ cnt.pSrc = pSrcList;
+ cnt.nThis = 0;
+ cnt.nOther = 0;
+ sqlite3WalkExprList(&w, pExpr->x.pList);
+ return cnt.nOther>0;
+}
+
+/*
+** Determine if any of the arguments to the pExpr Function reference
+** pSrcList. Return true if they do. Also return true if the function
+** has no arguments or has only constant arguments. Return false if pExpr
+** references columns but not columns of tables found in pSrcList.
+*/
+int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
+ Walker w;
+ struct SrcCount cnt;
+ assert( pExpr->op==TK_AGG_FUNCTION );
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = exprSrcCount;
+ w.u.pSrcCount = &cnt;
+ cnt.pSrc = pSrcList;
+ cnt.nThis = 0;
+ cnt.nOther = 0;
+ sqlite3WalkExprList(&w, pExpr->x.pList);
+ return cnt.nThis>0 || cnt.nOther==0;
}
/*
diff --git a/src/resolve.c b/src/resolve.c
index a66f88fdc..bfbcd2041 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -568,13 +568,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
nId, zId);
pNC->nErr++;
}
+ if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
+ sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
+ NameContext *pNC2 = pNC;
pExpr->op = TK_AGG_FUNCTION;
- pNC->ncFlags |= NC_HasAgg;
+ pExpr->op2 = 0;
+ while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
+ pExpr->op2++;
+ pNC2 = pNC2->pNext;
+ }
+ if( pNC2 ) pNC2->ncFlags |= NC_HasAgg;
+ pNC->ncFlags |= NC_AllowAgg;
}
- if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
- sqlite3WalkExprList(pWalker, pList);
- if( is_agg ) pNC->ncFlags |= NC_AllowAgg;
/* FIX ME: Compute pExpr->affinity based on the expected return
** type of the function
*/
diff --git a/src/select.c b/src/select.c
index 491356acb..93a084eaf 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3521,7 +3521,7 @@ static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
/*
-** This routine sets of a SELECT statement for processing. The
+** This routine sets up a SELECT statement for processing. The
** following is accomplished:
**
** * VDBE Cursor numbers are assigned to all FROM-clause terms.
@@ -3553,7 +3553,8 @@ void sqlite3SelectPrep(
**
** The aggregate accumulator is a set of memory cells that hold
** intermediate results while calculating an aggregate. This
-** routine simply stores NULLs in all of those memory cells.
+** routine generates code that stores NULLs in all of those memory
+** cells.
*/
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b3cdb2363..443eaa403 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1690,8 +1690,9 @@ struct Expr {
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 flags2; /* Second set of flags. EP2_... */
- u8 op2; /* If a TK_REGISTER, the original value of Expr.op */
- /* If TK_COLUMN, the value of p5 for OP_Column */
+ u8 op2; /* TK_REGISTER: original value of Expr.op
+ ** TK_COLUMN: the value of p5 for OP_Column
+ ** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
Table *pTab; /* Table for TK_COLUMN expressions. */
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -2498,10 +2499,12 @@ struct Walker {
int (*xExprCallback)(Walker*, Expr*); /* Callback for expressions */
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
Parse *pParse; /* Parser context. */
+ int walkerDepth; /* Number of subqueries */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int i; /* Integer value */
SrcList *pSrcList; /* FROM clause */
+ struct SrcCount *pSrcCount; /* Counting column references */
} u;
};
@@ -2835,6 +2838,7 @@ int sqlite3ExprCompare(Expr*, Expr*);
int sqlite3ExprListCompare(ExprList*, ExprList*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
+int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
Vdbe *sqlite3GetVdbe(Parse*);
void sqlite3PrngSaveState(void);
void sqlite3PrngRestoreState(void);