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

Reply via email to