revision-id: 3226c5083266291ad8ee932e467ebc9d80491b12 (mariadb-10.4.3-168-g3226c50)
parent(s): 517a56c1884e74b7c7606b56b0884537e792089e
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-04-10 15:34:03 +0530
message:
MDEV-18880: Optimizer trace prints date in hexadecimal
Introducded a print_key_value function to makes sure that the trace prints data in readable format
for readable characters and the rest of the characters are printed as hexadecimal.
---
mysql-test/main/opt_trace.result | 442 +++++++++++++++++++++++++++++++++-
mysql-test/main/opt_trace.test | 56 +++++
mysql-test/main/opt_trace_ucs2.result | 54 +++++
mysql-test/main/opt_trace_ucs2.test | 10 +
sql/field.cc | 55 +++++
sql/field.h | 14 ++
sql/opt_range.cc | 34 +--
sql/sql_string.cc | 11 +
sql/sql_string.h | 3 +
9 files changed, 647 insertions(+), 32 deletions(-)
diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result
index ed5881e..3aec8aa 100644
--- a/mysql-test/main/opt_trace.result
+++ b/mysql-test/main/opt_trace.result
@@ -1446,7 +1446,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
{
"index": "id",
"covering": true,
- "ranges": ["(0x24a20f) <= (a)"],
+ "ranges": ["(2001-01-04) <= (a)"],
"rows": 9,
"cost": 2.35
}
@@ -1462,7 +1462,7 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"rows": 9,
"cost": 2.35,
"key_parts_used_for_access": ["id"],
- "ranges": ["(0x24a20f) <= (a)"],
+ "ranges": ["(2001-01-04) <= (a)"],
"chosen": false,
"cause": "cost"
},
@@ -1624,7 +1624,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
{
"index": "id",
"covering": true,
- "ranges": ["(0x24a20f) <= (a) <= (0x24a20f)"],
+ "ranges": ["(2001-01-04) <= (a) <= (2001-01-04)"],
"rows": 9,
"cost": 2.35
}
@@ -1640,7 +1640,7 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"rows": 9,
"cost": 2.35,
"key_parts_used_for_access": ["id", "a"],
- "ranges": ["(0x24a20f) <= (a) <= (0x24a20f)"],
+ "ranges": ["(2001-01-04) <= (a) <= (2001-01-04)"],
"chosen": false,
"cause": "cost"
},
@@ -6130,7 +6130,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
"index": "start_date",
"ranges":
[
- "(0x4ac60f,NULL) < (start_date,end_date)"
+ "(2019-02-10,NULL) < (start_date,end_date)"
],
"rowid_ordered": false,
"using_mrr": false,
@@ -6214,7 +6214,7 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
"index": "i_b",
"ranges":
[
- "(0xd95b94336a9946a39cf5b58cfe772d8c) <= (b) <= (0xd95b94336a9946a39cf5b58cfe772d8c)"
+ "(\xD9[\x943j\x99F\xA3\x9C\xF5\xB5\x8C\xFEw-\x8C) <= (b) <= (\xD9[\x943j\x99F\xA3\x9C\xF5\xB5\x8C\xFEw-\x8C)"
],
"rowid_ordered": true,
"using_mrr": false,
@@ -6268,4 +6268,434 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
}
]
drop table t1;
+#
+# MDEV-18880: Optimizer trace prints date in hexadecimal
+#
+CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10) CHARSET BINARY , INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 13 const 1 Using index condition
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "i_b",
+ "ranges":
+ [
+ "(ab\x0A) <= (b) <= (ab\x0A)"
+ ],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 2.3787,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+ALTER TABLE t1 modify column b BINARY(10) AFTER i;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 11 const 1 Using index condition
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "i_b",
+ "ranges":
+ [
+ "(ab\x0A\x00\x00\x00\x00\x00\x00\x00) <= (b) <= (ab\x0A\x00\x00\x00\x00\x00\x00\x00)"
+ ],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 2.3785,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+ALTER TABLE t1 modify column b VARBINARY(10) AFTER i;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 13 const 1 Using index condition
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "i_b",
+ "ranges":
+ [
+ "(ab\x0A) <= (b) <= (ab\x0A)"
+ ],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 2.3787,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+drop table t1;
+CREATE TABLE t1(i INT PRIMARY KEY, b CHAR(10), INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 11 const 1 Using index condition
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "i_b",
+ "ranges":
+ [
+ "(ab\n) <= (b) <= (ab\n)"
+ ],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 2.3785,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+drop table t1;
+CREATE TABLE t1(i INT PRIMARY KEY, b blob , INDEX i_b(b));
+Warnings:
+Note 1071 Specified key was too long; max key length is 1000 bytes
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 1003 const 1 Using where
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "i_b",
+ "ranges":
+ [
+ "(ab\x0A) <= (b) <= (ab\x0A)"
+ ],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1,
+ "cost": 3.5719,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+drop table t1;
+CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10), INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, 'ab\n');
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i_b i_b 13 const 2 Using index condition
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n') {
+ "steps": [
+ {
+ "join_preparation": {
+ "select_id": 1,
+ "steps": [
+ {
+ "expanded_query": "select t1.i AS i,t1.b AS b from t1 where t1.b = 'ab\n'"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select_id": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "t1.b = 'ab\n'",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal('ab\n', t1.b)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal('ab\n', t1.b)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal('ab\n', t1.b)"
+ }
+ ]
+ }
+ },
+ {
+ "table_dependencies": [
+ {
+ "table": "t1",
+ "row_may_be_null": false,
+ "map_bit": 0,
+ "depends_on_map_bits": []
+ }
+ ]
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "table": "t1",
+ "field": "b",
+ "equals": "'ab\n'",
+ "null_rejecting": false
+ }
+ ]
+ },
+ {
+ "rows_estimation": [
+ {
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "rows": 2,
+ "cost": 4.5098
+ },
+ "potential_range_indexes": [
+ {
+ "index": "PRIMARY",
+ "usable": false,
+ "cause": "not applicable"
+ },
+ {
+ "index": "i_b",
+ "usable": true,
+ "key_parts": ["b"]
+ }
+ ],
+ "setup_range_conditions": [],
+ "group_index_range": {
+ "chosen": false,
+ "cause": "no group by or distinct"
+ },
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "i_b",
+ "ranges": ["(ab\n) <= (b) <= (ab\n)"],
+ "rowid_ordered": true,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 2,
+ "cost": 3.6324,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect": {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union": []
+ },
+ "chosen_range_access_summary": {
+ "range_access_plan": {
+ "type": "range_scan",
+ "index": "i_b",
+ "rows": 2,
+ "ranges": ["(ab\n) <= (b) <= (ab\n)"]
+ },
+ "rows_for_plan": 2,
+ "cost_for_plan": 3.6324,
+ "chosen": true
+ }
+ }
+ },
+ {
+ "selectivity_for_indexes": [
+ {
+ "index_name": "i_b",
+ "selectivity_from_index": 1
+ }
+ ],
+ "selectivity_for_columns": [],
+ "cond_selectivity": 1
+ }
+ ]
+ },
+ {
+ "considered_execution_plans": [
+ {
+ "plan_prefix": [],
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "ref",
+ "index": "i_b",
+ "used_range_estimates": true,
+ "rows": 2,
+ "cost": 3,
+ "chosen": true
+ },
+ {
+ "type": "scan",
+ "chosen": false,
+ "cause": "cost"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "t1.b = 'ab\n'",
+ "attached_conditions_computation": [],
+ "attached_conditions_summary": [
+ {
+ "table": "t1",
+ "attached": "t1.b = 'ab\n'"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select_id": 1,
+ "steps": []
+ }
+ }
+ ]
+} 0 0
+drop table t1;
+create table t0(a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table one_k (a int);
+insert into one_k select A.a + B.a*10 + C.a*100 from t0 A, t0 B, t0 C;
+create table t1 (start_date date, end_date date, filler char(100), key(start_date, end_date)) ;
+insert into t1 select date_add(now(), interval a day), date_add(now(), interval (a+7) day), 'data' from one_k;
+explain format=json select * from t1 force index(start_date) where start_date >= '2019-02-10' and end_date <'2019-04-01';
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "range",
+ "possible_keys": ["start_date"],
+ "key": "start_date",
+ "key_length": "8",
+ "used_key_parts": ["start_date", "end_date"],
+ "rows": 1000,
+ "filtered": 100,
+ "index_condition": "t1.start_date >= '2019-02-10' and t1.end_date < '2019-04-01'"
+ }
+ }
+}
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "start_date",
+ "ranges":
+ [
+ "(2019-02-10,NULL) < (start_date,end_date)"
+ ],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 1000,
+ "cost": 1282.2,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+drop table t1, t0, one_k;
set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test
index 981a53a..36bdc86 100644
--- a/mysql-test/main/opt_trace.test
+++ b/mysql-test/main/opt_trace.test
@@ -444,4 +444,60 @@ select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) fr
drop table t1;
+--echo #
+--echo # MDEV-18880: Optimizer trace prints date in hexadecimal
+--echo #
+
+CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10) CHARSET BINARY , INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+ALTER TABLE t1 modify column b BINARY(10) AFTER i;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+ALTER TABLE t1 modify column b VARBINARY(10) AFTER i;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
+
+CREATE TABLE t1(i INT PRIMARY KEY, b CHAR(10), INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
+
+
+CREATE TABLE t1(i INT PRIMARY KEY, b blob , INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, NULL);
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
+
+CREATE TABLE t1(i INT PRIMARY KEY, b VARCHAR(10), INDEX i_b(b));
+INSERT INTO t1 VALUES (1, 'ab\n');
+INSERT INTO t1 VALUES (2, 'ab\n');
+set optimizer_trace=1;
+EXPLAIN SELECT * FROM t1 WHERE b IN ('ab\n');
+select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+#select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
+create table t0(a int);
+insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table one_k (a int);
+insert into one_k select A.a + B.a*10 + C.a*100 from t0 A, t0 B, t0 C;
+create table t1 (start_date date, end_date date, filler char(100), key(start_date, end_date)) ;
+--disable_warnings
+insert into t1 select date_add(now(), interval a day), date_add(now(), interval (a+7) day), 'data' from one_k;
+--enable_warnings
+explain format=json select * from t1 force index(start_date) where start_date >= '2019-02-10' and end_date <'2019-04-01';
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1, t0, one_k;
+
set optimizer_trace='enabled=off';
diff --git a/mysql-test/main/opt_trace_ucs2.result b/mysql-test/main/opt_trace_ucs2.result
new file mode 100644
index 0000000..306fdbf
--- /dev/null
+++ b/mysql-test/main/opt_trace_ucs2.result
@@ -0,0 +1,54 @@
+create or replace table t1 (col1 char(10) character set ucs2, filler char(100), key(col1)) ;
+insert into t1 values ('a', 'a');
+insert into t1 values ('a', 'a');
+set optimizer_trace=1;
+explain format=json select * from t1 force index(col1) where col1 >='a';
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "range",
+ "possible_keys": ["col1"],
+ "key": "col1",
+ "key_length": "21",
+ "used_key_parts": ["col1"],
+ "rows": 2,
+ "filtered": 100,
+ "index_condition": "t1.col1 >= 'a'"
+ }
+ }
+}
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives'))
+[
+
+ {
+ "range_scan_alternatives":
+ [
+
+ {
+ "index": "col1",
+ "ranges":
+ [
+ "(a) <= (col1)"
+ ],
+ "rowid_ordered": false,
+ "using_mrr": false,
+ "index_only": false,
+ "rows": 2,
+ "cost": 3.7609,
+ "chosen": true
+ }
+ ],
+ "analyzing_roworder_intersect":
+ {
+ "cause": "too few roworder scans"
+ },
+ "analyzing_index_merge_union":
+ [
+ ]
+ }
+]
+drop table t1;
diff --git a/mysql-test/main/opt_trace_ucs2.test b/mysql-test/main/opt_trace_ucs2.test
new file mode 100644
index 0000000..827dc40
--- /dev/null
+++ b/mysql-test/main/opt_trace_ucs2.test
@@ -0,0 +1,10 @@
+--source include/not_embedded.inc
+--source include/have_ucs2.inc
+
+create or replace table t1 (col1 char(10) character set ucs2, filler char(100), key(col1)) ;
+insert into t1 values ('a', 'a');
+insert into t1 values ('a', 'a');
+set optimizer_trace=1;
+explain format=json select * from t1 force index(col1) where col1 >='a';
+select JSON_DETAILED(JSON_EXTRACT(trace, '$**.analyzing_range_alternatives')) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+drop table t1;
diff --git a/sql/field.cc b/sql/field.cc
index 4a93464..028d304 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -11228,3 +11228,58 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
thd->variables.sql_mode= sql_mode_backup;
return rc;
}
+
+
+void Field::print_key_value(String *out, uint length)
+{
+ if (charset() == &my_charset_bin)
+ print_key_value_binary(out, ptr, length);
+ else
+ val_str(out);
+}
+
+
+void Field_string::print_key_value(String *out, uint length)
+{
+ if (charset() == &my_charset_bin)
+ {
+ length= field_charset->cset->lengthsp(field_charset, (const char*) ptr, length);
+ print_key_value_binary(out, ptr, length);
+ }
+ else
+ {
+ THD *thd= get_thd();
+ sql_mode_t sql_mode_backup= thd->variables.sql_mode;
+ thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ val_str(out,out);
+ thd->variables.sql_mode= sql_mode_backup;
+ }
+}
+
+
+void Field_varstring::print_key_value(String *out, uint length)
+{
+ if (charset() == &my_charset_bin)
+ print_key_value_binary(out, get_data(), get_length());
+ else
+ val_str(out,out);
+}
+
+
+void Field_blob::print_key_value(String *out, uint length)
+{
+ if (charset() == &my_charset_bin)
+ {
+ uchar *blob;
+ memcpy(&blob, ptr+packlength, sizeof(uchar*));
+ print_key_value_binary(out, blob, get_length());
+ }
+ else
+ val_str(out, out);
+}
+
+
+void Field::print_key_value_binary(String *out, const uchar* key, uint length)
+{
+ out->append_semi_hex((const char*)key, length, charset());
+}
diff --git a/sql/field.h b/sql/field.h
index 8bd7343..0fbbc04 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1380,6 +1380,8 @@ class Field: public Value_source
virtual int set_time() { return 1; }
bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
int cuted_increment, ulong current_row=0) const;
+ virtual void print_key_value(String *out, uint length);
+ void print_key_value_binary(String *out, const uchar* key, uint length);
protected:
bool set_warning(unsigned int code, int cuted_increment) const
{
@@ -3587,6 +3589,7 @@ class Field_string :public Field_longstr {
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
virtual uint get_key_image(uchar *buff,uint length, imagetype type);
+ void print_key_value(String *out, uint length);
private:
int save_field_metadata(uchar *first_byte);
};
@@ -3692,6 +3695,8 @@ class Field_varstring :public Field_longstr {
uint is_equal(Create_field *new_field);
void hash(ulong *nr, ulong *nr2);
uint length_size() { return length_bytes; }
+ void print_key_value(String *out, uint length);
+
private:
int save_field_metadata(uchar *first_byte);
};
@@ -4029,6 +4034,7 @@ class Field_blob :public Field_longstr {
uint32 char_length() const;
uint32 character_octet_length() const;
uint is_equal(Create_field *new_field);
+ void print_key_value(String *out, uint length);
friend void TABLE::remember_blob_values(String *blob_storage);
friend void TABLE::restore_blob_values(String *blob_storage);
@@ -4153,6 +4159,10 @@ class Field_geom :public Field_blob {
geometry_type get_geometry_type() { return geom_type; };
static geometry_type geometry_type_merge(geometry_type, geometry_type);
uint get_srid() { return srid; }
+ void print_key_value(String *out, uint length)
+ {
+ out->append(STRING_WITH_LEN("unprintable_geometry_value"));
+ }
};
uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields);
@@ -4445,6 +4455,10 @@ class Field_bit :public Field {
{
return get_mm_leaf_int(param, key_part, cond, op, value, true);
}
+ void print_key_value(String *out, uint length)
+ {
+ val_int_as_str(out, 1);
+ }
private:
virtual size_t do_last_null_byte() const;
int save_field_metadata(uchar *first_byte);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 7c40a99..461df77 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -15785,7 +15785,7 @@ static void append_range_all_keyparts(Json_writer_array *range_trace,
uint n_key_parts= param.table->actual_n_key_parts(keyinfo);
seq.keyno= idx;
seq.real_keyno= param.real_keynr[idx];
- seq.param= ¶m;
+ seq.param= ¶m;
seq.start= keypart;
const KEY_PART_INFO *cur_key_part= key_parts + keypart->part;
seq_it= seq_if.init((void *) &seq, 0, flags);
@@ -15828,12 +15828,10 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
{
// Byte 0 of a nullable key is the null-byte. If set, key is NULL.
if (field->real_maybe_null() && *key)
+ {
out->append(STRING_WITH_LEN("NULL"));
- else
- (field->type() == MYSQL_TYPE_GEOMETRY)
- ? out->append(STRING_WITH_LEN("unprintable_geometry_value"))
- : out->append(STRING_WITH_LEN("unprintable_blob_value"));
- goto next;
+ goto next;
+ }
}
if (field->real_maybe_null())
@@ -15852,28 +15850,12 @@ static void print_key_value(String *out, const KEY_PART_INFO *key_part,
store_length--;
}
- /*
- Binary data cannot be converted to UTF8 which is what the
- optimizer trace expects. If the column is binary, the hex
- representation is printed to the trace instead.
- */
- if (field->flags & BINARY_FLAG)
- {
- out->append("0x");
- for (uint i = 0; i < store_length; i++)
- {
- out->append(_dig_vec_lower[*(key + i) >> 4]);
- out->append(_dig_vec_lower[*(key + i) & 0x0F]);
- }
- goto next;
- }
-
field->set_key_image(key, key_part->length);
- if (field->type() == MYSQL_TYPE_BIT)
- (void)field->val_int_as_str(&tmp, 1); // may change tmp's charset
+ field->print_key_value(&tmp, key_part->length);
+ if (field->charset() == &my_charset_bin)
+ out->append(tmp.ptr(), tmp.length(), tmp.charset());
else
- field->val_str(&tmp); // may change tmp's charset
- out->append(tmp.ptr(), tmp.length(), tmp.charset());
+ tmp.print(out, system_charset_info);
next:
if (key + store_length < key_end)
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 45af08f..dbc5f4f 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1175,3 +1175,14 @@ uint convert_to_printable(char *to, size_t to_len,
*t= '\0';
return (uint) (t - to);
}
+
+bool String::append_semi_hex(const char *s, uint len, CHARSET_INFO *cs)
+{
+ size_t dst_len= len * 4;
+ if (reserve(dst_len))
+ return true;
+ uint nbytes= convert_to_printable(Ptr + str_length, dst_len, s, len, cs);
+ DBUG_ASSERT((ulonglong) str_length + nbytes < UINT32_MAX);
+ str_length+= nbytes;
+ return false;
+}
\ No newline at end of file
diff --git a/sql/sql_string.h b/sql/sql_string.h
index fa941c8..ae8e7ea 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -666,6 +666,7 @@ class Binary_string: public Static_binary_string
int reserve(size_t space_needed)
{
+ DBUG_ASSERT((ulonglong) str_length + space_needed < UINT32_MAX);
return realloc(str_length + space_needed);
}
int reserve(size_t space_needed, size_t grow_by);
@@ -951,6 +952,8 @@ class String: public Charset, public Binary_string
{
return !sortcmp(this, other, cs);
}
+private:
+ bool append_semi_hex(const char *s, uint len, CHARSET_INFO *cs);
};