/ Check-in [5dddcc78]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Slightly smaller and faster LIKE/GLOB comparison implementation.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5dddcc78eec5bcd0c7e8fe1b70875ce775488f0c
User & Date: drh 2016-01-11 03:48:18
Context
2016-01-11
12:13
If a single page is written to the wal file more than once, instead of appending the second and subsequent copy to the wal file, overwrite the first. Update: See the important bug fix at [f694e60a]! check-in: d493d4f1 user: dan tags: trunk
03:48
Slightly smaller and faster LIKE/GLOB comparison implementation. check-in: 5dddcc78 user: drh tags: trunk
2016-01-08
22:31
Typo fix in the previous commit. check-in: 52c16603 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/func.c.

   563    563     sqlite3_result_int(context, sqlite3_total_changes(db));
   564    564   }
   565    565   
   566    566   /*
   567    567   ** A structure defining how to do GLOB-style comparisons.
   568    568   */
   569    569   struct compareInfo {
   570         -  u8 matchAll;
   571         -  u8 matchOne;
   572         -  u8 matchSet;
   573         -  u8 noCase;
          570  +  u8 matchAll;          /* "*" or "%" */
          571  +  u8 matchOne;          /* "?" or "_" */
          572  +  u8 matchSet;          /* "[" or 0 */
          573  +  u8 noCase;            /* true to ignore case differences */
   574    574   };
   575    575   
   576    576   /*
   577    577   ** For LIKE and GLOB matching on EBCDIC machines, assume that every
   578    578   ** character is exactly one byte in size.  Also, provde the Utf8Read()
   579    579   ** macro for fast reading of the next character in the common case where
   580    580   ** the next character is ASCII.
................................................................................
   629    629   **
   630    630   ** This routine is usually quick, but can be N**2 in the worst case.
   631    631   */
   632    632   static int patternCompare(
   633    633     const u8 *zPattern,              /* The glob pattern */
   634    634     const u8 *zString,               /* The string to compare against the glob */
   635    635     const struct compareInfo *pInfo, /* Information about how to do the compare */
   636         -  u32 esc                          /* The escape character */
          636  +  u32 matchOther                   /* The escape char (LIKE) or '[' (GLOB) */
   637    637   ){
   638    638     u32 c, c2;                       /* Next pattern and input string chars */
   639    639     u32 matchOne = pInfo->matchOne;  /* "?" or "_" */
   640    640     u32 matchAll = pInfo->matchAll;  /* "*" or "%" */
   641         -  u32 matchOther;                  /* "[" or the escape character */
   642    641     u8 noCase = pInfo->noCase;       /* True if uppercase==lowercase */
   643    642     const u8 *zEscaped = 0;          /* One past the last escaped input char */
   644    643     
   645         -  /* The GLOB operator does not have an ESCAPE clause.  And LIKE does not
   646         -  ** have the matchSet operator.  So we either have to look for one or
   647         -  ** the other, never both.  Hence the single variable matchOther is used
   648         -  ** to store the one we have to look for.
   649         -  */
   650         -  matchOther = esc ? esc : pInfo->matchSet;
   651         -
   652    644     while( (c = Utf8Read(zPattern))!=0 ){
   653    645       if( c==matchAll ){  /* Match "*" */
   654    646         /* Skip over multiple "*" characters in the pattern.  If there
   655    647         ** are also "?" characters, skip those as well, but consume a
   656    648         ** single character of the input string for each "?" skipped */
   657    649         while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
   658    650           if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
   659    651             return 0;
   660    652           }
   661    653         }
   662    654         if( c==0 ){
   663    655           return 1;   /* "*" at the end of the pattern matches */
   664    656         }else if( c==matchOther ){
   665         -        if( esc ){
          657  +        if( pInfo->matchSet==0 ){
   666    658             c = sqlite3Utf8Read(&zPattern);
   667    659             if( c==0 ) return 0;
   668    660           }else{
   669    661             /* "[...]" immediately follows the "*".  We have to do a slow
   670    662             ** recursive search in this case, but it is an unusual case. */
   671    663             assert( matchOther<0x80 );  /* '[' is a single-byte character */
   672    664             while( *zString
   673         -                 && patternCompare(&zPattern[-1],zString,pInfo,esc)==0 ){
          665  +                 && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
   674    666               SQLITE_SKIP_UTF8(zString);
   675    667             }
   676    668             return *zString!=0;
   677    669           }
   678    670         }
   679    671   
   680    672         /* At this point variable c contains the first character of the
................................................................................
   692    684             cx = sqlite3Toupper(c);
   693    685             c = sqlite3Tolower(c);
   694    686           }else{
   695    687             cx = c;
   696    688           }
   697    689           while( (c2 = *(zString++))!=0 ){
   698    690             if( c2!=c && c2!=cx ) continue;
   699         -          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
          691  +          if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
   700    692           }
   701    693         }else{
   702    694           while( (c2 = Utf8Read(zString))!=0 ){
   703    695             if( c2!=c ) continue;
   704         -          if( patternCompare(zPattern,zString,pInfo,esc) ) return 1;
          696  +          if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
   705    697           }
   706    698         }
   707    699         return 0;
   708    700       }
   709    701       if( c==matchOther ){
   710         -      if( esc ){
          702  +      if( pInfo->matchSet==0 ){
   711    703           c = sqlite3Utf8Read(&zPattern);
   712    704           if( c==0 ) return 0;
   713    705           zEscaped = zPattern;
   714    706         }else{
   715    707           u32 prior_c = 0;
   716    708           int seen = 0;
   717    709           int invert = 0;
................................................................................
   756    748     return *zString==0;
   757    749   }
   758    750   
   759    751   /*
   760    752   ** The sqlite3_strglob() interface.
   761    753   */
   762    754   int sqlite3_strglob(const char *zGlobPattern, const char *zString){
   763         -  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
          755  +  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
   764    756   }
   765    757   
   766    758   /*
   767    759   ** The sqlite3_strlike() interface.
   768    760   */
   769    761   int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
   770    762     return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0;
................................................................................
   794    786   */
   795    787   static void likeFunc(
   796    788     sqlite3_context *context, 
   797    789     int argc, 
   798    790     sqlite3_value **argv
   799    791   ){
   800    792     const unsigned char *zA, *zB;
   801         -  u32 escape = 0;
          793  +  u32 escape;
   802    794     int nPat;
   803    795     sqlite3 *db = sqlite3_context_db_handle(context);
          796  +  struct compareInfo *pInfo = sqlite3_user_data(context);
   804    797   
   805    798   #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
   806    799     if( sqlite3_value_type(argv[0])==SQLITE_BLOB
   807    800      || sqlite3_value_type(argv[1])==SQLITE_BLOB
   808    801     ){
   809    802   #ifdef SQLITE_TEST
   810    803       sqlite3_like_count++;
................................................................................
   836    829       if( zEsc==0 ) return;
   837    830       if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
   838    831         sqlite3_result_error(context, 
   839    832             "ESCAPE expression must be a single character", -1);
   840    833         return;
   841    834       }
   842    835       escape = sqlite3Utf8Read(&zEsc);
          836  +  }else{
          837  +    escape = pInfo->matchSet;
   843    838     }
   844    839     if( zA && zB ){
   845         -    struct compareInfo *pInfo = sqlite3_user_data(context);
   846    840   #ifdef SQLITE_TEST
   847    841       sqlite3_like_count++;
   848    842   #endif
   849         -    
   850    843       sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
   851    844     }
   852    845   }
   853    846   
   854    847   /*
   855    848   ** Implementation of the NULLIF(x,y) function.  The result is the first
   856    849   ** argument if the arguments are different.  The result is NULL if the