⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 select.c

📁 在VC6环境下开发
💻 C
字号:
#include "eDbInit.h"
void eDbSelectDelete(Select *p){
	if( p==0 ) return;
	eDbExprListDelete(p->pEList);
	eDbSrcListDelete(p->pSrc);
	eDbExprDelete(p->pWhere);
	eDbExprListDelete(p->pGroupBy);
	eDbExprDelete(p->pHaving);
	eDbExprListDelete(p->pOrderBy);
	eDbSelectDelete(p->pPrior);
	eDbFree(p->zSelect);
	eDbFree(p);
}


/*
** Allocate a new Select structure and return a pointer to that
** structure.
*/
Select *eDbSelectNew(
	ExprList *pEList,     /* which columns to include in the result */
	SrcList *pSrc,        /* the FROM clause -- which tables to scan */
	Expr *pWhere,         /* the WHERE clause */
	ExprList *pGroupBy,   /* the GROUP BY clause */
	Expr *pHaving,        /* the HAVING clause */
	ExprList *pOrderBy,   /* the ORDER BY clause */
	int isDistinct        /* true if the DISTINCT keyword is present */
){
	Select *pNew;
	pNew = eDbMalloc( sizeof(*pNew) );
	if( pNew==0 ){
		eDbExprListDelete(pEList);
		eDbSrcListDelete(pSrc);
		eDbExprDelete(pWhere);
		eDbExprListDelete(pGroupBy);
		eDbExprDelete(pHaving);
		eDbExprListDelete(pOrderBy);
	}else{
		if( pEList==0 ){
			pEList = eDbExprListAppend(0, eDbExpr(TK_ALL,0,0,0), 0);
		}
		pNew->pEList = pEList;
		pNew->pSrc = pSrc;
		pNew->pWhere = pWhere;
		pNew->pGroupBy = pGroupBy;
		pNew->pHaving = pHaving;
		pNew->pOrderBy = pOrderBy;
		pNew->isDistinct = isDistinct;
		pNew->op = TK_SELECT;
	}
	return pNew;
}
/*
** Return the index of a column in a table.  Return -1 if the column
** is not contained in the table.
*/
static int columnIndex(Table *pTab, const char *zCol){
	int i;
	for(i=0; i<pTab->nCol; i++){
		if( eDbStrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
	}
	return -1;
}
/*
** For the given SELECT statement, do three things.
**
**    (1)  Fill in the pTabList->a[].pTab fields in the SrcList that 
**         defines the set of tables that should be scanned.  For views,
**         fill pTabList->a[].pSelect with a copy of the SELECT statement
**         that implements the view.  A copy is made of the view's SELECT
**         statement so that we can freely modify or delete that statement
**         without worrying about messing up the presistent representation
**         of the view.
**
**    (2)  Add terms to the WHERE clause to accomodate the NATURAL keyword
**         on joins and the ON and USING clause of joins.
**
**    (3)  Scan the list of columns in the result set (pEList) looking
**         for instances of the "*" operator or the TABLE.* operator.
**         If found, expand each "*" to be every column in every table
**         and TABLE.* to be every column in TABLE.
**
** Return 0 on success.  If there are problems, leave an error message
** in pParse and return non-zero.
*/
static int fillInColumnList(Parser *pParse, Select *p){
	int i, j, k, rc;
	SrcList *pTabList;
	ExprList *pEList;
	Table *pTab;

	if( p==0 || p->pSrc==0 ) return 1;
	pTabList = p->pSrc;
	pEList = p->pEList;

	/* Look up every table in the table list.
	*/
	for(i=0; i<pTabList->nSrc; i++){
		if( pTabList->a[i].pTab ){
			/* This routine has run before!  No need to continue */
			return 0;
		}		
		/* An ordinary table or view name in the FROM clause */
		pTabList->a[i].pTab = pTab = 
			eDbLocateTable(pParse,pTabList->a[i].zName,pTabList->a[i].zDatabase);
		if( pTab==0 ){
			return 1;
		}  
	}

	/* For every "*" that occurs in the column list, insert the names of
	** all columns in all tables.  And for every TABLE.* insert the names
	** of all columns in TABLE.  The parser inserted a special expression
	** with the TK_ALL operator for each "*" that it found in the column list.
	** The following code just has to locate the TK_ALL expressions and expand
	** each one to the list of all columns in all tables.
	**
	** The first loop just checks to see if there are any "*" operators
	** that need expanding.
	*/
	for(k=0; k<pEList->nExpr; k++){
		Expr *pE = pEList->a[k].pExpr;
		if( pE->op==TK_ALL ) break;
		if( pE->op==TK_DOT && pE->pRight && pE->pRight->op==TK_ALL
			 && pE->pLeft && pE->pLeft->op==TK_ID ) break;
	}
	rc = 0;
	if( k<pEList->nExpr ){
		/*
		** If we get here it means the result set contains one or more "*"
		** operators that need to be expanded.  Loop through each expression
		** in the result set and expand them one by one.
		*/
		struct ExprList_item *a = pEList->a;
		ExprList *pNew = 0;
		for(k=0; k<pEList->nExpr; k++){
			Expr *pE = a[k].pExpr;
			if( pE->op!=TK_ALL &&
				(pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){
				/* This particular expression does not need to be expanded.
				*/
				pNew = eDbExprListAppend(pNew, a[k].pExpr, 0);
				pNew->a[pNew->nExpr-1].zName = a[k].zName;
				a[k].pExpr = 0;
				a[k].zName = 0;
			}else{
				/* This expression is a "*" or a "TABLE.*" and needs to be
				** expanded. */
				int tableSeen = 0;      /* Set to 1 when TABLE matches */
				Token *pName;           /* text of name of TABLE */
				if( pE->op==TK_DOT && pE->pLeft ){
					pName = &pE->pLeft->token;
				}else{
					pName = 0;
				}
				for(i=0; i<pTabList->nSrc; i++){
					Table *pTab = pTabList->a[i].pTab;
					char *zTabName = pTabList->a[i].zAlias;
					if( zTabName==0 || zTabName[0]==0 ){ 
						zTabName = pTab->zName;
					}
					if( pName && (zTabName==0 || zTabName[0]==0 || 
						 eDbStrNICmp(pName->z, zTabName, pName->n)!=0 ||
						 zTabName[pName->n]!=0) ){
						continue;
					}
					tableSeen = 1;
					for(j=0; j<pTab->nCol; j++){
						Expr *pExpr, *pLeft, *pRight;
						char *zName = pTab->aCol[j].zName;

						if( i>0 && (pTabList->a[i-1].jointype & JT_NATURAL)!=0 &&
							columnIndex(pTabList->a[i-1].pTab, zName)>=0 ){
							/* In a NATURAL join, omit the join columns from the 
							** table on the right */
							continue;
						}
						if( i>0 && eDbIdListIndex(pTabList->a[i-1].pUsing, zName)>=0 ){
							  /* In a join with a USING clause, omit columns in the
							  ** using clause from the table on the right. */
							  continue;
						}
						pRight = eDbExpr(TK_ID, 0, 0, 0);
						if( pRight==0 ) break;
						pRight->token.z = zName;
						pRight->token.n = strlen(zName);
						pRight->token.dyn = 0;
						if( zTabName && pTabList->nSrc>1 ){
							pLeft = eDbExpr(TK_ID, 0, 0, 0);
							pExpr = eDbExpr(TK_DOT, pLeft, pRight, 0);
							if( pExpr==0 ) break;
							pLeft->token.z = zTabName;
							pLeft->token.n = strlen(zTabName);
							pLeft->token.dyn = 0;
							eDbSetString((char**)&pExpr->span.z, zTabName, ".", zName, 0);
							pExpr->span.n = strlen(pExpr->span.z);
							pExpr->span.dyn = 1;
							pExpr->token.z = 0;
							pExpr->token.n = 0;
							pExpr->token.dyn = 0;
						}else{
							pExpr = pRight;
							pExpr->span = pExpr->token;
						}
						pNew = eDbExprListAppend(pNew, pExpr, 0);
					}
				}
				if( !tableSeen ){
					if( pName ){
						char *z=0;
						eDbSetNString(&z,pName->z,pName->n,0);
						eDbErrorMsg(pParse, "no such table: %s", z);
						eDbFree(z);
					}else{
						eDbErrorMsg(pParse, "no tables specified");
					}
					rc = 1;
				}
			}
		}
		eDbExprListDelete(pEList);
		p->pEList = pNew;
	}
	return rc;
}


/*
** Generate code for the given SELECT statement.
**
** The results are distributed in various ways depending on the
** value of eDest and iParm.
**
**     eDest Value       Result
**     ------------    -------------------------------------------
**     SRT_Callback    Invoke the callback for each row of the result.
**
**     SRT_Mem         Store first result in memory cell iParm
**
**     SRT_Set         Store results as keys of a table with cursor iParm
**
**     SRT_Union       Store results as a key in a temporary table iParm
**
**     SRT_Except      Remove results from the temporary table iParm.
**
**     SRT_Table       Store results in temporary table iParm
**
** The table above is incomplete.  Additional eDist value have be added
** since this comment was written.  See the selectInnerLoop() function for
** a complete listing of the allowed values of eDest and their meanings.
**
** This routine returns the number of errors.  If any errors are
** encountered, then an appropriate error message is left in
** pParse->zErrMsg.
**
** This routine does NOT free the Select structure passed in.  The
** calling function needs to do that.
**
** The pParent, parentTab, and *pParentAgg fields are filled in if this
** SELECT is a subquery.  This routine may try to combine this SELECT
** with its parent to form a single flat query.  In so doing, it might
** change the parent query from a non-aggregate to an aggregate query.
** For that reason, the pParentAgg flag is passed as a pointer, so it
** can be changed.
**
** Example 1:   The meaning of the pParent parameter.
**
**    SELECT * FROM t1 JOIN (SELECT x, count(*) FROM t2) JOIN t3;
**    \                      \_______ subquery _______/        /
**     \                                                      /
**      \____________________ outer query ___________________/
**
** This routine is called for the outer query first.   For that call,
** pParent will be NULL.  During the processing of the outer query, this 
** routine is called recursively to handle the subquery.  For the recursive
** call, pParent will point to the outer query.  Because the subquery is
** the second element in a three-way join, the parentTab parameter will
** be 1 (the 2nd value of a 0-indexed array.)
*/
int eDbSelect(Parser *pParse,Select *p){
	int i;
	int isAgg;
	ExprList *pEList;      /* List of columns to extract. */
	SrcList *pTabList;     /* List of tables to select from */
	Expr *pWhere;          /* The WHERE clause.  May be NULL */
	ExprList *pOrderBy;    /* The ORDER BY clause.  May be NULL */
	ExprList *pGroupBy;    /* The GROUP BY clause.  May be NULL */
	Expr *pHaving;         /* The HAVING clause.  May be NULL */
	int isDistinct;        /* True if the DISTINCT keyword is present */
	int rc = 1;            /* Value to return from this function */
	ParseResult *pRes = eDbMalloc(sizeof(ParseResult));

	if( eDb_malloc_failed || pParse->nErr || p==0 ) return 1;

	/* Make local copies of the parameters for this query.
	*/
	pTabList = p->pSrc;
	pWhere = p->pWhere;
	pOrderBy = p->pOrderBy;
	pGroupBy = p->pGroupBy;
	pHaving = p->pHaving;
	isDistinct = p->isDistinct;
	if( pTabList->nSrc > 3){
		eDbErrorMsg(pParse,"total of tables must be no more than 3!\n");
		goto select_end;
	}

	/* Allocate cursors for each table in the FROM clause
	*/
	eDbSrcListAssignCursors(pParse, pTabList);

	/* 
	** Do not even attempt to generate any code if we have already seen
	** errors before this routine starts.
	*/
	if( pParse->nErr>0 ) goto select_end;

	/* Expand any "*" terms in the result set.  (For example the "*" in
	** "SELECT * FROM t1")  The fillInColumnlist() routine also does some
	** other housekeeping - see the header comment for details.
	*/
	if( fillInColumnList(pParse, p) ){
		goto select_end;
	}
	pWhere = p->pWhere;
	pEList = p->pEList;
	if( pEList==0 ) goto select_end;

	/* At this point, we should have allocated all the cursors that we
	** need to handle subquerys and temporary tables.  
	**
	** Resolve the column names and do a semantics check on all the expressions.
	*/
	for(i=0; i<pEList->nExpr; i++){
		if( eDbExprResolveIds(pParse, pTabList, 0, pEList->a[i].pExpr) ){
			goto select_end;
		}
		if( eDbExprCheck(pParse, pEList->a[i].pExpr, 1, &isAgg) ){
			goto select_end;
		}
	}
	if( pWhere ){
		if( eDbExprResolveIds(pParse, pTabList, pEList, pWhere) ){
			goto select_end;
		}
		if( eDbExprCheck(pParse, pWhere, 0, 0) ){
			goto select_end;
		}
		eDbDealwithWhereClause(pTabList,pWhere);
	}
	if( pHaving ){
		/*
		if( pGroupBy==0 ){
			eDbErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
			goto select_end;
		}
		if( eDbExprResolveIds(pParse, pTabList, pEList, pHaving) ){
			goto select_end;
		}
		if( eDbExprCheck(pParse, pHaving, 1, &isAgg) ){
			goto select_end;
		}
		*/
	}
	if( pOrderBy ){
		/*
		for(i=0; i<pOrderBy->nExpr; i++){
			int iCol;
			Expr *pE = pOrderBy->a[i].pExpr;
			if( eDbExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
				eDbExprDelete(pE);
				pE = pOrderBy->a[i].pExpr = eDbExprDup(pEList->a[iCol-1].pExpr);
			}
			if( eDbExprResolveIds(pParse, pTabList, pEList, pE) ){
				goto select_end;
			}
			if( eDbExprCheck(pParse, pE, isAgg, 0) ){
				goto select_end;
			}
			if( eDbExprIsConstant(pE) ){
				if( eDbExprIsInteger(pE, &iCol)==0 ){
					eDbErrorMsg(pParse,
						"ORDER BY terms must not be non-integer constants");
					goto select_end;
				}else if( iCol<=0 || iCol>pEList->nExpr ){
					eDbErrorMsg(pParse, 
						"ORDER BY column number %d out of range - should be "
						"between 1 and %d", iCol, pEList->nExpr);
					goto select_end;
				}
			}
		}
		*/
	}/*END if( pOrderBy )*/
	if( pGroupBy ){
		/*
		for(i=0; i<pGroupBy->nExpr; i++){
			int iCol;
			Expr *pE = pGroupBy->a[i].pExpr;
			if( eDbExprIsInteger(pE, &iCol) && iCol>0 && iCol<=pEList->nExpr ){
				eDbExprDelete(pE);
				pE = pGroupBy->a[i].pExpr = eDbExprDup(pEList->a[iCol-1].pExpr);
			}
			if( eDbExprResolveIds(pParse, pTabList, pEList, pE) ){
				goto select_end;
			}
			if( eDbExprCheck(pParse, pE, isAgg, 0) ){
				goto select_end;
			}
			if( eDbExprIsConstant(pE) ){
				if( eDbExprIsInteger(pE, &iCol)==0 ){
					eDbErrorMsg(pParse,
						"GROUP BY terms must not be non-integer constants");
					goto select_end;
				}else if( iCol<=0 || iCol>pEList->nExpr ){
					eDbErrorMsg(pParse,
						"GROUP BY column number %d out of range - should be "
						"between 1 and %d", iCol, pEList->nExpr);
					goto select_end;
				}
			}
		}
		*/
	}
	rc = 0;
	pRes->pSelect = p;
	pRes->op = Op_Select;
	pParse->pResult = pRes;
	/* Control jumps to here if an error is encountered above, or upon
	** successful coding of the SELECT.
	*/
	return eDb_OK;
select_end:	
	eDbSelectDelete(p);
	return rc;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -