revision-id: 70d97cc103fd98c7a4952e7b3a54f272fa7b36f4 (fb-prod201801-191-g70d97cc103f)
parent(s): 1dd0e500095ac01f5b103714f4712276551385a1
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-01-21 20:02:18 +0300
message:
Update test result
---
mysql-test/suite/rocksdb/r/range_locking_escalation.result | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mysql-test/suite/rocksdb/r/range_locking_escalation.result b/mysql-test/suite/rocksdb/r/range_locking_escalation.result
index bef02dea860..722c99fec84 100644
--- a/mysql-test/suite/rocksdb/r/range_locking_escalation.result
+++ b/mysql-test/suite/rocksdb/r/range_locking_escalation.result
@@ -23,5 +23,5 @@ count(*)
10000
show status like 'rocksdb_locktree_escalation_count';
Variable_name Value
-rocksdb_locktree_escalation_count 3313
+rocksdb_locktree_escalation_count 3324
drop table t0,t1;
1
0

[Commits] 7d1cb6f1ea9: MDEV-14605 Changes to "ON UPDATE CURRENT_TIMESTAMP" fields are not
by andrei.elkin@pp.inet.fi 21 Jan '19
by andrei.elkin@pp.inet.fi 21 Jan '19
21 Jan '19
revision-id: 7d1cb6f1ea99bc58bf45c3aa22edb8e25230257b (mariadb-10.1.37-63-g7d1cb6f1ea9)
parent(s): c1aae370879490dc0a3cd63c5b1010fa21b1f62c
author: Andrei Elkin
committer: Andrei Elkin
timestamp: 2019-01-21 18:19:00 +0200
message:
MDEV-14605 Changes to "ON UPDATE CURRENT_TIMESTAMP" fields are not
always logged properly with binlog_row_image=MINIMAL
There are two issues fixed in this commit.
The first is an observation of a multi-table UPDATE binlogged
in row-format in binlog_row_image=MINIMAL mode. While the UPDATE aims
at a table with an ON-UPDATE attribute its binlog after-image misses
to record also installed default value.
The reason for that turns out missed marking of default-capable fields
in TABLE::write_set.
This is fixed to mark such fields similarly to 10.2's MDEV-10134 patch (db7edfed17efe6)
that introduced it. The marking affects 93d1e5ce0b841bed's TABLE:rpl_write_set
though and thus does not intervene (in 10.1) with MDEV-10134 agenda.
The 2nd issue is extra columns in in binlog_row_image=MINIMAL before-image
while merely a packed primary key is enough. The test main.mysqlbinlog_row_minimal
always had a wrong result recorded.
This is fixed to invoke a function that intended for read_set
possible filtering and which is called (supposed to) in all type of MDL, UPDATE
including; the test results have gotten corrected.
---
mysql-test/r/mysqlbinlog_row_minimal.result | 45 ++++++++++++++---------------
sql/sql_class.cc | 23 +++++++++++++--
sql/table.cc | 6 ++--
sql/table.h | 6 +++-
4 files changed, 51 insertions(+), 29 deletions(-)
diff --git a/mysql-test/r/mysqlbinlog_row_minimal.result b/mysql-test/r/mysqlbinlog_row_minimal.result
index 6ffaeeafc53..a0f2e0cefbb 100644
--- a/mysql-test/r/mysqlbinlog_row_minimal.result
+++ b/mysql-test/r/mysqlbinlog_row_minimal.result
@@ -214,39 +214,36 @@ BEGIN
# at 1997
#<date> server id 1 end_log_pos 2049 Table_map: `test`.`t2` mapped to number 31
# at 2049
-#<date> server id 1 end_log_pos 2119 Update_rows: table id 31 flags: STMT_END_F
+#<date> server id 1 end_log_pos 2111 Update_rows: table id 31 flags: STMT_END_F
### UPDATE `test`.`t2`
### WHERE
### @1=10 /* INT meta=0 nullable=0 is_null=0 */
-### @5=4 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @5=5 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `test`.`t2`
### WHERE
### @1=11 /* INT meta=0 nullable=0 is_null=0 */
-### @5=4 /* INT meta=0 nullable=1 is_null=0 */
### SET
### @5=5 /* INT meta=0 nullable=1 is_null=0 */
### UPDATE `test`.`t2`
### WHERE
### @1=12 /* INT meta=0 nullable=0 is_null=0 */
-### @5=NULL /* INT meta=0 nullable=1 is_null=1 */
### SET
### @5=5 /* INT meta=0 nullable=1 is_null=0 */
-# at 2119
-#<date> server id 1 end_log_pos 2188 Query thread_id=4 exec_time=x error_code=0
+# at 2111
+#<date> server id 1 end_log_pos 2180 Query thread_id=4 exec_time=x error_code=0
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
-# at 2188
-#<date> server id 1 end_log_pos 2226 GTID 0-1-9
+# at 2180
+#<date> server id 1 end_log_pos 2218 GTID 0-1-9
/*!100001 SET @@session.gtid_seq_no=9*//*!*/;
BEGIN
/*!*/;
-# at 2226
-#<date> server id 1 end_log_pos 2278 Table_map: `test`.`t1` mapped to number 30
-# at 2278
-#<date> server id 1 end_log_pos 2328 Delete_rows: table id 30 flags: STMT_END_F
+# at 2218
+#<date> server id 1 end_log_pos 2270 Table_map: `test`.`t1` mapped to number 30
+# at 2270
+#<date> server id 1 end_log_pos 2320 Delete_rows: table id 30 flags: STMT_END_F
### DELETE FROM `test`.`t1`
### WHERE
### @1=10 /* INT meta=0 nullable=0 is_null=0 */
@@ -259,20 +256,20 @@ BEGIN
### DELETE FROM `test`.`t1`
### WHERE
### @1=13 /* INT meta=0 nullable=0 is_null=0 */
-# at 2328
-#<date> server id 1 end_log_pos 2397 Query thread_id=4 exec_time=x error_code=0
+# at 2320
+#<date> server id 1 end_log_pos 2389 Query thread_id=4 exec_time=x error_code=0
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
-# at 2397
-#<date> server id 1 end_log_pos 2435 GTID 0-1-10
+# at 2389
+#<date> server id 1 end_log_pos 2427 GTID 0-1-10
/*!100001 SET @@session.gtid_seq_no=10*//*!*/;
BEGIN
/*!*/;
-# at 2435
-#<date> server id 1 end_log_pos 2487 Table_map: `test`.`t2` mapped to number 31
-# at 2487
-#<date> server id 1 end_log_pos 2537 Delete_rows: table id 31 flags: STMT_END_F
+# at 2427
+#<date> server id 1 end_log_pos 2479 Table_map: `test`.`t2` mapped to number 31
+# at 2479
+#<date> server id 1 end_log_pos 2529 Delete_rows: table id 31 flags: STMT_END_F
### DELETE FROM `test`.`t2`
### WHERE
### @1=10 /* INT meta=0 nullable=0 is_null=0 */
@@ -285,13 +282,13 @@ BEGIN
### DELETE FROM `test`.`t2`
### WHERE
### @1=13 /* INT meta=0 nullable=0 is_null=0 */
-# at 2537
-#<date> server id 1 end_log_pos 2606 Query thread_id=4 exec_time=x error_code=0
+# at 2529
+#<date> server id 1 end_log_pos 2598 Query thread_id=4 exec_time=x error_code=0
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
-# at 2606
-#<date> server id 1 end_log_pos 2650 Rotate to master-bin.000002 pos: 4
+# at 2598
+#<date> server id 1 end_log_pos 2642 Rotate to master-bin.000002 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 8424b4477c3..0971d4fdaaa 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -6390,6 +6390,22 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
((WSREP(this) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
+ /**
+ Save a reference to the original read bitmaps
+ We will need this to restore the bitmaps at the end as
+ binlog_prepare_row_images() may change table->read_set.
+ table->read_set is used by pack_row and deep in
+ binlog_prepare_pending_events().
+ */
+ MY_BITMAP *old_read_set= table->read_set;
+
+ /**
+ This will remove spurious fields required during execution but
+ not needed for binlogging. This is done according to the:
+ binlog-row-image option.
+ */
+ binlog_prepare_row_images(table);
+
size_t const before_maxlen = max_row_length(table, before_record);
size_t const after_maxlen = max_row_length(table, after_record);
@@ -6401,9 +6417,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
uchar *after_row= row_data.slot(1);
size_t const before_size= pack_row(table, table->read_set, before_row,
- before_record);
+ before_record);
size_t const after_size= pack_row(table, table->rpl_write_set, after_row,
- after_record);
+ after_record);
/* Ensure that all events in a GTID group are in the same cache */
if (variables.option_bits & OPTION_GTID_BEGIN)
@@ -6431,6 +6447,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
int error= ev->add_row_data(before_row, before_size) ||
ev->add_row_data(after_row, after_size);
+ /* restore read set for the rest of execution */
+ table->column_bitmaps_set_no_signal(old_read_set,
+ table->write_set);
return error;
}
diff --git a/sql/table.cc b/sql/table.cc
index ca06eee077c..31f0d255847 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -6137,6 +6137,8 @@ void TABLE::mark_columns_per_binlog_row_image()
mark_columns_used_by_index_no_reset(s->primary_key, read_set);
/* Only write columns that have changed */
rpl_write_set= write_set;
+ if (default_field)
+ mark_default_fields_for_write(rpl_write_set);
break;
default:
@@ -6283,7 +6285,7 @@ bool TABLE::has_default_function(bool is_update)
Add all fields that have a default function to the table write set.
*/
-void TABLE::mark_default_fields_for_write()
+void TABLE::mark_default_fields_for_write(MY_BITMAP* bset)
{
Field **dfield_ptr, *dfield;
enum_sql_command cmd= in_use->lex->sql_command;
@@ -6294,7 +6296,7 @@ void TABLE::mark_default_fields_for_write()
dfield->has_insert_default_function()) ||
((sql_command_flags[cmd] & CF_UPDATES_DATA) &&
dfield->has_update_default_function()))
- bitmap_set_bit(write_set, dfield->field_index);
+ bitmap_set_bit(bset, dfield->field_index);
}
}
diff --git a/sql/table.h b/sql/table.h
index ca32234579f..d57eeb559a1 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1353,7 +1353,11 @@ struct TABLE
void mark_columns_per_binlog_row_image(void);
bool mark_virtual_col(Field *field);
void mark_virtual_columns_for_write(bool insert_fl);
- void mark_default_fields_for_write();
+ void mark_default_fields_for_write(MY_BITMAP* bset);
+ inline void mark_default_fields_for_write()
+ {
+ mark_default_fields_for_write(write_set);
+ }
bool has_default_function(bool is_update);
inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
MY_BITMAP *write_set_arg)
1
0
revision-id: 9efd264d8773a54dbceb929869e3dc88b8ee3c13 (mariadb-10.3.6-339-g9efd264d877)
parent(s): c1defbca61c230f05f0ca5e1488ce79bb902654c
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-01-21 10:58:01 +0200
message:
Fix test failure on galera_many_rows
---
mysql-test/suite/galera/t/galera_many_rows.cnf | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/mysql-test/suite/galera/t/galera_many_rows.cnf b/mysql-test/suite/galera/t/galera_many_rows.cnf
new file mode 100644
index 00000000000..24c4cc1c60d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_many_rows.cnf
@@ -0,0 +1,10 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+innodb-status-output=ON
+innodb-status-output-locks=ON
+
+[mysqld.2]
+innodb-status-output=ON
+innodb-status-output-locks=ON
+
1
0

[Commits] 322f916: MDEV-16188: Rearchitected the classes for rowid filters.
by IgorBabaev 20 Jan '19
by IgorBabaev 20 Jan '19
20 Jan '19
revision-id: 322f91664bac5692e86e986778bcd7adfb743ede (mariadb-10.3.6-103-g322f916)
parent(s): 8a9532f2cc1a8eeb53ff04ca2c28b4756afc845b
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-01-19 23:53:47 -0800
message:
MDEV-16188: Rearchitected the classes for rowid filters.
Also consistently renamed variables and functions where rowid filters were used.
---
mysql-test/main/show_explain.cc | 0
mysql-test/main/show_explain.result | 8 -
mysql-test/main/show_explain.test | 10 -
mysql-test/main/subselect_sj2.result | 5 +
mysql-test/main/subselect_sj2.test | 2 +
mysql-test/main/subselect_sj2_jcl6.result | 13 ++
mysql-test/main/subselect_sj2_jcl6.test | 11 +
mysql-test/main/subselect_sj2_mat.result | 5 +
sql/opt_subselect.h | 2 +-
sql/rowid_filter.cc | 158 ++++++++------
sql/rowid_filter.h | 330 ++++++++++++++----------------
sql/sql_select.cc | 65 +++---
sql/sql_select.h | 14 +-
sql/table.cc | 6 +-
sql/table.h | 17 +-
15 files changed, 332 insertions(+), 314 deletions(-)
diff --git a/mysql-test/main/show_explain.cc b/mysql-test/main/show_explain.cc
new file mode 100644
index 0000000..e69de29
diff --git a/mysql-test/main/show_explain.result b/mysql-test/main/show_explain.result
index 4cf6b66..32364d0 100644
--- a/mysql-test/main/show_explain.result
+++ b/mysql-test/main/show_explain.result
@@ -1,8 +1,3 @@
-set @innodb_stats_persistent_save= @@innodb_stats_persistent;
-set @innodb_stats_persistent_sample_pages_save=
-@@innodb_stats_persistent_sample_pages;
-set global innodb_stats_persistent= 1;
-set global innodb_stats_persistent_sample_pages=100;
drop table if exists t0, t1, t2, t3, t4;
drop view if exists v1;
SET @old_debug= @@session.debug;
@@ -1320,6 +1315,3 @@ drop table t0,t1,t2;
connection default;
disconnect con1;
set debug_sync='RESET';
-set global innodb_stats_persistent= @innodb_stats_persistent_save;
-set global innodb_stats_persistent_sample_pages=
-@innodb_stats_persistent_sample_pages_save;
diff --git a/mysql-test/main/show_explain.test b/mysql-test/main/show_explain.test
index 4145e79..6647ca0 100644
--- a/mysql-test/main/show_explain.test
+++ b/mysql-test/main/show_explain.test
@@ -4,12 +4,6 @@
--source include/have_debug.inc
--source include/have_innodb.inc
-set @innodb_stats_persistent_save= @@innodb_stats_persistent;
-set @innodb_stats_persistent_sample_pages_save=
- @@innodb_stats_persistent_sample_pages;
-
-set global innodb_stats_persistent= 1;
-set global innodb_stats_persistent_sample_pages=100;
--disable_warnings
drop table if exists t0, t1, t2, t3, t4;
@@ -1211,7 +1205,3 @@ connection default;
disconnect con1;
set debug_sync='RESET';
-set global innodb_stats_persistent= @innodb_stats_persistent_save;
-set global innodb_stats_persistent_sample_pages=
- @innodb_stats_persistent_sample_pages_save;
-
diff --git a/mysql-test/main/subselect_sj2.result b/mysql-test/main/subselect_sj2.result
index 9025dce..e5ed30c 100644
--- a/mysql-test/main/subselect_sj2.result
+++ b/mysql-test/main/subselect_sj2.result
@@ -1251,6 +1251,11 @@ INSERT IGNORE INTO t2 (t2id, t1idref) SELECT t1id, t1id FROM t1;
INSERT IGNORE INTO t1 VALUES (200001, 'a');
INSERT IGNORE INTO t2 (t2id, t1idref) VALUES (200011, 200001),(200012, 200001),(200013, 200001);
INSERT IGNORE INTO t3 VALUES (1, 200011, 1), (1, 200012, 2), (1, 200013, 3);
+ANALYZE TABLE t1,t2,t3;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+test.t3 analyze status OK
set @tmp7474= @@optimizer_search_depth;
SET SESSION optimizer_search_depth = 1;
SELECT SQL_NO_CACHE
diff --git a/mysql-test/main/subselect_sj2.test b/mysql-test/main/subselect_sj2.test
index e04c15f..9ed886d 100644
--- a/mysql-test/main/subselect_sj2.test
+++ b/mysql-test/main/subselect_sj2.test
@@ -1395,6 +1395,8 @@ INSERT IGNORE INTO t1 VALUES (200001, 'a');
INSERT IGNORE INTO t2 (t2id, t1idref) VALUES (200011, 200001),(200012, 200001),(200013, 200001);
INSERT IGNORE INTO t3 VALUES (1, 200011, 1), (1, 200012, 2), (1, 200013, 3);
+ANALYZE TABLE t1,t2,t3;
+
set @tmp7474= @@optimizer_search_depth;
SET SESSION optimizer_search_depth = 1;
diff --git a/mysql-test/main/subselect_sj2_jcl6.result b/mysql-test/main/subselect_sj2_jcl6.result
index 5dcaa08..b930bdc 100644
--- a/mysql-test/main/subselect_sj2_jcl6.result
+++ b/mysql-test/main/subselect_sj2_jcl6.result
@@ -1267,6 +1267,11 @@ INSERT IGNORE INTO t2 (t2id, t1idref) SELECT t1id, t1id FROM t1;
INSERT IGNORE INTO t1 VALUES (200001, 'a');
INSERT IGNORE INTO t2 (t2id, t1idref) VALUES (200011, 200001),(200012, 200001),(200013, 200001);
INSERT IGNORE INTO t3 VALUES (1, 200011, 1), (1, 200012, 2), (1, 200013, 3);
+ANALYZE TABLE t1,t2,t3;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+test.t3 analyze status OK
set @tmp7474= @@optimizer_search_depth;
SET SESSION optimizer_search_depth = 1;
SELECT SQL_NO_CACHE
@@ -1371,6 +1376,11 @@ set global innodb_stats_persistent= @innodb_stats_persistent_save;
set global innodb_stats_persistent_sample_pages=
@innodb_stats_persistent_sample_pages_save;
set optimizer_switch=@subselect_sj2_tmp;
+set @innodb_stats_persistent_save= @@innodb_stats_persistent;
+set @innodb_stats_persistent_sample_pages_save=
+@@innodb_stats_persistent_sample_pages;
+set global innodb_stats_persistent= 1;
+set global innodb_stats_persistent_sample_pages=100;
#
# Bug #898073: potential incremental join cache for semijoin
#
@@ -1463,6 +1473,9 @@ set join_cache_level=default;
show variables like 'join_cache_level';
Variable_name Value
join_cache_level 2
+set global innodb_stats_persistent= @innodb_stats_persistent_save;
+set global innodb_stats_persistent_sample_pages=
+@innodb_stats_persistent_sample_pages_save;
set @@optimizer_switch=@save_optimizer_switch_jcl6;
set @optimizer_switch_for_subselect_sj2_test=NULL;
set @join_cache_level_subselect_sj2_test=NULL;
diff --git a/mysql-test/main/subselect_sj2_jcl6.test b/mysql-test/main/subselect_sj2_jcl6.test
index 7ff0871..9be6102 100644
--- a/mysql-test/main/subselect_sj2_jcl6.test
+++ b/mysql-test/main/subselect_sj2_jcl6.test
@@ -16,6 +16,13 @@ set @join_cache_level_for_subselect_sj2_test=@@join_cache_level;
--source subselect_sj2.test
+set @innodb_stats_persistent_save= @@innodb_stats_persistent;
+set @innodb_stats_persistent_sample_pages_save=
+ @@innodb_stats_persistent_sample_pages;
+
+set global innodb_stats_persistent= 1;
+set global innodb_stats_persistent_sample_pages=100;
+
--echo #
--echo # Bug #898073: potential incremental join cache for semijoin
--echo #
@@ -107,6 +114,10 @@ DROP TABLE t1,t2;
set join_cache_level=default;
show variables like 'join_cache_level';
+set global innodb_stats_persistent= @innodb_stats_persistent_save;
+set global innodb_stats_persistent_sample_pages=
+ @innodb_stats_persistent_sample_pages_save;
+
set @@optimizer_switch=@save_optimizer_switch_jcl6;
set @optimizer_switch_for_subselect_sj2_test=NULL;
set @join_cache_level_subselect_sj2_test=NULL;
diff --git a/mysql-test/main/subselect_sj2_mat.result b/mysql-test/main/subselect_sj2_mat.result
index 29a3737..65dfddc 100644
--- a/mysql-test/main/subselect_sj2_mat.result
+++ b/mysql-test/main/subselect_sj2_mat.result
@@ -1253,6 +1253,11 @@ INSERT IGNORE INTO t2 (t2id, t1idref) SELECT t1id, t1id FROM t1;
INSERT IGNORE INTO t1 VALUES (200001, 'a');
INSERT IGNORE INTO t2 (t2id, t1idref) VALUES (200011, 200001),(200012, 200001),(200013, 200001);
INSERT IGNORE INTO t3 VALUES (1, 200011, 1), (1, 200012, 2), (1, 200013, 3);
+ANALYZE TABLE t1,t2,t3;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+test.t3 analyze status OK
set @tmp7474= @@optimizer_search_depth;
SET SESSION optimizer_search_depth = 1;
SELECT SQL_NO_CACHE
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index 846add7..e81b100 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -303,7 +303,7 @@ class Loose_scan_opt
pos->loosescan_picker.loosescan_parts= best_max_loose_keypart + 1;
pos->use_join_buffer= FALSE;
pos->table= tab;
- pos->filter= tab->filter;
+ pos->range_rowid_filter_info= tab->range_rowid_filter_info;
// todo need ref_depend_map ?
DBUG_PRINT("info", ("Produced a LooseScan plan, key %s, %s",
tab->table->key_info[best_loose_scan_key].name.str,
diff --git a/sql/rowid_filter.cc b/sql/rowid_filter.cc
index 7af9c4e..6b357e1 100644
--- a/sql/rowid_filter.cc
+++ b/sql/rowid_filter.cc
@@ -6,11 +6,11 @@
#include "sql_select.h"
inline
-double Range_filter_cost_info::lookup_cost(
- Rowid_filter_container_type cont_type)
+double Range_rowid_filter_cost_info::lookup_cost(
+ Rowid_filter_container_type cont_type)
{
switch (cont_type) {
- case ORDERED_ARRAY_CONTAINER:
+ case SORTED_ARRAY_CONTAINER:
return log(est_elements)*0.01;
default:
DBUG_ASSERT(0);
@@ -20,8 +20,8 @@ double Range_filter_cost_info::lookup_cost(
inline
-double Range_filter_cost_info::avg_access_and_eval_gain_per_row(
- Rowid_filter_container_type cont_type)
+double Range_rowid_filter_cost_info::avg_access_and_eval_gain_per_row(
+ Rowid_filter_container_type cont_type)
{
return (1+1.0/TIME_FOR_COMPARE) * (1 - selectivity) -
lookup_cost(cont_type);
@@ -33,8 +33,8 @@ double Range_filter_cost_info::avg_access_and_eval_gain_per_row(
and gets slope and interscept values.
*/
-void Range_filter_cost_info::init(Rowid_filter_container_type cont_type,
- TABLE *tab, uint idx)
+void Range_rowid_filter_cost_info::init(Rowid_filter_container_type cont_type,
+ TABLE *tab, uint idx)
{
container_type= cont_type;
table= tab;
@@ -49,15 +49,15 @@ void Range_filter_cost_info::init(Rowid_filter_container_type cont_type,
}
double
-Range_filter_cost_info::build_cost(Rowid_filter_container_type container_type)
+Range_rowid_filter_cost_info::build_cost(Rowid_filter_container_type cont_type)
{
double cost= 0;
cost+= table->quick_index_only_costs[key_no];
- switch (container_type) {
+ switch (cont_type) {
- case ORDERED_ARRAY_CONTAINER:
+ case SORTED_ARRAY_CONTAINER:
cost+= ARRAY_WRITE_COST * est_elements; /* cost filling the container */
cost+= ARRAY_SORT_C * est_elements * log(est_elements); /* sorting cost */
break;
@@ -68,10 +68,27 @@ Range_filter_cost_info::build_cost(Rowid_filter_container_type container_type)
return cost;
}
+
+Rowid_filter_container *Range_rowid_filter_cost_info::create_container()
+{
+ THD *thd= table->in_use;
+ uint elem_sz= table->file->ref_length;
+ Rowid_filter_container *res= 0;
+
+ switch (container_type) {
+ case SORTED_ARRAY_CONTAINER:
+ res= new (thd->mem_root) Rowid_filter_sorted_array(est_elements, elem_sz);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return res;
+}
static
-int compare_range_filter_cost_info_by_a(Range_filter_cost_info **filter_ptr_1,
- Range_filter_cost_info **filter_ptr_2)
+int compare_range_rowid_filter_cost_info_by_a(
+ Range_rowid_filter_cost_info **filter_ptr_1,
+ Range_rowid_filter_cost_info **filter_ptr_2)
{
double diff= (*filter_ptr_2)->a - (*filter_ptr_1)->a;
return (diff < 0 ? -1 : (diff > 0 ? 1 : 0));
@@ -83,16 +100,16 @@ int compare_range_filter_cost_info_by_a(Range_filter_cost_info **filter_ptr_1,
@details
*/
-void TABLE::prune_range_filters()
+void TABLE::prune_range_rowid_filters()
{
uint i, j;
- Range_filter_cost_info **filter_ptr_1= range_filter_cost_info_ptr;
- for (i= 0; i < range_filter_cost_info_elems; i++, filter_ptr_1++)
+ Range_rowid_filter_cost_info **filter_ptr_1= range_rowid_filter_cost_info_ptr;
+ for (i= 0; i < range_rowid_filter_cost_info_elems; i++, filter_ptr_1++)
{
uint key_no= (*filter_ptr_1)->key_no;
- Range_filter_cost_info **filter_ptr_2= filter_ptr_1 + 1;
- for (j= i+1; j < range_filter_cost_info_elems; j++, filter_ptr_2++)
+ Range_rowid_filter_cost_info **filter_ptr_2= filter_ptr_1 + 1;
+ for (j= i+1; j < range_rowid_filter_cost_info_elems; j++, filter_ptr_2++)
{
key_map map= key_info[key_no].overlapped;
map.intersect(key_info[(*filter_ptr_2)->key_no].overlapped);
@@ -105,16 +122,18 @@ void TABLE::prune_range_filters()
}
/* Sort the array range_filter_cost_info by 'a' */
- my_qsort(range_filter_cost_info_ptr,
- range_filter_cost_info_elems,
- sizeof(Range_filter_cost_info *),
- (qsort_cmp) compare_range_filter_cost_info_by_a);
-
- Range_filter_cost_info **cand_filter_ptr= range_filter_cost_info_ptr;
- for (i= 0; i < range_filter_cost_info_elems; i++, cand_filter_ptr++)
+ my_qsort(range_rowid_filter_cost_info_ptr,
+ range_rowid_filter_cost_info_elems,
+ sizeof(Range_rowid_filter_cost_info *),
+ (qsort_cmp) compare_range_rowid_filter_cost_info_by_a);
+
+ Range_rowid_filter_cost_info **cand_filter_ptr=
+ range_rowid_filter_cost_info_ptr;
+ for (i= 0; i < range_rowid_filter_cost_info_elems; i++, cand_filter_ptr++)
{
bool is_pruned= false;
- Range_filter_cost_info **usable_filter_ptr= range_filter_cost_info_ptr;
+ Range_rowid_filter_cost_info **usable_filter_ptr=
+ range_rowid_filter_cost_info_ptr;
key_map abs_indep;
abs_indep.clear_all();
for (uint j= 0; j < i; j++, usable_filter_ptr++)
@@ -130,29 +149,30 @@ void TABLE::prune_range_filters()
}
else
{
- Range_filter_cost_info *moved= *cand_filter_ptr;
+ Range_rowid_filter_cost_info *moved= *cand_filter_ptr;
memmove(usable_filter_ptr+1, usable_filter_ptr,
- sizeof(Range_filter_cost_info *) * (i-j-1));
+ sizeof(Range_rowid_filter_cost_info *) * (i-j-1));
*usable_filter_ptr= moved;
}
}
if (is_pruned)
{
memmove(cand_filter_ptr, cand_filter_ptr+1,
- sizeof(Range_filter_cost_info *) *
- (range_filter_cost_info_elems - 1 - i));
- range_filter_cost_info_elems--;
+ sizeof(Range_rowid_filter_cost_info *) *
+ (range_rowid_filter_cost_info_elems - 1 - i));
+ range_rowid_filter_cost_info_elems--;
}
}
}
static uint
-get_max_range_filter_elements_for_table(THD *thd, TABLE *tab,
- Rowid_filter_container_type cont_type)
+get_max_range_rowid_filter_elems_for_table(
+ THD *thd, TABLE *tab,
+ Rowid_filter_container_type cont_type)
{
switch (cont_type) {
- case ORDERED_ARRAY_CONTAINER :
+ case SORTED_ARRAY_CONTAINER :
return thd->variables.max_rowid_filter_size/tab->file->ref_length;
default :
DBUG_ASSERT(0);
@@ -160,7 +180,7 @@ get_max_range_filter_elements_for_table(THD *thd, TABLE *tab,
}
}
-void TABLE::init_cost_info_for_usable_range_filters(THD *thd)
+void TABLE::init_cost_info_for_usable_range_rowid_filters(THD *thd)
{
uint key_no;
key_map usable_range_filter_keys;
@@ -173,60 +193,64 @@ void TABLE::init_cost_info_for_usable_range_filters(THD *thd)
if (key_no == s->primary_key && file->primary_key_is_clustered())
continue;
if (quick_rows[key_no] >
- get_max_range_filter_elements_for_table(thd, this,
- ORDERED_ARRAY_CONTAINER))
+ get_max_range_rowid_filter_elems_for_table(thd, this,
+ SORTED_ARRAY_CONTAINER))
continue;
usable_range_filter_keys.set_bit(key_no);
}
- range_filter_cost_info_elems= usable_range_filter_keys.bits_set();
- if (!range_filter_cost_info_elems)
+ range_rowid_filter_cost_info_elems= usable_range_filter_keys.bits_set();
+ if (!range_rowid_filter_cost_info_elems)
return;
- range_filter_cost_info_ptr=
- (Range_filter_cost_info **) thd->calloc(sizeof(Range_filter_cost_info *) *
- range_filter_cost_info_elems);
- range_filter_cost_info=
- new (thd->mem_root) Range_filter_cost_info[range_filter_cost_info_elems];
- if (!range_filter_cost_info_ptr || !range_filter_cost_info)
+ range_rowid_filter_cost_info_ptr=
+ (Range_rowid_filter_cost_info **)
+ thd->calloc(sizeof(Range_rowid_filter_cost_info *) *
+ range_rowid_filter_cost_info_elems);
+ range_rowid_filter_cost_info=
+ new (thd->mem_root)
+ Range_rowid_filter_cost_info[range_rowid_filter_cost_info_elems];
+ if (!range_rowid_filter_cost_info_ptr || !range_rowid_filter_cost_info)
{
- range_filter_cost_info_elems= 0;
+ range_rowid_filter_cost_info_elems= 0;
return;
}
- Range_filter_cost_info **curr_ptr= range_filter_cost_info_ptr;
- Range_filter_cost_info *curr_filter_cost_info= range_filter_cost_info;
+ Range_rowid_filter_cost_info **curr_ptr= range_rowid_filter_cost_info_ptr;
+ Range_rowid_filter_cost_info *curr_filter_cost_info=
+ range_rowid_filter_cost_info;
key_map::Iterator li(usable_range_filter_keys);
while ((key_no= li++) != key_map::Iterator::BITMAP_END)
{
*curr_ptr= curr_filter_cost_info;
- curr_filter_cost_info->init(ORDERED_ARRAY_CONTAINER, this, key_no);
+ curr_filter_cost_info->init(SORTED_ARRAY_CONTAINER, this, key_no);
curr_ptr++;
curr_filter_cost_info++;
}
- prune_range_filters();
+ prune_range_rowid_filters();
}
-Range_filter_cost_info *TABLE::best_filter_for_partial_join(uint access_key_no,
- double records)
+Range_rowid_filter_cost_info *
+TABLE::best_range_rowid_filter_for_partial_join(uint access_key_no,
+ double records)
{
- if (!this || range_filter_cost_info_elems == 0 ||
+ if (!this || range_rowid_filter_cost_info_elems == 0 ||
covering_keys.is_set(access_key_no))
return 0;
if (access_key_no == s->primary_key && file->primary_key_is_clustered())
return 0;
- Range_filter_cost_info *best_filter= 0;
+ Range_rowid_filter_cost_info *best_filter= 0;
double best_filter_gain= 0;
key_map *overlapped= &key_info[access_key_no].overlapped;
- for (uint i= 0; i < range_filter_cost_info_elems ; i++)
+ for (uint i= 0; i < range_rowid_filter_cost_info_elems ; i++)
{
double curr_gain = 0;
- Range_filter_cost_info *filter= range_filter_cost_info_ptr[i];
+ Range_rowid_filter_cost_info *filter= range_rowid_filter_cost_info_ptr[i];
if ((filter->key_no == access_key_no) ||
overlapped->is_set(filter->key_no))
continue;
@@ -243,7 +267,7 @@ Range_filter_cost_info *TABLE::best_filter_for_partial_join(uint access_key_no,
}
-bool Range_filter_ordered_array::fill()
+bool Range_rowid_filter::fill()
{
int rc= 0;
handler *file= table->file;
@@ -275,7 +299,7 @@ bool Range_filter_ordered_array::fill()
if (!rc)
{
file->position(quick->record);
- if (refpos_container.add((char*) file->ref))
+ if (container->add(NULL, (char*) file->ref))
rc= 1;
}
}
@@ -288,21 +312,19 @@ bool Range_filter_ordered_array::fill()
file->in_range_check_pushed_down= in_range_check_pushed_down_save;
if (rc != HA_ERR_END_OF_FILE)
return 1;
- container_is_filled= true;
table->file->rowid_filter_is_active= true;
return 0;
}
-bool Range_filter_ordered_array::sort()
-{
- refpos_container.sort(refpos_order_cmp, (void *) (table->file));
- return false;
-}
-
-
-bool Range_filter_ordered_array::check(char *elem)
+bool Rowid_filter_sorted_array::check(void *ctxt, char *elem)
{
+ TABLE *table= (TABLE *) ctxt;
+ if (!is_checked)
+ {
+ refpos_container.sort(refpos_order_cmp, (void *) (table->file));
+ is_checked= true;
+ }
int l= 0;
int r= refpos_container.elements()-1;
while (l <= r)
@@ -321,8 +343,10 @@ bool Range_filter_ordered_array::check(char *elem)
}
-Range_filter_ordered_array::~Range_filter_ordered_array()
+Range_rowid_filter::~Range_rowid_filter()
{
+ delete container;
+ container= 0;
if (select)
{
if (select->quick)
diff --git a/sql/rowid_filter.h b/sql/rowid_filter.h
index 7cec865..3578866 100644
--- a/sql/rowid_filter.h
+++ b/sql/rowid_filter.h
@@ -1,117 +1,66 @@
#ifndef ROWID_FILTER_INCLUDED
#define ROWID_FILTER_INCLUDED
-/**
- It makes sense to apply filters for a certain join order when the following
- inequality holds:
-
- #T + c4*#T > #T*sel(Fi) + c4*#T*sel(Fi) +
- I/O(Fi) + c1*#(Fi) + c2*#(Fi)*log(#(Fi)) +
- c3*#T (1),
-
- where #T - the fanout of the partial join
- Fi - a filter for the index with the number i in
- the key_map of available indexes for this table
- sel(Fi) - the selectivity of the index with the number
- i
- c4*#T,
- c4*#T*sel(Fi) - a cost to apply available predicates
- c4 - a constant to apply available predicates
- I/O(Fi) - a cost of the I/O accesses to Fi
- #(Fi) - a number of estimated records that range
- access would use
- c1*#(Fi) - a cost to write in Fi
- c1 - a constant to write one element in Fi
- c2*#(Fi)*log(#(Fi)) - a cost to sort in Fi
- c2 - a sorting constant
- c3*(#T) - a cost to look-up into a current partial join
- c3 - a constant to look-up into Fi
-
- Let's set a new variable FBCi (filter building cost for the filter with
- index i):
-
- FBCi = I/O(Fi) + c1*#(Fi) + c2*#(Fi)*log(#(Fi))
-
- It can be seen that FBCi doesn't depend on #T.
-
- So using this variable (1) can be rewritten:
-
- #T + c4*#T > #T*sel(Fi) + c4*#T*sel(Fi) +
- FBCi +
- c3*#T
-
- To get a possible cost improvement when a filter is used right part
- of the (1) inequality should be deducted from the left part.
- Denote it as G(#T):
-
- G(#T)= #T + c4*#T - (#T*sel(Fi) + c4*#T*sel(Fi) + FBCi + c3*#T) (2)
-
- On the prepare stage when filters are created #T value isn't known.
-
- To find out what filter is the best among available one for the table
- (what filter gives the biggest gain) a knowledge about linear functions
- can be used. Consider filter gain as a linear function:
-
- Gi(#T)= ai*#T + bi (3)
-
- where ai= 1+c4-c3-sel(Fi)*(1+c4),
- bi= -FBCi
-
- Filter gain can be interpreted as an ordinate, #T as abscissa.
-
- So the aim is to find the linear function that has the biggest ordinate value
- for each positive abscissa (because #T can't be negative) comparing with
- the other available functions.
-
- Consider two filters Fi, Fj or linear functions with a positive slope.
- To find out which linear function is better let's find their intersection
- point coordinates.
-
- Gi(#T0)= Gj(#T0) (using (2))=>
- #T0= (bj - bi)/(ai - aj) (using (3))
- =>
- #T0= (BCFj-BCFi)/((sel(Fj)-sel(Fi))*(1+c4))
-
- If put #T0 value into the (3) formula G(#T0) can be easily found.
-
- It can be seen that if two linear functions intersect in II, III or IV
- quadrants the linear function with a bigger slope value will always
- be better.
-
- If two functions intersect in the I quadrant for #T1 < #T0 a function
- with a smaller slope value will give a better gain and when #T1 > #T0
- function with a bigger slope will give better gain.
-
- for each #T1 > #T0 if (ai > aj) => (Gi(#T1) >= Gj(#T1))
- #T1 <= #T0 if (ai > aj) => (Gi(#T1) <= Gj(#T1))
-
- So both linear functions should be saved.
-
- Interesting cases:
-
- 1. For Fi,Fj filters ai=aj.
-
- In this case intercepts bi and bj should be compared.
- The filter with the biggest intercept will give a better result.
-
- 2. Only one filter remains after the calculations and for some join order
- it is equal to the index that is used to access table. Therefore, this
- filter can't be used.
-
- In this case the gain is computed for every filter that can be constructed
- for this table.
-
- After information about filters is computed for each partial join order
- it is checked if the filter can be applied to the current table.
- If it gives a cost improvement it is saved as the best plan for this
- partial join.
-*/
#include "mariadb.h"
#include "sql_array.h"
+/**
+ @class Rowid_filter
+
+ What rowid / primary filters are
+ --------------------------------
+
+ Consider a join query Q of the form
+ SELECT * FROM T1, ... , Tk WHERE P.
+
+ For any of the table reference Ti(Q) from the from clause of Q different
+ rowid / primary key filters (pk-filters for short) can be built.
+ A pk-filter F built for Ti(Q) is a set of rowids / primary keys of Ti
+ F= {pk1,...,pkN} such that for any row r=r1||...||rk from the result set of Q
+ ri's rowid / primary key pk(ri) is contained in F.
+
+ When pk-filters are useful
+ --------------------------
+
+ If building a pk-filter F for Ti(Q )is not too costly and its cardinality #F
+ is much less than the cardinality of T - #T then using the pk-filter when
+ executing Q might be quite beneficial.
+
+ Let r be a random row from Ti. Let s(F) be the probability that pk(r)
+ belongs to F. Let BC(F) be the cost of building F.
+
+ Suppose that the optimizer has chosen for Q a plan with this join order
+ T1 => ... Tk and that the table Ti is accessed by a ref access using index I.
+ Let K = {k1,...,kM} be the set of all rowid/primary keys values used to access
+ rows of Ti when looking for matches in this table.to join Ti by index I.
+
+ Let's assume that two set sets K and F are uncorrelated. With this assumption
+ if before accessing data from Ti by the rowid / primary key k we first
+ check whether k is in F then we can expect saving on M*(1-s(S)) accesses of
+ data rows from Ti. If we can guarantee that test whether k is in F is
+ relatively cheap then we can gain a lot assuming that BC(F) is much less
+ then the cost of fetching M*(1-s(S)) records from Ti and following
+ evaluation of conditions pushed into Ti.
+
+ Making pk-filter test cheap
+ ---------------------------
+
+ If the search structure to test whether an element is in F can be fully
+ placed in RAM then this test is expected to be be much cheaper than a random
+ access of a record from Ti. We'll consider two search structures for
+ pk-filters: ordered array and bloom filter. Ordered array is easy to
+ implement, but it's space consuming. If a filter contains primary keys
+ then at least space for each primary key from the filter must be allocated
+ in the search structure. On a the opposite a bloom filter requires a
+ fixed number of bits and this number does not depend on the cardinality
+ of the pk-filter (10 bits per element will serve pk-filter of any size).
+*/
+
class TABLE;
class SQL_SELECT;
+class Rowid_filter_container;
+class Range_rowid_filter_cost_info;
/* Cost to write rowid into array */
#define ARRAY_WRITE_COST 0.005
@@ -122,73 +71,76 @@ class SQL_SELECT;
typedef enum
{
- ORDERED_ARRAY_CONTAINER,
+ SORTED_ARRAY_CONTAINER,
BLOOM_FILTER_CONTAINER
} Rowid_filter_container_type;
-class Range_filter_cost_info : public Sql_alloc
+class Rowid_filter_container : public Sql_alloc
{
public:
- Rowid_filter_container_type container_type;
- TABLE *table;
- uint key_no;
- double est_elements;
- double b; // intercept of the linear function
- double a; // slope of the linear function
- double selectivity;
- double cross_x;
- key_map abs_independent;
+ virtual Rowid_filter_container_type get_type() = 0;
+ virtual bool alloc() = 0;
+ virtual bool add(void *ctxt, char *elem) = 0;
+ virtual bool check(void *ctxt, char *elem) = 0;
+ virtual ~Rowid_filter_container() {}
+};
- /**
- Filter cost functions
- */
- Range_filter_cost_info() : table(0), key_no(0) {}
+class Rowid_filter : public Sql_alloc
+{
+protected:
+ Rowid_filter_container *container;
+public:
+ Rowid_filter(Rowid_filter_container *container_arg)
+ : container(container_arg) {}
+
+ virtual bool build() = 0;
+ virtual bool check(char *elem) = 0;
- void init(Rowid_filter_container_type cont_type,
- TABLE *tab, uint key_numb);
+ virtual ~Rowid_filter() {}
- double build_cost(Rowid_filter_container_type container_type);
+ Rowid_filter_container *get_container() { return container; }
+};
- inline double lookup_cost(Rowid_filter_container_type cont_type);
- inline double
- avg_access_and_eval_gain_per_row(Rowid_filter_container_type cont_type);
+class Range_rowid_filter: public Rowid_filter
+{
+ TABLE *table;
+ SQL_SELECT *select;
+ Range_rowid_filter_cost_info *cost_info;
- /**
- Get the gain that usage of filter promises for 'rows' key entries
- */
- inline double get_gain(double rows)
- {
- return rows * a - b;
- }
+public:
+ Range_rowid_filter(TABLE *tab,
+ Range_rowid_filter_cost_info *cost_arg,
+ Rowid_filter_container *container_arg,
+ SQL_SELECT *sel)
+ : Rowid_filter(container_arg), table(tab), select(sel), cost_info(cost_arg)
+ {}
- inline double get_adjusted_gain(double rows, double worst_seeks)
- {
- return get_gain(rows) -
- (1 - selectivity) * (rows - MY_MIN(rows, worst_seeks));
- }
+ ~Range_rowid_filter();
- inline double get_cmp_gain(double rows)
- {
- return rows * (1 - selectivity) / TIME_FOR_COMPARE;
- }
+ bool build() { return fill(); }
+
+ bool check(char *elem) { return container->check(table, elem); }
+
+ bool fill();
+ SQL_SELECT *get_select() { return select; }
};
-class Refpos_container_ordered_array : public Sql_alloc
+class Refpos_container_sorted_array : public Sql_alloc
{
- uint elem_size;
uint max_elements;
+ uint elem_size;
Dynamic_array<char> *array;
public:
- Refpos_container_ordered_array(uint elem_sz, uint max_elems)
- : elem_size(elem_sz), max_elements(max_elems), array(0) {}
+ Refpos_container_sorted_array(uint max_elems, uint elem_sz)
+ : max_elements(max_elems), elem_size(elem_sz), array(0) {}
- ~Refpos_container_ordered_array()
+ ~Refpos_container_sorted_array()
{
delete array;
array= 0;
@@ -226,57 +178,77 @@ class Refpos_container_ordered_array : public Sql_alloc
}
};
-class Range_filter_ordered_array : public Sql_alloc
+class Rowid_filter_sorted_array: public Rowid_filter_container
{
- TABLE *table;
- SQL_SELECT *select;
- bool container_is_filled;
- Refpos_container_ordered_array refpos_container;
-
+ Refpos_container_sorted_array refpos_container;
+ bool is_checked;
+
public:
- Range_filter_ordered_array(TABLE *tab, SQL_SELECT *sel, uint elems)
- : table(tab), select(sel), container_is_filled(false),
- refpos_container(table->file->ref_length, elems)
- {}
-
- ~Range_filter_ordered_array();
+ Rowid_filter_sorted_array(uint elems, uint elem_size)
+ : refpos_container(elems, elem_size), is_checked(false) {}
- SQL_SELECT *get_select() { return select; }
+ Rowid_filter_container_type get_type()
+ { return SORTED_ARRAY_CONTAINER; }
bool alloc() { return refpos_container.alloc(); }
- bool is_filled() { return container_is_filled; }
-
- bool fill();
+ bool add(void *ctxt, char *elem) { return refpos_container.add(elem); }
- bool sort();
-
- bool check(char *elem);
+ bool check(void *ctxt, char *elem);
};
-class Rowid_filter : public Sql_alloc
-{
- Range_filter_cost_info *cost_info;
- Range_filter_ordered_array *container;
+class Range_rowid_filter_cost_info : public Sql_alloc
+{
public:
- Rowid_filter(Range_filter_cost_info *cost_arg,
- Range_filter_ordered_array *container_arg)
- : cost_info(cost_arg), container(container_arg) {}
+ Rowid_filter_container_type container_type;
+ TABLE *table;
+ uint key_no;
+ double est_elements;
+ double b; // intercept of the linear function
+ double a; // slope of the linear function
+ double selectivity;
+ double cross_x;
+ key_map abs_independent;
+
+ /**
+ Filter cost functions
+ */
+
+ Range_rowid_filter_cost_info() : table(0), key_no(0) {}
+
+ void init(Rowid_filter_container_type cont_type,
+ TABLE *tab, uint key_numb);
+
+ double build_cost(Rowid_filter_container_type container_type);
+
+ inline double lookup_cost(Rowid_filter_container_type cont_type);
+
+ inline double
+ avg_access_and_eval_gain_per_row(Rowid_filter_container_type cont_type);
- Range_filter_ordered_array *get_container() { return container; }
+ /**
+ Get the gain that usage of filter promises for 'rows' key entries
+ */
+ inline double get_gain(double rows)
+ {
+ return rows * a - b;
+ }
- ~Rowid_filter()
+ inline double get_adjusted_gain(double rows, double worst_seeks)
{
- delete container;
+ return get_gain(rows) -
+ (1 - selectivity) * (rows - MY_MIN(rows, worst_seeks));
}
- bool is_active()
+ inline double get_cmp_gain(double rows)
{
- return get_container()->is_filled();
+ return rows * (1 - selectivity) / TIME_FOR_COMPARE;
}
- bool check(char *buf) { return get_container()->check(buf); }
+ Rowid_filter_container *create_container();
+
};
+
#endif /* ROWID_FILTER_INCLUDED */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 724e156..531fe5f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1465,9 +1465,9 @@ int JOIN::optimize()
}
-bool JOIN::make_range_filters()
+bool JOIN::make_range_rowid_filters()
{
- DBUG_ENTER("make_range_filters");
+ DBUG_ENTER("make_range_rowid_filters");
JOIN_TAB *tab;
@@ -1475,12 +1475,11 @@ bool JOIN::make_range_filters()
tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
- if (tab->filter)
+ if (tab->range_rowid_filter_info)
{
int err;
SQL_SELECT *sel;
- uint elems;
- Range_filter_ordered_array *filter_container= NULL;
+ Rowid_filter_container *filter_container= NULL;
Item **sargable_cond= get_sargable_cond(this, tab->table);
sel= make_select(tab->table, const_table_map, const_table_map,
*sargable_cond, (SORT_INFO*) 0, 1, &err);
@@ -1489,7 +1488,7 @@ bool JOIN::make_range_filters()
key_map filter_map;
filter_map.clear_all();
- filter_map.set_bit(tab->filter->key_no);
+ filter_map.set_bit(tab->range_rowid_filter_info->key_no);
filter_map.merge(tab->table->with_impossible_ranges);
bool force_index_save= tab->table->force_index;
tab->table->force_index= true;
@@ -1500,13 +1499,15 @@ bool JOIN::make_range_filters()
if (thd->is_error())
DBUG_RETURN(1);
DBUG_ASSERT(sel->quick);
- elems= (uint) tab->filter->est_elements;
filter_container=
- new (thd->mem_root) Range_filter_ordered_array(tab->table, sel, elems);
+ tab->range_rowid_filter_info->create_container();
if (filter_container)
{
tab->rowid_filter=
- new (thd->mem_root) Rowid_filter(tab->filter, filter_container);
+ new (thd->mem_root) Range_rowid_filter(
+ tab->table,
+ tab->range_rowid_filter_info,
+ filter_container, sel);
}
}
}
@@ -1515,9 +1516,9 @@ bool JOIN::make_range_filters()
bool
-JOIN::init_range_filters()
+JOIN::init_range_rowid_filters()
{
- DBUG_ENTER("init_range_filters");
+ DBUG_ENTER("init_range_rowid_filters");
JOIN_TAB *tab;
@@ -1534,7 +1535,7 @@ JOIN::init_range_filters()
continue;
}
tab->table->file->rowid_filter_push(tab->rowid_filter);
- tab->is_rowid_filter_filled= false;
+ tab->is_rowid_filter_built= false;
}
DBUG_RETURN(0);
}
@@ -2058,7 +2059,7 @@ int JOIN::optimize_stage2()
if (get_best_combination())
DBUG_RETURN(1);
- if (make_range_filters())
+ if (make_range_rowid_filters())
DBUG_RETURN(1);
if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE))
@@ -2725,7 +2726,7 @@ int JOIN::optimize_stage2()
if (init_join_caches())
DBUG_RETURN(1);
- if (init_range_filters())
+ if (init_range_rowid_filters())
DBUG_RETURN(1);
error= 0;
@@ -5120,7 +5121,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
impossible_range= records == 0 && s->table->reginfo.impossible_range;
if (join->thd->lex->sql_command == SQLCOM_SELECT &&
optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER))
- s->table->init_cost_info_for_usable_range_filters(join->thd);
+ s->table->init_cost_info_for_usable_range_rowid_filters(join->thd);
}
if (!impossible_range)
{
@@ -6926,14 +6927,14 @@ best_access_path(JOIN *join,
double best_time= DBL_MAX;
double records= DBL_MAX;
table_map best_ref_depends_map= 0;
- Range_filter_cost_info *best_filter= 0;
+ Range_rowid_filter_cost_info *best_filter= 0;
double tmp;
ha_rows rec;
bool best_uses_jbuf= FALSE;
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
KEYUSE *hj_start_key= 0;
SplM_plan_info *spl_plan= 0;
- Range_filter_cost_info *filter= 0;
+ Range_rowid_filter_cost_info *filter= 0;
disable_jbuf= disable_jbuf || idx == join->const_tables;
@@ -7329,7 +7330,8 @@ best_access_path(JOIN *join,
if (records < DBL_MAX)
{
double rows= record_count * records;
- filter= table->best_filter_for_partial_join(start_key->key, rows);
+ filter=
+ table->best_range_rowid_filter_for_partial_join(start_key->key, rows);
if (filter)
{
tmp-= filter->get_adjusted_gain(rows, s->worst_seeks) -
@@ -7461,7 +7463,8 @@ best_access_path(JOIN *join,
{
double rows= record_count * s->found_records;
uint key_no= s->quick->index;
- filter= s->table->best_filter_for_partial_join(key_no, rows);
+ filter= s->table->best_range_rowid_filter_for_partial_join(key_no,
+ rows);
if (filter)
{
tmp-= filter->get_gain(rows);
@@ -7559,7 +7562,7 @@ best_access_path(JOIN *join,
pos->loosescan_picker.loosescan_key= MAX_KEY;
pos->use_join_buffer= best_uses_jbuf;
pos->spl_plan= spl_plan;
- pos->filter= best_filter;
+ pos->range_rowid_filter_info= best_filter;
loose_scan_opt.save_to_position(s, loose_scan_pos);
@@ -9825,7 +9828,7 @@ bool JOIN::get_best_combination()
is_hash_join_key_no(j->ref.key))
hash_join= TRUE;
- j->filter= best_positions[tablenr].filter;
+ j->range_rowid_filter_info= best_positions[tablenr].range_rowid_filter_info;
loop_end:
/*
@@ -12566,14 +12569,13 @@ bool error_if_full_join(JOIN *join)
}
-void JOIN_TAB::fill_range_filter_if_needed()
+void JOIN_TAB::build_range_rowid_filter_if_needed()
{
- if (rowid_filter && !is_rowid_filter_filled)
+ if (rowid_filter && !is_rowid_filter_built)
{
- if (!rowid_filter->get_container()->fill())
+ if (!rowid_filter->build())
{
- rowid_filter->get_container()->sort();
- is_rowid_filter_filled= true;
+ is_rowid_filter_built= true;
}
else
{
@@ -19493,7 +19495,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
if (!join_tab->preread_init_done && join_tab->preread_init())
DBUG_RETURN(NESTED_LOOP_ERROR);
- join_tab->fill_range_filter_if_needed();
+ join_tab->build_range_rowid_filter_if_needed();
join->return_tab= join_tab;
@@ -20439,7 +20441,7 @@ int join_init_read_record(JOIN_TAB *tab)
if (tab->filesort && tab->sort_table()) // Sort table.
return 1;
- tab->fill_range_filter_if_needed();
+ tab->build_range_rowid_filter_if_needed();
DBUG_EXECUTE_IF("kill_join_init_read_record",
tab->join->thd->set_killed(KILL_QUERY););
@@ -22490,7 +22492,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
tab->use_quick=1;
tab->ref.key= -1;
tab->ref.key_parts=0; // Don't use ref key.
- tab->filter= 0;
+ tab->range_rowid_filter_info= 0;
if (tab->rowid_filter)
{
delete tab->rowid_filter;
@@ -25331,11 +25333,12 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
if (rowid_filter)
{
- QUICK_SELECT_I *quick= rowid_filter->get_container()->get_select()->quick;
+ Range_rowid_filter *range_filter= (Range_rowid_filter *) rowid_filter;
+ QUICK_SELECT_I *quick= range_filter->get_select()->quick;
Explain_rowid_filter *erf= new (thd->mem_root) Explain_rowid_filter;
erf->quick= quick->get_explain(thd->mem_root);
- erf->selectivity= filter->selectivity;
+ erf->selectivity= range_rowid_filter_info->selectivity;
erf->rows= quick->records;
eta->rowid_filter= erf;
//psergey-todo: also do setup for ANALYZE here.
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 2fea84d..bfa4274 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -510,11 +510,11 @@ typedef struct st_join_table {
uint n_sj_tables;
bool preread_init_done;
- Range_filter_cost_info *filter;
+ Range_rowid_filter_cost_info *range_rowid_filter_info;
Rowid_filter *rowid_filter;
- bool is_rowid_filter_filled;
+ bool is_rowid_filter_built;
- void fill_range_filter_if_needed();
+ void build_range_rowid_filter_if_needed();
void cleanup();
inline bool is_using_loose_index_scan()
{
@@ -889,7 +889,7 @@ class Sj_materialization_picker : public Semi_join_strategy_picker
};
-class Range_filter_cost_info;
+class Range_rowid_filter_cost_info;
class Rowid_filter;
@@ -976,7 +976,7 @@ typedef struct st_position
/* Info on splitting plan used at this position */
SplM_plan_info *spl_plan;
/* The index for which filter can be built */
- Range_filter_cost_info *filter;
+ Range_rowid_filter_cost_info *range_rowid_filter_info;
} POSITION;
typedef Bounds_checked_array<Item_null_result*> Item_null_array;
@@ -1626,8 +1626,8 @@ class JOIN :public Sql_alloc
bool optimize_unflattened_subqueries();
bool optimize_constant_subqueries();
int init_join_caches();
- bool make_range_filters();
- bool init_range_filters();
+ bool make_range_rowid_filters();
+ bool init_range_rowid_filters();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by, bool recompute= FALSE);
diff --git a/sql/table.cc b/sql/table.cc
index 67c369f..bb18940 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4695,9 +4695,9 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
created= TRUE;
cond_selectivity= 1.0;
cond_selectivity_sampling_explain= NULL;
- range_filter_cost_info_elems= 0;
- range_filter_cost_info_ptr= NULL;
- range_filter_cost_info= NULL;
+ range_rowid_filter_cost_info_elems= 0;
+ range_rowid_filter_cost_info_ptr= NULL;
+ range_rowid_filter_cost_info= NULL;
#ifdef HAVE_REPLICATION
/* used in RBR Triggers */
master_had_triggers= 0;
diff --git a/sql/table.h b/sql/table.h
index feeb9ee..9918758 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -55,7 +55,7 @@ class Virtual_column_info;
class Table_triggers_list;
class TMP_TABLE_PARAM;
class SEQUENCE;
-class Range_filter_cost_info;
+class Range_rowid_filter_cost_info;
/*
Used to identify NESTED_JOIN structures within a join (applicable only to
@@ -1504,13 +1504,14 @@ struct TABLE
void add_splitting_info_for_key_field(struct KEY_FIELD *key_field);
key_map with_impossible_ranges;
- uint range_filter_cost_info_elems;
- Range_filter_cost_info **range_filter_cost_info_ptr;
- Range_filter_cost_info *range_filter_cost_info;
- void init_cost_info_for_usable_range_filters(THD *thd);
- void prune_range_filters();
- Range_filter_cost_info *best_filter_for_partial_join(uint access_key_no,
- double records);
+ uint range_rowid_filter_cost_info_elems;
+ Range_rowid_filter_cost_info **range_rowid_filter_cost_info_ptr;
+ Range_rowid_filter_cost_info *range_rowid_filter_cost_info;
+ void init_cost_info_for_usable_range_rowid_filters(THD *thd);
+ void prune_range_rowid_filters();
+ Range_rowid_filter_cost_info *
+ best_range_rowid_filter_for_partial_join(uint access_key_no,
+ double records);
/**
System Versioning support
*/
1
0

19 Jan '19
revision-id: 81768c1a878ee11e39d2b4d1ed0d52a35a00c6dc (mariadb-10.4.1-102-g81768c1)
parent(s): 4edb29380c98058a28e49c826bacee9c83473579
committer: Alexey Botchkov
timestamp: 2019-01-20 02:45:58 +0400
message:
MDEV-5313 Improving audit plugin API.
service_sql added.
---
include/mysql/service_sql.h | 101 ++++++++++++++++++++++++++++++++++++++++++++
include/mysql/services.h | 1 +
include/service_versions.h | 1 +
libservices/CMakeLists.txt | 1 +
libservices/sql_service.c | 19 +++++++++
sql/sql_plugin_services.ic | 22 +++++++++-
6 files changed, 143 insertions(+), 2 deletions(-)
diff --git a/include/mysql/service_sql.h b/include/mysql/service_sql.h
new file mode 100644
index 0000000..2af5177
--- /dev/null
+++ b/include/mysql/service_sql.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#ifndef MYSQL_SERVICE_SQL
+#define MYSQL_SERVICE_SQL
+
+/**
+ @file
+ sql service
+
+ Provides interface for plugins to execute SQL queries.
+
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct st_mysql MYSQL;
+typedef struct st_mysql_res MYSQL_RES;
+typedef char **MYSQL_ROW;
+
+
+extern struct sql_service_st {
+ MYSQL *(*sqls_init)(MYSQL *mysql);
+ void (*sqls_close)(MYSQL *mysql);
+ int (*sqls_real_query)(MYSQL *mysql, const char *q,
+ unsigned long length);
+ unsigned long (*sqls_affected_rows)(MYSQL *mysql);
+ uint (*sqls_errno)(MYSQL *mysql);
+ const char *(*sqls_error)(MYSQL *mysql);
+ MYSQL_RES *(*sqls_store_result)(MYSQL *mysql);
+ void (*sqls_free_result)(MYSQL_RES *result);
+ unsigned long (*sqls_num_rows)(MYSQL_RES *res);
+ unsigned int (*sqls_num_fields)(MYSQL_RES *res);
+ MYSQL_ROW (*sqls_fetch_row)(MYSQL_RES *result);
+ unsigned long * (*sqls_fetch_lengths)(MYSQL_RES *result);
+} *sql_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define sqls_init sql_service->sqls_init
+#define sqls_close sql_service->sqls_close
+#define sqls_real_query sql_service->sqls_real_query
+#define sqls_affected_rows sql_service->sqls_affected_rows
+#define sqls_warning_count sql_service->sqls_warning_count
+#define sqls_errno sql_service->sqls_errno
+#define sqls_sqlstate sql_service->sqls_sqlstate
+#define sqls_error sql_service->sqls_error
+#define sqls_store_result sql_service->sqls_store_result
+#define sqls_free_result sql_service->sqls_free_result
+#define sqls_num_rows sql_service->sqls_num_rows
+#define sqls_num_fields sql_service->sqls_num_fields
+#define sqls_fetch_field sql_service->sqls_fetch_field
+#define sqls_field_seek sql_service->sqls_field_seek
+#define sqls_fetch_row sql_service->sqls_fetch_row
+#define sqls_fetch_lengths sql_service->sqls_fetch_lengths
+
+#else
+
+MYSQL *sqls_init(MYSQL *mysql);
+void sqls_close(MYSQL *mysql);
+int sqls_real_query(MYSQL *mysql, const char *q,
+ unsigned long length);
+
+unsigned long sqls_affected_rows(MYSQL *mysql);
+#define sqls_errno mysql_errno
+#define sqls_error mysql_error
+#define sqls_store_result mysql_store_result
+#define sqls_free_result mysql_free_result
+unsigned long sqls_num_rows(MYSQL_RES *res);
+#define sqls_num_fields mysql_num_fields
+#define sqls_fetch_field mysql_fetch_field
+#define sqls_field_seek mysql_field_seek
+#define sqls_fetch_row mysql_fetch_row
+#define sqls_fetch_lengths mysql_fetch_lengths
+
+#endif /*MYSQL_DYNAMIC_PLUGIN*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//#undef MYSQL_SERVER
+
+#endif /*MYSQL_SERVICE_SQL */
+
+
diff --git a/include/mysql/services.h b/include/mysql/services.h
index 6dc970d..1ad5ae1 100644
--- a/include/mysql/services.h
+++ b/include/mysql/services.h
@@ -40,6 +40,7 @@ extern "C" {
#include <mysql/service_thd_timezone.h>
#include <mysql/service_thd_wait.h>
#include <mysql/service_json.h>
+#include <mysql/service_sql.h>
/*#include <mysql/service_wsrep.h>*/
#ifdef __cplusplus
diff --git a/include/service_versions.h b/include/service_versions.h
index 050012d..4cb4725 100644
--- a/include/service_versions.h
+++ b/include/service_versions.h
@@ -43,3 +43,4 @@
#define VERSION_thd_wait 0x0100
#define VERSION_wsrep 0x0202
#define VERSION_json 0x0100
+#define VERSION_sql 0x0100
diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt
index b99be71..0120648 100644
--- a/libservices/CMakeLists.txt
+++ b/libservices/CMakeLists.txt
@@ -38,6 +38,7 @@ SET(MYSQLSERVICES_SOURCES
thd_wait_service.c
wsrep_service.c
json_service.c
+ sql_service.c
)
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
diff --git a/libservices/sql_service.c b/libservices/sql_service.c
new file mode 100644
index 0000000..39a9d0a
--- /dev/null
+++ b/libservices/sql_service.c
@@ -0,0 +1,19 @@
+
+/* Copyright (c) 2019, Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <service_versions.h>
+SERVICE_VERSION sql_service= (void*)VERSION_sql;
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index c730490..fd0dba4 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -17,6 +17,7 @@
/* support for Services */
#include <service_versions.h>
#include <mysql/service_wsrep.h>
+#include <mysql.h>
struct st_service_ref {
const char *name;
@@ -217,7 +218,7 @@ static struct my_print_error_service_st my_print_error_handler=
my_printv_error
};
-struct json_service_st json_handler=
+static struct json_service_st json_handler=
{
json_type,
json_get_array_item,
@@ -227,6 +228,22 @@ struct json_service_st json_handler=
json_unescape_json
};
+static struct sql_service_st sql_handler=
+{
+ sqls_init,
+ sqls_close,
+ sqls_real_query,
+ sqls_affected_rows,
+ mysql_errno,
+ mysql_error,
+ mysql_store_result,
+ mysql_free_result,
+ sqls_num_rows,
+ mysql_num_fields,
+ mysql_fetch_row,
+ mysql_fetch_lengths
+};
+
static struct st_service_ref list_of_services[]=
{
{ "base64_service", VERSION_base64, &base64_handler },
@@ -250,6 +267,7 @@ static struct st_service_ref list_of_services[]=
{ "thd_timezone_service", VERSION_thd_timezone, &thd_timezone_handler },
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "wsrep_service", VERSION_wsrep, &wsrep_handler },
- { "json_service", VERSION_json, &json_handler }
+ { "json_service", VERSION_json, &json_handler },
+ { "sql_service", VERSION_sql, &sql_handler }
};
1
0

19 Jan '19
revision-id: 83b46d0e18da954033cfe7ba807ef6a6a8bbf257 (mariadb-10.0.37-41-g83b46d0e18d)
parent(s): d0d0f88f2cd4da23c2c2da702da51fb533e7fb8a
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-01-19 20:12:00 +0530
message:
MDEV-18255: Server crashes in Bitmap<64u>::intersect
The server crashes here because we try to update condition comprising
of a non-merged semi-join which was cleaned up due to the IMPOSSIBLE WHERE
in the parent.
So the approach to fix this is for a certain select $X:
at the end of its JOIN::optimize() call
we call JOIN::optimize_unflattened_subqueries (this causes children of select $X be optimized)
then for the current select we update_used_tables() inside JOIN::optimize_unflattened_subqueries
Updated few test results
---
mysql-test/r/subselect.result | 6 +++---
mysql-test/r/subselect_mat.result | 18 +++++++++++++++++-
mysql-test/r/subselect_no_exists_to_in.result | 6 +++---
mysql-test/r/subselect_no_mat.result | 6 +++---
mysql-test/r/subselect_no_opts.result | 6 +++---
mysql-test/r/subselect_no_scache.result | 6 +++---
mysql-test/r/subselect_no_semijoin.result | 6 +++---
mysql-test/r/subselect_sj.result | 2 +-
mysql-test/r/subselect_sj_jcl6.result | 2 +-
mysql-test/r/subselect_sj_mat.result | 2 +-
mysql-test/t/subselect_mat.test | 13 +++++++++++++
sql/opt_subselect.cc | 6 +++++-
sql/sql_lex.cc | 1 -
13 files changed, 56 insertions(+), 24 deletions(-)
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index b074fb371a5..dbfc33639be 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -4584,7 +4584,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6656,7 +6656,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6664,7 +6664,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result
index aa0ac73abd2..cceda9f8599 100644
--- a/mysql-test/r/subselect_mat.result
+++ b/mysql-test/r/subselect_mat.result
@@ -1896,7 +1896,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = `<subquery2>`.`MAX(c)`) and (<cache>(isnull(/*always not null*/ 1)) or (`<subquery2>`.`MAX(c)` = 7)))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = `<subquery2>`.`MAX(c)`) and (0 or (`<subquery2>`.`MAX(c)` = 7)))
SELECT * FROM t1
WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b);
a b
@@ -2822,3 +2822,19 @@ id select_type table type possible_keys key key_len ref rows Extra
SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 );
f
DROP TABLE t1, t2;
+#
+# MDEV-18255: Server crashes in Bitmap<64u>::intersect
+#
+create table t1 (v1 varchar(1)) engine=myisam ;
+create table t2 (v1 varchar(1)) engine=myisam ;
+explain
+select 1 from t1 where exists
+(select 1 from t1 where t1.v1 in (select t2.v1 from t2 having t2.v1 < 'j')) ;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
+2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+select 1 from t1 where exists
+(select 1 from t1 where t1.v1 in (select t2.v1 from t2 having t2.v1 < 'j')) ;
+1
+drop table t1,t2;
diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result
index d5aa16a2ce9..664ffe015d1 100644
--- a/mysql-test/r/subselect_no_exists_to_in.result
+++ b/mysql-test/r/subselect_no_exists_to_in.result
@@ -4586,7 +4586,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6656,7 +6656,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6664,7 +6664,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result
index aff68bd6729..1ad808a7e8a 100644
--- a/mysql-test/r/subselect_no_mat.result
+++ b/mysql-test/r/subselect_no_mat.result
@@ -4584,7 +4584,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6651,7 +6651,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6659,7 +6659,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result
index f1181785a5c..d33d561bc3d 100644
--- a/mysql-test/r/subselect_no_opts.result
+++ b/mysql-test/r/subselect_no_opts.result
@@ -4580,7 +4580,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6647,7 +6647,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6655,7 +6655,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result
index 6cefce21c20..e2762cde548 100644
--- a/mysql-test/r/subselect_no_scache.result
+++ b/mysql-test/r/subselect_no_scache.result
@@ -4590,7 +4590,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6662,7 +6662,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6670,7 +6670,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result
index 884374a74b1..d812b84cbd9 100644
--- a/mysql-test/r/subselect_no_semijoin.result
+++ b/mysql-test/r/subselect_no_semijoin.result
@@ -4580,7 +4580,7 @@ SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
FROM t1
WHERE a = 230;
MAX(b) (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b)
-NULL NULL
+NULL 0
DROP TABLE t1, st1, st2;
#
# Bug #48709: Assertion failed in sql_select.cc:11782:
@@ -6647,7 +6647,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), (SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 NULL
+0 7
EXPLAIN
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
@@ -6655,7 +6655,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 SUBQUERY t1 ALL NULL NULL NULL NULL 2
SELECT COUNT(f1), exists(SELECT f1 FROM t1 WHERE f2 > 0 limit 1) AS f4 FROM t2, t1 WHERE 'v'= f3;
COUNT(f1) f4
-0 0
+0 1
EXPLAIN
SELECT COUNT(f1), f2 > ALL (SELECT f1 FROM t1 WHERE f2 > 0) AS f4 FROM t2, t1 WHERE 'v'= f3;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/subselect_sj.result b/mysql-test/r/subselect_sj.result
index fd9a66d8ef1..6f94b6236aa 100644
--- a/mysql-test/r/subselect_sj.result
+++ b/mysql-test/r/subselect_sj.result
@@ -3132,7 +3132,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00 Using where
2 SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
-Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t3`.`c3` = `test`.`t1`.`c1`) and <cache>(<in_optimizer>(1,<exists>(select `test`.`t4`.`c4` from `test`.`t4` where (1 = `test`.`t4`.`c4`)))))) where 1
+Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t3`.`c3` = `test`.`t1`.`c1`) and 0)) where 1
# mdev-12820
SELECT *
FROM t1
diff --git a/mysql-test/r/subselect_sj_jcl6.result b/mysql-test/r/subselect_sj_jcl6.result
index 71493df594f..e8a7b789bb8 100644
--- a/mysql-test/r/subselect_sj_jcl6.result
+++ b/mysql-test/r/subselect_sj_jcl6.result
@@ -3146,7 +3146,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 100.00 Using where; Using join buffer (incremental, BNL join)
2 SUBQUERY t4 ALL NULL NULL NULL NULL 2 100.00 Using where
Warnings:
-Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t3`.`c3` = `test`.`t1`.`c1`) and <cache>(<in_optimizer>(1,<exists>(select `test`.`t4`.`c4` from `test`.`t4` where (1 = `test`.`t4`.`c4`)))))) where 1
+Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` left join (`test`.`t2` join `test`.`t3`) on(((`test`.`t3`.`c3` = `test`.`t1`.`c1`) and 0)) where 1
# mdev-12820
SELECT *
FROM t1
diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result
index b48be32441a..2cb99ae450b 100644
--- a/mysql-test/r/subselect_sj_mat.result
+++ b/mysql-test/r/subselect_sj_mat.result
@@ -1934,7 +1934,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00
Warnings:
-Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = `<subquery2>`.`MAX(c)`) and (<cache>(isnull(/*always not null*/ 1)) or (`<subquery2>`.`MAX(c)` = 7)))
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from <materialize> (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = `<subquery2>`.`MAX(c)`) and (0 or (`<subquery2>`.`MAX(c)` = 7)))
SELECT * FROM t1
WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b);
a b
diff --git a/mysql-test/t/subselect_mat.test b/mysql-test/t/subselect_mat.test
index 5211f35b48b..66a6cc97acb 100644
--- a/mysql-test/t/subselect_mat.test
+++ b/mysql-test/t/subselect_mat.test
@@ -267,3 +267,16 @@ explain
SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 );
SELECT * FROM t2 WHERE f IN ( SELECT LEFT('foo',0) FROM t1 ORDER BY 1 );
DROP TABLE t1, t2;
+
+--echo #
+--echo # MDEV-18255: Server crashes in Bitmap<64u>::intersect
+--echo #
+create table t1 (v1 varchar(1)) engine=myisam ;
+create table t2 (v1 varchar(1)) engine=myisam ;
+
+explain
+select 1 from t1 where exists
+ (select 1 from t1 where t1.v1 in (select t2.v1 from t2 having t2.v1 < 'j')) ;
+select 1 from t1 where exists
+ (select 1 from t1 where t1.v1 in (select t2.v1 from t2 having t2.v1 < 'j')) ;
+drop table t1,t2;
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index f757823be7c..8a8e390ade3 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -5298,7 +5298,11 @@ static void remove_subq_pushed_predicates(JOIN *join, Item **where)
bool JOIN::optimize_unflattened_subqueries()
{
- return select_lex->optimize_unflattened_subqueries(false);
+ bool val= select_lex->optimize_unflattened_subqueries(false);
+ if (val)
+ return val;
+ select_lex->update_used_tables();
+ return false;
}
/**
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 08c169c5999..891cf9987c6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -3551,7 +3551,6 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
inner_join->select_options|= SELECT_DESCRIBE;
}
res= inner_join->optimize();
- sl->update_used_tables();
sl->update_correlated_cache();
is_correlated_unit|= sl->is_correlated;
inner_join->select_options= save_options;
1
0
revision-id: b14a70f4c8a6a3b0f26f622e0728eabaab95b957 (mariadb-10.3.6-330-gb14a70f4c8a)
parent(s): 140fcab9571dbd15652ed7c7b798818556e3805d
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-01-18 17:05:30 +0200
message:
Fixed compiler error on embedded server linking
---
sql/wsrep_dummy.cc | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 593cfeca8ef..916788483ab 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -85,3 +85,42 @@ my_bool wsrep_thd_is_aborting(const THD *)
void wsrep_set_data_home_dir(const char *)
{ }
+
+my_bool wsrep_thd_is_local(const THD *)
+{ return 0; }
+
+void wsrep_thd_self_abort(THD *)
+{ }
+
+int wsrep_thd_append_key(THD *, const struct wsrep_key*, int, enum Wsrep_service_key_type)
+{ return 0; }
+
+const char* wsrep_thd_client_state_str(const THD*)
+{ return 0; }
+
+const char* wsrep_thd_client_mode_str(const THD*)
+{ return 0; }
+
+const char* wsrep_thd_transaction_state_str(const THD*)
+{ return 0; }
+
+query_id_t wsrep_thd_transaction_id(const THD *)
+{ return 0; }
+
+my_bool wsrep_thd_bf_abort(const THD *, THD *, my_bool)
+{ return 0; }
+
+my_bool wsrep_thd_order_before(const THD*, const THD *)
+{ return 0; }
+
+void wsrep_handle_SR_rollback(THD*, THD*)
+{ }
+
+my_bool wsrep_thd_skip_locking(const THD*)
+{ return 0;}
+
+const char* wsrep_get_sr_table_name()
+{ return 0; }
+
+my_bool wsrep_get_debug()
+{ return 0;}
1
0

[Commits] 140fcab9571: Fixed compilation failure with dynamic InnoDB (-DPLUGIN_INNOBASE=DYNAMIC)
by jan 18 Jan '19
by jan 18 Jan '19
18 Jan '19
revision-id: 140fcab9571dbd15652ed7c7b798818556e3805d (mariadb-10.3.6-329-g140fcab9571)
parent(s): 06fd4e7ffbeacbcd951d07eab30d7cef709940c5
author: Jan Lindström
committer: Jan Lindström
timestamp: 2019-01-18 16:19:31 +0200
message:
Fixed compilation failure with dynamic InnoDB (-DPLUGIN_INNOBASE=DYNAMIC)
Fixed test failure on galera_var_slave_threads
---
include/mysql/service_wsrep.h | 60 ++-
.../suite/galera/r/galera_var_slave_threads.result | 402 +--------------------
.../suite/galera/t/galera_var_slave_threads.cnf | 7 +
.../suite/galera/t/galera_var_slave_threads.test | 10 +-
sql/service_wsrep.cc | 10 +
sql/sql_plugin_services.ic | 16 +-
storage/innobase/buf/buf0dump.cc | 2 +-
storage/innobase/handler/ha_innodb.cc | 14 +-
storage/innobase/row/row0ins.cc | 4 +-
storage/innobase/row/row0sel.cc | 2 +-
storage/innobase/row/row0upd.cc | 6 +-
storage/innobase/srv/srv0conc.cc | 6 +-
storage/innobase/srv/srv0start.cc | 2 +-
13 files changed, 108 insertions(+), 433 deletions(-)
diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h
index 4c485d92659..5aa97cdb47e 100644
--- a/include/mysql/service_wsrep.h
+++ b/include/mysql/service_wsrep.h
@@ -1,6 +1,14 @@
#ifndef MYSQL_SERVICE_WSREP_INCLUDED
#define MYSQL_SERVICE_WSREP_INCLUDED
+enum Wsrep_service_key_type
+{
+ WSREP_SERVICE_KEY_SHARED,
+ WSREP_SERVICE_KEY_REFERENCE,
+ WSREP_SERVICE_KEY_UPDATE,
+ WSREP_SERVICE_KEY_EXCLUSIVE
+};
+
#if (defined (MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED)) || (!defined(MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_STATIC_INCLUDED))
#else
@@ -36,6 +44,10 @@ struct xid_t;
struct wsrep_ws_handle;
struct wsrep_buf;
+/* Must match to definition in sql/mysqld.h */
+typedef int64 query_id_t;
+
+
extern struct wsrep_service_st {
my_bool (*get_wsrep_recovery_func)();
bool (*wsrep_consistency_check_func)(MYSQL_THD thd);
@@ -52,6 +64,23 @@ extern struct wsrep_service_st {
long long (*wsrep_thd_trx_seqno_func)(const MYSQL_THD thd);
my_bool (*wsrep_thd_is_aborting_func)(const MYSQL_THD thd);
void (*wsrep_set_data_home_dir_func)(const char *data_dir);
+ my_bool (*wsrep_thd_is_BF_func)(const MYSQL_THD thd, my_bool sync);
+ my_bool (*wsrep_thd_is_local_func)(const MYSQL_THD thd);
+ void (*wsrep_thd_self_abort_func)(MYSQL_THD thd);
+ int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key,
+ int n_keys, enum Wsrep_service_key_type);
+ const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd);
+ const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd);
+ const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd);
+ query_id_t (*wsrep_thd_transaction_id_func)(const MYSQL_THD thd);
+ my_bool (*wsrep_thd_bf_abort_func)(const MYSQL_THD bf_thd,
+ MYSQL_THD victim_thd,
+ my_bool signal);
+ my_bool (*wsrep_thd_order_before_func)(const MYSQL_THD left, const MYSQL_THD right);
+ void (*wsrep_handle_SR_rollback_func)(MYSQL_THD BF_thd, MYSQL_THD victim_thd);
+ my_bool (*wsrep_thd_skip_locking_func)(const MYSQL_THD thd);
+ const char* (*wsrep_get_sr_table_name_func)();
+ my_bool (*wsrep_get_debug_func)();
} *wsrep_service;
#define MYSQL_SERVICE_WSREP_INCLUDED
@@ -66,7 +95,7 @@ extern struct wsrep_service_st {
#define wsrep_xid_seqno(X) wsrep_service->wsrep_xid_seqno_func(X)
#define wsrep_xid_uuid(X) wsrep_service->wsrep_xid_uuid_func(X)
#define wsrep_on(X) wsrep_service->wsrep_on_func(X)
-#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F.G)
+#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
#define wsrep_thd_query(T) wsrep_service->wsrep_thd_query_func(T)
@@ -74,8 +103,21 @@ extern struct wsrep_service_st {
#define wsrep_thd_ignore_table(T) wsrep_service->wsrep_thd_ignore_table_func(T)
#define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T)
#define wsrep_set_data_home_dir(A) wsrep_service->wsrep_set_data_home_dir_func(A)
-
#define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S)
+#define wsrep_thd_is_aborting(T) wsrep_service->wsrep_thd_is_aborting_func(T)
+#define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T)
+#define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T)
+#define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K)
+#define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T)
+#define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T)
+#define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T)
+#define wsrep_thd_transaction_id(T) wsrep_service->wsrep_thd_transaction_id_func(T)
+#define wsrep_thd_bf_abort(T,T2,S) wsrep_service->wsrep_thd_bf_abort_func(T,T2,S)
+#define wsrep_thd_order_before(L,R) wsrep_service->wsrep_thd_order_before_func(L,R)
+#define wsrep_handle_SR_rollback(B,V) wsrep_service->wsrep_handle_SR_rollback_func(B,V)
+#define wsrep_thd_skip_locking(T) wsrep_service->wsrep_thd_skip_locking_func(T)
+#define wsrep_get_sr_table_name() wsrep_service->wsrep_get_sr_table_name_func()
+#define wsrep_get_debug() wsrep_service->wsrep_get_debug_func()
#else
@@ -99,12 +141,9 @@ my_bool get_wsrep_recovery();
bool wsrep_thd_ignore_table(MYSQL_THD thd);
void wsrep_set_data_home_dir(const char *data_dir);
-
/* from mysql wsrep-lib */
#include "my_global.h"
#include "my_pthread.h"
-/* Must match to definition in sql/mysqld.h */
-typedef int64 query_id_t;
/* Return true if wsrep is enabled for a thd. This means that
wsrep is enabled globally and the thd has wsrep on */
@@ -155,14 +194,6 @@ extern "C" my_bool wsrep_thd_skip_locking(const MYSQL_THD thd);
/* Return true if thd is aborting */
extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd);
-
-enum Wsrep_service_key_type
-{
- WSREP_SERVICE_KEY_SHARED,
- WSREP_SERVICE_KEY_REFERENCE,
- WSREP_SERVICE_KEY_UPDATE,
- WSREP_SERVICE_KEY_EXCLUSIVE
-};
struct wsrep_key;
struct wsrep_key_array;
extern "C" int wsrep_thd_append_key(MYSQL_THD thd,
@@ -172,5 +203,8 @@ extern "C" int wsrep_thd_append_key(MYSQL_THD thd,
extern const char* wsrep_sr_table_name_full;
+extern "C" const char* wsrep_get_sr_table_name();
+
+extern "C" my_bool wsrep_get_debug();
#endif
#endif /* MYSQL_SERVICE_WSREP_INCLUDED */
diff --git a/mysql-test/suite/galera/r/galera_var_slave_threads.result b/mysql-test/suite/galera/r/galera_var_slave_threads.result
index 108908551f6..168b45154b8 100644
--- a/mysql-test/suite/galera/r/galera_var_slave_threads.result
+++ b/mysql-test/suite/galera/r/galera_var_slave_threads.result
@@ -27,8 +27,8 @@ SET GLOBAL wsrep_slave_threads = 64;
connection node_1;
INSERT INTO t1 VALUES (1);
connection node_2;
-SELECT COUNT(*) = 1 FROM t1;
-COUNT(*) = 1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
1
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
COUNT(*)
@@ -65,401 +65,19 @@ connection node_2;
SET GLOBAL wsrep_slave_threads = 1;
connection node_1;
connection node_2;
-SELECT * FROM t1;
-f1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
1
-SELECT * FROM t2;
-f1
-3
-5
-7
-9
-11
-13
-15
-17
-19
-21
-23
-25
-27
-29
-31
-33
-35
-37
-39
-41
-43
-45
-47
-49
-51
-53
-55
-57
-59
-61
-63
-65
-67
-69
-71
-73
-75
-77
-79
-81
-83
-85
-87
-89
-91
-93
-95
-97
-99
-101
-103
-105
-107
-109
-111
-113
-115
-117
-119
-121
-123
-125
-127
-129
-132
-134
-136
-138
-140
-142
-144
-146
-148
-150
-152
-154
-156
-158
-160
-162
-164
-166
-168
-170
-172
-174
-176
-178
-180
-182
-184
-186
-188
-190
+SELECT COUNT(*) FROM t2;
+COUNT(*)
192
-194
-196
-198
-200
-202
-204
-206
-208
-210
-212
-214
-216
-218
-220
-222
-224
-226
-228
-230
-232
-234
-236
-238
-240
-242
-244
-246
-248
-250
-252
-254
-256
-258
-259
-261
-263
-265
-267
-269
-271
-273
-275
-277
-279
-281
-283
-285
-287
-289
-291
-293
-295
-297
-299
-301
-303
-305
-307
-309
-311
-313
-315
-317
-319
-321
-323
-325
-327
-329
-331
-333
-335
-337
-339
-341
-343
-345
-347
-349
-351
-353
-355
-357
-359
-361
-363
-365
-367
-369
-371
-373
-375
-377
-379
-381
-383
-385
connection node_1;
-SELECT * FROM t1;
-f1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
1
-SELECT * FROM t2;
-f1
-3
-5
-7
-9
-11
-13
-15
-17
-19
-21
-23
-25
-27
-29
-31
-33
-35
-37
-39
-41
-43
-45
-47
-49
-51
-53
-55
-57
-59
-61
-63
-65
-67
-69
-71
-73
-75
-77
-79
-81
-83
-85
-87
-89
-91
-93
-95
-97
-99
-101
-103
-105
-107
-109
-111
-113
-115
-117
-119
-121
-123
-125
-127
-129
-132
-134
-136
-138
-140
-142
-144
-146
-148
-150
-152
-154
-156
-158
-160
-162
-164
-166
-168
-170
-172
-174
-176
-178
-180
-182
-184
-186
-188
-190
+SELECT COUNT(*) FROM t2;
+COUNT(*)
192
-194
-196
-198
-200
-202
-204
-206
-208
-210
-212
-214
-216
-218
-220
-222
-224
-226
-228
-230
-232
-234
-236
-238
-240
-242
-244
-246
-248
-250
-252
-254
-256
-258
-259
-261
-263
-265
-267
-269
-271
-273
-275
-277
-279
-281
-283
-285
-287
-289
-291
-293
-295
-297
-299
-301
-303
-305
-307
-309
-311
-313
-315
-317
-319
-321
-323
-325
-327
-329
-331
-333
-335
-337
-339
-341
-343
-345
-347
-349
-351
-353
-355
-357
-359
-361
-363
-365
-367
-369
-371
-373
-375
-377
-379
-381
-383
-385
DROP TABLE t1;
DROP TABLE t2;
# End of tests
diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.cnf b/mysql-test/suite/galera/t/galera_var_slave_threads.cnf
new file mode 100644
index 00000000000..889c81b4a0a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_slave_threads.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+auto_increment_offset=1
+
+[mysqld.2]
+auto_increment_offset=2
diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.test b/mysql-test/suite/galera/t/galera_var_slave_threads.test
index d0784bfd871..12d8006db4b 100644
--- a/mysql-test/suite/galera/t/galera_var_slave_threads.test
+++ b/mysql-test/suite/galera/t/galera_var_slave_threads.test
@@ -39,7 +39,7 @@ SET GLOBAL wsrep_slave_threads = 64;
INSERT INTO t1 VALUES (1);
--connection node_2
-SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) FROM t1;
#
# note, in wsrep API #26, we have 2 rollbacker threads, counted as system user's
@@ -177,13 +177,13 @@ while ($count)
--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
--source include/wait_condition.inc
-SELECT * FROM t1;
-SELECT * FROM t2;
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
--connection node_1
-SELECT * FROM t1;
-SELECT * FROM t2;
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
DROP TABLE t1;
DROP TABLE t2;
diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc
index 3375073311f..f4cf49b9b84 100644
--- a/sql/service_wsrep.cc
+++ b/sql/service_wsrep.cc
@@ -80,6 +80,16 @@ extern "C" void wsrep_thd_self_abort(THD *thd)
thd->wsrep_cs().bf_abort(wsrep::seqno(0));
}
+extern "C" const char* wsrep_get_sr_table_name()
+{
+ return wsrep_sr_table_name_full;
+}
+
+extern "C" my_bool wsrep_get_debug()
+{
+ return wsrep_debug;
+}
+
extern "C" my_bool wsrep_thd_is_local(const THD *thd)
{
return thd->wsrep_cs().mode() == wsrep::client_state::m_local;
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index 0feecf219bd..8893ea361e3 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -156,7 +156,21 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_thd_ignore_table,
wsrep_thd_trx_seqno,
wsrep_thd_is_aborting,
- wsrep_set_data_home_dir
+ wsrep_set_data_home_dir,
+ wsrep_thd_is_BF,
+ wsrep_thd_is_local,
+ wsrep_thd_self_abort,
+ wsrep_thd_append_key,
+ wsrep_thd_client_state_str,
+ wsrep_thd_client_mode_str,
+ wsrep_thd_transaction_state_str,
+ wsrep_thd_transaction_id,
+ wsrep_thd_bf_abort,
+ wsrep_thd_order_before,
+ wsrep_handle_SR_rollback,
+ wsrep_thd_skip_locking,
+ wsrep_get_sr_table_name,
+ wsrep_get_debug
};
static struct thd_specifics_service_st thd_specifics_handler=
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index c745bc9f4c3..2747a6fa338 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -856,7 +856,7 @@ DECLARE_THREAD(buf_dump_thread)(void*)
"Dumping of buffer pool not started"
" as load was incomplete");
#ifdef WITH_WSREP
- } else if (wsrep_recovery) {
+ } else if (get_wsrep_recovery()) {
#endif /* WITH_WSREP */
} else {
buf_dump(FALSE/* do complete dump at shutdown */);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index e194c47a518..9511051fbe2 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -131,6 +131,9 @@ void close_thread_tables(THD* thd);
#define tdc_size 400
#endif
+#include <mysql/plugin.h>
+#include <mysql/service_wsrep.h>
+
#include "ha_innodb.h"
#include "i_s.h"
#include "sync0sync.h"
@@ -138,9 +141,6 @@ void close_thread_tables(THD* thd);
#include <string>
#include <sstream>
-#include <mysql/plugin.h>
-#include <mysql/service_wsrep.h>
-
#ifdef WITH_WSREP
#include "dict0priv.h"
#include <mysql/service_md5.h>
@@ -148,14 +148,6 @@ void close_thread_tables(THD* thd);
extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
-extern bool wsrep_prepare_key_for_innodb(
- THD* thd,
- const uchar *cache_key,
- size_t cache_key_len,
- const uchar* row_id,
- size_t row_id_len,
- wsrep_buf_t* key,
- size_t* key_len);
#endif /* WITH_WSREP */
/** to force correct commit order in binlog */
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 4acf244bf55..ed72f6d482b 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -3241,11 +3241,11 @@ row_ins_clust_index_entry(
: (index->table->is_temporary() || skip_locking)
? BTR_NO_LOCKING_FLAG : 0;
#ifdef UNIV_DEBUG
- if (skip_locking && strcmp(wsrep_sr_table_name_full,
+ if (skip_locking && strcmp(wsrep_get_sr_table_name(),
index->table->name.m_name)) {
WSREP_ERROR("Record locking is disabled in this thread, "
"but the table being modified is not "
- "`%s`: `%s`.", wsrep_sr_table_name_full,
+ "`%s`: `%s`.", wsrep_get_sr_table_name(),
index->table->name.m_name);
ut_error;
}
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index aeaa98b5676..2657839c93e 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -4468,7 +4468,7 @@ row_search_mvcc(
}
#ifdef WITH_WSREP
else if (wsrep_thd_skip_locking(trx->mysql_thd)) {
- ut_ad(!strcmp(wsrep_sr_table_name_full,
+ ut_ad(!strcmp(wsrep_get_sr_table_name(),
prebuilt->table->name.m_name));
set_also_gap_locks = FALSE;
}
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 591ae238c43..a60210c77c8 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -2458,7 +2458,7 @@ row_upd_sec_index_entry(
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
@@ -2773,7 +2773,7 @@ row_upd_clust_rec_by_insert(
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
@@ -3002,7 +3002,7 @@ row_upd_del_mark_clust_rec(
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc
index ec1e151c03b..b2b464e31fa 100644
--- a/storage/innobase/srv/srv0conc.cc
+++ b/storage/innobase/srv/srv0conc.cc
@@ -120,7 +120,7 @@ srv_conc_enter_innodb_with_atomics(
#ifdef WITH_WSREP
if (wsrep_on(trx->mysql_thd) &&
wsrep_thd_is_aborting(trx->mysql_thd)) {
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::info() <<
"srv_conc_enter due to MUST_ABORT";
}
@@ -308,14 +308,14 @@ wsrep_srv_conc_cancel_wait(
srv_conc_enter_innodb_with_atomics(). No need to cancel here,
thr will wake up after os_sleep and let to enter innodb
*/
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::info() << "WSREP: conc slot cancel, no atomics";
}
#else
// JAN: TODO: MySQL 5.7
//os_fast_mutex_lock(&srv_conc_mutex);
if (trx->wsrep_event) {
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::info() << "WSREP: conc slot cancel";
}
os_event_set(trx->wsrep_event);
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 54b0e75fd80..e15afcf9cd7 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2328,7 +2328,7 @@ dberr_t srv_start(bool create_new_db)
Create the dump/load thread only when not running with
--wsrep-recover.
*/
- if (!wsrep_recovery) {
+ if (!get_wsrep_recovery()) {
#endif /* WITH_WSREP */
/* Create the buffer pool dump/load thread */
1
0
revision-id: 79b48d9a6656b5cf7aa43742e28aa53e6c110604 (mariadb-10.1.37-65-g79b48d9a665)
parent(s): 71463b21321ea3532d6e78f811b191eee61e7841
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2019-01-18 14:30:15 +0100
message:
c
---
sql/sql_view.cc | 31 ++++++++++++-------------------
sql/sql_view.h | 2 +-
sql/table.cc | 21 ++++++++++++++-------
sql/table.h | 26 ++++++++++++++++++++++++++
4 files changed, 53 insertions(+), 27 deletions(-)
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index ee169de4c93..45f5426b117 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1135,7 +1135,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
DBUG_RETURN(error);
}
-#define MD5_LEN 32
/**
Check is TABLE_LEST and SHARE match
@param[in] view TABLE_LIST of the view
@@ -1144,28 +1143,22 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
@return false on error or misspatch
*/
-bool mariadb_view_version_check(TABLE_LIST *view, TABLE_SHARE *share)
+bool mariadb_view_version_get(TABLE_SHARE *share)
{
- LEX_STRING md5;
- char md5_buffer[MD5_LEN + 1];
- md5.str= md5_buffer;
- md5.length= MD5_LEN;
+ DBUG_ASSERT(share->is_view);
- /*
- Check that both were views (view->is_view() could not be checked
- because it is not opened).
- */
- if (!share->is_view || view->md5.length != MD5_LEN)
- return FALSE;
+ if (!(share->tabledef_version.str=
+ (uchar*) alloc_root(&share->mem_root, VIEW_MD5_LEN + 1)))
+ return TRUE;
+ share->tabledef_version.length= VIEW_MD5_LEN;
DBUG_ASSERT(share->view_def != NULL);
- if (share->view_def->parse((uchar*)&md5, NULL,
- view_md5_parameters,
- 1,
- &file_parser_dummy_hook))
- return FALSE;
- DBUG_ASSERT(md5.length == MD5_LEN);
- return (strncmp(md5.str, view->md5.str, MD5_LEN) == 0);
+ if (share->view_def->parse((uchar *) &share->tabledef_version, NULL,
+ view_md5_parameters, 1,
+ &file_parser_dummy_hook))
+ return TRUE;
+ DBUG_ASSERT(share->tabledef_version.length == VIEW_MD5_LEN);
+ return FALSE;
}
/**
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 1685169420d..67187a0624a 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -37,7 +37,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *view,
bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
bool open_view_no_parse);
-bool mariadb_view_version_check(TABLE_LIST *view, TABLE_SHARE *share);
+bool mariadb_view_version_get(TABLE_SHARE *share);
bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
diff --git a/sql/table.cc b/sql/table.cc
index 60f263ee841..7d1d5d3a85a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -609,7 +609,11 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
if (!share->view_def)
share->error= OPEN_FRM_ERROR_ALREADY_ISSUED;
else
+ {
share->error= OPEN_FRM_OK;
+ if (mariadb_view_version_get(share))
+ share->error= OPEN_FRM_CORRUPTED;
+ }
}
else
share->error= OPEN_FRM_NOT_A_TABLE;
@@ -7504,19 +7508,22 @@ bool TABLE_LIST::is_table_ref_id_equal(TABLE_SHARE *s)
bool res= m_table_ref_version == s->get_table_ref_version();
/*
- If definition is different object with view we can check MD5 in frm
- to check if the same view got into table definition cache again.
+ If definition is different check content version
*/
- if (!res &&
- tp == TABLE_REF_VIEW &&
- mariadb_view_version_check(this, s))
+ if (tabledef_version.length &&
+ tabledef_version.length == s->tabledef_version.length &&
+ memcmp(tabledef_version.str, s->tabledef_version.str,
+ tabledef_version.length) == 0)
{
- // to avoid relatively expensive parsing of frm next time
- set_table_ref_id(s);
+ set_table_id(s);
return TRUE;
}
+ else
+ tabledef_version.length= 0;
return res;
}
+ else
+ set_tabledef_version(s);
return FALSE;
}
diff --git a/sql/table.h b/sql/table.h
index 9e1a061e606..c9dd8d0146c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -61,6 +61,8 @@ class TDC_element;
*/
typedef ulonglong nested_join_map;
+#define VIEW_MD5_LEN 32
+
#define tmp_file_prefix "#sql" /**< Prefix for tmp tables */
#define tmp_file_prefix_length 4
@@ -1998,6 +2000,10 @@ struct TABLE_LIST
to view with SQL SECURITY DEFINER)
*/
Security_context *security_ctx;
+ uchar tabledef_version_buf[MY_UUID_SIZE > VIEW_MD5_LEN ?
+ MY_UUID_SIZE + 1 : VIEW_MD5_LEN + 1];
+ LEX_CUSTRING tabledef_version;
+
/*
This view security context (non-zero only for views with
SQL SECURITY DEFINER)
@@ -2290,6 +2296,26 @@ struct TABLE_LIST
m_table_ref_version= table_ref_version_arg;
}
+ void set_table_id(TABLE_SHARE *s)
+ {
+ set_table_ref_id(s);
+ set_tabledef_version(s);
+ }
+
+ void set_tabledef_version(TABLE_SHARE *s)
+ {
+ if (!tabledef_version.length && s->tabledef_version.length)
+ {
+ DBUG_ASSERT(s->tabledef_version.length <
+ sizeof(tabledef_version_buf));
+ tabledef_version.str= tabledef_version_buf;
+ memcpy(tabledef_version_buf, s->tabledef_version.str,
+ (tabledef_version.length= s->tabledef_version.length));
+ // safety
+ tabledef_version_buf[tabledef_version.length]= 0;
+ }
+ }
+
/* Set of functions returning/setting state of a derived table/view. */
inline bool is_non_derived()
{
1
0
revision-id: cc18a5db9bce667c9b8722cdf6f51ee83b55a4b0 (mariadb-10.4.1-98-gcc18a5d)
parent(s): dd03cb3776e6d25dc1dd2c3a83473a1b78ae99f9
committer: Alexey Botchkov
timestamp: 2019-01-18 03:18:02 +0400
message:
MDEV-5313 Improving audit API.
json_locate_key() implemented.
get rid of 'key_len' argument in functions.
---
include/json_lib.h | 5 ++
include/mysql/plugin_audit.h.pp | 4 +-
include/mysql/plugin_auth.h.pp | 4 +-
include/mysql/plugin_encryption.h.pp | 4 +-
include/mysql/plugin_ftparser.h.pp | 4 +-
include/mysql/plugin_password_validation.h.pp | 4 +-
include/mysql/service_json.h | 4 +-
sql/sql_acl.cc | 100 +++++++++++++-------------
strings/json_lib.c | 94 +++++++++++++++++++++++-
unittest/strings/json-t.c | 28 +++++++-
10 files changed, 185 insertions(+), 66 deletions(-)
diff --git a/include/json_lib.h b/include/json_lib.h
index a347538..b6add6d 100644
--- a/include/json_lib.h
+++ b/include/json_lib.h
@@ -425,6 +425,11 @@ int json_path_compare(const json_path_t *a, const json_path_t *b,
int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs);
+int json_locate_key(const char *js, const char *js_end,
+ const char *kname,
+ const char **key_start, const char **key_end,
+ int *comma_pos);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp
index 47f07ae..c5ae678 100644
--- a/include/mysql/plugin_audit.h.pp
+++ b/include/mysql/plugin_audit.h.pp
@@ -393,7 +393,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp
index f9d01a8..41cb7d07 100644
--- a/include/mysql/plugin_auth.h.pp
+++ b/include/mysql/plugin_auth.h.pp
@@ -393,7 +393,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp
index e55a034..6597dec 100644
--- a/include/mysql/plugin_encryption.h.pp
+++ b/include/mysql/plugin_encryption.h.pp
@@ -393,7 +393,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp
index f9d9844..bd1cfc7 100644
--- a/include/mysql/plugin_ftparser.h.pp
+++ b/include/mysql/plugin_ftparser.h.pp
@@ -393,7 +393,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp
index b672db6..2f9d229 100644
--- a/include/mysql/plugin_password_validation.h.pp
+++ b/include/mysql/plugin_password_validation.h.pp
@@ -393,7 +393,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -410,7 +410,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/include/mysql/service_json.h b/include/mysql/service_json.h
index 734787a..141b762 100644
--- a/include/mysql/service_json.h
+++ b/include/mysql/service_json.h
@@ -66,7 +66,7 @@ extern struct json_service_st {
int n_item,
const char **value, int *value_len);
enum json_types (*json_get_object_key)(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types (*json_get_object_nkey)(const char *js,const char *js_end,
int nkey,
@@ -95,7 +95,7 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
int n_item,
const char **value, int *value_len);
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len);
enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey,
const char **keyname, const char **keyname_end,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 61d6812..bb5a397 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1204,16 +1204,16 @@ class User_table_json: public User_table
int get_auth(THD *thd, MEM_ROOT *root, const char **plugin, const char **authstr) const
{
- *plugin= get_str_value(root, STRING_WITH_LEN("plugin"));
+ *plugin= get_str_value(root, "plugin");
if (!**plugin)
*plugin= native_password_plugin_name.str;
- *authstr= get_str_value(root, STRING_WITH_LEN("authentication_string"));
+ *authstr= get_str_value(root, "authentication_string");
return *plugin == NULL || *authstr == NULL;
}
void set_auth(const char *p, size_t pl, const char *as, size_t asl) const
{
- set_str_value(STRING_WITH_LEN("plugin"), p, pl);
- set_str_value(STRING_WITH_LEN("authentication_string"), as, asl);
+ set_str_value("plugin", p, pl);
+ set_str_value("authentication_string", as, asl);
}
ulong get_access() const
{
@@ -1222,7 +1222,7 @@ class User_table_json: public User_table
(or, for example, my_count_bits(GLOBAL_ACLS))
in the json too, and it'll allow us to do privilege upgrades
*/
- return get_int_value(STRING_WITH_LEN("access")) & GLOBAL_ACLS;
+ return get_int_value("access") & GLOBAL_ACLS;
}
void set_access(ulong rights, bool revoke) const
{
@@ -1231,53 +1231,53 @@ class User_table_json: public User_table
access&= ~rights;
else
access|= rights;
- set_int_value(STRING_WITH_LEN("access"), access & GLOBAL_ACLS);
+ set_int_value("access", access & GLOBAL_ACLS);
}
SSL_type get_ssl_type () const
- { return (SSL_type)get_int_value(STRING_WITH_LEN("ssl_type")); }
+ { return (SSL_type)get_int_value("ssl_type"); }
int set_ssl_type (SSL_type x) const
- { return set_int_value(STRING_WITH_LEN("ssl_type"), x); }
+ { return set_int_value("ssl_type", x); }
const char* get_ssl_cipher (MEM_ROOT *root) const
- { return get_str_value(root, STRING_WITH_LEN("ssl_cipher")); }
+ { return get_str_value(root, "ssl_cipher"); }
int set_ssl_cipher (const char *s, size_t l) const
- { return set_str_value(STRING_WITH_LEN("ssl_cipher"), s, l); }
+ { return set_str_value("ssl_cipher", s, l); }
const char* get_x509_issuer (MEM_ROOT *root) const
- { return get_str_value(root, STRING_WITH_LEN("x509_issuer")); }
+ { return get_str_value(root, "x509_issuer"); }
int set_x509_issuer (const char *s, size_t l) const
- { return set_str_value(STRING_WITH_LEN("x509_issuer"), s, l); }
+ { return set_str_value("x509_issuer", s, l); }
const char* get_x509_subject (MEM_ROOT *root) const
- { return get_str_value(root, STRING_WITH_LEN("x509_subject")); }
+ { return get_str_value(root, "x509_subject"); }
int set_x509_subject (const char *s, size_t l) const
- { return set_str_value(STRING_WITH_LEN("x509_subject"), s, l); }
+ { return set_str_value("x509_subject", s, l); }
longlong get_max_questions () const
- { return get_int_value(STRING_WITH_LEN("max_questions")); }
+ { return get_int_value("max_questions"); }
int set_max_questions (longlong x) const
- { return set_int_value(STRING_WITH_LEN("max_questions"), x); }
+ { return set_int_value("max_questions", x); }
longlong get_max_updates () const
- { return get_int_value(STRING_WITH_LEN("max_updates")); }
+ { return get_int_value("max_updates"); }
int set_max_updates (longlong x) const
- { return set_int_value(STRING_WITH_LEN("max_updates"), x); }
+ { return set_int_value("max_updates", x); }
longlong get_max_connections () const
- { return get_int_value(STRING_WITH_LEN("max_connections")); }
+ { return get_int_value("max_connections"); }
int set_max_connections (longlong x) const
- { return set_int_value(STRING_WITH_LEN("max_connections"), x); }
+ { return set_int_value("max_connections", x); }
longlong get_max_user_connections () const
- { return get_int_value(STRING_WITH_LEN("max_user_connections")); }
+ { return get_int_value("max_user_connections"); }
int set_max_user_connections (longlong x) const
- { return set_int_value(STRING_WITH_LEN("max_user_connections"), x); }
+ { return set_int_value("max_user_connections", x); }
double get_max_statement_time () const
- { return get_double_value(STRING_WITH_LEN("max_statement_time")); }
+ { return get_double_value("max_statement_time"); }
int set_max_statement_time (double x) const
- { return set_double_value(STRING_WITH_LEN("max_statement_time"), x); }
+ { return set_double_value("max_statement_time", x); }
bool get_is_role () const
- { return get_bool_value(STRING_WITH_LEN("is_role")); }
+ { return get_bool_value("is_role"); }
int set_is_role (bool x) const
- { return set_bool_value(STRING_WITH_LEN("is_role"), x); }
+ { return set_bool_value("is_role", x); }
const char* get_default_role (MEM_ROOT *root) const
- { return get_str_value(root, STRING_WITH_LEN("default_role")); }
+ { return get_str_value(root, "default_role"); }
int set_default_role (const char *s, size_t l) const
- { return set_str_value(STRING_WITH_LEN("default_role"), s, l); }
+ { return set_str_value("default_role", s, l); }
~User_table_json() {}
private:
@@ -1290,24 +1290,24 @@ class User_table_json: public User_table
USERNAME_CHAR_LENGTH);
return 0;
}
- bool get_value(const char *key, size_t klen,
+ bool get_value(const char *key,
enum json_types vt, const char **v, size_t *vl) const
{
enum json_types value_type;
int int_vl;
String str, *res= m_table->field[2]->val_str(&str);
if (!res ||
- (value_type= json_get_object_key(res->ptr(), res->end(),
- key, key+klen, v, &int_vl)) == JSV_BAD_JSON)
+ (value_type= json_get_object_key(res->ptr(), res->end(), key,
+ v, &int_vl)) == JSV_BAD_JSON)
return 1; // invalid
*vl= int_vl;
return value_type != vt;
}
- const char *get_str_value(MEM_ROOT *root, const char *key, size_t klen) const
+ const char *get_str_value(MEM_ROOT *root, const char *key) const
{
size_t value_len;
const char *value_start;
- if (get_value(key, klen, JSV_STRING, &value_start, &value_len))
+ if (get_value(key, JSV_STRING, &value_start, &value_len))
return "";
char *ptr= (char*)alloca(value_len);
int len= json_unescape(m_table->field[2]->charset(),
@@ -1319,35 +1319,35 @@ class User_table_json: public User_table
return NULL;
return strmake_root(root, ptr, len);
}
- longlong get_int_value(const char *key, size_t klen) const
+ longlong get_int_value(const char *key) const
{
int err;
size_t value_len;
const char *value_start;
- if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len))
+ if (get_value(key, JSV_NUMBER, &value_start, &value_len))
return 0;
const char *value_end= value_start + value_len;
return my_strtoll10(value_start, (char**)&value_end, &err);
}
- double get_double_value(const char *key, size_t klen) const
+ double get_double_value(const char *key) const
{
int err;
size_t value_len;
const char *value_start;
- if (get_value(key, klen, JSV_NUMBER, &value_start, &value_len))
+ if (get_value(key, JSV_NUMBER, &value_start, &value_len))
return 0;
const char *value_end= value_start + value_len;
return my_strtod(value_start, (char**)&value_end, &err);
}
- bool get_bool_value(const char *key, size_t klen) const
+ bool get_bool_value(const char *key) const
{
size_t value_len;
const char *value_start;
- if (get_value(key, klen, JSV_TRUE, &value_start, &value_len))
+ if (get_value(key, JSV_TRUE, &value_start, &value_len))
return false;
return true;
}
- bool set_value(const char *key, size_t klen,
+ bool set_value(const char *key,
const char *val, size_t vlen, bool string) const
{
int value_len;
@@ -1356,7 +1356,7 @@ class User_table_json: public User_table
String str, *res= m_table->field[2]->val_str(&str);
if (!res || !res->length())
(res= &str)->set(STRING_WITH_LEN("{}"), m_table->field[2]->charset());
- value_type= json_get_object_key(res->ptr(), res->end(), key, key+klen,
+ value_type= json_get_object_key(res->ptr(), res->end(), key,
&value_start, &value_len);
if (value_type == JSV_BAD_JSON)
return 1; // invalid
@@ -1367,7 +1367,7 @@ class User_table_json: public User_table
if (value_len)
json.append(',');
json.append('"');
- json.append(key, klen);
+ json.append(STRING_WITH_LEN(key));
json.append(STRING_WITH_LEN("\":"));
if (string)
json.append('"');
@@ -1382,7 +1382,7 @@ class User_table_json: public User_table
m_table->field[2]->store(json.ptr(), json.length(), json.charset());
return 0;
}
- bool set_str_value(const char *key, size_t klen, const char *val, size_t vlen) const
+ bool set_str_value(const char *key, const char *val, size_t vlen) const
{
char buf[JSON_SIZE];
int blen= json_escape(system_charset_info,
@@ -1391,22 +1391,22 @@ class User_table_json: public User_table
(uchar*)buf, (uchar*)buf+sizeof(buf));
if (blen < 0)
return 1;
- return set_value(key, klen, buf, blen, true);
+ return set_value(key, buf, blen, true);
}
- bool set_int_value(const char *key, size_t klen, longlong val) const
+ bool set_int_value(const char *key, longlong val) const
{
char v[MY_INT64_NUM_DECIMAL_DIGITS+1];
size_t vlen= longlong10_to_str(val, v, -10) - v;
- return set_value(key, klen, v, vlen, false);
+ return set_value(key, v, vlen, false);
}
- bool set_double_value(const char *key, size_t klen, double val) const
+ bool set_double_value(const char *key, double val) const
{
char v[FLOATING_POINT_BUFFER+1];
size_t vlen= my_fcvt(val, TIME_SECOND_PART_DIGITS, v, NULL);
- return set_value(key, klen, v, vlen, false);
+ return set_value(key, v, vlen, false);
}
- bool set_bool_value(const char *key, size_t klen, bool val) const
- { return set_value(key, klen, val ? "true" : "false", val ? 4 : 5, false); }
+ bool set_bool_value(const char *key, bool val) const
+ { return set_value(key, val ? "true" : "false", val ? 4 : 5, false); }
};
class Db_table: public Grant_table_base
diff --git a/strings/json_lib.c b/strings/json_lib.c
index e28ec3c..6c94ce2 100644
--- a/strings/json_lib.c
+++ b/strings/json_lib.c
@@ -1943,9 +1943,10 @@ enum json_types json_get_array_item(const char *js, const char *js_end,
@retval JSV_NOTHING - no such key found.
*/
enum json_types json_get_object_key(const char *js, const char *js_end,
- const char *key, const char *key_end,
+ const char *key,
const char **value, int *value_len)
{
+ const char *key_end= key + strlen(key);
json_engine_t je;
json_string_t key_name;
int n_keys= 0;
@@ -1999,10 +2000,99 @@ enum json_types json_get_object_nkey(const char *js,const char *js_end, int nkey
@retval 0 - success, json is well-formed
@retval 1 - error, json is invalid
-*/int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs)
+*/
+int json_valid(const char *js, size_t js_len, CHARSET_INFO *cs)
{
json_engine_t je;
json_scan_start(&je, cs, (const uchar *) js, (const uchar *) js + js_len);
while (json_scan_next(&je) == 0) /* no-op */ ;
return je.s.error == 0;
}
+
+
+/*
+ Expects the JSON object as an js argument, and the key name.
+ Looks for this key in the object and returns
+ the location of all the text related to it.
+ The text includes the comma, separating this key.
+
+ comma_pos - the hint where the comma is. It is important
+ if you plan to replace the key rather than just cut.
+ 1 - comma is on the left
+ 2 - comma is on the right.
+ 0 - no comma at all (the object has just this single key)
+
+ if no such key found *key_start is set to NULL.
+*/
+int json_locate_key(const char *js, const char *js_end,
+ const char *kname,
+ const char **key_start, const char **key_end,
+ int *comma_pos)
+{
+ const char *kname_end= kname + strlen(kname);
+ json_engine_t je;
+ json_string_t key_name;
+ int t_next, c_len, match_result;
+
+ json_string_set_cs(&key_name, &my_charset_utf8mb4_bin);
+
+ json_scan_start(&je, &my_charset_utf8mb4_bin,(const uchar *) js,
+ (const uchar *) js_end);
+
+ if (json_read_value(&je) ||
+ je.value_type != JSON_VALUE_OBJECT)
+ goto err_return;
+
+ *key_start= (const char *) je.s.c_str;
+ *comma_pos= 0;
+
+ while (!json_scan_next(&je))
+ {
+ switch (je.state)
+ {
+ case JST_KEY:
+ json_string_set_str(&key_name, (const uchar *) kname,
+ (const uchar *) kname_end);
+ match_result= json_key_matches(&je, &key_name);
+ if (json_skip_key(&je))
+ goto err_return;
+ get_first_nonspace(&je.s, &t_next, &c_len);
+ je.s.c_str-= c_len;
+
+ if (match_result)
+ {
+ *key_end= (const char *) je.s.c_str;
+
+ if (*comma_pos == 1)
+ return 0;
+
+ DBUG_ASSERT(*comma_pos == 0);
+
+ if (t_next == C_COMMA)
+ {
+ *key_end+= c_len;
+ *comma_pos= 2;
+ }
+ else if (t_next == C_RCURB)
+ *comma_pos= 0;
+ else
+ goto err_return;
+ return 0;
+ }
+
+ *key_start= (const char *) je.s.c_str;
+ *comma_pos= 1;
+ break;
+
+ case JST_OBJ_END:
+ *key_start= NULL;
+ return 0;
+ }
+ }
+
+err_return:
+ return 1;
+
+}
+
+
diff --git a/unittest/strings/json-t.c b/unittest/strings/json-t.c
index 8af8636..ce0f04d 100644
--- a/unittest/strings/json-t.c
+++ b/unittest/strings/json-t.c
@@ -17,21 +17,29 @@
#include <my_sys.h>
#include <json_lib.h>
+int json_locate_key(const char *js, const char *js_end, const char *kname,
+ const char **key_start, const char **key_end,
+ int *comma_pos);
int main()
{
const char *json="{\"int\":1, \"str\":\"foo bar\", "
"\"array\":[10,20,{\"c\":\"d\"}],\"bool\":false}";
const char *json_ar="[1, \"foo bar\", " "[10,20,{\"c\":\"d\"}], false]";
+ const char *json_w="{\"int\" : 1 , \"str\" : \"foo bar\" , "
+ "\"array\" : [10,20,{\"c\":\"d\"}] , \"bool\" : false }";
+ const char *json_1="{ \"str\" : \"foo bar\" }";
enum json_types value_type;
const char *value_start;
int value_len;
+ const char *key_start, *key_end;
+ int result, comma_pos;
- plan(10);
+ plan(15);
#define do_json(V) \
do { \
value_type= json_get_object_key(json, json+strlen(json), \
- V, V + (sizeof(V) - 1),&value_start, &value_len); \
+ V, &value_start, &value_len); \
ok(value_type != JSV_BAD_JSON, V); \
diag("type=%d, value=\"%.*s\"", value_type, (int)value_len, value_start); \
} while(0)
@@ -42,6 +50,16 @@ int main()
ok(value_type != JSV_BAD_JSON, #N); \
diag("type=%d, value=\"%.*s\"", value_type, (int)value_len, value_start); \
} while(0)
+#define do_json_locate(J, V) \
+ do { \
+ result= json_locate_key(J, J+strlen(J), \
+ V, &key_start, &key_end, &comma_pos); \
+ ok(result == 0, V); \
+ if (key_start) \
+ diag("key_str=\"%.*s\" comma_pos= %d", (int)(key_end - key_start), key_start, comma_pos); \
+ else \
+ diag("no key found"); \
+ } while(0)
do_json("int");
do_json("str");
@@ -54,5 +72,11 @@ int main()
do_json_ar(2);
do_json_ar(3);
do_json_ar(4);
+
+ do_json_locate(json_w, "bool");
+ do_json_locate(json_w, "int");
+ do_json_locate(json_w, "array");
+ do_json_locate(json_1, "str");
+ do_json_locate(json_w, "c");
return exit_status();
}
1
0