Enhance user function API to support association of meta-data with constant
arguments and the specification of text encoding preference. The LIKE
operator takes advantage of both. (CVS 1534)
FossilOrigin-Name: 92337d8f79b9754cd61c73e7db2e792a1f482f50
diff --git a/src/expr.c b/src/expr.c
index b3ba9f4..dd2a8ce 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -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.134 2004/06/05 10:22:17 danielk1977 Exp $
+** $Id: expr.c,v 1.135 2004/06/06 09:44:04 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -968,11 +968,12 @@
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef;
+ int iPrefEnc = (pParse->db->enc==TEXT_Utf8)?0:1;
getFunctionName(pExpr, &zId, &nId);
- pDef = sqlite3FindFunction(pParse->db, zId, nId, n, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, n, iPrefEnc, 0);
if( pDef==0 ){
- pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, iPrefEnc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{
@@ -1233,12 +1234,15 @@
const char *zId;
int p2 = 0;
int i;
+ int iPrefEnc = (pParse->db->enc==TEXT_Utf8)?0:1;
getFunctionName(pExpr, &zId, &nId);
- pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, iPrefEnc, 0);
assert( pDef!=0 );
nExpr = sqlite3ExprCodeExprList(pParse, pList);
for(i=0; i<nExpr && i<32; i++){
- p2 &= (1<<i);
+ if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
+ p2 |= (1<<i);
+ }
}
sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
break;
@@ -1645,13 +1649,14 @@
}
}
if( i>=pParse->nAgg ){
+ int iPrefEnc = (pParse->db->enc==TEXT_Utf8)?0:1;
i = appendAggInfo(pParse);
if( i<0 ) return 1;
pParse->aAgg[i].isAgg = 1;
pParse->aAgg[i].pExpr = pExpr;
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
pExpr->token.z, pExpr->token.n,
- pExpr->pList ? pExpr->pList->nExpr : 0, 0);
+ pExpr->pList ? pExpr->pList->nExpr : 0, iPrefEnc, 0);
}
pExpr->iAgg = i;
break;
@@ -1677,9 +1682,10 @@
}
/*
-** Locate a user function given a name and a number of arguments.
-** Return a pointer to the FuncDef structure that defines that
-** function, or return NULL if the function does not exist.
+** Locate a user function given a name, a number of arguments and a flag
+** indicating whether the function prefers UTF-16 over UTF-8. Return a
+** pointer to the FuncDef structure that defines that function, or return
+** NULL if the function does not exist.
**
** If the createFlag argument is true, then a new (blank) FuncDef
** structure is created and liked into the "db" structure if a
@@ -1690,39 +1696,70 @@
** 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.
+**
+** If createFlag is false, then a function with the required name and
+** number of arguments may be returned even if the eTextRep flag does not
+** match that requested.
*/
FuncDef *sqlite3FindFunction(
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 eTextRep, /* True to retrieve UTF-16 versions. */
int createFlag /* Create new entry if true and does not otherwise exist */
){
- FuncDef *pFirst, *p, *pMaybe;
- pFirst = p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
- if( p && !createFlag && nArg<0 ){
- while( p && p->xFunc==0 && p->xStep==0 ){ p = p->pNext; }
- return p;
+ FuncDef *p; /* Iterator variable */
+ FuncDef *pFirst; /* First function with this name */
+ FuncDef *pBest = 0; /* Best match found so far */
+ int matchqual = 0;
+
+ /* Normalize argument values to simplify comparisons below. */
+ if( eTextRep ) eTextRep = 1;
+ if( nArg<-1 ) nArg = -1;
+
+ pFirst = (FuncDef*)sqlite3HashFind(&db->aFunc, zName, nName);
+ for(p=pFirst; p; p=p->pNext){
+ if( 1 || p->xFunc || p->xStep ){
+ if( p->nArg==nArg && p->iPrefEnc==eTextRep ){
+ /* A perfect match. */
+ pBest = p;
+ matchqual = 4;
+ break;
+ }
+ if( p->nArg==nArg ){
+ /* Number of arguments matches, but not the text encoding */
+ pBest = p;
+ matchqual = 3;
+ }
+ else if( (p->nArg<0) || (nArg<0) ){
+ if( matchqual<2 && p->iPrefEnc==eTextRep ){
+ /* Matched a varargs function with correct text encoding */
+ pBest = p;
+ matchqual = 2;
+ }
+ if( matchqual<1 ){
+ /* Matched a varargs function with incorrect text encoding */
+ pBest = p;
+ matchqual = 1;
+ }
+ }
+ }
}
- pMaybe = 0;
- while( p && p->nArg!=nArg ){
- if( p->nArg<0 && !createFlag && (p->xFunc || p->xStep) ) pMaybe = p;
- p = p->pNext;
+
+ if( createFlag && matchqual<4 &&
+ (pBest = sqliteMalloc(sizeof(*pBest)+nName+1)) ){
+ pBest->nArg = nArg;
+ pBest->pNext = pFirst;
+ pBest->zName = (char*)&pBest[1];
+ memcpy(pBest->zName, zName, nName);
+ pBest->zName[nName] = 0;
+ sqlite3HashInsert(&db->aFunc, pBest->zName, nName, (void*)pBest);
}
- if( p && !createFlag && p->xFunc==0 && p->xStep==0 ){
- return 0;
+
+ if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
+ return pBest;
}
- if( p==0 && pMaybe ){
- assert( createFlag==0 );
- return pMaybe;
- }
- if( p==0 && createFlag && (p = sqliteMalloc(sizeof(*p)+nName+1))!=0 ){
- p->nArg = nArg;
- p->pNext = pFirst;
- p->zName = (char*)&p[1];
- memcpy(p->zName, zName, nName);
- p->zName[nName] = 0;
- sqlite3HashInsert(&db->aFunc, p->zName, nName, (void*)p);
- }
- return p;
+ return 0;
}
+