diff options
-rw-r--r-- | include/ma_dyncol.h | 3 | ||||
-rw-r--r-- | mysql-test/r/dyncol.result | 10 | ||||
-rw-r--r-- | mysql-test/t/dyncol.test | 8 | ||||
-rw-r--r-- | mysys/ma_dyncol.c | 60 |
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; } } |