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

📄 expr.c

📁 在VC6环境下开发
💻 C
字号:
#include "eDbInit.h"
/*
** Construct a new expression node and return a pointer to it.  Memory
** for this node is obtained from eDbMalloc().  The calling function
** is responsible for making sure the node eventually gets freed.
*/
Expr *eDbExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
	Expr *pNew;
	pNew = eDbMalloc( sizeof(Expr) );
	if( pNew==0 ){
		/* When malloc fails, we leak memory from pLeft and pRight */
		return 0;
	}
	pNew->op = op;
	pNew->pLeft = pLeft;
	pNew->pRight = pRight;
	if( pToken ){
		assert( pToken->dyn==0 );
		pNew->token = *pToken;
		pNew->span = *pToken;
	}else{
		assert( pNew->token.dyn==0 );
		assert( pNew->token.z==0 );
		assert( pNew->token.n==0 );
		if( pLeft && pRight ){
			eDbExprSpan(pNew, &pLeft->span, &pRight->span);
		}else{
			pNew->span = pNew->token;
		}
	}
	return pNew;
}

/*
** Set the Expr.span field of the given expression to span all
** text between the two given tokens.
*/
void eDbExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
	assert( pRight!=0 );
	assert( pLeft!=0 );
	/* Note: pExpr might be NULL due to a prior malloc failure */
	if( pExpr && pRight->z && pLeft->z ){
		if( pLeft->dyn==0 && pRight->dyn==0 ){
			pExpr->span.z = pLeft->z;
			pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
		}else{
			pExpr->span.z = 0;
		}
	}
}
/*
** Recursively delete an expression tree.
*/
void eDbExprDelete(Expr *p){
	if( p==0 ) return;
	if( p->span.dyn ) eDbFree((char*)p->span.z);
	if( p->token.dyn ) eDbFree((char*)p->token.z);
	eDbExprDelete(p->pLeft);
	eDbExprDelete(p->pRight);
	eDbExprListDelete(p->pList);
	eDbSelectDelete(p->pSelect);
	eDbFree(p);
}



/*
** Add a new element to the end of an expression list.  If pList is
** initially NULL, then create a new expression list.
*/
ExprList *eDbExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
	if( pList==0 ){
		pList = eDbMalloc( sizeof(ExprList) );
		if( pList==0 ){
			/* eDbExprDelete(pExpr); // Leak memory if malloc fails */
			return 0;
		}
		assert( pList->nAlloc==0 );
	}
	if( pList->nAlloc<=pList->nExpr ){
		pList->nAlloc = pList->nAlloc*2 + 4;
		pList->a = eDbRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]));
		if( pList->a==0 ){
			/* eDbExprDelete(pExpr); // Leak memory if malloc fails */
			pList->nExpr = pList->nAlloc = 0;
			return pList;
		}
	}
	assert( pList->a!=0 );
	if( pExpr || pName ){
		struct ExprList_item *pItem = &pList->a[pList->nExpr++];
		memset(pItem, 0, sizeof(*pItem));
		pItem->pExpr = pExpr;
		if( pName ){
			eDbSetNString(&pItem->zName, pName->z, pName->n, 0);
			eDbDequote(pItem->zName);
		}
	}
	return pList;
}

/*
** Add a new element to the end of an expression list.  If pList is
** initially NULL, then create a new expression list.
*/
IdExprList *eDbIdExprListAppend(IdExprList *pList, Expr *pExpr, Token *pId){
	if( pList==0 ){
		pList = eDbMalloc( sizeof(IdExprList) );
		if( pList==0 ){
			/* eDbExprDelete(pExpr); // Leak memory if malloc fails */
			return 0;
		}
	}
	pList->pIdList = eDbIdListAppend(pList->pIdList,pId);
	pList->pEList = eDbExprListAppend(pList->pEList,pExpr,0);
	return pList;
}

