1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Continued refactoring of the name resolution logic and query optimizer. (CVS 2236)

FossilOrigin-Name: d8b2a7e09187564fe66a2b4bf0992c6a017146cf
This commit is contained in:
drh
2005-01-19 23:24:50 +00:00
parent 76b047d957
commit 1398ad3639
16 changed files with 182 additions and 107 deletions

View File

@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.181 2005/01/18 17:20:10 drh Exp $
** $Id: expr.c,v 1.182 2005/01/19 23:24:50 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1095,6 +1095,9 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
return 0;
}
/* Forward declaration */
static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
/*
** This routine walks an expression tree and resolves references to
** table columns. Nodes of the form ID.ID or ID resolve into an
@@ -1117,12 +1120,13 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
** property on the expression.
*/
int sqlite3ExprResolveNames(
Parse *pParse, /* The parser context */
SrcList *pSrcList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */
Expr *pExpr, /* The expression to be analyzed. */
int allowAgg, /* True to allow aggregate expressions */
int codeSubquery /* If true, then generate code for subqueries too */
Parse *pParse, /* The parser context */
SrcList *pSrcList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */
NameContext *pNC, /* Namespace of enclosing statement */
Expr *pExpr, /* The expression to be analyzed. */
int allowAgg, /* True to allow aggregate expressions */
int codeSubquery /* If true, then generate code for subqueries too */
){
NameContext sNC;
@@ -1132,18 +1136,29 @@ int sqlite3ExprResolveNames(
sNC.pParse = pParse;
sNC.pEList = pEList;
sNC.allowAgg = allowAgg;
sNC.pNext = pNC;
walkExprTree(pExpr, nameResolverStep, &sNC);
if( sNC.hasAgg ){
ExprSetProperty(pExpr, EP_Agg);
}
if( sNC.nErr>0 ){
ExprSetProperty(pExpr, EP_Error);
}else if( codeSubquery && sqlite3ExprCodeSubquery(pParse, pExpr) ){
}else if( codeSubquery && sqlite3ExprCodeSubquery(pParse, &sNC, pExpr) ){
return 1;
}
return ExprHasProperty(pExpr, EP_Error);
}
/*
** A pointer instance of this structure is used to pass information
** through walkExprTree into codeSubqueryStep().
*/
typedef struct QueryCoder QueryCoder;
struct QueryCoder {
Parse *pParse; /* The parsing context */
NameContext *pNC; /* Namespace of first enclosing query */
};
/*
** Generate code for subqueries and IN operators.
@@ -1167,7 +1182,8 @@ int sqlite3ExprResolveNames(
** additional information.
*/
static int codeSubqueryStep(void *pArg, Expr *pExpr){
Parse *pParse = (Parse*)pArg;
QueryCoder *pCoder = (QueryCoder*)pArg;
Parse *pParse = pCoder->pParse;
switch( pExpr->op ){
case TK_IN: {
@@ -1207,7 +1223,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
int iParm = pExpr->iTable + (((int)affinity)<<16);
ExprList *pEList;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0, 0);
pEList = pExpr->pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
@@ -1237,7 +1253,7 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
"right-hand side of IN operator must be constant");
return 2;
}
if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0) ){
if( sqlite3ExprResolveNames(pParse, 0, 0, 0, pE2, 0, 0) ){
return 2;
}
@@ -1257,8 +1273,27 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
** value of this select in a memory cell and record the number
** of the memory cell in iColumn.
*/
NameContext *pNC;
int nRef;
Vdbe *v;
int addr;
pNC = pCoder->pNC;
if( pNC ) nRef = pNC->nRef;
v = sqlite3GetVdbe(pParse);
addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
pExpr->iColumn = pParse->nMem++;
sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0);
sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0,pNC);
if( pNC && pNC->nRef>nRef ){
/* Subquery value changes. Evaluate at each use */
pExpr->iTable = addr+1;
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
}else{
/* Subquery value is constant. evaluate only once. */
pExpr->iTable = -1;
sqlite3VdbeChangeP2(v, addr, addr+1);
}
return 1;
}
}
@@ -1269,8 +1304,15 @@ static int codeSubqueryStep(void *pArg, Expr *pExpr){
** Generate code to evaluate subqueries and IN operators contained
** in expression pExpr.
*/
int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){
walkExprTree(pExpr, codeSubqueryStep, pParse);
static int sqlite3ExprCodeSubquery(
Parse *pParse, /* Parser */
NameContext *pNC, /* First enclosing namespace. Often NULL */
Expr *pExpr /* Subquery to be coded */
){
QueryCoder sCoder;
sCoder.pParse = pParse;
sCoder.pNC = pNC;
walkExprTree(pExpr, codeSubqueryStep, &sCoder);
return 0;
}
@@ -1478,6 +1520,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
break;
}
case TK_SELECT: {
if( pExpr->iTable>=0 ){
sqlite3VdbeAddOp(v, OP_Gosub, 0, pExpr->iTable);
VdbeComment((v, "# run subquery"));
}
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
VdbeComment((v, "# load subquery result"));
break;