From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id B6DCA280D9 for ; Tue, 31 Jul 2018 09:27:35 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2JLtfZqPh21Y for ; Tue, 31 Jul 2018 09:27:35 -0400 (EDT) Received: from mail-lj1-f174.google.com (mail-lj1-f174.google.com [209.85.208.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 0A1C6280CE for ; Tue, 31 Jul 2018 09:27:34 -0400 (EDT) Received: by mail-lj1-f174.google.com with SMTP id f8-v6so13737416ljk.1 for ; Tue, 31 Jul 2018 06:27:34 -0700 (PDT) MIME-Version: 1.0 References: <1530190036-10105-1-git-send-email-hollow653@gmail.com> <20180718024314.be245cmsgklxuvnk@tkn_work_nb> <20180727130601.b2oby7dleapd5upg@tkn_work_nb> <20180727202219.ikwbax7tysfnmgr4@tkn_work_nb> In-Reply-To: <20180727202219.ikwbax7tysfnmgr4@tkn_work_nb> From: Nikita Tatunov Date: Tue, 31 Jul 2018 16:27:21 +0300 Message-ID: Subject: [tarantool-patches] Re: [PATCH] sql: LIKE & GLOB pattern comparison issue Content-Type: multipart/alternative; boundary="00000000000064860205724b8af0" Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: Alexander Turenko Cc: tarantool-patches@freelists.org --00000000000064860205724b8af0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hello, thank you for review! Diff in the end. =D0=BF=D1=82, 27 =D0=B8=D1=8E=D0=BB. 2018 =D0=B3. =D0=B2 23:22, Alexander T= urenko < alexander.turenko@tarantool.org>: > Minor comments are below. Looks good for me in general. > > Please, review the patch with Lesha after the fixes. > > WBR, Alexander Turenko. > > > > > With the patch applied an error will be returned in case there's > > > > invalid UTF-8 symbol in pattern & pattern will not be matched > > > > with the string that contains it. Some minor corrections to functio= n > > > > were made as well. > > > > > > > > > > Nitpicking: 'error will be returned' is third situatuon, other then > > > 'matched' and 'not matched'. > > > > > > > > I guess commit message is about changes. Do I really need to > > mention valid cases that didn't change? > > > > Ok, now I got that 'it' is 'invalid symbol'. Misunderstood it before as > description of the one case when a pattern has invalid UTF-8 symbols. > The sentence is correct. Maybe it can be clarified like so: '& correct > UTF-8 pattern will not be matched with a string with invalid UTF-8 > symbols'. Or in another way you like. > > 'Some minor corrections to function were made as well' -- describe > certain behaviour or code changes (like 'fixed infinite loop during > pattern matching and incorrect matching as well') or remove this > abstract sentence. > > Fixed. > > > The function itself looks good except lines longer then 80 columns. > > > > > > > As i said before I don't think breaking these lines will increase > > readability. > > > > There are two little length exceed place in the code, it needs some > refactoring to decrease code blocks nesting level. I think we can lease > it as is for now (if other reviewer don't ask for that). > > But comments within the function are worth to fix to fit the limit. > > Fixed. > > +test:do_catchsql_set_test(like_test_cases, prefix) > > + > > +-- Invalid testcases. > > + > > +for i, tested_string in ipairs(invalid_testcases) do > > + > > +-- We should raise an error if pattern contains invalid characters. > > Again, indent comments to the same level as code in the block. > > If a comment is related to several code blocks (with empty lines btw), > then separate it with the empty line from the code (to don't > misinterpret it as related to the first block). > > Fixed > > + local test_name =3D prefix .. "2." .. tostring(i) > > + local test_itself =3D "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" > > + -- > > + }) > > + > > Are there reason to format it like so? Maybe just: > > test:do_catchsql_test(test_name, test_itself, > {1, "LIKE or GLOB pattern can only contain UTF-8 characters"}) > Fixed. diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 2f989d4..7f93ef6 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -703,11 +703,16 @@ sql_utf8_pattern_compare(const char * pattern, const struct compareInfo *pInfo, UChar32 matchOther) { - UChar32 c, c2; /* Next pattern and input string chars */ - UChar32 matchOne =3D pInfo->matchOne; /* "?" or "_" */ - UChar32 matchAll =3D pInfo->matchAll; /* "*" or "%" */ - UChar32 noCase =3D pInfo->noCase; /* True if uppercase=3D=3Dlowercase */ - const char *zEscaped =3D 0; /* One past the last escaped input char */ + /* Next pattern and input string chars */ + UChar32 c, c2; + /* "?" or "_" */ + UChar32 matchOne =3D pInfo->matchOne; + /* "*" or "%" */ + UChar32 matchAll =3D pInfo->matchAll; + /* True if uppercase=3D=3Dlowercase */ + UChar32 noCase =3D pInfo->noCase; + /* One past the last escaped input char */ + const char *zEscaped =3D 0; const char * pattern_end =3D pattern + strlen(pattern); const char * string_end =3D string + strlen(string); UErrorCode status =3D U_ZERO_ERROR; @@ -716,9 +721,11 @@ sql_utf8_pattern_compare(const char * pattern, if (c =3D=3D SQL_INVALID_UTF8_SYMBOL) return SQL_PROHIBITED_PATTERN; if (c =3D=3D matchAll) { /* Match "*" */ - /* 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 + /* 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. */ while ((c =3D Utf8Read(pattern, pattern_end)) !=3D SQL_END_OF_STRING) { @@ -733,7 +740,9 @@ sql_utf8_pattern_compare(const char * pattern, if (c2 =3D=3D SQL_INVALID_UTF8_SYMBOL) return SQLITE_NOMATCH; } - /* "*" at the end of the pattern matches */ + /* + * "*" at the end of the pattern matches. + */ if (c =3D=3D SQL_END_OF_STRING) { while ((c2 =3D Utf8Read(string, string_end)) !=3D SQL_END_OF_STRING) @@ -749,10 +758,14 @@ sql_utf8_pattern_compare(const char * pattern, if (c =3D=3D SQL_END_OF_STRING) return SQLITE_NOWILDCARDMATCH; } else { - /* "[...]" immediately follows the "*". We have to do a slow - * recursive search in this case, but it is an unusual case. + /* "[...]" immediately + * follows the "*". We + * have to do a slow + * recursive search in + * this case, but it is + * an unusual case. */ - assert(matchOther < 0x80); /* '[' is a single-byte character */ + assert(matchOther < 0x80); while (string < string_end) { int bMatch =3D sql_utf8_pattern_compare( @@ -770,14 +783,17 @@ sql_utf8_pattern_compare(const char * pattern, } } - /* At this point variable c contains the first character of the - * pattern string past the "*". Search in the input string for the - * first matching character and recursively continue the match from - * that point. + /* At this point variable c contains the + * first character of the pattern string + * past the "*". Search in the input + * string for the first matching + * character and recursively continue the + * match from that point. * - * For a case-insensitive search, set variable cx to be the same as - * c but in the other case and search the input string for either - * c or cx. + * For a case-insensitive search, set + * variable cx to be the same as c but in + * the other case and search the input + * string for either c or cx. */ int bMatch; @@ -785,12 +801,14 @@ sql_utf8_pattern_compare(const char * pattern, c =3D u_tolower(c); while (string < string_end){ /** - * This loop could have been implemented - * without if converting c2 to lower case - * (by holding c_upper and c_lower), however - * it is implemented this way because lower - * works better with German and Turkish - * languages. + * This loop could have been + * implemented without if + * converting c2 to lower case + * by holding c_upper and + * c_lower,however it is + * implemented this way because + * lower works better with German + * and Turkish languages. */ c2 =3D Utf8Read(string, string_end); if (c2 =3D=3D SQL_INVALID_UTF8_SYMBOL) @@ -878,11 +896,12 @@ sql_utf8_pattern_compare(const char * pattern, continue; if (noCase){ /** - * Small optimisation. Reduce number of calls - * to u_tolower function. - * SQL standards suggest use to_upper for symbol - * normalisation. However, using to_lower allows to - * respect Turkish '=C4=B0' in default locale. + * Small optimisation. Reduce number of + * calls to u_tolower function. SQL + * standards suggest use to_upper for + * symbol normalisation. However, using + * to_lower allows to respect Turkish '=C4=B0' + * in default locale. */ if (u_tolower(c) =3D=3D c2 || c =3D=3D u_tolower(c2)) 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 a823bc6..a8e4a12 100755 --- a/test/sql-tap/gh-3251-string-pattern-comparison.test.lua +++ b/test/sql-tap/gh-3251-string-pattern-comparison.test.lua @@ -6,276 +6,208 @@ local prefix =3D "like-test-" -- Unicode byte sequences. local valid_testcases =3D { - '\x01', - '\x09', - '\x1F', - '\x7F', - '\xC2\x80', - '\xC2\x90', - '\xC2\x9F', - '\xE2\x80\xA8', - '\x20\x0B', - '\xE2\x80\xA9', + '\x01', + '\x09', + '\x1F', + '\x7F', + '\xC2\x80', + '\xC2\x90', + '\xC2\x9F', + '\xE2\x80\xA8', + '\x20\x0B', + '\xE2\x80\xA9', } -- Non-Unicode byte sequences. local invalid_testcases =3D { - '\xE2\x80', - '\xFE\xFF', - '\xC2', - '\xED\xB0\x80', - '\xD0', + '\xE2\x80', + '\xFE\xFF', + '\xC2', + '\xED\xB0\x80', + '\xD0', } local like_test_cases =3D { - {"1.1", - "SELECT 'AB' LIKE '_B';", - {0, {1}} }, - {"1.2", - "SELECT 'CD' LIKE '_B';", - {0, {0}} }, - {"1.3", - "SELECT '' LIKE '_B';", - {0, {0}} }, - {"1.4", - "SELECT 'AB' LIKE '%B';", - {0, {1}} }, - {"1.5", - "SELECT 'CD' LIKE '%B';", - {0, {0}} }, - {"1.6", - "SELECT '' LIKE '%B';", - {0, {0}} }, - {"1.7", - "SELECT 'AB' LIKE 'A__';", - {0, {0}} }, - {"1.8", - "SELECT 'CD' LIKE 'A__';", - {0, {0}} }, - {"1.9", - "SELECT '' LIKE 'A__';", - {0, {0}} }, - {"1.10", - "SELECT 'AB' LIKE 'A_';", - {0, {1}} }, - {"1.11", - "SELECT 'CD' LIKE 'A_';", - {0, {0}} }, - {"1.12", - "SELECT '' LIKE 'A_';", - {0, {0}} }, - {"1.13", - "SELECT 'AB' LIKE 'A';", - {0, {0}} }, - {"1.14", - "SELECT 'CD' LIKE 'A';", - {0, {0}} }, - {"1.15", - "SELECT '' LIKE 'A';", - {0, {0}} }, - {"1.16", - "SELECT 'AB' LIKE '_';", - {0, {0}} }, - {"1.17", - "SELECT 'CD' LIKE '_';", - {0, {0}} }, - {"1.18", - "SELECT '' LIKE '_';", - {0, {0}} }, - {"1.19", - "SELECT 'AB' LIKE '__';", - {0, {1}} }, - {"1.20", - "SELECT 'CD' LIKE '__';", - {0, {1}} }, - {"1.21", - "SELECT '' LIKE '__';", - {0, {0}} }, - {"1.22", - "SELECT 'AB' LIKE '%A';", - {0, {0}} }, - {"1.23", - "SELECT 'AB' LIKE '%C';", - {0, {0}} }, - {"1.24", - "SELECT 'ab' LIKE '%df';", - {0, {0}} }, - {"1.25", - "SELECT 'abCDF' LIKE '%df';", - {0, {1}} }, - {"1.26", - "SELECT 'CDF' LIKE '%df';", - {0, {1}} }, - {"1.27", - "SELECT 'ab' LIKE 'a_';", - {0, {1}} }, - {"1.28", - "SELECT 'abCDF' LIKE 'a_';", - {0, {0}} }, - {"1.29", - "SELECT 'CDF' LIKE 'a_';", - {0, {0}} }, - {"1.30", - "SELECT 'ab' LIKE 'ab%';", - {0, {1}} }, - {"1.31", - "SELECT 'abCDF' LIKE 'ab%';", - {0, {1}} }, - {"1.32", - "SELECT 'CDF' LIKE 'ab%';", - {0, {0}} }, - {"1.33", - "SELECT 'ab' LIKE 'abC%';", - {0, {0}} }, - {"1.34", - "SELECT 'abCDF' LIKE 'abC%';", - {0, {1}} }, - {"1.35", - "SELECT 'CDF' LIKE 'abC%';", - {0, {0}} }, - {"1.36", - "SELECT 'ab' LIKE 'a_%';", - {0, {1}} }, - {"1.37", - "SELECT 'abCDF' LIKE 'a_%';", - {0, {1}} }, - {"1.38", - "SELECT 'CDF' LIKE 'a_%';", - {0, {0}} }, + {"1.1", + "SELECT 'AB' LIKE '_B';", + {0, {1}} }, + {"1.2", + "SELECT 'CD' LIKE '_B';", + {0, {0}} }, + {"1.3", + "SELECT '' LIKE '_B';", + {0, {0}} }, + {"1.4", + "SELECT 'AB' LIKE '%B';", + {0, {1}} }, + {"1.5", + "SELECT 'CD' LIKE '%B';", + {0, {0}} }, + {"1.6", + "SELECT '' LIKE '%B';", + {0, {0}} }, + {"1.7", + "SELECT 'AB' LIKE 'A__';", + {0, {0}} }, + {"1.8", + "SELECT 'CD' LIKE 'A__';", + {0, {0}} }, + {"1.9", + "SELECT '' LIKE 'A__';", + {0, {0}} }, + {"1.10", + "SELECT 'AB' LIKE 'A_';", + {0, {1}} }, + {"1.11", + "SELECT 'CD' LIKE 'A_';", + {0, {0}} }, + {"1.12", + "SELECT '' LIKE 'A_';", + {0, {0}} }, + {"1.13", + "SELECT 'AB' LIKE 'A';", + {0, {0}} }, + {"1.14", + "SELECT 'CD' LIKE 'A';", + {0, {0}} }, + {"1.15", + "SELECT '' LIKE 'A';", + {0, {0}} }, + {"1.16", + "SELECT 'AB' LIKE '_';", + {0, {0}} }, + {"1.17", + "SELECT 'CD' LIKE '_';", + {0, {0}} }, + {"1.18", + "SELECT '' LIKE '_';", + {0, {0}} }, + {"1.19", + "SELECT 'AB' LIKE '__';", + {0, {1}} }, + {"1.20", + "SELECT 'CD' LIKE '__';", + {0, {1}} }, + {"1.21", + "SELECT '' LIKE '__';", + {0, {0}} }, + {"1.22", + "SELECT 'AB' LIKE '%A';", + {0, {0}} }, + {"1.23", + "SELECT 'AB' LIKE '%C';", + {0, {0}} }, + {"1.24", + "SELECT 'ab' LIKE '%df';", + {0, {0}} }, + {"1.25", + "SELECT 'abCDF' LIKE '%df';", + {0, {1}} }, + {"1.26", + "SELECT 'CDF' LIKE '%df';", + {0, {1}} }, + {"1.27", + "SELECT 'ab' LIKE 'a_';", + {0, {1}} }, + {"1.28", + "SELECT 'abCDF' LIKE 'a_';", + {0, {0}} }, + {"1.29", + "SELECT 'CDF' LIKE 'a_';", + {0, {0}} }, + {"1.30", + "SELECT 'ab' LIKE 'ab%';", + {0, {1}} }, + {"1.31", + "SELECT 'abCDF' LIKE 'ab%';", + {0, {1}} }, + {"1.32", + "SELECT 'CDF' LIKE 'ab%';", + {0, {0}} }, + {"1.33", + "SELECT 'ab' LIKE 'abC%';", + {0, {0}} }, + {"1.34", + "SELECT 'abCDF' LIKE 'abC%';", + {0, {1}} }, + {"1.35", + "SELECT 'CDF' LIKE 'abC%';", + {0, {0}} }, + {"1.36", + "SELECT 'ab' LIKE 'a_%';", + {0, {1}} }, + {"1.37", + "SELECT 'abCDF' LIKE 'a_%';", + {0, {1}} }, + {"1.38", + "SELECT 'CDF' LIKE 'a_%';", + {0, {0}} }, } test:do_catchsql_set_test(like_test_cases, prefix) -- Invalid testcases. - for i, tested_string in ipairs(invalid_testcases) do --- We should raise an error if pattern contains invalid characters. - local test_name =3D prefix .. "2." .. tostring(i) - local test_itself =3D "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" - -- - }) + -- We should raise an error in case + -- pattern contains invalid characters. - test_name =3D prefix .. "3." .. tostring(i) - test_itself =3D "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" - -- - }) + local test_name =3D prefix .. "2." .. tostring(i) + local test_itself =3D "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"}) - test_name =3D prefix .. "4." .. tostring(i) - test_itself =3D "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" - -- - }) + test_name =3D prefix .. "3." .. tostring(i) + test_itself =3D "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"}) --- Just skipping if row value predicand contains invalid character. + test_name =3D prefix .. "4." .. tostring(i) + test_itself =3D "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"}) - test_name =3D prefix .. "5." .. tostring(i) - test_itself =3D "SELECT 'ab" .. tested_string .. "' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + -- Just skipping if row value predicand contains invalid character. - test_name =3D prefix .. "6." .. tostring(i) - test_itself =3D "SELECT 'abc" .. tested_string .. "' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test_name =3D prefix .. "5." .. tostring(i) + test_itself =3D "SELECT 'ab" .. tested_string .. "' LIKE 'abc';" + test:do_execsql_test(test_name, test_itself, {0}) - test_name =3D prefix .. "7." .. tostring(i) - test_itself =3D "SELECT 'ab" .. tested_string .. "c' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test_name =3D prefix .. "6." .. tostring(i) + test_itself =3D "SELECT 'abc" .. tested_string .. "' LIKE 'abc';" + test:do_execsql_test(test_name, test_itself, {0}) + + test_name =3D prefix .. "7." .. tostring(i) + test_itself =3D "SELECT 'ab" .. tested_string .. "c' LIKE 'abc';" + test:do_execsql_test(test_name, test_itself, {0}) end -- Valid testcases. - for i, tested_string in ipairs(valid_testcases) do test_name =3D prefix .. "8." .. tostring(i) local test_itself =3D "SELECT 'abc' LIKE 'ab" .. tested_string .. "';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) test_name =3D prefix .. "9." .. tostring(i) test_itself =3D "SELECT 'abc' LIKE 'abc" .. tested_string .. "';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) test_name =3D prefix .. "10." .. tostring(i) test_itself =3D "SELECT 'abc' LIKE 'ab" .. tested_string .. "c';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) + test_name =3D prefix .. "11." .. tostring(i) test_itself =3D "SELECT 'ab" .. tested_string .. "' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) test_name =3D prefix .. "12." .. tostring(i) test_itself =3D "SELECT 'abc" .. tested_string .. "' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) test_name =3D prefix .. "13." .. tostring(i) test_itself =3D "SELECT 'ab" .. tested_string .. "c' LIKE 'abc';" - test:do_execsql_test( - test_name, - test_itself, { - -- - 0 - -- - }) + test:do_execsql_test(test_name, test_itself, {0}) end test:finish_test() --00000000000064860205724b8af0 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hello, thank you for review!
Diff in the end.

<= br>
=D0=BF=D1=82, 27 =D0=B8=D1= =8E=D0=BB. 2018 =D0=B3. =D0=B2 23:22, Alexander Turenko <alexander.turenko@tarantool.org>= :
Minor comments= are below. Looks good for me in general.

Please, review the patch with Lesha after the fixes.

WBR, Alexander Turenko.

> > > With the patch applied an error will be returned in case the= re's
> > > invalid UTF-8 symbol in pattern & pattern will not be ma= tched
> > > with the string that contains it. Some minor corrections to = function
> > > were made as well.
> > >
> >
> > Nitpicking: 'error will be returned' is third situatuon, = other then
> > 'matched' and 'not matched'.
> >
> >
> I guess commit message is about changes. Do I really need to
> mention valid cases that didn't change?
>

Ok, now I got that 'it' is 'invalid symbol'. Misunderstood = it before as
description of the one case when a pattern has invalid UTF-8 symbols.
The sentence is correct. Maybe it can be clarified like so: '& corr= ect
UTF-8 pattern will not be matched with a string with invalid UTF-8
symbols'. Or in another way you like.

'Some minor corrections to function were made as well' -- describe<= br> certain behaviour or code changes (like 'fixed infinite loop during
pattern matching and incorrect matching as well') or remove this
abstract sentence.


Fixed.
=C2=A0
> > The function itself looks good except lines longer then 80 column= s.
> >
>
> As i said before I don't think breaking these lines will increase<= br> > readability.
>

There are two little length exceed place in the code, it needs some
refactoring to decrease code blocks nesting level. I think we can lease
it as is for now (if other reviewer don't ask for that).

But comments within the function are worth to fix to fit the limit.


Fixed.
=C2=A0
> +test:do_catchsql_set_test(like_test_cases, prefix)
> +
> +-- Invalid testcases.
> +
> +for i, tested_string in ipairs(invalid_testcases) do
> +
> +-- We should raise an error if pattern contains invalid characters.
Again, indent comments to the same level as code in the block.

If a comment is related to several code blocks (with empty lines btw),
then separate it with the empty line from the code (to don't
misinterpret it as related to the first block).


Fixed
=C2=A0
> + local test_name =3D prefix .. "2." .. tostring(i)
> + local test_itself =3D "SELECT 'abc' LIKE 'ab" = .. tested_string .. "';"
> + test:do_catchsql_test(
> + test_name,
> + test_itself, {
> + -- <test_name>
> + 1, "LIKE or GLOB pattern can only contain UTF-8 characters"= ;
> + -- <test_name>
> + })
> +

Are there reason to format it like so? Maybe just:

test:do_catchsql_test(test_name, test_itself,
=C2=A0 =C2=A0 {1, "LIKE or GLOB pattern can only contain UTF-8 charact= ers"})

Fixed.=C2=A0

=
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
<= div>index 2f989d4..7f93ef6 100644
--- a/src/box/sql/func.c
<= div>+++ b/src/box/sql/func.c
@@ -703,11 +703,16 @@ sql_utf8_patte= rn_compare(const char * pattern,
=C2=A0 const struct compareInfo *pInfo,
=C2=A0 UChar32 matchOther)
=C2=A0{
- UChar32 c, c2; /* Next pattern and input string chars */
- UChar32 matchOne =3D pInfo-= >matchOne; /* "?" or &q= uot;_" */
- UChar32 m= atchAll =3D pInfo->matchAll; /* &= quot;*" or "%" */
- UChar32 noCase =3D pInfo->noCase; /* True if uppercase=3D=3Dlowercase */
- const char *zEscaped =3D 0; /* One past the last escaped input char */
+ /* Next pattern and input string chars = */
+ UChar32 c, c2;
<= div>+ /* "?" or "_&qu= ot; */
+ UChar32 matchOne = =3D pInfo->matchOne;
+ = /* "*" or "%" */
+ UChar32 matchAll =3D pInfo->matchAll;
+ /* True if uppercase=3D=3Dlowercase */
<= div>+ UChar32 noCase =3D pInfo->n= oCase;
+ /* One past the l= ast escaped input char */
+ const char *zEscaped =3D 0;
=C2=A0 const char * pattern_end =3D pattern + strlen(pattern);
=C2=A0 const char * string_end =3D= string + strlen(string);
=C2=A0 = UErrorCode status =3D U_ZERO_ERROR;
@@ -716,9 +721,11 @@ s= ql_utf8_pattern_compare(const char * pattern,
=C2=A0 if (c =3D=3D SQL_INVALID_UTF8_SYMBOL)
=C2=A0 return SQL_PROHIBITED_PA= TTERN;
=C2=A0 if (c =3D= =3D matchAll) { /* Match "*&quo= t; */
- /* Skip over mul= tiple "*" characters in the pattern.=C2=A0 If there
- * are also "?" character= s, skip those as well, but consume a
- * single character of the input string for each "?&quo= t; skipped
+ /* Skip ove= r multiple "*" characters in
+ * the pattern. If there are also "?"
= + * characters, skip those as wel= l, but
+ * consume a si= ngle character of the
+ = * input string for each "?" skipped.
=C2=A0 */
=C2=A0 while ((c =3D Utf8Read(pattern, pattern_end)) !=3D
<= div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0SQL_END_OF_STRING) {
@@ -733,7 +740,9 @@ sql_utf8_pattern_c= ompare(const char * pattern,
=C2=A0 if (c2 =3D=3D SQL_INVALID_UTF8_SYMBOL)
=C2=A0 return SQLITE_NOMATCH;
=C2= =A0 }
- /* "*" at the end of the pattern matches= */
+ /*
+ * "*" at the end of the pa= ttern matches.
+ */
=C2=A0 if (c =3D=3D SQL_END= _OF_STRING) {
=C2=A0 wh= ile ((c2 =3D Utf8Read(string, string_end)) !=3D
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0SQL_END_OF_STRIN= G)
@@ -749,10 +758,14 @@ sql_utf8_pattern_compare(const char * pa= ttern,
=C2=A0 if (c = =3D=3D SQL_END_OF_STRING)
=C2=A0 = return SQLITE_NOWILDCARDMATCH;
=C2=A0 } else {
- /* "[...]" immediately follows the "*".= =C2=A0 We have to do a slow
- = * recursive search in this case, but it is an unusual case.
<= div>+ /* "[...]" immed= iately
+ * follows th= e "*". We
+ = * have to do a slow
+ * recursive search in
+ * this case, but it is
+ = * an unusual case.
=C2=A0 */
- ass= ert(matchOther < 0x80); /* '[= ' is a single-byte character */
+ assert(matchOther < 0x80);
=C2=A0 while (string < string_end) {
=C2=A0 int bMatch =3D=C2=A0 =C2=A0 =C2=A0 sql_utf8= _pattern_compare(
@@ -770,14 +783,17 @@ sql_utf8_pattern_compare(= const char * pattern,
=C2=A0 <= /span>}
=C2=A0 }
=C2=A0
- /* At this p= oint variable c contains the first character of the
- * pattern string past the "*".=C2= =A0 Search in the input string for the
- * first matching character and recursively continue the m= atch from
- * that poin= t.
+ /* At this point va= riable c contains the
+ = * first character of the pattern string
+ * past the "*". Search in the input
+ * string for the first matchin= g
+ * character and rec= ursively continue the
+ = * match from that point.
=C2=A0 = *
- * For a c= ase-insensitive search, set variable cx to be the same as
- * c but in the other case and search t= he input string for either
- * c or cx.
+ * Fo= r a case-insensitive search, set
+ * variable cx to be the same as c but in
+ * the other case and search the input
=
+ * string for either c or c= x.
=C2=A0 */
= =C2=A0
=C2=A0 int bMatch= ;
@@ -785,12 +801,14 @@ sql_utf8_pattern_compare(const char * pat= tern,
=C2=A0 c =3D u_to= lower(c);
=C2=A0 while (= string < string_end){
=C2=A0 = /**
- * This = loop could have been implemented
- * without if converting c2 to lower case
- * (by holding c_upper and c_lower), howev= er
- * it is implement= ed this way because lower
- * works better with German and Turkish
- * languages.
+ * This loop could have been
+ * implemented without if
+ * converting c2 to lower case
+<= span style=3D"white-space:pre"> * by holding c_upper and
+ * c_lower,however it is
+ * implemented this way = because
+ * lower work= s better with German
+ = * and Turkish languages.
=C2=A0 = */
=C2=A0 c2= =3D Utf8Read(string, string_end);
=C2=A0 if (c2 =3D=3D SQL_INVALID_UTF8_SYMBOL)
@@ -878= ,11 +896,12 @@ sql_utf8_pattern_compare(const char * pattern,
=C2= =A0 continue;
=C2=A0 if (noCase){
=C2=A0 /**
- * Small optimisation. Reduce number of calls
- * to u_tolower function.
= - * SQL standards suggest use to_= upper for symbol
- * no= rmalisation. However, using to_lower allows to
- * respect Turkish '=C4=B0' in default loc= ale.
+ * Small optimisa= tion. Reduce number of
+ * calls to u_tolower function. SQL
+ * standards suggest use to_upper for
+ * symbol normalisation. However, using
+ * to_lower allows to resp= ect Turkish '=C4=B0'
+ = * in default locale.
=C2=A0 */
=C2=A0 i= f (u_tolower(c) =3D=3D c2 ||
=C2=A0 =C2=A0 =C2=A0 c =3D=3D u_tolower(c2))
diff --git a/te= st/sql-tap/gh-3251-string-pattern-comparison.test.lua b/test/sql-tap/gh-325= 1-string-pattern-comparison.test.lua
index a823bc6..a8e4a12 10075= 5
--- a/test/sql-tap/gh-3251-string-pattern-comparison.test.lua
+++ b/test/sql-tap/gh-3251-string-pattern-comparison.test.lua
@@ -6,276 +6,208 @@ local prefix =3D "like-test-"
=C2=A0
=C2=A0-- Unicode byte sequences.
=C2=A0local va= lid_testcases =3D {
- '= ;\x01',
- '\x09= 9;,
- '\x1F',
- '\x7F',
-<= span style=3D"white-space:pre"> '\xC2\x80',
- '\xC2\x90',
- '\xC2\x9F',
- '\xE2\x80\xA8',
- '\x20\x0B',
- '\xE2\x80\xA9',
+=C2=A0 =C2=A0 &= #39;\x01',
+=C2=A0 =C2=A0 '\x09',
+=C2=A0 = =C2=A0 '\x1F',
+=C2=A0 =C2=A0 '\x7F',
+= =C2=A0 =C2=A0 '\xC2\x80',
+=C2=A0 =C2=A0 '\xC2\x90= 9;,
+=C2=A0 =C2=A0 '\xC2\x9F',
+=C2=A0 =C2=A0 &= #39;\xE2\x80\xA8',
+=C2=A0 =C2=A0 '\x20\x0B',
+=C2=A0 =C2=A0 '\xE2\x80\xA9',
=C2=A0}
=C2= =A0
=C2=A0-- Non-Unicode byte sequences.
=C2=A0local in= valid_testcases =3D {
- &#= 39;\xE2\x80',
- '\= xFE\xFF',
- '\xC2&= #39;,
- '\xED\xB0\x80&= #39;,
- '\xD0',
+=C2=A0 =C2=A0 '\xE2\x80',
+=C2=A0 =C2=A0 '\x= FE\xFF',
+=C2=A0 =C2=A0 '\xC2',
+=C2=A0 =C2= =A0 '\xED\xB0\x80',
+=C2=A0 =C2=A0 '\xD0',
<= div>=C2=A0}
=C2=A0
=C2=A0local like_test_cases =3D
=C2=A0{
- {"1.1= ",
- "SELECT &#= 39;AB' LIKE '_B';",
- {0, {1}} },
- {"1.2",
- &qu= ot;SELECT 'CD' LIKE '_B';",
- {0, {0}} },
- {"1.3",
-= "SELECT '' LIKE '_B';",
- {0, {0}} },
- {"1.4",
- "SELECT 'AB' LIKE '%B';",
- {0, {1}} },
- {"1.5",
- "SELECT 'CD' LIKE '%B';= ",
- {0, {0}} },
- {"1.6",
- "SELECT '' LIKE = 9;%B';",
- {0, {= 0}} },
- {"1.7",=
- "SELECT 'AB&#= 39; LIKE 'A__';",
- = {0, {0}} },
- {&qu= ot;1.8",
- "SEL= ECT 'CD' LIKE 'A__';",
- {0, {0}} },
- {"1.9",
- "SELECT '' LIKE 'A__';",
- {0, {0}} },
- {"1.10",
- "SELECT 'AB' LIKE 'A_';",
- {0, {1}} },
- {"1.11",
- "SELECT 'CD' LIKE 'A_';&= quot;,
- {0, {0}} },
- {"1.12",
- "SELECT '' LIKE = 9;A_';",
- {0, {= 0}} },
- {"1.13"= ,
- "SELECT 'AB&= #39; LIKE 'A';",
- = {0, {0}} },
- {&quo= t;1.14",
- "SEL= ECT 'CD' LIKE 'A';",
- {0, {0}} },
- = {"1.15",
- "SELECT '' LIKE 'A';",
- {0, {0}} },
- {"1.16",
- "SELECT 'AB' LIKE '_';",
= - {0, {0}} },
- {"1.17",
- "SELECT 'CD' LIKE '_';"= ,
- {0, {0}} },
- {"1.18",
- "SELECT '' LIKE '_&#= 39;;",
- {0, {0}} },=
- {"1.19",
- "SELECT 'AB' L= IKE '__';",
- {0, {1}} },
- {"1.2= 0",
- "SELECT &= #39;CD' LIKE '__';",
- {0, {1}} },
- {"1.21",
- &= quot;SELECT '' LIKE '__';",
- {0, {0}} },
- {"1.22",
- "SELECT 'AB' LIKE '%A';",
- {0, {0}} },
- {"1.23",
- "SELECT 'AB' LIKE '%C';"= ,
- {0, {0}} },
- {"1.24",
- "SELECT 'ab' LIKE '%= df';",
- {0, {0}= } },
- {"1.25",<= /div>
- "SELECT 'abCDF= ' LIKE '%df';",
- {0, {1}} },
- {&= quot;1.26",
- "= SELECT 'CDF' LIKE '%df';",
- {0, {1}} },
- {"1.27",
-= "SELECT 'ab' LIKE 'a_';",
- {0, {1}} },
- {"1.28",
- "SELECT 'abCDF' LIKE 'a_';"= ,
- {0, {0}} },
- {"1.29",
- "SELECT 'CDF' LIKE '= a_';",
- {0, {0}= } },
- {"1.30",<= /div>
- "SELECT 'ab= 9; LIKE 'ab%';",
- = {0, {1}} },
- {&quo= t;1.31",
- "SEL= ECT 'abCDF' LIKE 'ab%';",
- {0, {1}} },
- {"1.32",
- = "SELECT 'CDF' LIKE 'ab%';",
- {0, {0}} },
- {"1.33",
- "SELECT 'ab' LIKE 'abC%';&quo= t;,
- {0, {0}} },
- {"1.34",
-<= span style=3D"white-space:pre"> "SELECT 'abCDF' LIKE &= #39;abC%';",
- {= 0, {1}} },
- {"1.35&q= uot;,
- "SELECT '= ;CDF' LIKE 'abC%';",
- {0, {0}} },
- {"1.36",
- &= quot;SELECT 'ab' LIKE 'a_%';",
- {0, {1}} },
- {"1.37",
- "SELECT 'abCDF' LIKE 'a_%';",
=
- {0, {1}} },
- {"1.38",
- "SELECT 'CDF' LIKE 'a_%'= ;;",
- {0, {0}} },
+=C2=A0 =C2=A0 {"1.1",
+=C2=A0 =C2=A0 =C2=A0 = =C2=A0 "SELECT 'AB' LIKE '_B';",
+=C2= =A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2=A0 {"1.2&qu= ot;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'CD' LIKE = '_B';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.3",
+=C2=A0 =C2=A0 =C2=A0 =C2= =A0 "SELECT '' LIKE '_B';",
+=C2=A0 =C2= =A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.4",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'AB' LIKE '%B= ';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
= +=C2=A0 =C2=A0 {"1.5",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 &qu= ot;SELECT 'CD' LIKE '%B';",
+=C2=A0 =C2=A0 = =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.6",
<= div>+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT '' LIKE '%B';= ",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2= =A0 =C2=A0 {"1.7",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "S= ELECT 'AB' LIKE 'A__';",
+=C2=A0 =C2=A0 =C2= =A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.8",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'CD' LIKE 'A__';= ",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2= =A0 =C2=A0 {"1.9",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "S= ELECT '' LIKE 'A__';",
+=C2=A0 =C2=A0 =C2=A0= =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.10",
+= =C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'AB' LIKE 'A_';&qu= ot;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 = =C2=A0 {"1.11",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELE= CT 'CD' LIKE 'A_';",
+=C2=A0 =C2=A0 =C2=A0 = =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.12",
+= =C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT '' LIKE 'A_';"= ;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2= =A0 {"1.13",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT = 'AB' LIKE 'A';",
+=C2=A0 =C2=A0 =C2=A0 =C2= =A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.14",
+=C2= =A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'CD' LIKE 'A';",=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2= =A0 {"1.15",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT = '' LIKE 'A';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 = {0, {0}} },
+=C2=A0 =C2=A0 {"1.16",
+=C2=A0 = =C2=A0 =C2=A0 =C2=A0 "SELECT 'AB' LIKE '_';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {&= quot;1.17",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'C= D' LIKE '_';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, = {0}} },
+=C2=A0 =C2=A0 {"1.18",
+=C2=A0 =C2= =A0 =C2=A0 =C2=A0 "SELECT '' LIKE '_';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"= 1.19",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'AB'= ; LIKE '__';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}}= },
+=C2=A0 =C2=A0 {"1.20",
+=C2=A0 =C2=A0 = =C2=A0 =C2=A0 "SELECT 'CD' LIKE '__';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2=A0 {"1= .21",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT '' L= IKE '__';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },=
+=C2=A0 =C2=A0 {"1.22",
+=C2=A0 =C2=A0 =C2= =A0 =C2=A0 "SELECT 'AB' LIKE '%A';",
+= =C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.2= 3",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'AB' L= IKE '%C';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },=
+=C2=A0 =C2=A0 {"1.24",
+=C2=A0 =C2=A0 =C2= =A0 =C2=A0 "SELECT 'ab' LIKE '%df';",
+= =C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.2= 5",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'abCDF'= ; LIKE '%df';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}= } },
+=C2=A0 =C2=A0 {"1.26",
+=C2=A0 =C2=A0 = =C2=A0 =C2=A0 "SELECT 'CDF' LIKE '%df';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2=A0 {"= ;1.27",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'ab= 9; LIKE 'a_';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}= } },
+=C2=A0 =C2=A0 {"1.28",
+=C2=A0 =C2=A0 = =C2=A0 =C2=A0 "SELECT 'abCDF' LIKE 'a_';",
<= div>+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {&quo= t;1.29",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'CDF&= #39; LIKE 'a_';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {= 0}} },
+=C2=A0 =C2=A0 {"1.30",
+=C2=A0 =C2=A0= =C2=A0 =C2=A0 "SELECT 'ab' LIKE 'ab%';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2=A0 {"= ;1.31",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'abCDF= ' LIKE 'ab%';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0,= {1}} },
+=C2=A0 =C2=A0 {"1.32",
+=C2=A0 =C2= =A0 =C2=A0 =C2=A0 "SELECT 'CDF' LIKE 'ab%';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {&= quot;1.33",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'a= b' LIKE 'abC%';",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {= 0, {0}} },
+=C2=A0 =C2=A0 {"1.34",
+=C2=A0 = =C2=A0 =C2=A0 =C2=A0 "SELECT 'abCDF' LIKE 'abC%';"= ;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2= =A0 {"1.35",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT = 'CDF' LIKE 'abC%';",
+=C2=A0 =C2=A0 =C2=A0 = =C2=A0 {0, {0}} },
+=C2=A0 =C2=A0 {"1.36",
+= =C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'ab' LIKE 'a_%';&q= uot;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {1}} },
+=C2=A0 = =C2=A0 {"1.37",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELE= CT 'abCDF' LIKE 'a_%';",
+=C2=A0 =C2=A0 =C2= =A0 =C2=A0 {0, {1}} },
+=C2=A0 =C2=A0 {"1.38",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 "SELECT 'CDF' LIKE 'a_%'= ;;",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {0, {0}} },
=C2= =A0}
=C2=A0
=C2=A0test:do_catchsql_set_test(like_test_c= ases, prefix)
=C2=A0
=C2=A0-- Invalid testcases.
<= div>-
=C2=A0for i, tested_string in ipairs(invalid_testcases) do<= /div>
=C2=A0
--- We should raise an error if pattern contains= invalid characters.
- loc= al test_name =3D prefix .. "2." .. tostring(i)
- local test_itself =3D "SELECT 'ab= c' LIKE 'ab" .. tested_string .. "';"
= - test:do_catchsql_test(
-= test_name,
- test_itself, {
- -- <test_name>
- 1, "LIKE or GLOB pattern can only contain UTF-8 = characters"
- -- &l= t;test_name>
- })
+=C2=A0 =C2=A0 -- We should raise an error in case
+=C2=A0 = =C2=A0 -- pattern contains invalid characters.
=C2=A0
-= test_name =3D prefix .. "3.&qu= ot; .. tostring(i)
- test_= itself =3D "SELECT 'abc' LIKE 'abc" .. tested_string = .. "';"
- te= st:do_catchsql_test(
- te= st_name,
- test_itself, {=
- -- <test_name><= /div>
- 1, "LIKE or GLOB = pattern can only contain UTF-8 characters"
- -- <test_name>
- })
+=C2=A0 =C2=A0 local test_name =3D pre= fix .. "2." .. tostring(i)
+=C2=A0 =C2=A0 local test_it= self =3D "SELECT 'abc' LIKE 'ab" .. tested_string .. = "';"
+=C2=A0 =C2=A0 test:do_catchsql_test(test_name= , test_itself,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {1, "LIKE or GLOB pattern ca= n only contain UTF-8 characters"})
=C2=A0
- test_name =3D prefix .. "4." .. = tostring(i)
- test_itself = =3D "SELECT 'abc' LIKE 'ab" .. tested_string .. "= ;c';"
- test:do_c= atchsql_test(
- test_name= ,
- test_itself, {
<= div>- -- <test_name>
- 1, "LIKE or GLOB pattern= can only contain UTF-8 characters"
- -- <test_name>
- })
+=C2=A0 =C2=A0 test_name =3D prefix .. "= 3." .. tostring(i)
+=C2=A0 =C2=A0 test_itself =3D "SELE= CT 'abc' LIKE 'abc" .. tested_string .. "';"=
+=C2=A0 =C2=A0 test:do_catchsql_test(test_name, test_itself,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 {1, "LIKE or GLOB pattern can only contain UT= F-8 characters"})
=C2=A0
--- Just skipping if row = value predicand contains invalid character.
+=C2=A0 =C2=A0 test_n= ame =3D prefix .. "4." .. tostring(i)
+=C2=A0 =C2=A0 te= st_itself =3D "SELECT 'abc' LIKE 'ab" .. tested_strin= g .. "c';"
+=C2=A0 =C2=A0 test:do_catchsql_test(tes= t_name, test_itself,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {1, "LIKE or GLOB pat= tern can only contain UTF-8 characters"})
=C2=A0
-= test_name =3D prefix .. "5.&qu= ot; .. tostring(i)
- test_= itself =3D "SELECT 'ab" .. tested_string .. "' LIKE = 'abc';"
- tes= t:do_execsql_test(
- test= _name,
- test_itself, {
- -- <test_name>
- 0
- -- <test_name>
- })
+=C2=A0 =C2=A0 -- Just skipping = if row value predicand contains invalid character.
=C2=A0
- test_name =3D prefix .. "6= ." .. tostring(i)
- t= est_itself =3D "SELECT 'abc" .. tested_string .. "' = LIKE 'abc';"
- test:do_execsql_test(
- test_name,
- test_itself= , {
- -- <test_name&g= t;
- 0
- -- <test_name>
- })
+=C2=A0 =C2=A0 test_name =3D= prefix .. "5." .. tostring(i)
+=C2=A0 =C2=A0 test_itse= lf =3D "SELECT 'ab" .. tested_string .. "' LIKE '= ;abc';"
+=C2=A0 =C2=A0 test:do_execsql_test(test_name, t= est_itself, {0})
=C2=A0
- test_name =3D prefix .. "7." .. tostring(i)
-= test_itself =3D "SELECT 'a= b" .. tested_string .. "c' LIKE 'abc';"
- test:do_execsql_test(
= - test_name,
- test_itself, {
- -- <test_name>
- 0
- -- <test_name>
- = })
+=C2=A0 =C2=A0 test_name =3D prefix .. "6." .. tostr= ing(i)
+=C2=A0 =C2=A0 test_itself =3D "SELECT 'abc"= .. tested_string .. "' LIKE 'abc';"
+=C2= =A0 =C2=A0 test:do_execsql_test(test_name, test_itself, {0})
+
+=C2=A0 =C2=A0 test_name =3D prefix .. "7." .. tostring(i= )
+=C2=A0 =C2=A0 test_itself =3D "SELECT 'ab" .. te= sted_string .. "c' LIKE 'abc';"
+=C2=A0 =C2= =A0 test:do_execsql_test(test_name, test_itself, {0})
=C2=A0end
=C2=A0
=C2=A0-- Valid testcases.
-
= =C2=A0for i, tested_string in ipairs(valid_testcases) do
=C2=A0 test_name =3D prefix .. "8."= ; .. tostring(i)
=C2=A0 lo= cal test_itself =3D "SELECT 'abc' LIKE 'ab" .. tested= _string .. "';"
- <= /span>test:do_execsql_test(
- test_name,
- test_it= self, {
- -- <test_na= me>
- 0
- -- <test_name>
- })
+ test:do_execsql_test(test_name, test_itself, {0})
=C2=A0
=C2=A0 test_name = =3D prefix .. "9." .. tostring(i)
=C2=A0 test_itself =3D "SELECT 'abc' LIKE &#= 39;abc" .. tested_string .. "';"
- test:do_execsql_test(
- test_name,
- test_itself, {
- -- <test_name>
-= 0
- -- <tes= t_name>
- })
+ test:do_execsql_test(test_name, t= est_itself, {0})
=C2=A0
=C2=A0 test_name =3D prefix .. "10." .. tostring(i)
=
=C2=A0 test_itself =3D "SE= LECT 'abc' LIKE 'ab" .. tested_string .. "c';&quo= t;
- test:do_execsql_test(=
- test_name,
-= test_itself, {
- -- <test_name>
- 0
- -- <test_name>
- })
+ test:do_ex= ecsql_test(test_name, test_itself, {= 0})
+
=C2=A0 tes= t_name =3D prefix .. "11." .. tostring(i)
=C2=A0 test_itself =3D "SELECT 'ab"= .. tested_string .. "' LIKE 'abc';"
- test:do_execsql_test(
- test_name,
- test_itself, {
- -- <test_name>
- 0
- -- <= ;test_name>
- })
=
+ test:do_execsql_test(test_nam= e, test_itself, {0})
=C2= =A0
=C2=A0 test_name =3D p= refix .. "12." .. tostring(i)
=C2=A0 test_itself =3D "SELECT 'abc" .. tested_= string .. "' LIKE 'abc';"
- test:do_execsql_test(
- test_name,
- test_itself, {
- -- <test_name>
- 0
- -- <test_name&= gt;
- })
+ test:do_execsql_test(test_name, test_its= elf, {0})
=C2=A0
=C2=A0= test_name =3D prefix .. "13." .. tostring(i)
= =C2=A0 test_itself =3D "SELECT = 'ab" .. tested_string .. "c' LIKE 'abc';"
- test:do_execsql_test(
- test_name,
- test_itself, {
- -- <test_name>
- 0
- -- <test_name>
-= })
+ test:do_exec= sql_test(test_name, test_itself, {0})
=C2=A0end
=C2=A0<= /div>
=C2=A0test:finish_test()


--00000000000064860205724b8af0--