📄 resolve.c
字号:
return 1; }}/*** This routine is callback for sqlite3WalkExpr().**** Resolve symbolic names into TK_COLUMN operators for the current** node in the expression tree. Return 0 to continue the search down** the tree or 2 to abort the tree walk.**** This routine also does error checking and name resolution for** function names. The operator for aggregate functions is changed** to TK_AGG_FUNCTION.*/static int resolveExprStep(Walker *pWalker, Expr *pExpr){ NameContext *pNC; Parse *pParse; pNC = pWalker->u.pNC; assert( pNC!=0 ); pParse = pNC->pParse; assert( pParse==pWalker->pParse ); if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return WRC_Prune; ExprSetProperty(pExpr, EP_Resolved);#ifndef NDEBUG if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){ SrcList *pSrcList = pNC->pSrcList; int i; for(i=0; i<pNC->pSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); } }#endif switch( pExpr->op ){ /* A lone identifier is the name of a column. */ case TK_ID: { lookupName(pParse, 0, 0, &pExpr->token, pNC, pExpr); return WRC_Prune; } /* A table name and column name: ID.ID ** Or a database, table and column: ID.ID.ID */ case TK_DOT: { Token *pColumn; Token *pTable; Token *pDb; Expr *pRight; /* if( pSrcList==0 ) break; */ 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; } lookupName(pParse, pDb, pTable, pColumn, pNC, pExpr); return WRC_Prune; } /* Resolve function names */ case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pList = pExpr->pList; /* The argument list */ int n = pList ? pList->nExpr : 0; /* Number of arguments */ int no_such_func = 0; /* True if no such function exists */ int wrong_num_args = 0; /* True if wrong number of arguments */ int is_agg = 0; /* True if is an aggregate function */ int auth; /* Authorization to use the function */ int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ int enc = ENC(pParse->db); /* The database encoding */ zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); if( pDef==0 ){ no_such_func = 1; }else{ wrong_num_args = 1; } }else{ is_agg = pDef->xFunc==0; }#ifndef SQLITE_OMIT_AUTHORIZATION if( pDef ){ auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0); if( auth!=SQLITE_OK ){ if( auth==SQLITE_DENY ){ sqlite3ErrorMsg(pParse, "not authorized to use function: %s", pDef->zName); pNC->nErr++; } pExpr->op = TK_NULL; return WRC_Prune; } }#endif if( is_agg && !pNC->allowAgg ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; }else if( no_such_func ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); pNC->nErr++; } if( is_agg ){ pExpr->op = TK_AGG_FUNCTION; pNC->hasAgg = 1; } if( is_agg ) pNC->allowAgg = 0; sqlite3WalkExprList(pWalker, pList); if( is_agg ) pNC->allowAgg = 1; /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; }#ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: case TK_EXISTS:#endif case TK_IN: { if( pExpr->pSelect ){ int nRef = pNC->nRef;#ifndef SQLITE_OMIT_CHECK if( pNC->isCheck ){ sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); }#endif sqlite3WalkSelect(pWalker, pExpr->pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); } } break; }#ifndef SQLITE_OMIT_CHECK case TK_VARIABLE: { if( pNC->isCheck ){ sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); } break; }#endif } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;}/*** pEList is a list of expressions which are really the result set of the** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause.** This routine checks to see if pE is a simple identifier which corresponds** to the AS-name of one of the terms of the expression list. If it is,** this routine return an integer between 1 and N where N is the number of** elements in pEList, corresponding to the matching entry. If there is** no match, or if pE is not a simple identifier, then this routine** return 0.**** pEList has been resolved. pE has not.*/static int resolveAsName( Parse *pParse, /* Parsing context for error messages */ ExprList *pEList, /* List of expressions to scan */ Expr *pE /* Expression we are trying to match */){ int i; /* Loop counter */ if( pE->op==TK_ID || (pE->op==TK_STRING && pE->token.z[0]!='\'') ){ sqlite3 *db = pParse->db; char *zCol = sqlite3NameFromToken(db, &pE->token); if( zCol==0 ){ return -1; } for(i=0; i<pEList->nExpr; i++){ char *zAs = pEList->a[i].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ sqlite3DbFree(db, zCol); return i+1; } } sqlite3DbFree(db, zCol); } return 0;}/*** pE is a pointer to an expression which is a single term in the** ORDER BY of a compound SELECT. The expression has not been** name resolved.**** At the point this routine is called, we already know that the** ORDER BY term is not an integer index into the result set. That** case is handled by the calling routine.**** Attempt to match pE against result set columns in the left-most** SELECT statement. Return the index i of the matching column,** as an indication to the caller that it should sort by the i-th column.** The left-most column is 1. In other words, the value returned is the** same integer value that would be used in the SQL statement to indicate** the column.**** If there is no match, return 0. Return -1 if an error occurs.*/static int resolveOrderByTermToExprList( Parse *pParse, /* Parsing context for error messages */ Select *pSelect, /* The SELECT statement with the ORDER BY clause */ Expr *pE /* The specific ORDER BY term */){ int i; /* Loop counter */ ExprList *pEList; /* The columns of the result set */ NameContext nc; /* Name context for resolving pE */ assert( sqlite3ExprIsInteger(pE, &i)==0 ); pEList = pSelect->pEList; /* Resolve all names in the ORDER BY term expression */ memset(&nc, 0, sizeof(nc)); nc.pParse = pParse; nc.pSrcList = pSelect->pSrc; nc.pEList = pEList; nc.allowAgg = 1; nc.nErr = 0; if( sqlite3ResolveExprNames(&nc, pE) ){ sqlite3ErrorClear(pParse); return 0; } /* Try to match the ORDER BY expression against an expression ** in the result set. Return an 1-based index of the matching ** result-set entry. */ for(i=0; i<pEList->nExpr; i++){ if( sqlite3ExprCompare(pEList->a[i].pExpr, pE) ){ return i+1; } } /* If no match, return 0. */ return 0;}/*** Generate an ORDER BY or GROUP BY term out-of-range error.*/static void resolveOutOfRangeError( Parse *pParse, /* The error context into which to write the error */ const char *zType, /* "ORDER" or "GROUP" */ int i, /* The index (1-based) of the term out of range */ int mx /* Largest permissible value of i */){ sqlite3ErrorMsg(pParse, "%r %s BY term out of range - should be " "between 1 and %d", i, zType, mx);}/*** Analyze the ORDER BY clause in a compound SELECT statement. Modify** each term of the ORDER BY clause is a constant integer between 1** and N where N is the number of columns in the compound SELECT.**** ORDER BY terms that are already an integer between 1 and N are** unmodified. ORDER BY terms that are integers outside the range of** 1 through N generate an error. ORDER BY terms that are expressions** are matched against result set expressions of compound SELECT** beginning with the left-most SELECT and working toward the right.** At the first match, the ORDER BY expression is transformed into** the integer column number.**** Return the number of errors seen.*/static int resolveCompoundOrderBy( Parse *pParse, /* Parsing context. Leave error messages here */ Select *pSelect /* The SELECT statement containing the ORDER BY */){ int i; ExprList *pOrderBy; ExprList *pEList; sqlite3 *db; int moreToDo = 1; pOrderBy = pSelect->pOrderBy; if( pOrderBy==0 ) return 0; db = pParse->db;#if SQLITE_MAX_COLUMN if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; }#endif for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; } pSelect->pNext = 0; while( pSelect->pPrior ){ pSelect->pPrior->pNext = pSelect; pSelect = pSelect->pPrior; } while( pSelect && moreToDo ){ struct ExprList_item *pItem; moreToDo = 0; pEList = pSelect->pEList; assert( pEList!=0 ); for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ int iCol = -1; Expr *pE, *pDup; if( pItem->done ) continue; pE = pItem->pExpr; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<0 || iCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); return 1; } }else{ iCol = resolveAsName(pParse, pEList, pE); if( iCol==0 ){ pDup = sqlite3ExprDup(db, pE); if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); } sqlite3ExprDelete(db, pDup); } if( iCol<0 ){ return 1; } } if( iCol>0 ){ CollSeq *pColl = pE->pColl; int flags = pE->flags & EP_ExpCollate; sqlite3ExprDelete(db, pE); pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0, 0, 0); if( pE==0 ) return 1; pE->pColl = pColl; pE->flags |= EP_IntValue | flags; pE->iTable = iCol; pItem->iCol = iCol; pItem->done = 1; }else{ moreToDo = 1; } } pSelect = pSelect->pNext; } for(i=0; i<pOrderBy->nExpr; i++){ if( pOrderBy->a[i].done==0 ){ sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any " "column in the result set", i+1); return 1; } } return 0;}/*** Check every term in the ORDER BY or GROUP BY clause pOrderBy of** the SELECT statement pSelect. If any term is reference to a** result set expression (as determined by the ExprList.a.iCol field)** then convert that term into a copy of the corresponding result set** column.**** If any errors are detected, add an error message to pParse and** return non-zero. Return zero if no errors are seen.*/int sqlite3ResolveOrderGroupBy( Parse *pParse, /* Parsing context. Leave error messages here */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -