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

Added support for user-defined normal functions. Support for user-defined

aggregates is pending. (CVS 390)

FossilOrigin-Name: c490a1ff951c5d4a2de8e4f8d349189bfaef7f74
This commit is contained in:
drh
2002-02-23 23:45:45 +00:00
parent b29b0a5227
commit 8e0a2f903a
13 changed files with 380 additions and 45 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.42 2002/02/23 02:32:10 drh Exp $
** $Id: expr.c,v 1.43 2002/02/23 23:45:45 drh Exp $
*/
#include "sqliteInt.h"
@@ -606,29 +606,40 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
int no_such_func = 0;
int too_many_args = 0;
int too_few_args = 0;
int wrong_num_args = 0;
int is_agg = 0;
int i;
pExpr->iColumn = id;
switch( id ){
case FN_Unknown: {
no_such_func = 1;
case FN_Unknown: {
UserFunc *pUser = sqliteFindUserFunction(pParse->db,
pExpr->token.z, pExpr->token.n, n, 0);
if( pUser==0 ){
pUser = sqliteFindUserFunction(pParse->db,
pExpr->token.z, pExpr->token.n, -1, 0);
if( pUser==0 ){
no_such_func = 1;
}else{
wrong_num_args = 1;
}
}else{
is_agg = pUser->xFunc==0;
}
break;
}
case FN_Count: {
no_such_func = !allowAgg;
too_many_args = n>1;
is_agg = 1;
break;
}
case FN_Max:
case FN_Min: {
too_few_args = allowAgg ? n<1 : n<2;
too_few_args = n<1;
is_agg = n==1;
break;
}
case FN_Avg:
case FN_Sum: {
no_such_func = !allowAgg;
too_many_args = n>1;
too_few_args = n<1;
is_agg = 1;
@@ -652,7 +663,13 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
}
default: break;
}
if( no_such_func ){
if( is_agg && !allowAgg ){
sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1,
pExpr->token.z, pExpr->token.n, "()", 2, 0);
pParse->nErr++;
nErr++;
is_agg = 0;
}else if( no_such_func ){
sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1,
pExpr->token.z, pExpr->token.n, 0);
pParse->nErr++;
@@ -667,6 +684,12 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
pExpr->token.z, pExpr->token.n, "()", 2, 0);
pParse->nErr++;
nErr++;
}else if( wrong_num_args ){
sqliteSetNString(&pParse->zErrMsg,
"wrong number of arguments to function ",-1,
pExpr->token.z, pExpr->token.n, "()", 2, 0);
pParse->nErr++;
nErr++;
}
if( is_agg ) pExpr->op = TK_AGG_FUNCTION;
if( is_agg && pIsAgg ) *pIsAgg = 1;
@@ -886,6 +909,18 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Substr, 0, 0);
break;
}
case FN_Unknown: {
UserFunc *pUser;
pUser = sqliteFindUserFunction(pParse->db,
pExpr->token.z, pExpr->token.n, pList->nExpr, 0);
assert( pUser!=0 );
for(i=0; i<pList->nExpr; i++){
sqliteExprCode(pParse, pList->a[i].pExpr);
}
sqliteVdbeAddOp(v, OP_UserFunc, pList->nExpr, 0);
sqliteVdbeChangeP3(v, -1, (char*)pUser->xFunc, P3_POINTER);
break;
}
default: {
/* Can't happen! */
break;
@@ -1245,3 +1280,52 @@ int sqliteExprAnalyzeAggregates(Parse *pParse, Expr *pExpr){
}
return nErr;
}
/*
** Locate a user function given a name and a number of arguments.
** Return a pointer to the UserFunc structure that defines that
** function, or return NULL if the function does not exist.
**
** If the createFlag argument is true, then a new (blank) UserFunc
** structure is created and liked into the "db" structure if a
** no matching function previously existed. When createFlag is true
** and the nArg parameter is -1, then only a function that accepts
** any number of arguments will be returned.
**
** If createFlag is false and nArg is -1, then the first valid
** function found is returned. A function is valid if either xFunc
** or xStep is non-zero.
*/
UserFunc *sqliteFindUserFunction(
sqlite *db, /* An open database */
const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */
int nArg, /* Number of arguments. -1 means any number */
int createFlag /* Create new entry if true and does not otherwise exist */
){
UserFunc *pFirst, *p, *pMaybe;
pFirst = p = (UserFunc*)sqliteHashFind(&db->userFunc, zName, nName);
if( !createFlag && nArg<0 ){
while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
return p;
}
pMaybe = 0;
while( p && p->nArg!=nArg ){
if( p->nArg<0 && !createFlag && (p->xFunc || p->xStep) ) pMaybe = p;
p = p->pNext;
}
if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){
return 0;
}
if( p==0 && pMaybe ){
assert( createFlag==0 );
return pMaybe;
}
if( p==0 && createFlag ){
p = sqliteMalloc( sizeof(*p) );
p->nArg = nArg;
p->pNext = pFirst;
sqliteHashInsert(&db->userFunc, zName, nName, (void*)p);
}
return p;
}