<div dir="ltr"><div>Branch: <a href="https://github.com/tarantool/tarantool/tree/N_Tatunov/gh-3251-where-like-hanging">https://github.com/tarantool/tarantool/tree/N_Tatunov/gh-3251-where-like-hanging</a></div><div>Issue: <a href="https://github.com/tarantool/tarantool/issues/3251">https://github.com/tarantool/tarantool/issues/3251</a></div><div>Issue: <a href="https://github.com/tarantool/tarantool/issues/3334">https://github.com/tarantool/tarantool/issues/3334</a></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">чт, 28 июн. 2018 г. в 15:47, N.Tatunov <<a href="mailto:hollow653@gmail.com">hollow653@gmail.com</a>>:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Currently function that compares pattern and<br>
string for GLOB & LIKE operators doesn't work properly.<br>
It uses ICU reading function which perhaps was working<br>
differently before and the implementation for the<br>
comparison ending isn't paying attention to some<br>
special cases, hence in those cases it works improperly.<br>
Now the checks for comparison should work fine.<br>
<br>
Сloses: #3251<br>
Сloses: #3334<br>
---<br>
src/box/sql/func.c | 25 ++++----<br>
test/sql-tap/like1.test.lua | 152 ++++++++++++++++++++++++++++++++++++++++++++<br>
2 files changed, 165 insertions(+), 12 deletions(-)<br>
create mode 100755 test/sql-tap/like1.test.lua<br>
<br>
diff --git a/src/box/sql/func.c b/src/box/sql/func.c<br>
index c06e3bd..dcbd7e0 100644<br>
--- a/src/box/sql/func.c<br>
+++ b/src/box/sql/func.c<br>
@@ -643,6 +643,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };<br>
#define SQLITE_MATCH 0<br>
#define SQLITE_NOMATCH 1<br>
#define SQLITE_NOWILDCARDMATCH 2<br>
+#define SQL_NO_SYMBOLS_LEFT 65535<br>
<br>
/*<br>
* Compare two UTF-8 strings for equality where the first string is<br>
@@ -698,29 +699,28 @@ patternCompare(const char * pattern, /* The glob pattern */<br>
const char * string_end = string + strlen(string);<br>
UErrorCode status = U_ZERO_ERROR;<br>
<br>
- while (pattern < pattern_end){<br>
- c = Utf8Read(pattern, pattern_end);<br>
+ while ((c = Utf8Read(pattern, pattern_end)) != SQL_NO_SYMBOLS_LEFT) {<br>
if (c == matchAll) { /* Match "*" */<br>
/* Skip over multiple "*" characters in the pattern. If there<br>
* are also "?" characters, skip those as well, but consume a<br>
* single character of the input string for each "?" skipped<br>
*/<br>
- while (pattern < pattern_end){<br>
- c = Utf8Read(pattern, pattern_end);<br>
+ while ((c = Utf8Read(pattern, pattern_end)) !=<br>
+ SQL_NO_SYMBOLS_LEFT) {<br>
if (c != matchAll && c != matchOne)<br>
break;<br>
- if (c == matchOne<br>
- && Utf8Read(string, string_end) == 0) {<br>
+ if (c == matchOne &&<br>
+ Utf8Read(string, string_end) ==<br>
+ SQL_NO_SYMBOLS_LEFT)<br>
return SQLITE_NOWILDCARDMATCH;<br>
- }<br>
}<br>
/* "*" at the end of the pattern matches */<br>
- if (pattern == pattern_end)<br>
+ if (c == SQL_NO_SYMBOLS_LEFT)<br>
return SQLITE_MATCH;<br>
if (c == matchOther) {<br>
if (pInfo->matchSet == 0) {<br>
c = Utf8Read(pattern, pattern_end);<br>
- if (c == 0)<br>
+ if (c == SQL_NO_SYMBOLS_LEFT)<br>
return SQLITE_NOWILDCARDMATCH;<br>
} else {<br>
/* "[...]" immediately follows the "*". We have to do a slow<br>
@@ -782,7 +782,7 @@ patternCompare(const char * pattern, /* The glob pattern */<br>
if (c == matchOther) {<br>
if (pInfo->matchSet == 0) {<br>
c = Utf8Read(pattern, pattern_end);<br>
- if (c == 0)<br>
+ if (c == SQL_NO_SYMBOLS_LEFT)<br>
return SQLITE_NOMATCH;<br>
zEscaped = pattern;<br>
} else {<br>
@@ -802,7 +802,7 @@ patternCompare(const char * pattern, /* The glob pattern */<br>
seen = 1;<br>
c2 = Utf8Read(pattern, pattern_end);<br>
}<br>
- while (c2 && c2 != ']') {<br>
+ while (c2 != SQL_NO_SYMBOLS_LEFT && c2 != ']') {<br>
if (c2 == '-' && pattern[0] != ']'<br>
&& pattern < pattern_end<br>
&& prior_c > 0) {<br>
@@ -839,7 +839,8 @@ patternCompare(const char * pattern, /* The glob pattern */<br>
c == u_tolower(c2))<br>
continue;<br>
}<br>
- if (c == matchOne && pattern != zEscaped && c2 != 0)<br>
+ if (c == matchOne && pattern != zEscaped &&<br>
+ c2 != SQL_NO_SYMBOLS_LEFT)<br>
continue;<br>
return SQLITE_NOMATCH;<br>
}<br>
diff --git a/test/sql-tap/like1.test.lua b/test/sql-tap/like1.test.lua<br>
new file mode 100755<br>
index 0000000..42b4d43<br>
--- /dev/null<br>
+++ b/test/sql-tap/like1.test.lua<br>
@@ -0,0 +1,152 @@<br>
+#!/usr/bin/env tarantool<br>
+test = require("sqltester")<br>
+test:plan(13)<br>
+<br>
+test:do_catchsql_test(<br>
+ "like-test-1.1",<br>
+ [[<br>
+ CREATE TABLE t2 (column1 INTEGER,<br>
+ column2 VARCHAR(100),<br>
+ column3 BLOB,<br>
+ column4 FLOAT,<br>
+ PRIMARY KEY (column1, column2));<br>
+ INSERT INTO t2 VALUES (1, 'AB', X'4142', 5.5);<br>
+ INSERT INTO t2 VALUES (1, 'CD', X'2020', 1E4);<br>
+ INSERT INTO t2 VALUES (2, 'AB', X'2020', 12.34567);<br>
+ INSERT INTO t2 VALUES (-1000, '', X'', 0.0);<br>
+ CREATE TABLE t1 (a INT PRIMARY KEY, str VARCHAR(100));<br>
+ INSERT INTO t1 VALUES (1, 'ab');<br>
+ INSERT INTO t1 VALUES (2, 'abCDF');<br>
+ INSERT INTO t1 VALUES (3, 'CDF');<br>
+ CREATE TABLE t (s1 char(2) primary key, s2 char(2));<br>
+ INSERT INTO t VALUES ('AB', 'AB');<br>
+ ]], {<br>
+ -- <like-test-1.1><br>
+ 0<br>
+ -- <like-test-1.1><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.2",<br>
+ [[<br>
+ SELECT column1, column2, column1 * column4 FROM t2 WHERE column2 LIKE '_B';<br>
+ ]], {<br>
+ -- <like-test-1.2><br>
+ 1, 'AB', 5.5, 2, 'AB', 24.69134<br>
+ -- <like-test-1.2><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.3",<br>
+ [[<br>
+ SELECT column1, column2 FROM t2 WHERE column2 LIKE '%B';<br>
+ ]], {<br>
+ -- <like-test-1.3><br>
+ 1, 'AB', 2, 'AB'<br>
+ -- <like-test-1.3><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.4",<br>
+ [[<br>
+ SELECT column1, column2 FROM t2 WHERE column2 LIKE 'A__';<br>
+ ]], {<br>
+ -- <like-test-1.4><br>
+<br>
+ -- <like-test-1.4><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.5",<br>
+ [[<br>
+ SELECT column1, column2 FROM t2 WHERE column2 LIKE 'A_';<br>
+ ]], {<br>
+ -- <like-test-1.5><br>
+ 1, 'AB', 2, 'AB'<br>
+ -- <like-test-1.5><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.6",<br>
+ [[<br>
+ SELECT column1, column2 FROM t2 WHERE column2 LIKE 'A';<br>
+ ]], {<br>
+ -- <like-test-1.6><br>
+<br>
+ -- <like-test-1.6><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.7",<br>
+ [[<br>
+ SELECT column1, column2 FROM t2 WHERE column2 LIKE '_';<br>
+ ]], {<br>
+ -- <like-test-1.7><br>
+<br>
+ -- <like-test-1.7><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.8",<br>
+ [[<br>
+ SELECT * FROM t WHERE s1 LIKE '%A';<br>
+ ]], {<br>
+ -- <like-test-1.8><br>
+<br>
+ -- <like-test-1.8><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.9",<br>
+ [[<br>
+ SELECT * FROM t WHERE s1 LIKE '%C';<br>
+ ]], {<br>
+ -- <like-test-1.9><br>
+<br>
+ -- <like-test-1.9><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.10",<br>
+ [[<br>
+ SELECT * FROM t1 WHERE str LIKE '%df';<br>
+ ]], {<br>
+ -- <like-test-1.10><br>
+ 2, 'abCDF', 3, 'CDF'<br>
+ -- <like-test-1.10><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.11",<br>
+ [[<br>
+ SELECT * FROM t1 WHERE str LIKE 'a_';<br>
+ ]], {<br>
+ -- <like-test-1.11><br>
+ 1, 'ab'<br>
+ -- <like-test-1.11><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.12",<br>
+ [[<br>
+ select column1, column2 from t2 where column2 like '__';<br>
+ ]], {<br>
+ -- <like-test-1.12><br>
+ 1, 'AB', 1, 'CD', 2, 'AB'<br>
+ -- <like-test-1.12><br>
+ })<br>
+<br>
+test:do_execsql_test(<br>
+ "like-test-1.13",<br>
+ [[<br>
+ DROP TABLE t1;<br>
+ DROP TABLE t2;<br>
+ DROP TABLE t;<br>
+ ]], {<br>
+ -- <like-test-1.13><br>
+<br>
+ -- <like-test-1.13><br>
+ })<br>
+<br>
+<br>
+test:finish_test()<br>
-- <br>
2.7.4<br>
<br>
</blockquote></div>