[tarantool-patches] Re: [PATCH 2/2] sql: remove GLOB from Tarantool

Alex Khatskevich avkhatskevich at tarantool.org
Tue Sep 11 15:03:45 MSK 2018


>>>>>
>>>>> -    "ESCAPE expression must be a single character",
>>>>> +    "ESCAPE expression must be a"
>>>>> +    " single character",
>>>> Do not split error messages at the middle of a sentence. It makes 
>>>> errors ungreppable.
>>>> Make it <80 somehow different.
>>>>
>>>
>>> Have already been discussed in this thread.
>> I suppose that we concluded to try to fit into 80 and split the 
>> string only
>> in case it is impossible.
>
> I don’t think so. Anyways, Alexander could you please give your thoughts?
Discussed with Nikita, Alexander, Vladimir, Kirill... Conclusion: use 
`const char temp variable` if possible.
like this:
```
         const char *const err_msg =
             "ESCAPE expression must be a single character";
         if (sqlite3Utf8CharLen((char *)zEsc, -1) != 1) {
             sqlite3_result_error(context,
                          err_msg,
                          -1);
             return;
```

If it does not help (but it is) split the message.
>>> diff --git a/test/sql-tap/e_expr.test.lua b/test/sql-tap/e_expr.test.lua
>>> index 162026845..0d69e8535 100755
>>> --- a/test/sql-tap/e_expr.test.lua
>>> +++ b/test/sql-tap/e_expr.test.lua
>>> @@ -1,6 +1,6 @@
>>>  #!/usr/bin/env tarantool
>>>  test = require("sqltester")
>>> -test:plan(11521)
>>> +test:plan(10647)
>>>  --!./tcltestrunner.lua
>>>  -- 2010 July 16
>>> @@ -77,7 +77,7 @@ local operations = {
>>>      {"<>", "ne1"},
>>>      {"!=", "ne2"},
>>>      {"IS", "is"},
>>> -    {"LIKE", "like"},
>>> +--    {"LIKE", "like"},
>>>      {"AND", "and"},
>>>      {"OR", "or"},
>>>      {"MATCH", "match"},
>>> @@ -96,8 +96,9 @@ operations = {
>>>      {"<<", ">>", "&", "|"},
>>>      {"<", "<=", ">", ">="},
>>>  -- Another NOTE: MATCH & REGEXP aren't supported in Tarantool &
>>> --- are waiting for their hour.
>>> -    {"=", "==", "!=", "<>", "LIKE"}, --"MATCH", "REGEXP"},
>>> +-- are waiting for their hour, don't confuse them
>>> +-- being commented with commenting of "LIKE".
>>> +    {"=", "==", "!=", "<>"}, --"LIKE"}, --"MATCH", "REGEXP"},
>> Delete Like. No one returns here.
>
> It’s a table of all of the operators thus I think it still worth 
> leaving it there.
> Who knows, it may be that someone will revive tests for LIKE.
Delete Like. No one returns here.
We do not need a garbage. Like is not relevant anymore for this test.
>
> diff --git a/extra/mkkeywordhash.c b/extra/mkkeywordhash.c
> index 990c4199f..1fee3a7f2 100644
> --- a/extra/mkkeywordhash.c
> +++ b/extra/mkkeywordhash.c
> @@ -159,7 +159,6 @@ static Keyword aKeywordTable[] = {
>    { "FOR",                    "TK_FOR",         TRIGGER,         
>  true  },
>    { "FOREIGN",                "TK_FOREIGN",     FKEY,           true  },
>    { "FROM",                   "TK_FROM",        ALWAYS,           
> true  },
> -  { "GLOB",                   "TK_LIKE_KW",     ALWAYS,           
> false },
>    { "GROUP",                  "TK_GROUP",       ALWAYS,           
> true  },
>    { "HAVING",                 "TK_HAVING",      ALWAYS,           
> true  },
>    { "IF",                     "TK_IF",          ALWAYS,           
> true  },
> diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
> index 5f73f026e..fc7588c3f 100644
> --- a/src/box/sql/analyze.c
> +++ b/src/box/sql/analyze.c
> @@ -829,7 +829,7 @@ analyzeOneTable(Parse * pParse,/* Parser context */
> return;
> }
> assert(pTab->tnum != 0);
> -if (sqlite3_strlike("\\_%", pTab->def->name, '\\') == 0) {
> +if (sql_strlike_ci("\\_%", pTab->def->name, '\\') == 0) {
> /* Do not gather statistics on system tables */
> return;
> }
> @@ -1333,11 +1333,10 @@ analysis_loader(void *data, int argc, char 
> **argv, char **unused)
> /* Position ptr at the end of stat string. */
> for (; *z == ' ' || (*z >= '0' && *z <= '9'); ++z);
> while (z[0]) {
> -if (sqlite3_strglob("unordered*", z) == 0) {
> +if (sql_strlike_cs("unordered%", z, '[') == 0)
> index->def->opts.stat->is_unordered = true;
> -} else if (sqlite3_strglob("noskipscan*", z) == 0) {
> +else if (sql_strlike_cs("noskipscan%", z, '[') == 0)
> index->def->opts.stat->skip_scan_enabled = false;
> -}
> while (z[0] != 0 && z[0] != ' ')
> z++;
> while (z[0] == ' ')
> diff --git a/src/box/sql/func.c b/src/box/sql/func.c
> index 66cae17b5..28b435ae3 100644
> --- a/src/box/sql/func.c
> +++ b/src/box/sql/func.c
> @@ -607,41 +607,38 @@ total_changes(sqlite3_context * context, int 
> NotUsed, sqlite3_value ** NotUsed2)
> sqlite3_result_int(context, sqlite3_total_changes(db));
>  }
> -/*
> - * A structure defining how to do GLOB-style comparisons.
> - */
> -struct compareInfo {
> -u8 matchAll;/* "*" or "%" */
> -u8 matchOne;/* "?" or "_" */
> -u8 matchSet;/* "[" or 0 */
> -u8 noCase;/* true to ignore case differences */
> -};
> -
>  /**
> - * Providing there are symbols in string s this
> - * macro returns UTF-8 code of character and
> - * promotes pointer to the next symbol in the string.
> - * Otherwise return code is SQL_END_OF_STRING.
> + * Providing there are symbols in string s this macro returns
> + * UTF-8 code of character and promotes pointer to the next
> + * symbol in the string. If s points to an invalid UTF-8 symbol
> + * return code is SQL_INVALID_UTF8_SYMBOL. If there're no symbols
> + * left in string s return code is SQL_END_OF_STRING.
>   */
>  #define Utf8Read(s, e) ucnv_getNextUChar(pUtf8conv, &(s), (e), &(status))
>  #define SQL_END_OF_STRING        0xffff
>  #define SQL_INVALID_UTF8_SYMBOL  0xfffd
> -static const struct compareInfo globInfo = { '*', '?', '[', 0 };
> +/**
> + * If SQLITE_CASE_SENSITIVE_LIKE is not defined, then the LIKE
> + * operator is not case sensitive.
> + */
> +static const int case_insensitive_like = 1;
> -/* The correct SQL-92 behavior is for the LIKE operator to ignore
> - * case.  Thus  'a' LIKE 'A' would be true.
> +/**
> + * 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 likeInfoNorm = { '%', '_', 0, 1 };
> +static const int case_sensitive_like = 0;
> -/* If SQLITE_CASE_SENSITIVE_LIKE is defined, then the LIKE operator
> - * is case sensitive causing 'a' LIKE 'A' to be false
> +/**
> + * Wildcards.
>   */
> -static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
> +#define match_one '_'
> +#define match_all '%'
> -/*
> - * Possible error returns from sql_utf8_pattern_compare()
> +/**
> + * Possible error returns from sql_utf8_pattern_compare().
>   */
>  #define SQL_MATCH                0
>  #define SQL_NOMATCH              1
> @@ -650,138 +647,91 @@ static const struct compareInfo likeInfoAlt = { 
> '%', '_', 0, 0 };
>  /**
>   * Compare two UTF-8 strings for equality where the first string
> - * is a GLOB or LIKE expression.
> - *
> - * 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.
> + * is a LIKE expression.
>   *
>   * Like matching rules:
>   *
> - *      '%'       Matches any sequence of zero or more characters.
> + *      '%'       Matches any sequence of zero or more
> + *                characters.
>   *
>   *      '_'       Matches any one character.
>   *
> - *      Ec        Where E is the "esc" character and c is any other
> - *                character, including '%', '_', and esc, match
> - *                exactly c.
> - *
> - * The comments within this routine usually assume glob matching.
> + *      Ec        Where E is the "esc" character and c is any
> + *                other character, including '%', '_', and esc,
> + *                match exactly c.
>   *
>   * This routine is usually quick, but can be N**2 in the worst
>   * case.
>   *
>   * @param pattern String containing comparison pattern.
>   * @param string String being compared.
> - * @param compareInfo Information about how to compare.
> - * @param matchOther The escape char (LIKE) or '[' (GLOB).
> + * @param is_like_ci true if LIKE is case insensitive.
> + * @param match_other The escape char for LIKE.
>   *
>   * @retval SQL_MATCH:               Match.
>   *  SQL_NOMATCH:             No match.
> - *  SQL_NOWILDCARDMATCH:     No match in spite of having *
> - *   or % wildcards.
> + *  SQL_NOWILDCARDMATCH:     No match in spite of having %
> + *   wildcard.
>   *  SQL_INVALID_PATTERN:     Pattern contains invalid
>   *   symbol.
>   */
>  static int
>  sql_utf8_pattern_compare(const char *pattern,
> const char *string,
> -const struct compareInfo *pInfo,
> -UChar32 matchOther)
> +const int is_like_ci,
> +UChar32 match_other)
>  {
> /* Next pattern and input string chars */
> UChar32 c, c2;
> -/* "?" or "_" */
> -UChar32 matchOne = pInfo->matchOne;
> -/* "*" or "%" */
> -UChar32 matchAll = pInfo->matchAll;
> -/* True if uppercase==lowercase */
> -UChar32 noCase = pInfo->noCase;
> /* One past the last escaped input char */
> const char *zEscaped = 0;
> -const char * pattern_end = pattern + strlen(pattern);
> -const char * string_end = string + strlen(string);
> +const char *pattern_end = pattern + strlen(pattern);
> +const char *string_end = string + strlen(string);
> UErrorCode status = U_ZERO_ERROR;
> while (pattern < pattern_end) {
> c = Utf8Read(pattern, pattern_end);
> if (c == SQL_INVALID_UTF8_SYMBOL)
> return SQL_INVALID_PATTERN;
> -if (c == matchAll) {/* Match "*" */
> -/* Skip over multiple "*" characters in
> -* the pattern. If there are also "?"
> +if (c == match_all) {
> +/**
> +* Skip over multiple "%" characters in
> +* the pattern. If there are also "_"
> * characters, skip those as well, but
> * consume a single character of the
> -* input string for each "?" skipped.
> +* input string for each "_" skipped.
> */
> while ((c = Utf8Read(pattern, pattern_end)) !=
>       SQL_END_OF_STRING) {
> if (c == SQL_INVALID_UTF8_SYMBOL)
> return SQL_INVALID_PATTERN;
> -if (c != matchAll && c != matchOne)
> +if (c != match_all && c != match_one)
> break;
> -if (c == matchOne &&
> +if (c == match_one &&
>    (c2 = Utf8Read(string, string_end)) ==
>    SQL_END_OF_STRING)
> return SQL_NOWILDCARDMATCH;
> if (c2 == SQL_INVALID_UTF8_SYMBOL)
> return SQL_NOMATCH;
> }
> -/*
> -* "*" at the end of the pattern matches.
> +/**
> +* "%" at the end of the pattern matches.
> */
> if (c == SQL_END_OF_STRING) {
> return SQL_MATCH;
> }
> -if (c == matchOther) {
> -if (pInfo->matchSet == 0) {
> -c = Utf8Read(pattern, pattern_end);
> -if (c == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -if (c == SQL_END_OF_STRING)
> -return SQL_NOWILDCARDMATCH;
> -} else {
> -/* "[...]" immediately
> -* follows the "*". We
> -* have to do a slow
> -* recursive search in
> -* this case, but it is
> -* an unusual case.
> -*/
> -assert(matchOther < 0x80);
> -while (string < string_end) {
> -int bMatch =
> -   sql_utf8_pattern_compare(
> -&pattern[-1],
> -string,
> -pInfo,
> -matchOther);
> -if (bMatch != SQL_NOMATCH)
> -return bMatch;
> -c = Utf8Read(string, string_end);
> -if (c == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_NOMATCH;
> -}
> +if (c == match_other) {
> +c = Utf8Read(pattern, pattern_end);
> +if (c == SQL_INVALID_UTF8_SYMBOL)
> +return SQL_INVALID_PATTERN;
> +if (c == SQL_END_OF_STRING)
> return SQL_NOWILDCARDMATCH;
> -}
> }
> -/* At this point variable c contains the
> +/**
> +* At this point variable c contains the
> * first character of the pattern string
> -* past the "*". Search in the input
> +* past the "%". Search in the input
> * string for the first matching
> * character and recursively continue the
> * match from that point.
> @@ -793,7 +743,7 @@ sql_utf8_pattern_compare(const char *pattern,
> */
> int bMatch;
> -if (noCase)
> +if (is_like_ci)
> c = u_tolower(c);
> while (string < string_end){
> /**
> @@ -809,7 +759,7 @@ sql_utf8_pattern_compare(const char *pattern,
> c2 = Utf8Read(string, string_end);
> if (c2 == SQL_INVALID_UTF8_SYMBOL)
> return SQL_NOMATCH;
> -if (!noCase) {
> +if (!is_like_ci) {
> if (c2 != c)
> continue;
> } else {
> @@ -818,79 +768,27 @@ sql_utf8_pattern_compare(const char *pattern,
> }
> bMatch = sql_utf8_pattern_compare(pattern,
>  string,
> - pInfo,
> - matchOther);
> + is_like_ci,
> + match_other);
> if (bMatch != SQL_NOMATCH)
> return bMatch;
> }
> return SQL_NOWILDCARDMATCH;
> }
> -if (c == matchOther) {
> -if (pInfo->matchSet == 0) {
> -c = Utf8Read(pattern, pattern_end);
> -if (c == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -if (c == SQL_END_OF_STRING)
> -return SQL_NOMATCH;
> -zEscaped = pattern;
> -} else {
> -UChar32 prior_c = 0;
> -int seen = 0;
> -int invert = 0;
> -c = Utf8Read(string, string_end);
> -if (c == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_NOMATCH;
> -if (string == string_end)
> -return SQL_NOMATCH;
> -c2 = Utf8Read(pattern, pattern_end);
> -if (c2 == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -if (c2 == '^') {
> -invert = 1;
> -c2 = Utf8Read(pattern, pattern_end);
> -if (c2 == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -}
> -if (c2 == ']') {
> -if (c == ']')
> -seen = 1;
> -c2 = Utf8Read(pattern, pattern_end);
> -if (c2 == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -}
> -while (c2 != SQL_END_OF_STRING && c2 != ']') {
> -if (c2 == '-' && pattern[0] != ']'
> -   && pattern < pattern_end
> -   && prior_c > 0) {
> -c2 = Utf8Read(pattern, pattern_end);
> -if (c2 == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -if (c >= prior_c && c <= c2)
> -seen = 1;
> -prior_c = 0;
> -} else {
> -if (c == c2) {
> -seen = 1;
> -}
> -prior_c = c2;
> -}
> -c2 = Utf8Read(pattern, pattern_end);
> -if (c2 == SQL_INVALID_UTF8_SYMBOL)
> -return SQL_INVALID_PATTERN;
> -}
> -if (pattern == pattern_end ||
> -   (seen ^ invert) == 0) {
> -return SQL_NOMATCH;
> -}
> -continue;
> -}
> +if (c == match_other) {
> +c = Utf8Read(pattern, pattern_end);
> +if (c == SQL_INVALID_UTF8_SYMBOL)
> +return SQL_INVALID_PATTERN;
> +if (c == SQL_END_OF_STRING)
> +return SQL_NOMATCH;
> +zEscaped = pattern;
> }
> c2 = Utf8Read(string, string_end);
> if (c2 == SQL_INVALID_UTF8_SYMBOL)
> return SQL_NOMATCH;
> if (c == c2)
> continue;
> -if (noCase){
> +if (is_like_ci) {
> /**
> * Small optimisation. Reduce number of
> * calls to u_tolower function. SQL
> @@ -903,7 +801,7 @@ sql_utf8_pattern_compare(const char *pattern,
>    c == u_tolower(c2))
> continue;
> }
> -if (c == matchOne && pattern != zEscaped &&
> +if (c == match_one && pattern != zEscaped &&
>    c2 != SQL_END_OF_STRING)
> continue;
> return SQL_NOMATCH;
> @@ -911,55 +809,52 @@ sql_utf8_pattern_compare(const char *pattern,
> return string == string_end ? SQL_MATCH : SQL_NOMATCH;
>  }
> -/*
> - * The sqlite3_strglob() interface.  Return 0 on a match (like 
> strcmp()) and
> - * non-zero if there is no match.
> +/**
> + * Compare two UTF-8 strings for equality using case sensitive
> + * sql_utf8_pattern_compare.
>   */
>  int
> -sqlite3_strglob(const char *zGlobPattern, const char *zString)
> +sql_strlike_cs(const char *zPattern, const char *zStr, unsigned int esc)
>  {
> -return sql_utf8_pattern_compare(zGlobPattern, zString, &globInfo, '[');
> +return sql_utf8_pattern_compare(zPattern, zStr, case_sensitive_like, 
> esc);
>  }
> -/*
> - * The sqlite3_strlike() interface.  Return 0 on a match and non-zero for
> - * a miss - like strcmp().
> +/**
> + * Compare two UTF-8 strings for equality using case insensitive
> + * sql_utf8_pattern_compare.
>   */
>  int
> -sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc)
> +sql_strlike_ci(const char *zPattern, const char *zStr, unsigned int esc)
>  {
> -return sql_utf8_pattern_compare(zPattern, zStr, &likeInfoNorm, esc);
> +return sql_utf8_pattern_compare(zPattern, zStr, 
> case_insensitive_like, esc);
>  }
> -/*
> - * 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.
> +/**
> + * Count the number of times that the LIKE operator 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
> - * 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:
> +/**
> + * Implementation of the like() SQL function. This function
> + * implements the built-in LIKE operator. The first argument to
> + * the function is the pattern and the second argument is the
> + * string. So, the SQL statements of the following type:
>   *
>   *       A LIKE B
>   *
> - * is implemented as like(B,A).
> - *
> - * This same function (with a different compareInfo structure) computes
> - * the GLOB operator.
> + * are implemented as like(B,A).
>   */
>  static void
> -likeFunc(sqlite3_context * context, int argc, sqlite3_value ** argv)
> +likeFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
>  {
> const char *zA, *zB;
> u32 escape;
> int nPat;
> sqlite3 *db = sqlite3_context_db_handle(context);
> -struct compareInfo *pInfo = sqlite3_user_data(context);
> +int *is_like_ci = sqlite3_user_data(context);
>  #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
> if (sqlite3_value_type(argv[0]) == SQLITE_BLOB
> @@ -974,8 +869,9 @@ likeFunc(sqlite3_context * context, int argc, 
> sqlite3_value ** argv)
> zB = (const char *) sqlite3_value_text(argv[0]);
> zA = (const char *) sqlite3_value_text(argv[1]);
> -/* Limit the length of the LIKE or GLOB pattern to avoid
> -* problems of deep recursion and N*N behavior in
> +/**
> +* Limit the length of the LIKE pattern to avoid problems
> +* of deep recursion and N*N behavior in
> * sql_utf8_pattern_compare().
> */
> nPat = sqlite3_value_bytes(argv[0]);
> @@ -983,28 +879,29 @@ likeFunc(sqlite3_context * context, int argc, 
> sqlite3_value ** argv)
> testcase(nPat == db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] + 1);
> if (nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]) {
> sqlite3_result_error(context,
> -    "LIKE or GLOB pattern too complex", -1);
> +    "LIKE pattern is too complex", -1);
> return;
> }
> /* Encoding did not change */
> assert(zB == (const char *) sqlite3_value_text(argv[0]));
> if (argc == 3) {
> -/* The escape character string must consist of a single UTF-8 character.
> -* Otherwise, return an error.
> +/**
> +* The escape character string must consist of a
> +* single UTF-8 character. Otherwise, return an
> +* error.
> */
> const unsigned char *zEsc = sqlite3_value_text(argv[2]);
> if (zEsc == 0)
> return;
> if (sqlite3Utf8CharLen((char *)zEsc, -1) != 1) {
> sqlite3_result_error(context,
> -    "ESCAPE expression must be a single character",
> +    "ESCAPE expression must be a"
> +    " single character",
>     -1);
> return;
> }
> escape = sqlite3Utf8Read(&zEsc);
> -} else {
> -escape = pInfo->matchSet;
> }
> if (!zA || !zB)
> return;
> @@ -1012,10 +909,10 @@ likeFunc(sqlite3_context * context, int argc, 
> sqlite3_value ** argv)
> sqlite3_like_count++;
>  #endif
> int res;
> -res = sql_utf8_pattern_compare(zB, zA, pInfo, escape);
> +res = sql_utf8_pattern_compare(zB, zA, *is_like_ci, escape);
> if (res == SQL_INVALID_PATTERN) {
> -sqlite3_result_error(context, "LIKE or GLOB pattern can only"
> -    " contain UTF-8 characters", -1);
> +sqlite3_result_error(context, "LIKE pattern can only contain"
> +    " UTF-8 characters", -1);
> return;
> }
> sqlite3_result_int(context, res == SQL_MATCH);
> @@ -1811,64 +1708,54 @@ setLikeOptFlag(sqlite3 * db, const char 
> *zName, u8 flagVal)
> }
>  }
> -/*
> - * 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.
> +/**
> + * Register the built-in LIKE function.
> + *
> + * @param db database structure.
> + * @param is_case_sensitive whether like should be case sensitive
> + * or not.
> + *
> + * @retval none.
>   */
>  void
> -sqlite3RegisterLikeFunctions(sqlite3 * db, int caseSensitive)
> +sqlite3RegisterLikeFunctions(sqlite3 *db, int is_case_sensitive)
>  {
> -struct compareInfo *pInfo;
> -if (caseSensitive) {
> -pInfo = (struct compareInfo *)&likeInfoAlt;
> -} else {
> -pInfo = (struct compareInfo *)&likeInfoNorm;
> -}
> -sqlite3CreateFunc(db, "LIKE", 2, 0, pInfo, likeFunc, 0, 0, 0);
> -sqlite3CreateFunc(db, "LIKE", 3, 0, pInfo, likeFunc, 0, 0, 0);
> -sqlite3CreateFunc(db, "GLOB", 2, 0, (struct compareInfo *)&globInfo, 
> likeFunc, 0, 0, 0);
> -setLikeOptFlag(db, "GLOB", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
> +int *is_like_ci;
> +if (is_case_sensitive)
> +is_like_ci = (int *)&case_sensitive_like;
> +else
> +is_like_ci = (int *)&case_insensitive_like;
> +sqlite3CreateFunc(db, "LIKE", 2, 0, is_like_ci, likeFunc, 0, 0, 0);
> +sqlite3CreateFunc(db, "LIKE", 3, 0, is_like_ci, likeFunc, 0, 0, 0);
> setLikeOptFlag(db, "LIKE",
> -      caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) :
> -      SQLITE_FUNC_LIKE);
> +      is_case_sensitive ? (SQLITE_FUNC_LIKE |
> +      SQLITE_FUNC_CASE) : SQLITE_FUNC_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.
> +/**
> + * Check if the function implements LIKE-style comparison & if it
> + * is appropriate to apply a LIKE query optimization.
> + *
> + * @param db database structure.
> + * @param pExpr pointer to a function-implementing expression.
> + * @param is_like_ci true if LIKE is case insensitive.
>   *
> - * *pIsNocase is set to true if uppercase and lowercase are 
> equivalent for
> - * the function (default for LIKE).  If the function makes the 
> distinction
> - * between uppercase and lowercase (as does GLOB) then *pIsNocase is 
> set to
> - * false.
> + * @retval 0 if it's appropriate to apply optimization.
> + *         1 if it's not.
>   */
>  int
> -sqlite3IsLikeFunction(sqlite3 * db, Expr * pExpr, int *pIsNocase, 
> char *aWc)
> +sql_is_like_func(sqlite3 *db, Expr *pExpr, int *is_like_ci)
>  {
> FuncDef *pDef;
> -if (pExpr->op != TK_FUNCTION
> -   || !pExpr->x.pList || pExpr->x.pList->nExpr != 2) {
> +if (pExpr->op != TK_FUNCTION || !pExpr->x.pList ||
> +   pExpr->x.pList->nExpr != 2)
> return 0;
> -}
> assert(!ExprHasProperty(pExpr, EP_xIsSelect));
> pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, 0);
> if (NEVER(pDef == 0) || (pDef->funcFlags & SQLITE_FUNC_LIKE) == 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);
> -*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE) == 0;
> +*is_like_ci = (pDef->funcFlags & SQLITE_FUNC_CASE) == 0;
> return 1;
>  }
> @@ -1962,16 +1849,14 @@ sqlite3RegisterBuiltinFunctions(void)
> AGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
>  groupConcatFinalize),
> -LIKEFUNC(glob, 2, &globInfo,
> -SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE),
>  #ifdef SQLITE_CASE_SENSITIVE_LIKE
> -LIKEFUNC(like, 2, &likeInfoAlt,
> +LIKEFUNC(like, 2, &case_sensitive_like,
> SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE),
> -LIKEFUNC(like, 3, &likeInfoAlt,
> +LIKEFUNC(like, 3, &case_sensitive_like,
> SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE),
>  #else
> -LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
> -LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
> +LIKEFUNC(like, 2, &case_insensitive_like, SQLITE_FUNC_LIKE),
> +LIKEFUNC(like, 3, &case_insensitive_like, SQLITE_FUNC_LIKE),
>  #endif
>  #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
> FUNCTION(unknown, -1, 0, 0, unknownFunc),
> diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
> index 5fb29c75c..26a602b23 100644
> --- a/src/box/sql/pragma.c
> +++ b/src/box/sql/pragma.c
> @@ -771,8 +771,10 @@ sqlite3Pragma(Parse * pParse, Token * pId,/* 
> First part of [schema.]id field */
> }
>  #endif
> -/* Reinstall the LIKE and GLOB functions.  The variant of LIKE *
> -* used will be case sensitive or not depending on the RHS.
> +/**
> +* Reinstall the LIKE and functions. The variant
> +* of LIKE * used will be case sensitive or not
> +* depending on the RHS.
> */
> case PragTyp_CASE_SENSITIVE_LIKE:{
> if (zRight) {
> diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
> index e7a02dc1d..a805adf22 100644
> --- a/src/box/sql/sqliteInt.h
> +++ b/src/box/sql/sqliteInt.h
> @@ -565,16 +565,15 @@ char *
>  sqlite3_vsnprintf(int, char *, const char *, va_list);
>  int
> -sqlite3_strlike(const char *zGlob, const char *zStr,
> -unsigned int cEsc);
> +sql_strlike_cs(const char *zLike, const char *zStr, unsigned int cEsc);
> +
> +int
> +sql_strlike_ci(const char *zLike, const char *zStr, unsigned int cEsc);
>  typedef void (*sqlite3_destructor_type) (void *);
>  #define SQLITE_STATIC      ((sqlite3_destructor_type)0)
>  #define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)
> -int
> -sqlite3_strglob(const char *zGlob, const char *zStr);
> -
>  int
>  sqlite3_prepare(sqlite3 * db,/* Database handle */
> const char *zSql,/* SQL statement, UTF-8 encoded */
> @@ -701,9 +700,6 @@ struct on_conflict {
> enum on_conflict_action optimized_action;
>  };
> -void *
> -sqlite3_user_data(sqlite3_context *);
> -
>  void
>  sqlite3_randomness(int N, void *P);
> @@ -2355,7 +2351,7 @@ struct Expr {
>  #define EP_Distinct  0x000010/* Aggregate function with DISTINCT 
> keyword */
>  #define EP_VarSelect 0x000020/* pSelect is correlated, not constant */
>  #define EP_DblQuoted 0x000040/* token.z was originally in "..." */
> -#define EP_InfixFunc 0x000080/* True for an infix function: LIKE, 
> GLOB, etc */
> +#define EP_InfixFunc 0x000080/* True for an infix function: LIKE, etc */
>  #define EP_Collate   0x000100/* Tree contains a TK_COLLATE operator */
>  #define EP_Generic   0x000200/* Ignore COLLATE or affinity on this 
> tree */
>  #define EP_IntValue  0x000400/* Integer value contained in u.iValue */
> @@ -4378,7 +4374,7 @@ index_column_count(const Index *);
>  bool
>  index_is_unique_not_null(const Index *);
>  void sqlite3RegisterLikeFunctions(sqlite3 *, int);
> -int sqlite3IsLikeFunction(sqlite3 *, Expr *, int *, char *);
> +int sql_is_like_func(sqlite3 *db, Expr *pExpr, int *is_case_insensitive);
>  void sqlite3SchemaClear(sqlite3 *);
>  Schema *sqlite3SchemaCreate(sqlite3 *);
>  int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
> diff --git a/src/box/sql/sqliteLimit.h b/src/box/sql/sqliteLimit.h
> index b88c9c6d3..e76353aff 100644
> --- a/src/box/sql/sqliteLimit.h
> +++ b/src/box/sql/sqliteLimit.h
> @@ -164,8 +164,7 @@ enum {
>  #endif
>  /*
> - * Maximum length (in bytes) of the pattern in a LIKE or GLOB
> - * operator.
> + * Maximum length (in bytes) of the pattern in a LIKE operator.
>   */
>  #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
>  #define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 0c978142d..3f10f4d68 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -5521,7 +5521,7 @@ vdbe_return:
> testcase( nVmStep>0);
> p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
> assert(rc!=SQLITE_OK || nExtraDelete==0
> -|| sqlite3_strlike("DELETE%",p->zSql,0)!=0
> +|| sql_strlike_ci("DELETE%", p->zSql, 0) != 0
> );
> return rc;
> diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
> index c35c25ac4..f864ea7fa 100644
> --- a/src/box/sql/wherecode.c
> +++ b/src/box/sql/wherecode.c
> @@ -339,7 +339,7 @@ sqlite3WhereAddScanStatus(Vdbe * v,/* Vdbe to add 
> scanstatus entry to */
>   * automatically disabled.  In this way, terms get disabled if derived
>   * virtual terms are tested first.  For example:
>   *
> - *      x GLOB 'abc*' AND x>='abc' AND x<'acd'
> + *      x LIKE 'abc%' AND x>='abc' AND x<'acd'
>   *      \___________/     \______/     \_____/
>   *         parent          child1       child2
>   *
> diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
> index 612868695..2d9fb6453 100644
> --- a/src/box/sql/whereexpr.c
> +++ b/src/box/sql/whereexpr.c
> @@ -218,38 +218,61 @@ operatorMask(int op)
> return c;
>  }
> +/**
> + * Wildcard characters.
> + */
> +#define match_one '_'
> +#define match_all '%'
If possible - move the define to a header which both (whereexpr and 
func) file include.
This also require to give more descriptive name, e.g. LIKE_MATCH_ONE.
> +
>  #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION
> -/*
> - * Check to see if the given expression is a LIKE or GLOB operator that
> - * can be optimized using inequality constraints.  Return TRUE if it is
> - * so and false if not.
> +/**
> + * Check to see if the given expression is a LIKE operator that
> + * can be optimized using inequality constraints.
>   *
> - * In order for the operator to be optimizible, the RHS must be a string
> - * literal that does not begin with a wildcard.  The LHS must be a column
> - * that may only be NULL, a string, or a BLOB, never a number. The
> - * collating sequence for the column on the LHS must be appropriate for
> - * the operator.
> + * In order for the operator to be optimizible, the RHS must be a
> + * string literal that does not begin with a wildcard. The LHS
> + * must be a column that may only be NULL, a string, or a BLOB,
> + * never a number. The collating sequence for the column on the
> + * LHS must be appropriate for the operator.
> + *
> + * @param pParse      Parsing and code generating context.
> + * @param pExpr       Test this expression.
> + * @param ppPrefix    Pointer to TK_STRING expression with
> + *     pattern prefix.
> + * @param pisComplete True if the only wildcard is '%' in the
> + *      last character.
> + * @param pnoCase     True if case insensitive.
> + *
> + * @retval True if the given expr is a LIKE operator & is
> + *  optimizable using inequality constraints.
> + *   False if not.
>   */
>  static int
> -isLikeOrGlob(Parse * pParse,/* Parsing and code generating context */
> -    Expr * pExpr,/* Test this expression */
> -    Expr ** ppPrefix,/* Pointer to TK_STRING expression with pattern 
> prefix */
> -    int *pisComplete,/* True if the only wildcard is % in the last 
> character */
> -    int *pnoCase/* True if uppercase is equivalent to lowercase */
> -    )
> +is_like(Parse *pParse,
> +Expr *pExpr,
> +Expr **ppPrefix,
> +int *pisComplete,
> +int *pnoCase)
>  {
> -const char *z = 0;/* String on RHS of LIKE operator */
> -Expr *pRight, *pLeft;/* Right and left size of LIKE operator */
> -ExprList *pList;/* List of operands to the LIKE operator */
> -int c;/* One character in z[] */
> -int cnt;/* Number of non-wildcard prefix characters */
> -char wc[3];/* Wildcard characters */
> -sqlite3 *db = pParse->db;/* Database connection */
> +/* String on RHS of LIKE operator */
> +const char *z = 0;
> +/* Right and left size of LIKE operator */
> +Expr *pRight, *pLeft;
> +/* List of operands to the LIKE operator */
> +ExprList *pList;
> +/* One character in z[] */
> +int c;
> +/* Number of non-wildcard prefix characters */
> +int cnt;
> +/* Database connection */
> +sqlite3 *db = pParse->db;
> sqlite3_value *pVal = 0;
> -int op;/* Opcode of pRight */
> -int rc;/* Result code to return */
> +/* Opcode of pRight */
> +int op;
> +/* Result code to return */
> +int rc;
> -if (!sqlite3IsLikeFunction(db, pExpr, pnoCase, wc)) {
> +if (!sql_is_like_func(db, pExpr, pnoCase)) {
> return 0;
> }
> pList = pExpr->x.pList;
> @@ -257,8 +280,9 @@ isLikeOrGlob(Parse * pParse,/* Parsing and code 
> generating context */
> /* Value might be numeric */
> if (pLeft->op != TK_COLUMN ||
>    sqlite3ExprAffinity(pLeft) != AFFINITY_TEXT) {
> -/* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator 
> must
> -* be the name of an indexed column with TEXT affinity.
> +/* IMP: R-02065-49465 The left-hand side of the
> +* LIKE operator must be the name of an indexed
> +* column with TEXT affinity.
> */
> return 0;
> }
> @@ -281,13 +305,11 @@ isLikeOrGlob(Parse * pParse,/* Parsing and code 
> generating context */
> }
> if (z) {
> cnt = 0;
> -while ((c = z[cnt]) != 0 && c != wc[0] && c != wc[1]
> -      && c != wc[2]) {
> +while ((c = z[cnt]) != 0 && c != match_one && c != match_all)
> cnt++;
> -}
> if (cnt != 0 && 255 != (u8) z[cnt - 1]) {
> Expr *pPrefix;
> -*pisComplete = c == wc[0] && z[cnt + 1] == 0;
> +*pisComplete = c == match_all && z[cnt + 1] == 0;
> pPrefix = sqlite3Expr(db, TK_STRING, z);
> if (pPrefix)
> pPrefix->u.zToken[cnt] = 0;
> @@ -943,19 +965,32 @@ exprAnalyze(SrcList * pSrc,/* the FROM clause */
>    int idxTerm/* Index of the term to be analyzed */
>      )
>  {
> -WhereInfo *pWInfo = pWC->pWInfo;/* WHERE clause processing context */
> -WhereTerm *pTerm;/* The term to be analyzed */
> -WhereMaskSet *pMaskSet;/* Set of table index masks */
> -Expr *pExpr;/* The expression to be analyzed */
> -Bitmask prereqLeft;/* Prerequesites of the pExpr->pLeft */
> -Bitmask prereqAll;/* Prerequesites of pExpr */
> -Bitmask extraRight = 0;/* Extra dependencies on LEFT JOIN */
> -Expr *pStr1 = 0;/* RHS of LIKE/GLOB operator */
> -int isComplete = 0;/* RHS of LIKE/GLOB ends with wildcard */
> -int noCase = 0;/* uppercase equivalent to lowercase */
> -int op;/* Top-level operator.  pExpr->op */
> -Parse *pParse = pWInfo->pParse;/* Parsing context */
> -sqlite3 *db = pParse->db;/* Database connection */
> +/* WHERE clause processing context */
> +WhereInfo *pWInfo = pWC->pWInfo;
> +/* The term to be analyzed */
> +WhereTerm *pTerm;
> +/* Set of table index masks */
> +WhereMaskSet *pMaskSet;
> +/* The expression to be analyzed */
> +Expr *pExpr;
> +/* Prerequesites of the pExpr->pLeft */
> +Bitmask prereqLeft;
> +/* Prerequesites of pExpr */
> +Bitmask prereqAll;
> +/* Extra dependencies on LEFT JOIN */
> +Bitmask extraRight = 0;
> +/* RHS of LIKE operator */
> +Expr *pStr1 = 0;
> +/* RHS of LIKE ends with wildcard */
> +int isComplete = 0;
> +/* uppercase equivalent to lowercase */
> +int noCase = 0;
> +/* Top-level operator. pExpr->op */
> +int op;
> +/* Parsing context */
> +Parse *pParse = pWInfo->pParse;
> +/* Database connection */
> +sqlite3 *db = pParse->db;
> if (db->mallocFailed) {
> return;
> @@ -1111,37 +1146,44 @@ exprAnalyze(SrcList * pSrc,/* the FROM clause */
>  #endif/* SQLITE_OMIT_OR_OPTIMIZATION */
>  #ifndef SQLITE_OMIT_LIKE_OPTIMIZATION
> -/* Add constraints to reduce the search space on a LIKE or GLOB
> +/**
> +* Add constraints to reduce the search space on a LIKE
> * operator.
> *
> -* A like pattern of the form "x LIKE 'aBc%'" is changed into constraints
> +* A like pattern of the form "x LIKE 'aBc%'" is changed
> +* into constraints:
> *
> *          x>='ABC' AND x<'abd' AND x LIKE 'aBc%'
> *
> -* The last character of the prefix "abc" is incremented to form the
> -* termination condition "abd".  If case is not significant (the default
> -* for LIKE) then the lower-bound is made all uppercase and the upper-
> -* bound is made all lowercase so that the bounds also work when comparing
> -* BLOBs.
> +* The last character of the prefix "abc" is incremented
> +* to form the termination condition "abd". If case is
> +* not significant (the default for LIKE) then the
> +* lower-bound is made all uppercase and the upper-bound
> +* is made all lowercase so that the bounds also work
> +* when comparing BLOBs.
> */
> if (pWC->op == TK_AND
> -   && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
> -   ) {
> -Expr *pLeft;/* LHS of LIKE/GLOB operator */
> -Expr *pStr2;/* Copy of pStr1 - RHS of LIKE/GLOB operator */
> +   && is_like(pParse, pExpr, &pStr1, &isComplete, &noCase)) {
> +/* LHS of LIKE operator */
> +Expr *pLeft;
> +/* Copy of pStr1 - RHS of LIKE operator */
> +Expr *pStr2;
> Expr *pNewExpr1;
> Expr *pNewExpr2;
> int idxNew1;
> int idxNew2;
> -const char *zCollSeqName;/* Name of collating sequence */
> +/* Name of collating sequence */
> +const char *zCollSeqName;
> const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
> pLeft = pExpr->x.pList->a[1].pExpr;
> pStr2 = sqlite3ExprDup(db, pStr1, 0);
> -/* Convert the lower bound to upper-case and the upper bound to
> -* lower-case (upper-case is less than lower-case in ASCII) so that
> -* the range constraints also work for BLOBs
> +/**
> +* Convert the lower bound to upper-case and the
> +* upper bound to lower-case (upper-case is less
> +* than lower-case in ASCII) so that the range
> +* constraints also work for BLOBs
> */
> if (noCase && !pParse->db->mallocFailed) {
> int i;
> diff --git a/test/sql-tap/alter.test.lua b/test/sql-tap/alter.test.lua
> index cfe280121..98338c493 100755
> --- a/test/sql-tap/alter.test.lua
> +++ b/test/sql-tap/alter.test.lua
> @@ -232,7 +232,7 @@ test:do_execsql_test(
>      [[
>          CREATE TABLE xyz(x PRIMARY KEY);
>          ALTER TABLE xyz RENAME TO "xyz1234abc";
> -        SELECT "name" FROM "_space" WHERE "name" GLOB 'xyz*';
> +        SELECT "name" FROM "_space" WHERE "name" = 'xyz1234abc';
>      ]], {
>          -- <alter-5.1>
>          "xyz1234abc"
> @@ -243,7 +243,7 @@ test:do_execsql_test(
>      "alter-5.2",
>      [[
>          ALTER TABLE "xyz1234abc" RENAME TO xyzabc;
> -        SELECT "name" FROM "_space" WHERE "name" GLOB 'XYZ*';
> +        SELECT "name" FROM "_space" WHERE "name" = 'XYZABC';
>      ]], {
>          -- <alter-5.2>
>          "XYZABC"
> diff --git a/test/sql-tap/analyze9.test.lua 
> b/test/sql-tap/analyze9.test.lua
> index 3b3d52f67..ec3e545d8 100755
> --- a/test/sql-tap/analyze9.test.lua
> +++ b/test/sql-tap/analyze9.test.lua
> @@ -206,10 +206,10 @@ test:do_execsql_test(
>          INSERT INTO t1 VALUES(81, 1, 'one-i');
>          INSERT INTO t1 VALUES(91, 1, 'one-j');
>          INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
> -        INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 
> WHERE c GLOB 'one-*';
> -        INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE 
> c GLOB 'one-*';
> -        INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE 
> c GLOB 'one-*';
> -        INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE 
> c GLOB 'one-*';
> +        INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 
> WHERE c LIKE 'one-%';
> +        INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE 
> c LIKE 'one-%';
> +        INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE 
> c LIKE 'one-%';
> +        INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE 
> c LIKE 'one-%';
>          CREATE INDEX t1b ON t1(b);
>          ANALYZE;
>          SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
> diff --git a/test/sql-tap/e_expr.test.lua b/test/sql-tap/e_expr.test.lua
> index 9780d2cf9..0d69e8535 100755
> --- a/test/sql-tap/e_expr.test.lua
> +++ b/test/sql-tap/e_expr.test.lua
> @@ -1,6 +1,6 @@
>  #!/usr/bin/env tarantool
>  test = require("sqltester")
> -test:plan(10665)
> +test:plan(10647)
>  --!./tcltestrunner.lua
>  -- 2010 July 16
> @@ -77,10 +77,7 @@ local operations = {
>      {"<>", "ne1"},
>      {"!=", "ne2"},
>      {"IS", "is"},
> --- NOTE: This test needs refactoring after deletion of GLOB &
> ---type restrictions for LIKE. (See #3572)
>  --    {"LIKE", "like"},
> ---    {"GLOB", "glob"},
>      {"AND", "and"},
>      {"OR", "or"},
>      {"MATCH", "match"},
> @@ -98,12 +95,10 @@ operations = {
>      {"+", "-"},
>      {"<<", ">>", "&", "|"},
>      {"<", "<=", ">", ">="},
> --- NOTE: This test needs refactoring after deletion of GLOB &
> ---type restrictions for LIKE. (See #3572)
>  -- Another NOTE: MATCH & REGEXP aren't supported in Tarantool &
> --- are waiting for their hour, don't confuse them
> ---being commented with ticket above.
> -    {"=", "==", "!=", "<>"}, --"LIKE", "GLOB"}, --"MATCH", "REGEXP"},
> +--               are waiting for their hour, don't confuse them
> +--               being commented with commenting of "LIKE".
> +    {"=", "==", "!=", "<>"}, --"LIKE"}, --"MATCH", "REGEXP"},
>      {"AND"},
>      {"OR"},
>  }
> @@ -128,7 +123,7 @@ end
>  -- EVIDENCE-OF: R-15514-65163 SQLite understands the following binary
>  -- operators, in order from highest to lowest precedence: || * / % + -
>  -- << >> & | < <= > >= = == != <> IS IS
> --- NOT IN LIKE GLOB MATCH REGEXP AND OR
> +-- NOT IN LIKE MATCH REGEXP AND OR
>  --
>  -- EVIDENCE-OF: R-38759-38789 Operators IS and IS NOT have the same
>  -- precedence as =.
> @@ -482,7 +477,6 @@ for _, op in ipairs(oplist) do
>          end
>      end
>  end
> -
>  ---------------------------------------------------------------------------
>  -- Test the IS and IS NOT operators.
>  --
> @@ -1303,11 +1297,11 @@ end
>  test:execsql [[
>      CREATE TABLE tblname(cname PRIMARY KEY);
>  ]]
> +
>  local function glob(args)
>      return 1
>  end
> -box.internal.sql_create_function("GLOB", glob)
>  box.internal.sql_create_function("MATCH", glob)
>  box.internal.sql_create_function("REGEXP", glob)
>  local test_cases12 ={
> @@ -1369,47 +1363,43 @@ local test_cases12 ={
>      {47, "EXPR1 LIKE EXPR2"},
>      {48, "EXPR1 LIKE EXPR2 ESCAPE EXPR"},
> -    {49, "EXPR1 GLOB EXPR2"},
> -    {50, "EXPR1 GLOB EXPR2 ESCAPE EXPR"},
> -    {51, "EXPR1 REGEXP EXPR2"},
> -    {52, "EXPR1 REGEXP EXPR2 ESCAPE EXPR"},
> -    {53, "EXPR1 MATCH EXPR2"},
> -    {54, "EXPR1 MATCH EXPR2 ESCAPE EXPR"},
> -    {55, "EXPR1 NOT LIKE EXPR2"},
> -    {56, "EXPR1 NOT LIKE EXPR2 ESCAPE EXPR"},
> -    {57, "EXPR1 NOT GLOB EXPR2"},
> -    {58, "EXPR1 NOT GLOB EXPR2 ESCAPE EXPR"},
> -    {59, "EXPR1 NOT REGEXP EXPR2"},
> -    {60, "EXPR1 NOT REGEXP EXPR2 ESCAPE EXPR"},
> -    {61, "EXPR1 NOT MATCH EXPR2"},
> -    {62, "EXPR1 NOT MATCH EXPR2 ESCAPE EXPR"},
> -
> -    {63, "EXPR IS NULL"},
> -    {64, "EXPR IS NOT NULL"},
> -
> -    {65, "EXPR NOT BETWEEN EXPR1 AND EXPR2"},
> -    {66, "EXPR BETWEEN EXPR1 AND EXPR2"},
> -
> -    {67, "EXPR NOT IN (SELECT cname FROM tblname)"},
> -    {68, "EXPR NOT IN (1)"},
> -    {69, "EXPR NOT IN (1, 2, 3)"},
> -    {70, "EXPR NOT IN tblname"},
> -    {71, "EXPR IN (SELECT cname FROM tblname)"},
> -    {72, "EXPR IN (1)"},
> -    {73, "EXPR IN (1, 2, 3)"},
> -    {74, "EXPR IN tblname"},
> -
> -    {75, "EXISTS (SELECT cname FROM tblname)"},
> -    {76, "NOT EXISTS (SELECT cname FROM tblname)"},
> -
> -    {77, "CASE EXPR WHEN EXPR1 THEN EXPR2 ELSE EXPR END"},
> -    {78, "CASE EXPR WHEN EXPR1 THEN EXPR2 END"},
> -    {79, "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE 
> EXPR2 END"},
> -    {80, "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"},
> -    {81, "CASE WHEN EXPR1 THEN EXPR2 ELSE EXPR END"},
> -    {82, "CASE WHEN EXPR1 THEN EXPR2 END"},
> -    {83, "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE EXPR2 
> END"},
> -    {84, "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"},
> +    {49, "EXPR1 REGEXP EXPR2"},
> +    {50, "EXPR1 REGEXP EXPR2 ESCAPE EXPR"},
> +    {51, "EXPR1 MATCH EXPR2"},
> +    {52, "EXPR1 MATCH EXPR2 ESCAPE EXPR"},
> +    {53, "EXPR1 NOT LIKE EXPR2"},
> +    {54, "EXPR1 NOT LIKE EXPR2 ESCAPE EXPR"},
> +    {55, "EXPR1 NOT REGEXP EXPR2"},
> +    {56, "EXPR1 NOT REGEXP EXPR2 ESCAPE EXPR"},
> +    {57, "EXPR1 NOT MATCH EXPR2"},
> +    {58, "EXPR1 NOT MATCH EXPR2 ESCAPE EXPR"},
> +
> +    {59, "EXPR IS NULL"},
> +    {60, "EXPR IS NOT NULL"},
> +
> +    {61, "EXPR NOT BETWEEN EXPR1 AND EXPR2"},
> +    {62, "EXPR BETWEEN EXPR1 AND EXPR2"},
> +
> +    {63, "EXPR NOT IN (SELECT cname FROM tblname)"},
> +    {64, "EXPR NOT IN (1)"},
> +    {65, "EXPR NOT IN (1, 2, 3)"},
> +    {66, "EXPR NOT IN tblname"},
> +    {67, "EXPR IN (SELECT cname FROM tblname)"},
> +    {68, "EXPR IN (1)"},
> +    {69, "EXPR IN (1, 2, 3)"},
> +    {70, "EXPR IN tblname"},
> +
> +    {71, "EXISTS (SELECT cname FROM tblname)"},
> +    {72, "NOT EXISTS (SELECT cname FROM tblname)"},
> +
> +    {73, "CASE EXPR WHEN EXPR1 THEN EXPR2 ELSE EXPR END"},
> +    {74, "CASE EXPR WHEN EXPR1 THEN EXPR2 END"},
> +    {75, "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE 
> EXPR2 END"},
> +    {76, "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"},
> +    {77, "CASE WHEN EXPR1 THEN EXPR2 ELSE EXPR END"},
> +    {78, "CASE WHEN EXPR1 THEN EXPR2 END"},
> +    {79, "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE EXPR2 
> END"},
> +    {80, "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"},
>  }
>  for _, val in ipairs(test_cases12) do
> @@ -1802,7 +1792,7 @@ test:do_execsql_test(
>      })
>  ---------------------------------------------------------------------------
> --- Test the statements related to the LIKE and GLOB operators.
> +-- Test the statements related to the LIKE operator.
>  --
>  -- EVIDENCE-OF: R-16584-60189 The LIKE operator does a pattern matching
>  -- comparison.
> @@ -2274,102 +2264,38 @@ test:do_execsql_test(
>          -- </e_expr-16.1.7>
>      })
> --- EVIDENCE-OF: R-52087-12043 The GLOB operator is similar to LIKE but
> --- uses the Unix file globbing syntax for its wildcards.
> ---
> --- EVIDENCE-OF: R-09813-17279 Also, GLOB is case sensitive, unlike LIKE.
> +-- EVIDENCE-OF: R-39616-20555 LIKE may be preceded by the
> +-- NOT keyword to invert the sense of the test.
>  --
>  test:do_execsql_test(
> -    "e_expr-17.1.1",
> -    [[
> -        SELECT 'abcxyz' GLOB 'abc%'
> -    ]], {
> -        -- <e_expr-17.1.1>
> -        0
> -        -- </e_expr-17.1.1>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.2",
> -    [[
> -        SELECT 'abcxyz' GLOB 'abc*'
> -    ]], {
> -        -- <e_expr-17.1.2>
> -        1
> -        -- </e_expr-17.1.2>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.3",
> -    [[
> -        SELECT 'abcxyz' GLOB 'abc___'
> -    ]], {
> -        -- <e_expr-17.1.3>
> -        0
> -        -- </e_expr-17.1.3>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.4",
> -    [[
> -        SELECT 'abcxyz' GLOB 'abc???'
> -    ]], {
> -        -- <e_expr-17.1.4>
> -        1
> -        -- </e_expr-17.1.4>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.5",
> +    "e_expr-17.2.0",
>      [[
> -        SELECT 'abcxyz' GLOB 'abc*'
> +        PRAGMA case_sensitive_like = 1;
> +        SELECT 'abcxyz' NOT LIKE 'ABC%';
>      ]], {
> -        -- <e_expr-17.1.5>
> +        -- <e_expr-17.2.0>
>          1
> -        -- </e_expr-17.1.5>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.6",
> -    [[
> -        SELECT 'ABCxyz' GLOB 'abc*'
> -    ]], {
> -        -- <e_expr-17.1.6>
> -        0
> -        -- </e_expr-17.1.6>
> -    })
> -
> -test:do_execsql_test(
> -    "e_expr-17.1.7",
> -    [[
> -        SELECT 'abcxyz' GLOB 'ABC*'
> -    ]], {
> -        -- <e_expr-17.1.7>
> -        0
> -        -- </e_expr-17.1.7>
> +        -- </e_expr-17.2.0>
>      })
> --- EVIDENCE-OF: R-39616-20555 Both GLOB and LIKE may be preceded by the
> --- NOT keyword to invert the sense of the test.
> ---
>  test:do_execsql_test(
>      "e_expr-17.2.1",
>      [[
> -        SELECT 'abcxyz' NOT GLOB 'ABC*'
> +        SELECT 'abcxyz' NOT LIKE 'abc%'
>      ]], {
>          -- <e_expr-17.2.1>
> -        1
> +        0
>          -- </e_expr-17.2.1>
>      })
>  test:do_execsql_test(
>      "e_expr-17.2.2",
>      [[
> -        SELECT 'abcxyz' NOT GLOB 'abc*'
> +        PRAGMA case_sensitive_like = 0
>      ]], {
delete 17.2.1 17.2.2 (it was creaget for glob, like tested below), and move
`PRAGMA case_sensitive_like = 0` out of the test (it is not a test) (use 
just test:execsql or box.exequte)
>          -- <e_expr-17.2.2>
> -        0
> -        -- </e_expr-17.2.2>
> +
> +        -- <e_expr-17.2.2>
>      })
>  test:do_execsql_test(
> @@ -2448,62 +2374,6 @@ if 0>0 then
>      db("nullvalue", "")
>  end
> --- EVIDENCE-OF: R-39414-35489 The infix GLOB operator is implemented by
> --- calling the function glob(Y,X) and can be modified by overriding that
> --- function.
> -
> -local globargs = {}
> -local function globfunc(...)
> -    local args = {...}
> -    for i, v in ipairs(args) do
> -        table.insert(globargs, v)
> -    end
> -    return 1
> -end
> -box.internal.sql_create_function("GLOB", globfunc, 2)
> ---db("func", "glob", "-argcount", 2, "globfunc")
Do not delete this test. Rewrite it for like.
> -
> -test:do_execsql_test(
> -    "e_expr-17.3.1",
> -    [[
> -        SELECT 'abc' GLOB 'def'
> -    ]], {
> -        -- <e_expr-17.3.1>
> -        1
> -        -- </e_expr-17.3.1>
> -    })
> -
> -test:do_test(
> -    "e_expr-17.3.2",
> -    function()
> -        return globargs
> -    end, {
> -        -- <e_expr-17.3.2>
> -        "def", "abc"
> -        -- </e_expr-17.3.2>
> -    })
> -
> -globargs = {  }
> -test:do_execsql_test(
> -    "e_expr-17.3.3",
> -    [[
> -        SELECT 'X' NOT GLOB 'Y'
> -    ]], {
> -        -- <e_expr-17.3.3>
> -        0
> -        -- </e_expr-17.3.3>
> -    })
> -
> -test:do_test(
> -    "e_expr-17.3.4",
> -    function()
> -        return globargs
> -    end, {
> -        -- <e_expr-17.3.4>
> -        "Y", "X"
> -        -- </e_expr-17.3.4>
> -    })
> -
>  --sqlite3("db", "test.db")
>  -- EVIDENCE-OF: R-41650-20872 No regexp() user function is defined by
>  -- default and so use of the REGEXP operator will normally result in an
> diff --git a/test/sql-tap/gh-3251-string-pattern-comparison.test.lua 
> b/test/sql-tap/gh-3251-string-pattern-comparison.test.lua
> index addf0e36d..a6d822ccd 100755
> --- a/test/sql-tap/gh-3251-string-pattern-comparison.test.lua
> +++ b/test/sql-tap/gh-3251-string-pattern-comparison.test.lua
> @@ -142,17 +142,17 @@ for i, tested_string in ipairs(invalid_testcases) do
>      local test_name = prefix .. "2." .. tostring(i)
>      local test_itself = "SELECT 'abc' LIKE 'ab" .. tested_string .. "';"
>      test:do_catchsql_test(test_name, test_itself,
> -                          {1, "LIKE or GLOB pattern can only contain 
> UTF-8 characters"})
> +                          {1, "LIKE pattern can only contain UTF-8 
> characters"})
>      test_name = prefix .. "3." .. tostring(i)
>      test_itself = "SELECT 'abc' LIKE 'abc" .. tested_string .. "';"
>      test:do_catchsql_test(test_name, test_itself,
> -                          {1, "LIKE or GLOB pattern can only contain 
> UTF-8 characters"})
> +                          {1, "LIKE pattern can only contain UTF-8 
> characters"})
>      test_name = prefix .. "4." .. tostring(i)
>      test_itself = "SELECT 'abc' LIKE 'ab" .. tested_string .. "c';"
>      test:do_catchsql_test(test_name, test_itself,
> -                          {1, "LIKE or GLOB pattern can only contain 
> UTF-8 characters"})
> +                          {1, "LIKE pattern can only contain UTF-8 
> characters"})
>      -- Just skipping if row value predicand contains invalid character.
> @@ -185,7 +185,7 @@ local valid_testcases = {
>  -- Valid testcases.
>  for i, tested_string in ipairs(valid_testcases) do
> -    test_name = prefix .. "8." .. tostring(i)
> +    local test_name = prefix .. "8." .. tostring(i)
>      local test_itself = "SELECT 'abc' LIKE 'ab" .. tested_string .. "';"
>      test:do_execsql_test(test_name, test_itself, {0})
> diff --git a/test/sql-tap/like2.test.lua b/test/sql-tap/like2.test.lua
> index abcac39fb..c6c81cb4d 100755
> --- a/test/sql-tap/like2.test.lua
> +++ b/test/sql-tap/like2.test.lua
> @@ -12,11 +12,11 @@ test:plan(282)
>  --    May you find forgiveness for yourself and forgive others.
>  --    May you share freely, never taking more than you give.
>  --
> --------------------------------------------------------------------------
> --- This file implements regression tests for SQLite library.  The
> --- focus of this file is testing the LIKE and GLOB operators and
> --- in particular the optimizations that occur to help those operators
> --- run faster.
> +-----------------------------------------------------------------
> +-- This file implements regression tests for SQLite library. The
> +-- focus of this file is testing the LIKE operator and
> +-- in particular the optimizations that occur to help this
> +-- operator run faster.
>  --
>  -- $Id: like2.test,v 1.1 2008/05/26 18:33:41 drh Exp $
>  -- ["set","testdir",[["file","dirname",["argv0"]]]]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.tarantool.org/pipermail/tarantool-patches/attachments/20180911/96332d5e/attachment.html>


More information about the Tarantool-patches mailing list