/*
** Delete an entire expression list.
*/
void eDbExprListDelete(ExprList *pList){
	int i;
	if( pList==0 ) return;
	for(i=0; i<pList->nExpr; i++){
		eDbExprDelete(pList->a[i].pExpr);
		eDbFree(pList->a[i].zName);
	}
	eDbFree(pList->a);
	eDbFree(pList);
}
/*
** delete a IdExprList tree.
*/
void eDbIdExprListDelete(IdExprList *p){
	if( p==0 ) return;
	eDbIdListDelete(p->pIdList);
	eDbExprListDelete(p->pEList);
	eDbFree(p);
}
/*
** Given the name of a column of the form Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr 
** expression node refer back to that source column.  The following changes
** are made to pExpr:
**
**    pExpr->iTable        Set to the cursor number for the table obtained
**                         from pSrcList.
**    pExpr->iColumn       Set to the column number within the table.
**    pExpr->dataType      Set to the appropriate data type for the column.
**    pExpr->op            Set to TK_COLUMN.
**    pExpr->pLeft         Any expression this points to is deleted
**    pExpr->pRight        Any expression this points to is deleted.
**

** The pTableToken is the name of the table (the "Y").  This
** value can be NULL if pDbToken is also NULL.  If pTableToken is NULL it
** means that the form of the name is Z and that columns from any table
** can be used.
**
** If the name cannot be resolved unambiguously, leave an error message
** in pParse and return non-zero.  Return zero on success.
*/
static int lookupName(
	Parser *pParse,      /* The parsing context */
	Token *pTableToken,  /* Name of table containing column, or NULL */
	Token *pColumnToken, /* Name of the column. */
	SrcList *pSrcList,   /* List of tables used to resolve column names */
	ExprList *pEList,    /* List of expressions used to resolve "AS" */
	Expr *pExpr          /* Make this EXPR node point to the selected column */
){
	char *zTab = 0;      /* Name of the table.  The "Y" in Y.Z */
	char *zCol = 0;      /* Name of the column.  The "Z" */
	int i, j;            /* Loop counters */
	int cnt = 0;         /* Number of matching column names */
	int cntTab = 0;      /* Number of matching table names */
	
	if( pTableToken && pTableToken->z ){
		zTab = eDbStrNDup(pTableToken->z, pTableToken->n);
		eDbDequote(zTab);
	}else{
		zTab = 0;
	}
	zCol = eDbStrNDup(pColumnToken->z, pColumnToken->n);
	eDbDequote(zCol);
	if( eDb_malloc_failed ){
		return 1;  /* Leak memory (zDb and zTab) if malloc fails */
	}
	
	assert( zTab==0 || pEList==0 );
	pExpr->iTable = -1;
	for(i=0; i<pSrcList->nSrc; i++){
		struct SrcList_item *pItem = &pSrcList->a[i];
		Table *pTab = pItem->pTab;
		Column *pCol;

		if( pTab==0 ) continue;
		assert( pTab->nCol>0 );
		if( zTab ){
			if( pItem->zAlias ){
				char *zTabName = pItem->zAlias;
				if( eDbStrICmp(zTabName, zTab)!=0 ) continue;
			}else{
				char *zTabName = pTab->zName;
				if( zTabName==0 || eDbStrICmp(zTabName, zTab)!=0 ) continue;				
			}
		}
		if( 0==(cntTab++) ){
			pExpr->iTable = pItem->iCursor;
		}
		for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
			if( eDbStrICmp(pCol->zName, zCol)==0 ){
				cnt++;
				pExpr->iTable = pItem->iCursor;
				pExpr->iColumn = j;
				pExpr->dataType = pCol->type & eDb_SO_TYPEMASK;				
				pExpr->tnum = pTab->tnum;	
				pExpr->iIndex = eDbLookupIdxColumn(pTab,j);
				break;
			}
		}
	}/* end for(i=0; i<pSrcList->nSrc; i++) */
	/*
	** If the input is of the form Z (not Y.Z ) then the name Z
	** might refer to an result-set alias.  This happens, for example, when
	** we are resolving names in the WHERE clause of the following command:
	**
	**     SELECT a+b AS x FROM table WHERE x<10;
	**
	** In cases like this, replace pExpr with a copy of the expression that
	** forms the result set entry ("a+b" in the example) and return immediately.
	** Note that the expression in the result set should have already been
	** resolved by the time the WHERE clause is resolved.
	*/
	/*
	if( cnt==0 && pEList!=0 ){
		for(j=0; j<pEList->nExpr; j++){
			char *zAs = pEList->a[j].zName;
			if( zAs!=0 && eDbStrICmp(zAs, zCol)==0 ){
				assert( pExpr->pLeft==0 && pExpr->pRight==0 );
				pExpr->op = TK_AS;
				pExpr->iColumn = j;
				pExpr->pLeft = eDbExprDup(pEList->a[j].pExpr);
				eDbFree(zCol);
				assert( zTab==0 );
				return 0;
			}
		} 
	}
	*/

	/*
	** If X and Y are NULL (in other words if only the column name Z is
	** supplied) and the value of Z is enclosed in double-quotes, then
	** Z is a string literal if it doesn't match any column names.  In that
	** case, we need to return right away and not make any changes to
	** pExpr.
	*/
	if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
		eDbFree(zCol);
		return 0;
	}

	/*
	** cnt==0 means there was not match.  cnt>1 means there were two or
	** more matches.  Either way, we have an error.
	*/
	if( cnt!=1 ){
		char *z = 0;
		char *zErr;
		zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
		if( zTab ){
			eDbSetString(&z, zTab, ".", zCol, 0);
		}else{
			z = eDbStrDup(zCol);
		}
		eDbErrorMsg(pParse, zErr, z);
		eDbFree(z);
	}

	/* Clean up and return
	*/
	eDbFree(zTab);
	eDbFree(zCol);
	eDbExprDelete(pExpr->pLeft);
	pExpr->pLeft = 0;
	eDbExprDelete(pExpr->pRight);
	pExpr->pRight = 0;
	pExpr->op = TK_COLUMN;
	return cnt!=1;
}


