Changeset: e4cb5e4c3341 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=e4cb5e4c3341
Modified Files:
sql/backends/monet5/UDF/udf/udf.c
sql/test/SQLancer/Tests/sqlancer01.sql
sql/test/SQLancer/Tests/sqlancer01.stable.out
Branch: Jun2020
Log Message:
Fix for bug 6885. Added support for UTF-8 strings at reverse(string) function
diffs (107 lines):
diff --git a/sql/backends/monet5/UDF/udf/udf.c
b/sql/backends/monet5/UDF/udf/udf.c
--- a/sql/backends/monet5/UDF/udf/udf.c
+++ b/sql/backends/monet5/UDF/udf/udf.c
@@ -27,9 +27,7 @@ UDFreverse_(char **ret, const char *src)
if (strNil(src)) {
*ret = GDKstrdup(str_nil);
if (*ret == NULL)
- throw(MAL, "udf.reverse",
- "failed to create copy of str_nil");
-
+ throw(MAL, "udf.reverse", "failed to create copy of
str_nil");
return MAL_SUCCEED;
}
@@ -37,13 +35,48 @@ UDFreverse_(char **ret, const char *src)
len = strlen(src);
*ret = dst = GDKmalloc(len + 1);
if (dst == NULL)
- throw(MAL, "udf.reverse",
- "failed to allocate string of length %zu", len + 1);
+ throw(MAL, "udf.reverse", "failed to allocate string of length
%zu", len + 1);
- /* copy characters from src to dst in reverse order */
dst[len] = 0;
- while (len > 0)
- *dst++ = src[--len];
+ /* all strings in MonetDB are encoded using UTF-8; we must
+ * make sure that the reversed string is also encoded in valid
+ * UTF-8, so we treat multibyte characters as single units */
+ while (*src) {
+ if ((*src & 0xF8) == 0xF0) {
+ /* 4 byte UTF-8 sequence */
+ assert(len >= 4);
+ dst[len - 4] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 3] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 2] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 1] = *src++;
+ len -= 4;
+ } else if ((*src & 0xF0) == 0xE0) {
+ /* 3 byte UTF-8 sequence */
+ assert(len >= 3);
+ dst[len - 3] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 2] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 1] = *src++;
+ len -= 3;
+ } else if ((*src & 0xE0) == 0xC0) {
+ /* 2 byte UTF-8 sequence */
+ assert(len >= 2);
+ dst[len - 2] = *src++;
+ assert((*src & 0xC0) == 0x80);
+ dst[len - 1] = *src++;
+ len -= 2;
+ } else {
+ /* 1 byte UTF-8 "sequence" */
+ assert(len >= 1);
+ assert((*src & 0x80) == 0);
+ dst[--len] = *src++;
+ }
+ }
+ assert(len == 0);
return MAL_SUCCEED;
}
diff --git a/sql/test/SQLancer/Tests/sqlancer01.sql
b/sql/test/SQLancer/Tests/sqlancer01.sql
--- a/sql/test/SQLancer/Tests/sqlancer01.sql
+++ b/sql/test/SQLancer/Tests/sqlancer01.sql
@@ -22,6 +22,10 @@ UPDATE t0 SET a2 = (- (- (t0.a1))), a3 =
(ascii(CAST(ascii('}悂Y8K*韖5<c>^n8_X1X|p(''bX') AS STRING(920)))) WHERE NOT
(((0.27023923567918073) NOT IN (0.9149447665258329)) = FALSE);
--0 rows affected
insert into integers(i) values(((length(reverse('8
\rcr੧[bp1eMY쫺4j5s뮯!<Rn4*}')))>>(((- (- (528640982)))&(ascii('528640982'))))));
--Bug 6885
+SELECT i from integers order by i;
+ -- NULL
+ -- 0
+select reverse('8 \rcr੧[bp1eMY쫺4j5s뮯!<Rn4*}');
ROLLBACK;
diff --git a/sql/test/SQLancer/Tests/sqlancer01.stable.out
b/sql/test/SQLancer/Tests/sqlancer01.stable.out
--- a/sql/test/SQLancer/Tests/sqlancer01.stable.out
+++ b/sql/test/SQLancer/Tests/sqlancer01.stable.out
@@ -92,6 +92,21 @@ stdout of test 'sqlancer01` in directory
#CREATE TABLE t0 (a1 INT, a2 int, a3 int); --Bug 6884
#UPDATE t0 SET a2 = (- (- (t0.a1))), a3 =
(ascii(CAST(ascii('}悂Y8K*韖5<c>^n8_X1X|p(''bX') AS STRING(920)))) WHERE NOT
(((0.27023923567918073) NOT IN (0.9149447665258329)) = FALSE);
[ 0 ]
+#insert into integers(i) values(((length(reverse('8
\rcr੧[bp1eMY쫺4j5s뮯!<Rn4*}')))>>(((- (- (528640982)))&(ascii('528640982'))))));
--Bug 6885
+[ 1 ]
+#SELECT i from integers order by i;
+% sys.integers # table_name
+% i # name
+% int # type
+% 1 # length
+[ NULL ]
+[ 0 ]
+#select reverse('8 \rcr੧[bp1eMY쫺4j5s뮯!<Rn4*}');
+% .%2 # table_name
+% %2 # name
+% clob # type
+% 28 # length
+[ "}*4nR<!뮯s5j4쫺YMe1pb[੧rc\r 8" ]
#ROLLBACK;
#DROP TABLE tbl_ProductSales;
#DROP TABLE another_T;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list