Commit a4663af0 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

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)
parent ea78c574
......@@ -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,
......
......@@ -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
#
......@@ -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 #
......@@ -3819,6 +3819,58 @@ mariadb_dyncol_check(DYNAMIC_COLUMN *str)
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;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment