📄 expr.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 + -