int eDbExprResolveIds(
	Parser *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 i;

	if( pExpr==0 || pSrcList==0 ) return 0;
	for(i=0; i<pSrcList->nSrc; i++){
		assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
	}
	switch( pExpr->op ){		
		case TK_STRING: {
			if( pExpr->token.z[0]=='\'' ) break;
		}
		/* A lone identifier is the name of a columnd.
		*/
		case TK_ID: {
			if( lookupName(pParse, 0, &pExpr->token, pSrcList, pEList, pExpr) ){
				return 1;
			}
			break; 
		}
  
		/* A table name and column name:     ID.ID
		*/
		case TK_DOT: {
			Token *pColumn;
			Token *pTable;
			Token *pDb;
			Expr *pRight;

			pRight = pExpr->pRight;
			if( pRight->op==TK_ID ){
				pDb = 0;
				pTable = &pExpr->pLeft->token;
				pColumn = &pRight->token;
			}else{
				assert( pRight->op==TK_DOT );
				pDb = &pExpr->pLeft->token;
				pTable = &pRight->pLeft->token;
				pColumn = &pRight->pRight->token;
			}
			if( lookupName(pParse, pTable, pColumn, pSrcList, 0, pExpr) ){
				return 1;
			}
			break;
		}

		/* For all else, just recursively walk the tree */
		default: {
			if( pExpr->pLeft
				&& eDbExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
				return 1;
			}
			if( pExpr->pRight 
				&& eDbExprResolveIds(pParse, pSrcList, pEList, pExpr->pRight) ){
				return 1;
			}
			if( pExpr->pList ){
				int i;
				ExprList *pList = pExpr->pList;
				for(i=0; i<pList->nExpr; i++){
					Expr *pArg = pList->a[i].pExpr;
					if( eDbExprResolveIds(pParse, pSrcList, pEList, pArg) ){
						return 1;
					}
				}
			}
		}
	}
	return 0;
}

/*
** Error check the functions in an expression.  Make sure all
** function names are recognized and all functions have the correct
** number of arguments.  Leave an error message in pParse->zErrMsg
** if anything is amiss.  Return the number of errors.
**
** if pIsAgg is not null and this expression is an aggregate function
** (like count(*) or max(value)) then write a 1 into *pIsAgg.
*/
int eDbExprCheck(Parser *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){	
	return 0;
}


⌨️ 快捷键说明

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