summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2018-01-22 16:53:10 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2018-01-23 13:06:39 +0100
commita4663af05c1d1bd3abb537205df070ed2158e702 (patch)
tree935bf4702fc478f5ecb60c9194d37108161d5e13
parentea78c5744b958ddcd6946faf5ca24f115275a366 (diff)
downloadmariadb-git-a4663af05c1d1bd3abb537205df070ed2158e702.tar.gz
MDEV-7533: COLUMN_JSON() doesn't escape control characters in string values
escape all charecters less or equal 0x1F (control symbols) (shorter sequence are not used to make code simple, long encoding is always legal according to the rfc4627)
-rw-r--r--include/ma_dyncol.h3
-rw-r--r--mysql-test/r/dyncol.result10
-rw-r--r--mysql-test/t/dyncol.test8
-rw-r--r--mysys/ma_dyncol.c60
4 files changed, 79 insertions, 2 deletions
diff --git a/include/ma_dyncol.h b/include/ma_dyncol.h
index 300474e061e..4f05b425afd 100644
--- a/include/ma_dyncol.h
+++ b/include/ma_dyncol.h
@@ -69,6 +69,9 @@ typedef struct st_mysql_lex_string LEX_STRING;
#define DYNCOL_UTF (&my_charset_utf8_general_ci)
#endif
+/* escape json strings */
+#define DYNCOL_JSON_ESC ((char)1)
+
enum enum_dyncol_func_result
{
ER_DYNCOL_OK= 0,
diff --git a/mysql-test/r/dyncol.result b/mysql-test/r/dyncol.result
index b0d28a81043..81446da9e14 100644
--- a/mysql-test/r/dyncol.result
+++ b/mysql-test/r/dyncol.result
@@ -1873,5 +1873,15 @@ SELECT COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL));
COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL))
{"a":1,"b":1}
#
+# MDEV-7533: COLUMN_JSON() doesn't escape control characters
+# in string values
+#
+SELECT COLUMN_JSON(COLUMN_CREATE('test','"\\\t\n\Z')) AS json;
+json
+{"test":"\"\\\u0009\u000A\u001A"}
+SELECT COLUMN_JSON(COLUMN_CREATE('test','First line\nSecond line')) AS json;
+json
+{"test":"First line\u000ASecond line"}
+#
# end of 10.0 tests
#
diff --git a/mysql-test/t/dyncol.test b/mysql-test/t/dyncol.test
index 03e2345ba1c..2c93f75cb5a 100644
--- a/mysql-test/t/dyncol.test
+++ b/mysql-test/t/dyncol.test
@@ -920,6 +920,14 @@ SELECT COLUMN_JSON(COLUMN_CREATE('a',0 AS DECIMAL,'b',1 AS DECIMAL));
SELECT COLUMN_JSON(COLUMN_CREATE('a',1 AS DECIMAL,'b',1 AS DECIMAL));
+
+--echo #
+--echo # MDEV-7533: COLUMN_JSON() doesn't escape control characters
+--echo # in string values
+--echo #
+SELECT COLUMN_JSON(COLUMN_CREATE('test','"\\\t\n\Z')) AS json;
+SELECT COLUMN_JSON(COLUMN_CREATE('test','First line\nSecond line')) AS json;
+
--echo #
--echo # end of 10.0 tests
--echo #
diff --git a/mysys/ma_dyncol.c b/mysys/ma_dyncol.c
index 9f6df107316..0c54bd7a581 100644
--- a/mysys/ma_dyncol.c
+++ b/mysys/ma_dyncol.c
@@ -3819,6 +3819,58 @@ end:
DBUG_RETURN(rc);
}
+static
+my_bool dynstr_append_json_quoted(DYNAMIC_STRING *str,
+ const char *append, size_t len)
+{
+ uint additional= ((str->alloc_increment && str->alloc_increment > 6) ?
+ str->alloc_increment :
+ 10);
+ uint lim= additional;
+ uint i;
+ if (dynstr_realloc(str, len + additional + 2))
+ return TRUE;
+ str->str[str->length++]= '"';
+ for (i= 0; i < len; i++)
+ {
+ register char c= append[i];
+ if (unlikely(c <= 0x1F))
+ {
+ if (lim < 5)
+ {
+ if (dynstr_realloc(str, additional))
+ return TRUE;
+ lim+= additional;
+ }
+ lim-= 5;
+ str->str[str->length++]= '\\';
+ str->str[str->length++]= 'u';
+ str->str[str->length++]= '0';
+ str->str[str->length++]= '0';
+ str->str[str->length++]= (c < 0x10 ? '0' : '1');
+ c%= 0x10;
+ str->str[str->length++]= (c < 0xA ? '0' + c : 'A' + (c - 0xA));
+ }
+ else
+ {
+ if (c == '"' || c == '\\')
+ {
+ if (!lim)
+ {
+ if (dynstr_realloc(str, additional))
+ return TRUE;
+ lim= additional;
+ }
+ lim--;
+ str->str[str->length++]= '\\';
+ }
+ str->str[str->length++]= c;
+ }
+ }
+ str->str[str->length++]= '"';
+ return FALSE;
+}
+
enum enum_dyncol_func_result
mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
@@ -3884,7 +3936,10 @@ mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
return ER_DYNCOL_RESOURCE;
}
if (quote)
- rc= dynstr_append_quoted(str, from, len, quote);
+ if (quote == DYNCOL_JSON_ESC)
+ rc= dynstr_append_json_quoted(str, from, len);
+ else
+ rc= dynstr_append_quoted(str, from, len, quote);
else
rc= dynstr_append_mem(str, from, len);
if (alloc)
@@ -4184,7 +4239,8 @@ mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
}
else
{
- if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, '"')) < 0)
+ if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, DYNCOL_JSON_ESC))
+ < 0)
goto err;
}
}