diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-09-13 12:12:05 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-09-13 12:12:05 +0400 |
commit | 178540b904f3eca70488a3d1a0a55f5676087c04 (patch) | |
tree | c6b011a292ea8a3510dae01aa3ea43e87cf3662f | |
parent | 3a9ee22ba924160cbc5a4dd3fd047d62f11dabd2 (diff) | |
parent | a237a920991f417e9a4567957f4fc7aa5b538270 (diff) | |
download | mariadb-git-178540b904f3eca70488a3d1a0a55f5676087c04.tar.gz |
Merge remote-tracking branch 'origin/10.2' into bb-10.2-ext
25 files changed, 354 insertions, 58 deletions
diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index edd369e6ea9..60985dbb519 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -117,6 +117,7 @@ xb_mysql_connect() mysql_options(connection, MYSQL_PLUGIN_DIR, xb_plugin_dir); } mysql_options(connection, MYSQL_OPT_PROTOCOL, &opt_protocol); + mysql_options(connection,MYSQL_SET_CHARSET_NAME, "utf8"); msg_ts("Connecting to MySQL server host: %s, user: %s, password: %s, " "port: %s, socket: %s\n", opt_host ? opt_host : "localhost", @@ -1629,3 +1630,96 @@ backup_cleanup() mysql_close(mysql_connection); } } + + +static pthread_mutex_t mdl_lock_con_mutex; +static MYSQL *mdl_con = NULL; + +void +mdl_lock_init() +{ + pthread_mutex_init(&mdl_lock_con_mutex, NULL); + mdl_con = xb_mysql_connect(); + if (mdl_con) + { + xb_mysql_query(mdl_con, "BEGIN", false, true); + } +} + +#ifndef DBUF_OFF +/* Test that table is really locked, if lock_ddl_per_table is set. + The test is executed in DBUG_EXECUTE_IF block inside mdl_lock_table(). +*/ +static void check_mdl_lock_works(const char *table_name) +{ + MYSQL *test_con= xb_mysql_connect(); + char *query; + xb_a(asprintf(&query, + "SET STATEMENT max_statement_time=1 FOR ALTER TABLE %s" + " ADD COLUMN mdl_lock_column int", table_name)); + int err = mysql_query(test_con, query); + DBUG_ASSERT(err); + int err_no = mysql_errno(test_con); + DBUG_ASSERT(err_no == ER_STATEMENT_TIMEOUT); + mysql_close(test_con); +} +#endif + +extern void +dict_fs2utf8(const char*, char*, size_t, char*, size_t); + +void +mdl_lock_table(ulint space_id) +{ + char *query; + + pthread_mutex_lock(&mdl_lock_con_mutex); + + xb_a(asprintf(&query, + "SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES " + "WHERE SPACE = %llu AND NAME LIKE '%%/%%'", (ulonglong)space_id)); + + xb_mysql_query(mdl_con, query, true, true); + + MYSQL_RES *mysql_result = xb_mysql_query(mdl_con, query, true); + + MYSQL_ROW row; + while ((row = mysql_fetch_row(mysql_result))) { + char full_table_name[2*FN_REFLEN +2]; + char db_utf8[FN_REFLEN]; + char table_utf8[FN_REFLEN]; + + dict_fs2utf8(row[0], db_utf8, sizeof(db_utf8),table_utf8,sizeof(table_utf8)); + snprintf(full_table_name,sizeof(full_table_name),"`%s`.`%s`",db_utf8,table_utf8); + + char *lock_query; + + msg_ts("Locking MDL for %s\n", full_table_name); + + xb_a(asprintf(&lock_query, + "SELECT * FROM %s LIMIT 0", + full_table_name)); + + xb_mysql_query(mdl_con, lock_query, false, false); + + free(lock_query); + + DBUG_EXECUTE_IF("check_mdl_lock_works", + check_mdl_lock_works(full_table_name);); + } + + mysql_free_result(mysql_result); + free(query); + pthread_mutex_unlock(&mdl_lock_con_mutex); +} + + +void +mdl_unlock_all() +{ + msg_ts("Unlocking MDL for all tables"); + xb_mysql_query(mdl_con, "COMMIT", false, true); + mysql_close(mdl_con); + pthread_mutex_destroy(&mdl_lock_con_mutex); +} + diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 65aa913cc29..0027de960c1 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -296,6 +296,8 @@ my_bool opt_noversioncheck = FALSE; my_bool opt_no_backup_locks = FALSE; my_bool opt_decompress = FALSE; +my_bool opt_lock_ddl_per_table = FALSE; + static const char *binlog_info_values[] = {"off", "lockless", "on", "auto", NullS}; static TYPELIB binlog_info_typelib = {array_elements(binlog_info_values)-1, "", @@ -537,7 +539,8 @@ enum options_xtrabackup OPT_XTRA_TABLES_EXCLUDE, OPT_XTRA_DATABASES_EXCLUDE, - OPT_PROTOCOL + OPT_PROTOCOL, + OPT_LOCK_DDL_PER_TABLE }; struct my_option xb_client_options[] = @@ -1072,6 +1075,11 @@ struct my_option xb_server_options[] = (G_PTR*) &xb_open_files_limit, (G_PTR*) &xb_open_files_limit, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0}, + {"lock-ddl-per-table", OPT_LOCK_DDL_PER_TABLE, "Lock DDL for each table " + "before xtrabackup starts to copy it and until the backup is completed.", + (uchar*) &opt_lock_ddl_per_table, (uchar*) &opt_lock_ddl_per_table, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -2205,6 +2213,10 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n) return(FALSE); } + if (opt_lock_ddl_per_table) { + mdl_lock_table(node->space->id); + } + if (!changed_page_bitmap) { read_filter = &rf_pass_through; } @@ -2347,10 +2359,18 @@ xtrabackup_copy_log(copy_logfile copy, lsn_t start_lsn, lsn_t end_lsn) scanned_checkpoint = checkpoint; ulint data_len = log_block_get_data_len(log_block); - scanned_lsn += data_len; - if (data_len != OS_FILE_LOG_BLOCK_SIZE) { - /* The current end of the log was reached. */ + if (data_len == OS_FILE_LOG_BLOCK_SIZE) { + /* We got a full log block. */ + scanned_lsn += data_len; + } else if (data_len + >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE + || data_len <= LOG_BLOCK_HDR_SIZE) { + /* We got a garbage block (abrupt end of the log). */ + break; + } else { + /* We got a partial block (abrupt end of the log). */ + scanned_lsn += data_len; break; } } @@ -2363,7 +2383,7 @@ xtrabackup_copy_log(copy_logfile copy, lsn_t start_lsn, lsn_t end_lsn) if (ulint write_size = ulint(end_lsn - start_lsn)) { if (srv_encrypt_log) { - log_crypt(log_sys->buf, write_size); + log_crypt(log_sys->buf, start_lsn, write_size); } if (ds_write(dst_log_file, log_sys->buf, write_size)) { @@ -3552,6 +3572,10 @@ xtrabackup_backup_func() "or RENAME TABLE during the backup, inconsistent backup will be " "produced.\n"); + if (opt_lock_ddl_per_table) { + mdl_lock_init(); + } + /* initialize components */ if(innodb_init_param()) { fail: @@ -3741,10 +3765,10 @@ old_format: const byte* buf = log_sys->checkpoint_buf; - checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); - checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); - reread_log_header: + checkpoint_lsn_start = log_sys->log.lsn; + checkpoint_no_start = log_sys->next_checkpoint_no; + err = recv_find_max_checkpoint(&max_cp_field); if (err != DB_SUCCESS) { @@ -3758,10 +3782,9 @@ reread_log_header: ut_ad(!((log_sys->log.format ^ LOG_HEADER_FORMAT_CURRENT) & ~LOG_HEADER_FORMAT_ENCRYPTED)); - if (checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) { + log_group_header_read(&log_sys->log, max_cp_field); - checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); - checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); + if (checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) { goto reread_log_header; } @@ -3930,6 +3953,10 @@ reread_log_header: goto fail; } + if (opt_lock_ddl_per_table) { + mdl_unlock_all(); + } + xtrabackup_destroy_datasinks(); msg("xtrabackup: Redo log (from LSN " LSN_PF " to " LSN_PF diff --git a/extra/mariabackup/xtrabackup.h b/extra/mariabackup/xtrabackup.h index b226a9d1d83..a24626c48bc 100644 --- a/extra/mariabackup/xtrabackup.h +++ b/extra/mariabackup/xtrabackup.h @@ -193,4 +193,8 @@ xb_get_one_option(int optid, const char* xb_get_copy_action(const char *dflt = "Copying"); +void mdl_lock_init(); +void mdl_lock_table(ulint space_id); +void mdl_unlock_all(); + #endif /* XB_XTRABACKUP_H */ diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 81c0e440a30..f8a4f3572d5 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -669,6 +669,36 @@ JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = 1 select JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"'); JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"') "\u00f6" +select JSON_EXTRACT('{"foo": "bar" foobar foo invalid ', '$.foo'); +JSON_EXTRACT('{"foo": "bar" foobar foo invalid ', '$.foo') +NULL +Warnings: +Warning 4038 Syntax error in JSON text in argument 1 to function 'json_extract' at position 15 +SELECT JSON_OBJECT('foo', '`'); +JSON_OBJECT('foo', '`') +{"foo": "`"} +SELECT JSON_OBJECT("foo", "bar`bar"); +JSON_OBJECT("foo", "bar`bar") +{"foo": "bar`bar"} +SELECT JSON_SET('{}', '$.age', 87); +JSON_SET('{}', '$.age', 87) +{"age": 87} +SELECT JSON_MERGE('[]', '{"c":"d"}'); +JSON_MERGE('[]', '{"c":"d"}') +[{"c": "d"}] +SET @str = "{\"\\u00e4\\u00f6\":\"yes\"}"; +SET @path = "$.\"\\u00e4\\u00f6\""; +select @str, @path, JSON_EXTRACT(@str, @path); +@str @path JSON_EXTRACT(@str, @path) +{"\u00e4\u00f6":"yes"} $."\u00e4\u00f6" "yes" +SET @str = "{\"\\u00e4\":\"yes\"}"; +SET @path = "$.\"\\u00e4\""; +select @str, @path, JSON_EXTRACT(@str, @path); +@str @path JSON_EXTRACT(@str, @path) +{"\u00e4":"yes"} $."\u00e4" "yes" +select json_array(5,json_query('[1,2]','$')); +json_array(5,json_query('[1,2]','$')) +[5, [1,2]] # # Start of 10.3 tests # diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 8767b737ca7..36abece7743 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -6638,6 +6638,29 @@ drop table procViewTable; use test; drop database bugTest; # +# MDEV-13436: PREPARE doesn't work as expected & throws errors but +# MySQL is working fine +# +create table t1 (a int); +insert into t1 values (1),(2); +SET @sql_query = " + CREATE VIEW v1 AS + SELECT * FROM ( + SELECT CASE WHEN 1 IN (SELECT a from t1 where a < 2) THEN TRUE END AS testcase + ) testalias +"; +PREPARE stmt FROM @sql_query; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +show create view v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `testalias`.`testcase` AS `testcase` from (select case when 1 in (select `test`.`t1`.`a` from `test`.`t1` where `test`.`t1`.`a` < 2) then 1 end AS `testcase`) `testalias` latin1 latin1_swedish_ci +SELECT * FROM v1; +testcase +1 +drop view v1; +drop table t1; +# # End of 10.2 tests # # diff --git a/mysql-test/suite/innodb_gis/r/rtree.result b/mysql-test/suite/innodb_gis/r/rtree.result index 285a499b16c..d6604314909 100644 --- a/mysql-test/suite/innodb_gis/r/rtree.result +++ b/mysql-test/suite/innodb_gis/r/rtree.result @@ -56,6 +56,7 @@ INSERT INTO t1 VALUES("left3", ST_GeomFromText('POLYGON (( -3 0, -3 2, -1 2, -1 SET @p = ST_GeomFromText('POLYGON (( 0 0, 0 2, 2 2, 2 0, 0 0))'); SELECT name, ST_AsText(square) from t1 where MBRContains(@p, square); name ST_AsText(square) +small POLYGON((0 0,0 1,1 1,1 0,0 0)) SELECT name, ST_AsText(square) from t1 where MBRDisjoint(@p, square); name ST_AsText(square) up3 POLYGON((0 3,0 5,2 5,2 3,0 3)) @@ -90,6 +91,7 @@ down2 POLYGON((0 -2,0 0,2 0,2 -2,0 -2)) left2 POLYGON((-2 0,-2 2,0 2,0 0,-2 0)) SELECT name, ST_AsText(square) from t1 where MBRWithin(@p, square); name ST_AsText(square) +big POLYGON((0 0,0 3,3 3,3 0,0 0)) SET @vert1 = ST_GeomFromText('POLYGON ((0 -2, 0 2, 0 -2))'); SET @horiz1 = ST_GeomFromText('POLYGON ((-2 0, 2 0, -2 0))'); SET @horiz2 = ST_GeomFromText('POLYGON ((-1 0, 3 0, -1 0))'); @@ -217,7 +219,7 @@ SELECT COUNT(*) FROM t1 WHERE ST_CONTAINS(ST_GeomFromText('POLYGON((2 2,4 2, 4 4, 2 4, 2 2))'),way); COUNT(*) -0 +9 OPTIMIZE TABLE t1; Table Op Msg_type Msg_text test.t1 optimize note Table does not support optimize, doing recreate + analyze instead @@ -226,7 +228,7 @@ SELECT COUNT(*) FROM t1 WHERE ST_CONTAINS(ST_GeomFromText('POLYGON((2 2,4 2, 4 4, 2 4, 2 2))'),way); COUNT(*) -0 +9 DROP TABLE t1; CREATE TABLE t1( i INT, g GEOMETRY NOT NULL, SPATIAL INDEX (g)) ENGINE=InnoDB; INSERT INTO t1 VALUES(1, LINESTRING(POINT(1,1), POINT(4, 4))); diff --git a/mysql-test/suite/json/r/json_no_table.result b/mysql-test/suite/json/r/json_no_table.result index cf4cd5b8af8..034a4e6c0a6 100644 --- a/mysql-test/suite/json/r/json_no_table.result +++ b/mysql-test/suite/json/r/json_no_table.result @@ -2109,10 +2109,9 @@ ERROR 42000: Incorrect parameter count in the call to native function 'json_set' error ER_INVALID_JSON_TEXT_IN_PARAM SELECT JSON_SET('{}', '$.name', JSON_EXTRACT('', '$')); JSON_SET('{}', '$.name', JSON_EXTRACT('', '$')) -NULL +{"name": null} Warnings: Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_extract' -Warning 4038 Syntax error in JSON text in argument 1 to function 'json_set' at position 2 select json_set('[1,2,3]', '$[2]', 4); json_set('[1,2,3]', '$[2]', 4) [1, 2, 4] diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.result b/mysql-test/suite/mariabackup/lock_ddl_per_table.result new file mode 100644 index 00000000000..d0137a1e072 --- /dev/null +++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.result @@ -0,0 +1,4 @@ +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +# xtrabackup backup +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.test b/mysql-test/suite/mariabackup/lock_ddl_per_table.test new file mode 100644 index 00000000000..5b45aa7c61b --- /dev/null +++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.test @@ -0,0 +1,12 @@ +--source include/have_debug.inc + +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +echo # xtrabackup backup; +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; + +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table=1 --dbug=+d,check_mdl_lock_works; +--enable_result_log +DROP TABLE t; +rmdir $targetdir;
\ No newline at end of file diff --git a/mysql-test/suite/mariabackup/suite.opt b/mysql-test/suite/mariabackup/suite.opt index ba78b2d8957..defba074293 100644 --- a/mysql-test/suite/mariabackup/suite.opt +++ b/mysql-test/suite/mariabackup/suite.opt @@ -1 +1 @@ ---innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda
\ No newline at end of file +--innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda --innodb-sys-tables
\ No newline at end of file diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 823421520c8..14479d0df1b 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -317,6 +317,44 @@ select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = false; select JSON_EXTRACT('{\"asdf\":true}', "$.\"asdf\"") = 1; select JSON_EXTRACT('{\"input1\":\"\\u00f6\"}', '$.\"input1\"'); +# +# MDEV-129892 JSON_EXTRACT returns data for invalid JSON +# +select JSON_EXTRACT('{"foo": "bar" foobar foo invalid ', '$.foo'); + +# +# MDEV-13138 JSON_OBJECT returns null with strings containing backticks. +# +SELECT JSON_OBJECT('foo', '`'); +SELECT JSON_OBJECT("foo", "bar`bar"); + +# +# MDEV-13324 JSON_SET returns NULL instead of object. +# +SELECT JSON_SET('{}', '$.age', 87); + +# +# MDEV-13104 Json functions. +# +SELECT JSON_MERGE('[]', '{"c":"d"}'); + +# +# MDEV-12774 JSON_EXTRACT fails with some escaped unicode as key. +# + +SET @str = "{\"\\u00e4\\u00f6\":\"yes\"}"; +SET @path = "$.\"\\u00e4\\u00f6\""; +select @str, @path, JSON_EXTRACT(@str, @path); +SET @str = "{\"\\u00e4\":\"yes\"}"; +SET @path = "$.\"\\u00e4\""; +select @str, @path, JSON_EXTRACT(@str, @path); + +# +# MDEV-12877 Wrong result from JSON native function. +# +select json_array(5,json_query('[1,2]','$')); + + --echo # --echo # Start of 10.3 tests --echo # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index fc6ee46c1ac..00be48c172c 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -6351,6 +6351,27 @@ use test; drop database bugTest; --echo # +--echo # MDEV-13436: PREPARE doesn't work as expected & throws errors but +--echo # MySQL is working fine +--echo # + +create table t1 (a int); +insert into t1 values (1),(2); +SET @sql_query = " + CREATE VIEW v1 AS + SELECT * FROM ( + SELECT CASE WHEN 1 IN (SELECT a from t1 where a < 2) THEN TRUE END AS testcase + ) testalias +"; +PREPARE stmt FROM @sql_query; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +show create view v1; +SELECT * FROM v1; +drop view v1; +drop table t1; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index db720da18fd..d332d067c37 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -550,7 +550,18 @@ public: maybe_null= true; } enum Functype functype() const { return spatial_rel; } - enum Functype rev_functype() const { return spatial_rel; } + enum Functype rev_functype() const + { + switch (spatial_rel) + { + case SP_CONTAINS_FUNC: + return SP_WITHIN_FUNC; + case SP_WITHIN_FUNC: + return SP_CONTAINS_FUNC; + default: + return spatial_rel; + } + } bool is_null() { (void) val_int(); return null_value; } void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index dbaf2c6f6a3..4585427b442 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -650,6 +650,7 @@ static int alloc_tmp_paths(THD *thd, uint n_paths, if (*tmp_paths == 0) { MEM_ROOT *root= thd->stmt_arena->mem_root; + *paths= (json_path_with_flags *) alloc_root(root, sizeof(json_path_with_flags) * n_paths); *tmp_paths= (String *) alloc_root(root, sizeof(String) * n_paths); @@ -657,6 +658,8 @@ static int alloc_tmp_paths(THD *thd, uint n_paths, return 1; bzero(*tmp_paths, sizeof(String) * n_paths); + for (uint c_path=0; c_path < n_paths; c_path++) + (*tmp_paths)[c_path].set_charset(&my_charset_utf8_general_ci); } return 0; @@ -821,7 +824,11 @@ String *Item_func_json_extract::read_json(String *str, not_first_value= 1; if (!possible_multiple_values) + { + /* Loop to the end of the JSON just to make sure it's valid. */ + while (json_get_path_next(&je, &p) == 0) {} break; + } } if (je.s.error) @@ -869,7 +876,7 @@ longlong Item_func_json_extract::val_int() json_value_types type; char *value; int value_len; - longlong i; + longlong i= 0; if (read_json(NULL, &type, &value, &value_len) != NULL) { @@ -1968,14 +1975,25 @@ continue_j2: else { const uchar *end1, *beg1, *end2, *beg2; + int empty_array= 0; beg1= je1->value_begin; /* Merge as a single array. */ if (je1->value_type == JSON_VALUE_ARRAY) { - if (json_skip_level(je1)) + int cur_level= je1->stack_p; + empty_array= 1; + while (json_scan_next(je1) == 0) + { + if (je1->stack_p < cur_level) + break; + empty_array= 0; + } + + if (je1->s.error) return 1; + end1= je1->s.c_str - je1->sav_c_len; } else @@ -1992,8 +2010,8 @@ continue_j2: end1= je1->value_end; } - if (str->append((const char*) beg1, end1 - beg1), - str->append(", ", 2)) + if (str->append((const char*) beg1, end1 - beg1) || + (!empty_array && str->append(", ", 2))) return 3; if (json_value_scalar(je2)) @@ -2449,6 +2467,8 @@ String *Item_func_json_insert::val_str(String *str) } else /*JSON_PATH_KEY*/ { + uint n_key= 0; + if (je.value_type != JSON_VALUE_OBJECT) continue; @@ -2460,6 +2480,7 @@ String *Item_func_json_insert::val_str(String *str) json_string_set_str(&key_name, lp->key, lp->key_end); if (json_key_matches(&je, &key_name)) goto v_found; + n_key++; if (json_skip_key(&je)) goto js_error; break; @@ -2477,7 +2498,8 @@ String *Item_func_json_insert::val_str(String *str) v_to= (const char *) (je.s.c_str - je.sav_c_len); str->length(0); if (append_simple(str, js->ptr(), v_to - js->ptr()) || - str->append(", \"", 3) || + (n_key > 0 && str->append(", ", 2)) || + str->append("\"", 1) || append_simple(str, lp->key, lp->key_end - lp->key) || str->append("\":", 2) || append_json_value(str, args[n_arg+1], &tmp_val) || diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index 97f144c0fd3..7da72dc7f89 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -99,6 +99,7 @@ class Item_func_json_query: public Item_func_json_value public: Item_func_json_query(THD *thd, Item *js, Item *i_path): Item_func_json_value(thd, js, i_path) {} + bool is_json_type() { return true; } const char *func_name() const { return "json_query"; } bool check_and_get_value(json_engine_t *je, String *res, int *error); Item *get_copy(THD *thd, MEM_ROOT *mem_root) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 997ff2aeb38..f83df07a80f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2085,11 +2085,11 @@ static bool mysql_test_create_view(Prepared_statement *stmt) if (thd->open_temporary_tables(tables)) goto err; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, DT_PREPARE)) goto err; - lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; res= select_like_stmt_test(stmt, 0, 0); err: diff --git a/storage/innobase/include/log0crypt.h b/storage/innobase/include/log0crypt.h index d1282043665..a5f7c56cc3f 100644 --- a/storage/innobase/include/log0crypt.h +++ b/storage/innobase/include/log0crypt.h @@ -32,7 +32,11 @@ MDEV-11782: Rewritten for MariaDB 10.2 by Marko Mäkelä, MariaDB Corporation. /** innodb_encrypt_log: whether to encrypt the redo log */ extern my_bool srv_encrypt_log; -/** Initialize the redo log encryption key. +/** Initialize the redo log encryption key and random parameters +when creating a new redo log. +The random parameters will be persisted in the log checkpoint pages. +@see log_crypt_write_checkpoint_buf() +@see log_crypt_read_checkpoint_buf() @return whether the operation succeeded */ UNIV_INTERN bool @@ -71,10 +75,11 @@ log_crypt_read_checkpoint_buf(const byte* buf); /** Encrypt or decrypt log blocks. @param[in,out] buf log blocks to encrypt or decrypt +@param[in] lsn log sequence number of the start of the buffer @param[in] size size of the buffer, in bytes @param[in] decrypt whether to decrypt instead of encrypting */ UNIV_INTERN void -log_crypt(byte* buf, ulint size, bool decrypt = false); +log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt = false); #endif // log0crypt.h diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc index 69cfec10fed..c0a10c74073 100644 --- a/storage/innobase/log/log0crypt.cc +++ b/storage/innobase/log/log0crypt.cc @@ -103,11 +103,12 @@ get_crypt_info(ulint checkpoint_no) /** Encrypt or decrypt log blocks. @param[in,out] buf log blocks to encrypt or decrypt +@param[in] lsn log sequence number of the start of the buffer @param[in] size size of the buffer, in bytes @param[in] decrypt whether to decrypt instead of encrypting */ UNIV_INTERN void -log_crypt(byte* buf, ulint size, bool decrypt) +log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt) { ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(info.key_version); @@ -117,12 +118,12 @@ log_crypt(byte* buf, ulint size, bool decrypt) compile_time_assert(sizeof(uint32_t) == 4); #define LOG_CRYPT_HDR_SIZE 4 + lsn &= ~lsn_t(OS_FILE_LOG_BLOCK_SIZE - 1); for (const byte* const end = buf + size; buf != end; - buf += OS_FILE_LOG_BLOCK_SIZE) { + buf += OS_FILE_LOG_BLOCK_SIZE, lsn += OS_FILE_LOG_BLOCK_SIZE) { uint32_t dst[(OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE) / sizeof(uint32_t)]; - const ulint log_block_no = log_block_get_hdr_no(buf); /* The log block number is not encrypted. */ *aes_ctr_iv = @@ -137,10 +138,10 @@ log_crypt(byte* buf, ulint size, bool decrypt) # error "LOG_BLOCK_HDR_NO has been moved; redo log format affected!" #endif aes_ctr_iv[1] = info.crypt_nonce.word; - mach_write_to_8(reinterpret_cast<byte*>(aes_ctr_iv + 2), - log_block_get_start_lsn( - decrypt ? srv_start_lsn : log_sys->lsn, - log_block_no)); + mach_write_to_8(reinterpret_cast<byte*>(aes_ctr_iv + 2), lsn); + ut_ad(log_block_get_start_lsn(lsn, + log_block_get_hdr_no(buf)) + == lsn); int rc = encryption_crypt( buf + LOG_CRYPT_HDR_SIZE, sizeof dst, @@ -206,7 +207,11 @@ init_crypt_key(crypt_info_t* info, bool upgrade = false) return true; } -/** Initialize the redo log encryption key. +/** Initialize the redo log encryption key and random parameters +when creating a new redo log. +The random parameters will be persisted in the log checkpoint pages. +@see log_crypt_write_checkpoint_buf() +@see log_crypt_read_checkpoint_buf() @return whether the operation succeeded */ UNIV_INTERN bool diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 463914982cf..f7974d243d8 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -997,10 +997,6 @@ loop: || log_block_get_hdr_no(buf) == log_block_convert_lsn_to_no(start_lsn)); - if (log_sys->is_encrypted()) { - log_crypt(buf, write_len); - } - /* Calculate the checksums for each log block and write them to the trailer fields of the log blocks */ @@ -1264,6 +1260,12 @@ loop: ::memset(write_buf + area_end, 0, pad_size); } } + + if (log_sys->is_encrypted()) { + log_crypt(write_buf + area_start, log_sys->write_lsn, + area_end - area_start); + } + /* Do the write to the log files */ log_group_write_buf( &log_sys->log, write_buf + area_start, diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 8bc8df750e4..fd0940b08df 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -715,7 +715,8 @@ loop: } if (group->is_encrypted()) { - log_crypt(buf, OS_FILE_LOG_BLOCK_SIZE, true); + log_crypt(buf, start_lsn, + OS_FILE_LOG_BLOCK_SIZE, true); } } } @@ -1016,6 +1017,7 @@ recv_find_max_checkpoint(ulint* max_field) buf + LOG_CHECKPOINT_LSN); group->lsn_offset = mach_read_from_8( buf + LOG_CHECKPOINT_OFFSET); + log_sys->next_checkpoint_no = checkpoint_no; } } diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 21c1343f5b3..66866c98e62 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -2223,14 +2223,6 @@ files_checked: recv_sys->dblwr.pages.clear(); - if (err == DB_SUCCESS && !srv_read_only_mode) { - log_mutex_enter(); - if (log_sys->is_encrypted() && !log_crypt_init()) { - err = DB_ERROR; - } - log_mutex_exit(); - } - if (err == DB_SUCCESS) { /* Initialize the change buffer. */ err = dict_boot(); @@ -2733,13 +2725,6 @@ files_checked: fil_crypt_threads_init(); fil_system_exit(); - /* - Create a checkpoint before logging anything new, so that - the current encryption key in use is definitely logged - before any log blocks encrypted with that key. - */ - log_make_checkpoint_at(LSN_MAX, TRUE); - /* Initialize online defragmentation. */ btr_defragment_init(); btr_defragment_thread_active = true; diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index ac23234179c..2408e4bdaf4 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -619,6 +619,7 @@ trx_free_prepared( || (trx_state_eq(trx, TRX_STATE_ACTIVE) && trx->is_recovered && (!srv_was_started + || srv_operation == SRV_OPERATION_RESTORE || srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO))); ut_a(trx->magic_n == TRX_MAGIC_N); diff --git a/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc b/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc index d18faea61a8..91bcc68adb4 100644 --- a/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc +++ b/storage/rocksdb/mysql-test/rocksdb/include/index_merge1.inc @@ -402,12 +402,20 @@ analyze table t1; -- enable_query_log # index_merge on first table in join +if ($index_merge_random_rows_in_EXPLAIN) +{ + --replace_column 9 # +} explain select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; +if ($index_merge_random_rows_in_EXPLAIN) +{ + --replace_column 9 # +} explain select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); diff --git a/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result b/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result index bd9983d68a4..ff33e6061b3 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/index_merge_rocksdb2.result @@ -250,8 +250,8 @@ insert into t1 select * from t0; explain select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where -1 SIMPLE t1 ref i1 i1 4 test.t0.key1 2 +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # select * from t0 left join t1 on (t0.key1=t1.key1) where t0.key1=3 or t0.key2=4; key1 key2 key3 key4 key5 key6 key7 key8 key1 key2 key3 key4 key5 key6 key7 key8 @@ -260,8 +260,8 @@ key1 key2 key3 key4 key5 key6 key7 key8 key1 key2 key3 key4 key5 key6 key7 key8 explain select * from t0,t1 where (t0.key1=t1.key1) and ( t0.key1=3 or t0.key2=4); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 2 Using union(i1,i2); Using where -1 SIMPLE t1 ref i1 i1 4 test.t0.key1 2 +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL # Using union(i1,i2); Using where +1 SIMPLE t1 ref i1 i1 4 test.t0.key1 # explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2<4) and t1.key1=2; diff --git a/strings/json_lib.c b/strings/json_lib.c index b0c843caec1..25e5e81e6f9 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1586,7 +1586,7 @@ int json_escape(CHARSET_INFO *str_cs, enum json_esc_char_classes c_class; str+= c_len; - if (c_chr > 0x60 || (c_class= json_escape_chr_map[c_chr]) == ESC_) + if (c_chr >= 0x60 || (c_class= json_escape_chr_map[c_chr]) == ESC_) { if ((c_len= json_cs->cset->wc_mb(json_cs, c_chr, json, json_end)) > 0) { |