From 51ac57fbbef2f487b6bca5e0e5d9ddd4e3641d05 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 18 Mar 2021 15:36:28 +0400 Subject: [PATCH] MDEV-25151 JSON_TABLE: Unexpectedly padded values in a PATH column. Field length can increase after the change_charset(), so need to set field->ptr properly. also sensitive parts of the test moved to json_not_embedded.test. --- mysql-test/suite/json/r/json_table.result | 30 ++++++---------- .../json/r/json_table_notembedded.result | 20 +++++++++++ mysql-test/suite/json/t/json_table.test | 36 +++++-------------- .../suite/json/t/json_table_notembedded.test | 30 ++++++++++++++++ sql/json_table.cc | 25 +++++++++++-- 5 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 mysql-test/suite/json/r/json_table_notembedded.result create mode 100644 mysql-test/suite/json/t/json_table_notembedded.test diff --git a/mysql-test/suite/json/r/json_table.result b/mysql-test/suite/json/r/json_table.result index 3987b8b8e10..0909ce86899 100644 --- a/mysql-test/suite/json/r/json_table.result +++ b/mysql-test/suite/json/r/json_table.result @@ -98,26 +98,6 @@ a 1 connection default; disconnect con1; -create database db; -use db; -create table t (a text); -insert into t values ('{"foo":"bar"}'); -create user u@localhost; -grant select (a) on db.t to u@localhost; -connect con1,localhost,u,,db; -select a from t; -a -{"foo":"bar"} -select * from t, json_table(t.a, '$' columns(f varchar(20) path '$.foo')) as jt; -a f -{"foo":"bar"} bar -select * into outfile 'f' from json_table('[]', '$' columns(x for ordinality)) q; -ERROR 28000: Access denied for user 'u'@'localhost' (using password: NO) -connection default; -disconnect con1; -drop user u@localhost; -drop database db; -use test; create table t1 ( color varchar(32), price int @@ -515,5 +495,15 @@ a SELECT a, b FROM JSON_TABLE('[]', '$' COLUMNS (a FOR ORDINALITY, b INT PATH '$[*]' ERROR ON EMPTY)) AS t ORDER BY a; ERROR HY000: Field 'b' can't be set for JSON_TABLE 't'. # +# MDEV-25151 JSON_TABLE: Unexpectedly padded values in a PATH column. +# +SET @old_character_set_connection= @@character_set_connection; +SET @@character_set_connection= utf8; +select hex(a), b from json_table('["foo","bar"]','$[*]' columns (a char(3) path '$', b for ordinality)) t; +hex(a) b +666F6F 1 +626172 2 +SET @@character_set_connection= @old_character_set_connection; +# # End of 10.6 tests # diff --git a/mysql-test/suite/json/r/json_table_notembedded.result b/mysql-test/suite/json/r/json_table_notembedded.result new file mode 100644 index 00000000000..e277a87999d --- /dev/null +++ b/mysql-test/suite/json/r/json_table_notembedded.result @@ -0,0 +1,20 @@ +create database db; +use db; +create table t (a text); +insert into t values ('{"foo":"bar"}'); +create user u@localhost; +grant select (a) on db.t to u@localhost; +connect con1,localhost,u,,db; +select a from t; +a +{"foo":"bar"} +select * from t, json_table(t.a, '$' columns(f varchar(20) path '$.foo')) as jt; +a f +{"foo":"bar"} bar +select * into outfile 'f' from json_table('[]', '$' columns(x for ordinality)) q; +ERROR 28000: Access denied for user 'u'@'localhost' (using password: NO) +connection default; +disconnect con1; +drop user u@localhost; +drop database db; +use test; diff --git a/mysql-test/suite/json/t/json_table.test b/mysql-test/suite/json/t/json_table.test index 9cfdfe642c3..efb3ee527a8 100644 --- a/mysql-test/suite/json/t/json_table.test +++ b/mysql-test/suite/json/t/json_table.test @@ -59,34 +59,6 @@ select a from json_table('{"a":0}',"$" columns(a for ordinality)) foo; connection default; disconnect con1; -# -# MDEV-22302 JSON_TABLE: Column privilege is insufficient for query with json_table -# - -create database db; -use db; -create table t (a text); -insert into t values ('{"foo":"bar"}'); -create user u@localhost; -grant select (a) on db.t to u@localhost; - ---connect (con1,localhost,u,,db) -select a from t; -select * from t, json_table(t.a, '$' columns(f varchar(20) path '$.foo')) as jt; - -# -# MDEV-25141 JSON_TABLE: SELECT into outfile bypasses file privilege check -# ---error ER_ACCESS_DENIED_ERROR -select * into outfile 'f' from json_table('[]', '$' columns(x for ordinality)) q; - -connection default; -disconnect con1; - -drop user u@localhost; -drop database db; - -use test; create table t1 ( color varchar(32), price int @@ -407,6 +379,14 @@ EXECUTE stmt; --error ER_JSON_TABLE_ERROR_ON_FIELD SELECT a, b FROM JSON_TABLE('[]', '$' COLUMNS (a FOR ORDINALITY, b INT PATH '$[*]' ERROR ON EMPTY)) AS t ORDER BY a; +--echo # +--echo # MDEV-25151 JSON_TABLE: Unexpectedly padded values in a PATH column. +--echo # +SET @old_character_set_connection= @@character_set_connection; +SET @@character_set_connection= utf8; +select hex(a), b from json_table('["foo","bar"]','$[*]' columns (a char(3) path '$', b for ordinality)) t; +SET @@character_set_connection= @old_character_set_connection; + --echo # --echo # End of 10.6 tests --echo # diff --git a/mysql-test/suite/json/t/json_table_notembedded.test b/mysql-test/suite/json/t/json_table_notembedded.test new file mode 100644 index 00000000000..32bc042288b --- /dev/null +++ b/mysql-test/suite/json/t/json_table_notembedded.test @@ -0,0 +1,30 @@ +source include/not_embedded.inc; + +# +# MDEV-22302 JSON_TABLE: Column privilege is insufficient for query with json_table +# + +create database db; +use db; +create table t (a text); +insert into t values ('{"foo":"bar"}'); +create user u@localhost; +grant select (a) on db.t to u@localhost; + +--connect (con1,localhost,u,,db) +select a from t; +select * from t, json_table(t.a, '$' columns(f varchar(20) path '$.foo')) as jt; + +# +# MDEV-25141 JSON_TABLE: SELECT into outfile bypasses file privilege check +# +--error ER_ACCESS_DENIED_ERROR +select * into outfile 'f' from json_table('[]', '$' columns(x for ordinality)) q; + +connection default; +disconnect con1; + +drop user u@localhost; +drop database db; + +use test; diff --git a/sql/json_table.cc b/sql/json_table.cc index f7605fbda73..1146288a61a 100644 --- a/sql/json_table.cc +++ b/sql/json_table.cc @@ -1134,12 +1134,31 @@ int Table_function_json_table::setup(THD *thd, TABLE_LIST *sql_table, } { + /* + The m_json defines it's charset during the fix_fields stage so we're + changing the field's current charsets with it. + The complicated part is that the length of the field can be changed so + in this case we should move all the consequent fiedlds. + */ List_iterator_fast jc_i(m_columns); - for (uint i= 0; t->field[i]; i++) + int field_offset= 0; + Field *f; + for (uint i= 0; (f= t->field[i]); i++) { Json_table_column *jc= jc_i++; - t->field[i]->change_charset( - jc->m_explicit_cs ? jc->m_explicit_cs : m_json->collation); + uint32 old_pack_length= f->pack_length(); + + f->change_charset( + jc->m_explicit_cs ? jc->m_explicit_cs : m_json->collation); + + if (field_offset) + { + f->move_field(f->ptr + field_offset, f->null_ptr, f->null_bit); + f->reset(); + } + + field_offset= (field_offset + f->pack_length()) - old_pack_length; + /* The m_field->charset is going to be reused if it's the prepared statement running several times. So should restored the original