mirror of https://github.com/sqlite/sqlite
Combine the implementation of LIKE and GLOB into a single parameterized
function. (CVS 1923) FossilOrigin-Name: 0a47c8f86d1649e9ae7edd4c49a6fe5f5272351e
This commit is contained in:
parent
ee696e2218
commit
4e5ffc5f8d
18
manifest
18
manifest
|
@ -1,5 +1,5 @@
|
|||
C Better\sdetection\sand\shandling\sof\scorrupt\sdatabase\sfiles.\s(CVS\s1922)
|
||||
D 2004-08-30T16:52:18
|
||||
C Combine\sthe\simplementation\sof\sLIKE\sand\sGLOB\sinto\sa\ssingle\sparameterized\nfunction.\s(CVS\s1923)
|
||||
D 2004-08-31T00:52:37
|
||||
F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
|
@ -35,7 +35,7 @@ F src/date.c edff4aa851eeca8abbc737dc3933a2f0671156ce
|
|||
F src/delete.c 0ccc3424d72e5aaded165a8861b9d958c9d0afe6
|
||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||
F src/expr.c 3694386726ca140dddb839837ba24b58563d10af
|
||||
F src/func.c 7e2eeebe219aa612ce7a04c74ae6d57379c6656b
|
||||
F src/func.c ab1d6436edea1333f2a9398800a6404942661724
|
||||
F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c fc1ce65a0fe68f226143de9b43c3582164a92aff
|
||||
|
@ -61,7 +61,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
|||
F src/select.c 400b2dcc8e05c0101a65a370f7ebb33c9c85f0b3
|
||||
F src/shell.c 64932b37d79baffd34544172c14c99b2e08a11bb
|
||||
F src/sqlite.h.in b89ced1acc705bc9c79a2a4e725ac0eb64bd0614
|
||||
F src/sqliteInt.h c7ed161ecc40f9fd0f080fbcc00e34bd7d6735ee
|
||||
F src/sqliteInt.h 89c1555ceba68d460ee13530eb8a51944e57fad2
|
||||
F src/table.c 4521c278892f60e4d630788c0ea5cf4db1e75c49
|
||||
F src/tclsqlite.c b7dd8b3531b70188d03354db530de0f2ffcac697
|
||||
F src/test1.c 3670f318c473b5a81cae548d9cc42da3f6a6efee
|
||||
|
@ -72,8 +72,8 @@ F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1
|
|||
F src/tokenize.c 32171c3d576c7ec6acd6cf15e55c00ac0b314769
|
||||
F src/trigger.c 8b147c6b8ae0bab3a13463a4ca9ab6ad61f1361d
|
||||
F src/update.c 151f1869ce532ed883f1ce26306f0b0fa7b2589a
|
||||
F src/utf.c 3d8f7bffcbefcced69a436c9e0a1c7eb9e0bb4fa
|
||||
F src/util.c e2c631849cc9e035f6fd387f507ad8886f77cedd
|
||||
F src/utf.c 328890099db492dda5620ee5f924e244c6e57ff7
|
||||
F src/util.c d5aaf211543fb6e285654fada50252c857ac78aa
|
||||
F src/vacuum.c 9978a5760c2c430bc5b5e66505a02dad76f25813
|
||||
F src/vdbe.c bc7717be599d23c463c029d13eb2eb46c94a5e6e
|
||||
F src/vdbe.h e081c72cd0f7c19d49b1927460aeefcf0fbc85ac
|
||||
|
@ -246,7 +246,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
|
|||
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P 9322c439c5727f0d65548efdf4de4d7b89b4be66
|
||||
R 78b9eb3fdca60240e1b2bb671f0502fe
|
||||
P 8f5b199e845fa7ae3444ef69bd840716d305cf73
|
||||
R 616cb374fb9c8575e09ed1273dacb01d
|
||||
U drh
|
||||
Z b8b12d29336c5de9dba049e2bc96808c
|
||||
Z 33bccfa82a63e9342b9c97917948d9a3
|
||||
|
|
|
@ -1 +1 @@
|
|||
8f5b199e845fa7ae3444ef69bd840716d305cf73
|
||||
0a47c8f86d1649e9ae7edd4c49a6fe5f5272351e
|
348
src/func.c
348
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.80 2004/08/08 20:22:18 drh Exp $
|
||||
** $Id: func.c,v 1.81 2004/08/31 00:52:37 drh Exp $
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
@ -298,250 +298,145 @@ static void total_changes(
|
|||
sqlite3_result_int(context, sqlite3_total_changes(db));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/*
|
||||
** A LIKE pattern compiles to an instance of the following structure. Refer
|
||||
** to the comment for compileLike() function for details.
|
||||
** A structure defining how to do GLOB-style comparisons.
|
||||
*/
|
||||
struct LikePattern {
|
||||
int nState;
|
||||
struct LikeState {
|
||||
int val; /* Unicode codepoint or -1 for any char i.e. '_' */
|
||||
int failstate; /* State to jump to if next char is not val */
|
||||
} aState[1];
|
||||
struct compareInfo {
|
||||
u8 matchAll;
|
||||
u8 matchOne;
|
||||
u8 matchSet;
|
||||
u8 noCase;
|
||||
};
|
||||
typedef struct LikePattern LikePattern;
|
||||
|
||||
void deleteLike(void *pLike){
|
||||
sqliteFree(pLike);
|
||||
}
|
||||
/* #define TRACE_LIKE */
|
||||
#if defined(TRACE_LIKE) && !defined(NDEBUG)
|
||||
char *dumpLike(LikePattern *pLike){
|
||||
int i;
|
||||
int k = 0;
|
||||
char *zBuf = (char *)sqliteMalloc(pLike->nState*40);
|
||||
|
||||
k += sprintf(&zBuf[k], "%d states - ", pLike->nState);
|
||||
for(i=0; i<pLike->nState; i++){
|
||||
k += sprintf(&zBuf[k], " %d:(%d, %d)", i, pLike->aState[i].val,
|
||||
pLike->aState[i].failstate);
|
||||
}
|
||||
return zBuf;
|
||||
}
|
||||
#endif
|
||||
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
|
||||
static const struct compareInfo likeInfo = { '%', '_', 0, 1 };
|
||||
|
||||
/*
|
||||
** This function compiles an SQL 'LIKE' pattern into a state machine,
|
||||
** represented by a LikePattern structure.
|
||||
**
|
||||
** Each state of the state-machine has two attributes, 'val' and
|
||||
** 'failstate'. The val attribute is either the value of a unicode
|
||||
** codepoint, or -1, indicating a '_' wildcard (match any single
|
||||
** character). The failstate is either the number of another state
|
||||
** or -1, indicating jump to 'no match'.
|
||||
**
|
||||
** To see if a string matches a pattern the pattern is
|
||||
** compiled to a state machine that is executed according to the algorithm
|
||||
** below. The string is assumed to be terminated by a 'NUL' character
|
||||
** (unicode codepoint 0).
|
||||
**
|
||||
** 1 S = 0
|
||||
** 2 DO
|
||||
** 3 C = <Next character from input string>
|
||||
** 4 IF( C matches <State S val> )
|
||||
** 5 S = S+1
|
||||
** 6 ELSE IF( S != <State S failstate> )
|
||||
** 7 S = <State S failstate>
|
||||
** 8 <Rewind Input string 1 character>
|
||||
** 9 WHILE( (C != NUL) AND (S != FAILED) )
|
||||
** 10
|
||||
** 11 IF( S == <number of states> )
|
||||
** 12 RETURN MATCH
|
||||
** 13 ELSE
|
||||
** 14 RETURN NO-MATCH
|
||||
**
|
||||
** In practice there is a small optimization to avoid the <Rewind>
|
||||
** operation in line 8 of the description above.
|
||||
**
|
||||
** For example, the following pattern, 'X%ABabc%_Y' is compiled to
|
||||
** the state machine below.
|
||||
**
|
||||
** State Val FailState
|
||||
** -------------------------------
|
||||
** 0 120 (x) -1 (NO MATCH)
|
||||
** 1 97 (a) 1
|
||||
** 2 98 (b) 1
|
||||
** 3 97 (a) 1
|
||||
** 4 98 (b) 2
|
||||
** 5 99 (c) 3
|
||||
** 6 -1 (_) 6
|
||||
** 7 121 (y) 7
|
||||
** 8 0 (NUL) 7
|
||||
**
|
||||
** The algorithms implemented to compile and execute the state machine were
|
||||
** first presented in "Fast pattern matching in strings", Knuth, Morris and
|
||||
** Pratt, 1977.
|
||||
**
|
||||
** X is a pointer to the first byte of a UTF-8 character. Increment
|
||||
** X so that it points to the next character. This only works right
|
||||
** if X points to a well-formed UTF-8 string.
|
||||
*/
|
||||
LikePattern *compileLike(sqlite3_value *pPattern, u8 enc){
|
||||
LikePattern *pLike;
|
||||
struct LikeState *aState;
|
||||
int pc_state = -1; /* State number of previous '%' wild card */
|
||||
int n = 0;
|
||||
int c;
|
||||
#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
|
||||
#define sqliteCharVal(X) sqlite3ReadUtf8(X)
|
||||
|
||||
int offset = 0;
|
||||
const char *zLike;
|
||||
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
zLike = sqlite3_value_text(pPattern);
|
||||
n = sqlite3_value_bytes(pPattern) + 1;
|
||||
}else{
|
||||
zLike = sqlite3_value_text16(pPattern);
|
||||
n = sqlite3_value_bytes16(pPattern)/2 + 1;
|
||||
}
|
||||
|
||||
pLike = (LikePattern *)
|
||||
sqliteMalloc(sizeof(LikePattern)+n*sizeof(struct LikeState));
|
||||
aState = pLike->aState;
|
||||
|
||||
n = 0;
|
||||
do {
|
||||
c = sqlite3ReadUniChar(zLike, &offset, &enc, 1);
|
||||
if( c==95 ){ /* A '_' wildcard */
|
||||
aState[n].val = -1;
|
||||
n++;
|
||||
}else if( c==37 ){ /* A '%' wildcard */
|
||||
aState[n].failstate = n;
|
||||
pc_state = n;
|
||||
}else{ /* A regular character */
|
||||
aState[n].val = c;
|
||||
|
||||
assert( pc_state<=n );
|
||||
if( pc_state<0 ){
|
||||
aState[n].failstate = -1;
|
||||
}else if( pc_state==n ){
|
||||
if( c ){
|
||||
aState[n].failstate = pc_state;
|
||||
}else{
|
||||
aState[n].failstate = -2;
|
||||
}
|
||||
}else{
|
||||
int k = pLike->aState[n-1].failstate;
|
||||
while( k>pc_state && aState[k+1].val!=-1 && aState[k+1].val!=c ){
|
||||
k = aState[k].failstate;
|
||||
}
|
||||
if( k!=pc_state && aState[k+1].val==c ){
|
||||
assert( k==pc_state );
|
||||
k++;
|
||||
}
|
||||
aState[n].failstate = k;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}while( c );
|
||||
pLike->nState = n;
|
||||
#if defined(TRACE_LIKE) && !defined(NDEBUG)
|
||||
{
|
||||
char *zCompiled = dumpLike(pLike);
|
||||
printf("Pattern=\"%s\" Compiled=\"%s\"\n", zPattern, zCompiled);
|
||||
sqliteFree(zCompiled);
|
||||
}
|
||||
#endif
|
||||
return pLike;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the like() SQL function. This function implements
|
||||
** the build-in LIKE operator. The first argument to the function is the
|
||||
** pattern and the second argument is the string. So, the SQL statements:
|
||||
** Compare two UTF-8 strings for equality where the first string can
|
||||
** potentially be a "glob" expression. Return true (1) if they
|
||||
** are the same and false (0) if they are different.
|
||||
**
|
||||
** A LIKE B
|
||||
** Globbing rules:
|
||||
**
|
||||
** is implemented as like(B,A).
|
||||
** '*' Matches any sequence of zero or more characters.
|
||||
**
|
||||
** If the pointer retrieved by via a call to sqlite3_user_data() is
|
||||
** not NULL, then this function uses UTF-16. Otherwise UTF-8.
|
||||
** '?' Matches exactly one character.
|
||||
**
|
||||
** [...] Matches one character from the enclosed list of
|
||||
** characters.
|
||||
**
|
||||
** [^...] Matches one character not in the enclosed list.
|
||||
**
|
||||
** With the [...] and [^...] matching, a ']' character can be included
|
||||
** in the list by making it the first character after '[' or '^'. A
|
||||
** range of characters can be specified using '-'. Example:
|
||||
** "[a-z]" matches any single lower-case letter. To match a '-', make
|
||||
** it the last character in the list.
|
||||
**
|
||||
** This routine is usually quick, but can be N**2 in the worst case.
|
||||
**
|
||||
** Hints: to match '*' or '?', put them in "[]". Like this:
|
||||
**
|
||||
** abc[*]xyz Matches "abc*xyz" only
|
||||
*/
|
||||
static void likeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
int patternCompare(
|
||||
const u8 *zPattern, /* The glob pattern */
|
||||
const u8 *zString, /* The string to compare against the glob */
|
||||
const struct compareInfo *pInfo /* Information about how to do the compare */
|
||||
){
|
||||
register int c;
|
||||
u8 enc;
|
||||
int offset = 0;
|
||||
const unsigned char *zString;
|
||||
LikePattern *pLike = sqlite3_get_auxdata(context, 0);
|
||||
struct LikeState *aState;
|
||||
register struct LikeState *pState;
|
||||
int invert;
|
||||
int seen;
|
||||
int c2;
|
||||
u8 matchOne = pInfo->matchOne;
|
||||
u8 matchAll = pInfo->matchAll;
|
||||
u8 matchSet = pInfo->matchSet;
|
||||
u8 noCase = pInfo->noCase;
|
||||
|
||||
/* If either argument is NULL, the result is NULL */
|
||||
if( sqlite3_value_type(argv[1])==SQLITE_NULL ||
|
||||
sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the user-data pointer is NULL, use UTF-8. Otherwise UTF-16. */
|
||||
if( sqlite3_user_data(context) ){
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
zString = (const unsigned char *)sqlite3_value_text16(argv[1]);
|
||||
assert(0);
|
||||
}else{
|
||||
enc = SQLITE_UTF8;
|
||||
zString = sqlite3_value_text(argv[1]);
|
||||
}
|
||||
|
||||
/* If the LIKE pattern has not been compiled, compile it now. */
|
||||
if( !pLike ){
|
||||
pLike = compileLike(argv[0], enc);
|
||||
if( !pLike ){
|
||||
sqlite3_result_error(context, "out of memory", -1);
|
||||
return;
|
||||
}
|
||||
sqlite3_set_auxdata(context, 0, pLike, deleteLike);
|
||||
}
|
||||
aState = pLike->aState;
|
||||
pState = aState;
|
||||
|
||||
do {
|
||||
if( enc==SQLITE_UTF8 ){
|
||||
c = zString[offset++];
|
||||
if( c&0x80 ){
|
||||
offset--;
|
||||
c = sqlite3ReadUniChar(zString, &offset, &enc, 1);
|
||||
while( (c = *zPattern)!=0 ){
|
||||
if( c==matchAll ){
|
||||
while( (c=zPattern[1]) == matchAll || c == matchOne ){
|
||||
if( c==matchOne ){
|
||||
if( *zString==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
zPattern++;
|
||||
}
|
||||
}else{
|
||||
c = sqlite3ReadUniChar(zString, &offset, &enc, 1);
|
||||
}
|
||||
|
||||
skip_read:
|
||||
|
||||
#if defined(TRACE_LIKE) && !defined(NDEBUG)
|
||||
printf("State=%d:(%d, %d) Input=%d\n",
|
||||
(aState - pState), pState->val, pState->failstate, c);
|
||||
#endif
|
||||
|
||||
if( pState->val==-1 || pState->val==c ){
|
||||
pState++;
|
||||
}else{
|
||||
struct LikeState *pFailState = &aState[pState->failstate];
|
||||
if( pState!=pFailState ){
|
||||
pState = pFailState;
|
||||
if( c && pState>=aState ) goto skip_read;
|
||||
if( c==0 ) return 1;
|
||||
if( c==matchSet ){
|
||||
while( *zString && patternCompare(&zPattern[1],zString,pInfo)==0 ){
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return *zString!=0;
|
||||
}else{
|
||||
while( (c2 = *zString)!=0 ){
|
||||
if( noCase ){
|
||||
c2 = sqlite3UpperToLower[c2];
|
||||
c = sqlite3UpperToLower[c];
|
||||
while( c2 != 0 && c2 != c ){ c2 = sqlite3UpperToLower[*++zString]; }
|
||||
}else{
|
||||
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
|
||||
}
|
||||
if( c2==0 ) return 0;
|
||||
if( patternCompare(&zPattern[1],zString,pInfo) ) return 1;
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}else if( c==matchOne ){
|
||||
if( *zString==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
}else if( c==matchSet ){
|
||||
int prior_c = 0;
|
||||
seen = 0;
|
||||
invert = 0;
|
||||
c = sqliteCharVal(zString);
|
||||
if( c==0 ) return 0;
|
||||
c2 = *++zPattern;
|
||||
if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
|
||||
if( c2==']' ){
|
||||
if( c==']' ) seen = 1;
|
||||
c2 = *++zPattern;
|
||||
}
|
||||
while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
|
||||
if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
|
||||
zPattern++;
|
||||
c2 = sqliteCharVal(zPattern);
|
||||
if( c>=prior_c && c<=c2 ) seen = 1;
|
||||
prior_c = 0;
|
||||
}else if( c==c2 ){
|
||||
seen = 1;
|
||||
prior_c = c2;
|
||||
}else{
|
||||
prior_c = c2;
|
||||
}
|
||||
sqliteNextChar(zPattern);
|
||||
}
|
||||
if( c2==0 || (seen ^ invert)==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
}else{
|
||||
if( noCase ){
|
||||
if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
|
||||
}else{
|
||||
if( c != *zString ) return 0;
|
||||
}
|
||||
zPattern++;
|
||||
zString++;
|
||||
}
|
||||
}while( c && pState>=aState );
|
||||
|
||||
if( (pState-aState)==pLike->nState || (pState-aState)<-1 ){
|
||||
sqlite3_result_int(context, 1);
|
||||
}else{
|
||||
sqlite3_result_int(context, 0);
|
||||
}
|
||||
return *zString==0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Implementation of the like() SQL function. This function implements
|
||||
|
@ -563,7 +458,7 @@ static void likeFunc(
|
|||
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, sqlite3utf8LikeCompare(zA, zB));
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &likeInfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,7 +475,7 @@ 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, sqlite3GlobCompare(zA, zB));
|
||||
sqlite3_result_int(context, patternCompare(zA, zB, &globInfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1016,6 +911,7 @@ static void minMaxFinalize(sqlite3_context *context){
|
|||
sqlite3VdbeMemRelease(pRes);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.316 2004/08/21 17:54:45 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.317 2004/08/31 00:52:37 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
|
@ -1270,7 +1270,6 @@ void sqlite3UnlinkAndDeleteIndex(sqlite*,int,const char*);
|
|||
void sqlite3UnlinkAndDeleteTrigger(sqlite*,int,const char*);
|
||||
void sqlite3Vacuum(Parse*, Token*);
|
||||
int sqlite3RunVacuum(char**, sqlite*);
|
||||
int sqlite3GlobCompare(const unsigned char*,const unsigned char*);
|
||||
char *sqlite3NameFromToken(Token*);
|
||||
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
|
@ -1354,7 +1353,7 @@ int sqlite3GetInt32(const char *, int*);
|
|||
int sqlite3FitsIn64Bits(const char *);
|
||||
int sqlite3utf16ByteLen(const void *pData, int nChar);
|
||||
int sqlite3utf8CharLen(const char *pData, int nByte);
|
||||
int sqlite3utf8LikeCompare(const unsigned char*, const unsigned char*);
|
||||
int sqlite3ReadUtf8(const unsigned char *);
|
||||
int sqlite3PutVarint(unsigned char *, u64);
|
||||
int sqlite3GetVarint(const unsigned char *, u64 *);
|
||||
int sqlite3GetVarint32(const unsigned char *, u32 *);
|
||||
|
@ -1388,5 +1387,6 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
|||
void sqlite3ValueFree(sqlite3_value*);
|
||||
sqlite3_value *sqlite3ValueNew();
|
||||
sqlite3_value *sqlite3GetTransientValue(sqlite *db);
|
||||
extern const unsigned char sqlite3UpperToLower[];
|
||||
|
||||
#endif
|
||||
|
|
81
src/utf.c
81
src/utf.c
|
@ -12,7 +12,7 @@
|
|||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.27 2004/08/08 23:39:19 drh Exp $
|
||||
** $Id: utf.c,v 1.28 2004/08/31 00:52:37 drh Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
|
@ -62,27 +62,6 @@
|
|||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** The following macro, LOWERCASE(x), takes an integer representing a
|
||||
** unicode code point. The value returned is the same code point folded to
|
||||
** lower case, if applicable. SQLite currently understands the upper/lower
|
||||
** case relationship between the 26 characters used in the English
|
||||
** language only.
|
||||
**
|
||||
** This means that characters with umlauts etc. will not be folded
|
||||
** correctly (unless they are encoded as composite characters, which would
|
||||
** doubtless cause much trouble).
|
||||
*/
|
||||
#define LOWERCASE(x) (x<91?(int)(UpperToLower[x]):x)
|
||||
static unsigned char UpperToLower[91] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
|
||||
122,
|
||||
};
|
||||
|
||||
/*
|
||||
** This table maps from the first byte of a UTF-8 character to the number
|
||||
** of trailing bytes expected. A value '255' indicates that the table key
|
||||
|
@ -141,6 +120,11 @@ static const int xtra_utf8_bits[4] = {
|
|||
c -= xtra_utf8_bits[xtra]; \
|
||||
} \
|
||||
}
|
||||
int sqlite3ReadUtf8(const unsigned char *z){
|
||||
int c;
|
||||
READ_UTF8(z, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define SKIP_UTF8(zIn) { \
|
||||
zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \
|
||||
|
@ -491,59 +475,6 @@ int sqlite3utf16ByteLen(const void *zIn, int nChar){
|
|||
return (z-(char const *)zIn)-((c==0)?2:0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare two UTF-8 strings for equality using the "LIKE" operator of
|
||||
** SQL. The '%' character matches any sequence of 0 or more
|
||||
** characters and '_' matches any single character. Case is
|
||||
** not significant.
|
||||
*/
|
||||
int sqlite3utf8LikeCompare(
|
||||
const unsigned char *zPattern,
|
||||
const unsigned char *zString
|
||||
){
|
||||
register int c;
|
||||
int c2;
|
||||
|
||||
while( (c = LOWERCASE(*zPattern))!=0 ){
|
||||
switch( c ){
|
||||
case '%': {
|
||||
while( (c=zPattern[1]) == '%' || c == '_' ){
|
||||
if( c=='_' ){
|
||||
if( *zString==0 ) return 0;
|
||||
SKIP_UTF8(zString);
|
||||
}
|
||||
zPattern++;
|
||||
}
|
||||
if( c==0 ) return 1;
|
||||
c = LOWERCASE(c);
|
||||
while( (c2=LOWERCASE(*zString))!=0 ){
|
||||
while( c2 != 0 && c2 != c ){
|
||||
zString++;
|
||||
c2 = LOWERCASE(*zString);
|
||||
}
|
||||
if( c2==0 ) return 0;
|
||||
if( sqlite3utf8LikeCompare(&zPattern[1],zString) ) return 1;
|
||||
SKIP_UTF8(zString);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case '_': {
|
||||
if( *zString==0 ) return 0;
|
||||
SKIP_UTF8(zString);
|
||||
zPattern++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( c != LOWERCASE(*zString) ) return 0;
|
||||
zPattern++;
|
||||
zString++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *zString==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** UTF-16 implementation of the substr()
|
||||
*/
|
||||
|
|
167
src/util.c
167
src/util.c
|
@ -14,7 +14,7 @@
|
|||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.113 2004/08/18 02:10:15 drh Exp $
|
||||
** $Id: util.c,v 1.114 2004/08/31 00:52:37 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
|
@ -533,7 +533,7 @@ void sqlite3Dequote(char *z){
|
|||
/* An array to map all upper-case characters into their corresponding
|
||||
** lower-case character.
|
||||
*/
|
||||
static unsigned char UpperToLower[] = {
|
||||
const unsigned char sqlite3UpperToLower[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
|
@ -550,6 +550,7 @@ static unsigned char UpperToLower[] = {
|
|||
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
252,253,254,255
|
||||
};
|
||||
#define UpperToLower sqlite3UpperToLower
|
||||
|
||||
/*
|
||||
** This function computes a hash on the name of a keyword.
|
||||
|
@ -762,168 +763,6 @@ int sqlite3FitsIn64Bits(const char *zNum){
|
|||
return i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0);
|
||||
}
|
||||
|
||||
#if 1 /* We are now always UTF-8 */
|
||||
/*
|
||||
** X is a pointer to the first byte of a UTF-8 character. Increment
|
||||
** X so that it points to the next character. This only works right
|
||||
** if X points to a well-formed UTF-8 string.
|
||||
*/
|
||||
#define sqliteNextChar(X) while( (0xc0&*++(X))==0x80 ){}
|
||||
#define sqliteCharVal(X) sqlite3ReadUtf8(X)
|
||||
|
||||
#else /* !defined(SQLITE_UTF8) */
|
||||
/*
|
||||
** For iso8859 encoding, the next character is just the next byte.
|
||||
*/
|
||||
#define sqliteNextChar(X) (++(X));
|
||||
#define sqliteCharVal(X) ((int)*(X))
|
||||
|
||||
#endif /* defined(SQLITE_UTF8) */
|
||||
|
||||
|
||||
#if 1 /* We are now always UTF-8 */
|
||||
/*
|
||||
** Convert the UTF-8 character to which z points into a 31-bit
|
||||
** UCS character. This only works right if z points to a well-formed
|
||||
** UTF-8 string.
|
||||
*/
|
||||
int sqlite3ReadUtf8(const unsigned char *z){
|
||||
int c;
|
||||
static const char initVal[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
||||
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
||||
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
|
||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
||||
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
|
||||
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
||||
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
|
||||
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
||||
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 0, 1, 2,
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 0, 1, 254,
|
||||
255,
|
||||
};
|
||||
c = initVal[*(z++)];
|
||||
while( (0xc0&*z)==0x80 ){
|
||||
c = (c<<6) | (0x3f&*(z++));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Compare two UTF-8 strings for equality where the first string can
|
||||
** potentially be a "glob" expression. Return true (1) if they
|
||||
** are the same and false (0) if they are different.
|
||||
**
|
||||
** Globbing rules:
|
||||
**
|
||||
** '*' Matches any sequence of zero or more characters.
|
||||
**
|
||||
** '?' Matches exactly one character.
|
||||
**
|
||||
** [...] Matches one character from the enclosed list of
|
||||
** characters.
|
||||
**
|
||||
** [^...] Matches one character not in the enclosed list.
|
||||
**
|
||||
** With the [...] and [^...] matching, a ']' character can be included
|
||||
** in the list by making it the first character after '[' or '^'. A
|
||||
** range of characters can be specified using '-'. Example:
|
||||
** "[a-z]" matches any single lower-case letter. To match a '-', make
|
||||
** it the last character in the list.
|
||||
**
|
||||
** This routine is usually quick, but can be N**2 in the worst case.
|
||||
**
|
||||
** Hints: to match '*' or '?', put them in "[]". Like this:
|
||||
**
|
||||
** abc[*]xyz Matches "abc*xyz" only
|
||||
*/
|
||||
int
|
||||
sqlite3GlobCompare(const unsigned char *zPattern, const unsigned char *zString){
|
||||
register int c;
|
||||
int invert;
|
||||
int seen;
|
||||
int c2;
|
||||
|
||||
while( (c = *zPattern)!=0 ){
|
||||
switch( c ){
|
||||
case '*':
|
||||
while( (c=zPattern[1]) == '*' || c == '?' ){
|
||||
if( c=='?' ){
|
||||
if( *zString==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
zPattern++;
|
||||
}
|
||||
if( c==0 ) return 1;
|
||||
if( c=='[' ){
|
||||
while( *zString && sqlite3GlobCompare(&zPattern[1],zString)==0 ){
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return *zString!=0;
|
||||
}else{
|
||||
while( (c2 = *zString)!=0 ){
|
||||
while( c2 != 0 && c2 != c ){ c2 = *++zString; }
|
||||
if( c2==0 ) return 0;
|
||||
if( sqlite3GlobCompare(&zPattern[1],zString) ) return 1;
|
||||
sqliteNextChar(zString);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case '?': {
|
||||
if( *zString==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
break;
|
||||
}
|
||||
case '[': {
|
||||
int prior_c = 0;
|
||||
seen = 0;
|
||||
invert = 0;
|
||||
c = sqliteCharVal(zString);
|
||||
if( c==0 ) return 0;
|
||||
c2 = *++zPattern;
|
||||
if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
|
||||
if( c2==']' ){
|
||||
if( c==']' ) seen = 1;
|
||||
c2 = *++zPattern;
|
||||
}
|
||||
while( (c2 = sqliteCharVal(zPattern))!=0 && c2!=']' ){
|
||||
if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
|
||||
zPattern++;
|
||||
c2 = sqliteCharVal(zPattern);
|
||||
if( c>=prior_c && c<=c2 ) seen = 1;
|
||||
prior_c = 0;
|
||||
}else if( c==c2 ){
|
||||
seen = 1;
|
||||
prior_c = c2;
|
||||
}else{
|
||||
prior_c = c2;
|
||||
}
|
||||
sqliteNextChar(zPattern);
|
||||
}
|
||||
if( c2==0 || (seen ^ invert)==0 ) return 0;
|
||||
sqliteNextChar(zString);
|
||||
zPattern++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if( c != *zString ) return 0;
|
||||
zPattern++;
|
||||
zString++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *zString==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY.
|
||||
|
|
Loading…
Reference in New Issue