Rework the UTF8 reader logic in order to avoid the use of malloc().

Ticket #2523. (CVS 4175)

FossilOrigin-Name: 9a059cb6bced5cdc950f7816602ac92d89a899be
This commit is contained in:
drh
2007-07-23 19:12:41 +00:00
parent ad6b3159be
commit 6615095629
5 changed files with 134 additions and 195 deletions
+62 -65
View File
@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.161 2007/06/22 15:21:16 danielk1977 Exp $
** $Id: func.c,v 1.162 2007/07/23 19:12:42 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -26,6 +26,7 @@
#include "vdbeInt.h"
#include "os.h"
/*
** Return the collating function associated with a function.
*/
@@ -397,15 +398,6 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
** is case sensitive causing 'a' LIKE 'A' to be false */
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
** Read a single UTF-8 character and return its value.
*/
u32 sqlite3ReadUtf8(const unsigned char *z){
u32 c;
SQLITE_READ_UTF8(z, c);
return c;
}
/*
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression. Return true (1) if they
@@ -440,97 +432,102 @@ static int patternCompare(
const struct compareInfo *pInfo, /* Information about how to do the compare */
const int esc /* The escape character */
){
register int c;
int c, c2;
int invert;
int seen;
int c2;
u8 matchOne = pInfo->matchOne;
u8 matchAll = pInfo->matchAll;
u8 matchSet = pInfo->matchSet;
u8 noCase = pInfo->noCase;
int prevEscape = 0; /* True if the previous character was 'escape' */
while( (c = *zPattern)!=0 ){
while( (c = sqlite3Utf8Read(zPattern,0,&zPattern))!=0 ){
if( !prevEscape && c==matchAll ){
while( (c=zPattern[1]) == matchAll || c == matchOne ){
if( c==matchOne ){
if( *zString==0 ) return 0;
SQLITE_SKIP_UTF8(zString);
while( (c=sqlite3Utf8Read(zPattern,0,&zPattern)) == matchAll
|| c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(zString, 0, &zString)==0 ){
return 0;
}
zPattern++;
}
if( c && esc && sqlite3ReadUtf8(&zPattern[1])==esc ){
u8 const *zTemp = &zPattern[1];
SQLITE_SKIP_UTF8(zTemp);
c = *zTemp;
}
if( c==0 ) return 1;
if( c==matchSet ){
assert( esc==0 ); /* This is GLOB, not LIKE */
while( *zString && patternCompare(&zPattern[1],zString,pInfo,esc)==0 ){
if( c==0 ){
return 1;
}else if( c==esc ){
c = sqlite3Utf8Read(zPattern, 0, &zPattern);
if( c==0 ){
return 0;
}
}else if( c==matchSet ){
assert( esc==0 ); /* This is GLOB, not LIKE */
assert( matchSet<0x80 ); /* '[' is a single-byte character */
while( *zString && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
SQLITE_SKIP_UTF8(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; }
}
while( (c2 = sqlite3Utf8Read(zString,0,&zString))!=0 ){
if( noCase ){
c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2;
c = c<0x80 ? sqlite3UpperToLower[c] : c;
while( c2 != 0 && c2 != c ){
c2 = sqlite3Utf8Read(zString, 0, &zString);
if( c2<0x80 ) c2 = sqlite3UpperToLower[c2];
}
}else{
while( c2 != 0 && c2 != c ){
c2 = sqlite3Utf8Read(zString, 0, &zString);
}
if( c2==0 ) return 0;
if( patternCompare(&zPattern[1],zString,pInfo,esc) ) return 1;
SQLITE_SKIP_UTF8(zString);
}
if( c2==0 ) return 0;
if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
}
return 0;
}else if( !prevEscape && c==matchOne ){
if( sqlite3Utf8Read(zString, 0, &zString)==0 ){
return 0;
}
}else if( !prevEscape && c==matchOne ){
if( *zString==0 ) return 0;
SQLITE_SKIP_UTF8(zString);
zPattern++;
}else if( c==matchSet ){
int prior_c = 0;
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
seen = 0;
invert = 0;
c = sqlite3ReadUtf8(zString);
c = sqlite3Utf8Read(zString, 0, &zString);
if( c==0 ) return 0;
c2 = *++zPattern;
if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
if( c2=='^' ){
invert = 1;
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
}
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = *++zPattern;
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
}
while( (c2 = sqlite3ReadUtf8(zPattern))!=0 && c2!=']' ){
if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
zPattern++;
c2 = sqlite3ReadUtf8(zPattern);
while( c2 && c2!=']' ){
if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else if( c==c2 ){
seen = 1;
prior_c = c2;
}else{
if( c==c2 ){
seen = 1;
}
prior_c = c2;
}
SQLITE_SKIP_UTF8(zPattern);
c2 = sqlite3Utf8Read(zPattern, 0, &zPattern);
}
if( c2==0 || (seen ^ invert)==0 ) return 0;
SQLITE_SKIP_UTF8(zString);
zPattern++;
}else if( esc && !prevEscape && sqlite3ReadUtf8(zPattern)==esc){
if( c2==0 || (seen ^ invert)==0 ){
return 0;
}
}else if( esc==c && !prevEscape ){
prevEscape = 1;
SQLITE_SKIP_UTF8(zPattern);
}else{
c2 = sqlite3Utf8Read(zString, 0, &zString);
if( noCase ){
if( sqlite3UpperToLower[c] != sqlite3UpperToLower[*zString] ) return 0;
}else{
if( c != *zString ) return 0;
c = c<0x80 ? sqlite3UpperToLower[c] : c;
c2 = c2<0x80 ? sqlite3UpperToLower[c2] : c2;
}
if( c!=c2 ){
return 0;
}
zPattern++;
zString++;
prevEscape = 0;
}
}
@@ -590,7 +587,7 @@ static void likeFunc(
"ESCAPE expression must be a single character", -1);
return;
}
escape = sqlite3ReadUtf8(zEsc);
escape = sqlite3Utf8Read(zEsc, 0, &zEsc);
}
if( zA && zB ){
struct compareInfo *pInfo = sqlite3_user_data(context);