aboutsummaryrefslogtreecommitdiff
path: root/src/func.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/func.c')
-rw-r--r--src/func.c135
1 files changed, 99 insertions, 36 deletions
diff --git a/src/func.c b/src/func.c
index c58bf2186..43ee45899 100644
--- a/src/func.c
+++ b/src/func.c
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
-** $Id: func.c,v 1.103 2005/08/13 03:07:47 drh Exp $
+** $Id: func.c,v 1.104 2005/08/14 01:20:38 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -26,6 +26,9 @@
#include "vdbeInt.h"
#include "os.h"
+/*
+** Return the collating function associated with a function.
+*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
return context->pColl;
}
@@ -308,16 +311,14 @@ struct compareInfo {
u8 matchSet;
u8 noCase;
};
+
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
-#ifndef SQLITE_CASE_SENSITIVE_LIKE
- /* The correct SQL-92 behavior is for the LIKE operator to ignore
- ** case. Thus 'a' LIKE 'A' would be true. */
- static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
-#else
- /* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
- ** is case sensitive causing 'a' LIKE 'A' to be false */
- static const struct compareInfo likeInfo = { '%', '_', 0, 0 };
-#endif
+/* The correct SQL-92 behavior is for the LIKE operator to ignore
+** case. Thus 'a' LIKE 'A' would be true. */
+static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
+/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
+** is case sensitive causing 'a' LIKE 'A' to be false */
+static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
** X is a pointer to the first byte of a UTF-8 character. Increment
@@ -459,6 +460,15 @@ static int patternCompare(
return *zString==0;
}
+/*
+** Count the number of times that the LIKE operator (or GLOB which is
+** just a variation of LIKE) gets called. This is used for testing
+** only.
+*/
+#ifdef SQLITE_TEST
+int sqlite3_like_count = 0;
+#endif
+
/*
** Implementation of the like() SQL function. This function implements
@@ -469,8 +479,8 @@ static int patternCompare(
**
** is implemented as like(B,A).
**
-** If the pointer retrieved by via a call to sqlite3_user_data() is
-** not NULL, then this function uses UTF-16. Otherwise UTF-8.
+** This same function (with a different compareInfo structure) computes
+** the GLOB operator.
*/
static void likeFunc(
sqlite3_context *context,
@@ -493,24 +503,11 @@ static void likeFunc(
escape = sqlite3ReadUtf8(zEsc);
}
if( zA && zB ){
- sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo, escape));
- }
-}
-
-/*
-** Implementation of the glob() SQL function. This function implements
-** the build-in GLOB operator. The first argument to the function is the
-** string and the second argument is the pattern. So, the SQL statements:
-**
-** A GLOB B
-**
-** is implemented as glob(B,A).
-*/
-static void globFunc(sqlite3_context *context, int arg, sqlite3_value **argv){
- const unsigned char *zA = sqlite3_value_text(argv[0]);
- const unsigned char *zB = sqlite3_value_text(argv[1]);
- if( zA && zB ){
- sqlite3_result_int(context, patternCompare(zA, zB, &globInfo, 0));
+ struct compareInfo *pInfo = sqlite3_user_data(context);
+#ifdef SQLITE_TEST
+ sqlite3_like_count++;
+#endif
+ sqlite3_result_int(context, patternCompare(zA, zB, pInfo, escape));
}
}
@@ -971,9 +968,6 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
- { "like", 2, 0, SQLITE_UTF8, 0, likeFunc },
- { "like", 3, 0, SQLITE_UTF8, 0, likeFunc },
- { "glob", 2, 0, SQLITE_UTF8, 0, globFunc },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
@@ -1045,8 +1039,77 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
sqlite3RegisterDateTimeFunctions(db);
#ifdef SQLITE_SSE
- {
- sqlite3SseFunctions(db);
- }
+ sqlite3SseFunctions(db);
#endif
+#ifdef SQLITE_CASE_SENSITIVE_LIKE
+ sqlite3RegisterLikeFunctions(db, 1);
+#else
+ sqlite3RegisterLikeFunctions(db, 0);
+#endif
+}
+
+/*
+** Set the LIKEOPT flag on the 2-argument function with the given name.
+*/
+static void setLikeOptFlag(sqlite3 *db, const char *zName){
+ FuncDef *pDef;
+ pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
+ if( pDef ){
+ pDef->flags = SQLITE_FUNC_LIKEOPT;
+ }
+}
+
+/*
+** Register the built-in LIKE and GLOB functions. The caseSensitive
+** parameter determines whether or not the LIKE operator is case
+** sensitive. GLOB is always case sensitive.
+*/
+void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
+ struct compareInfo *pInfo;
+ if( caseSensitive ){
+ pInfo = (struct compareInfo*)&likeInfoAlt;
+ }else{
+ pInfo = (struct compareInfo*)&likeInfoNorm;
+ }
+ sqlite3_create_function(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+ sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
+ sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
+ (struct compareInfo*)&globInfo, likeFunc, 0,0);
+ setLikeOptFlag(db, "glob");
+ if( caseSensitive ){
+ setLikeOptFlag(db, "like");
+ }
+}
+
+/*
+** pExpr points to an expression which implements a function. If
+** it is appropriate to apply the LIKE optimization to that function
+** then set aWc[0] through aWc[2] to the wildcard characters and
+** return TRUE. If the function is not a LIKE-style function then
+** return FALSE.
+*/
+int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
+ FuncDef *pDef;
+ if( pExpr->op!=TK_FUNCTION ){
+ return 0;
+ }
+ if( pExpr->pList->nExpr!=2 ){
+ return 0;
+ }
+ pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
+ SQLITE_UTF8, 0);
+ if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKEOPT)==0 ){
+ return 0;
+ }
+
+ /* The memcpy() statement assumes that the wildcard characters are
+ ** the first three statements in the compareInfo structure. The
+ ** asserts() that follow verify that assumption
+ */
+ memcpy(aWc, pDef->pUserData, 3);
+ assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
+ assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
+ assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
+
+ return 1;
}