mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-33749 hyphen in table name can cause galera certification failures
Fix in this commit handles foreign key value appending into write set so that db and table names are converted from the filepath format to tablename format. This is compatible with key values appended from elsewhere in the code base There is a mtr test galera.galera_table_with_hyphen for regression testing Reviewer: monty@mariadb.com
This commit is contained in:
52
mysql-test/suite/galera/r/galera_table_with_hyphen.result
Normal file
52
mysql-test/suite/galera/r/galera_table_with_hyphen.result
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
connection node_2;
|
||||||
|
connection node_1;
|
||||||
|
connection node_1;
|
||||||
|
set wsrep_sync_wait=0;
|
||||||
|
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
connection node_1;
|
||||||
|
SET GLOBAL wsrep_slave_threads=2;
|
||||||
|
CREATE TABLE `par-ent` ( id INT AUTO_INCREMENT PRIMARY KEY, j INT) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE `child` (id INT AUTO_INCREMENT PRIMARY KEY, parent_id INT, j INT, FOREIGN KEY (parent_id) REFERENCES `par-ent`(id)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO `par-ent` VALUES (23,0);
|
||||||
|
connection node_2;
|
||||||
|
connection node_1a;
|
||||||
|
SET GLOBAL DEBUG_DBUG='+d,wsrep_ha_write_row';
|
||||||
|
connection node_2;
|
||||||
|
INSERT INTO `child` VALUES (21,23,0),(22,23,0),(23,23,0);
|
||||||
|
connection node_1a;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR wsrep_ha_write_row_reached';
|
||||||
|
connection node_2;
|
||||||
|
UPDATE `par-ent` SET j=2 WHERE id=23;
|
||||||
|
connection node_1a;
|
||||||
|
SET GLOBAL DEBUG_DBUG='-d,wsrep_ha_write_row';
|
||||||
|
SET DEBUG_SYNC='now SIGNAL wsrep_ha_write_row_continue';
|
||||||
|
SET GLOBAL DEBUG_DBUG="RESET";
|
||||||
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
SET GLOBAL wsrep_slave_threads=DEFAULT;
|
||||||
|
connection node_2;
|
||||||
|
drop table `child`;
|
||||||
|
drop table `par-ent`;
|
||||||
|
connection node_1;
|
||||||
|
SET GLOBAL wsrep_slave_threads=2;
|
||||||
|
CREATE TABLE `p-arent-` ( id INT AUTO_INCREMENT PRIMARY KEY, j INT) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE `c-hild` (id INT AUTO_INCREMENT PRIMARY KEY, parent_id INT, j INT, FOREIGN KEY (parent_id) REFERENCES `p-arent-`(id)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO `p-arent-` VALUES (23,0);
|
||||||
|
connection node_2;
|
||||||
|
connection node_1a;
|
||||||
|
SET GLOBAL DEBUG_DBUG='+d,wsrep_ha_write_row';
|
||||||
|
connection node_2;
|
||||||
|
INSERT INTO `c-hild` VALUES (21,23,0),(22,23,0),(23,23,0);
|
||||||
|
connection node_1a;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR wsrep_ha_write_row_reached';
|
||||||
|
connection node_2;
|
||||||
|
UPDATE `p-arent-` SET j=2 WHERE id=23;
|
||||||
|
connection node_1a;
|
||||||
|
SET GLOBAL DEBUG_DBUG='-d,wsrep_ha_write_row';
|
||||||
|
SET DEBUG_SYNC='now SIGNAL wsrep_ha_write_row_continue';
|
||||||
|
SET GLOBAL DEBUG_DBUG="RESET";
|
||||||
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
SET GLOBAL wsrep_slave_threads=DEFAULT;
|
||||||
|
connection node_2;
|
||||||
|
drop table `c-hild`;
|
||||||
|
drop table `p-arent-`;
|
48
mysql-test/suite/galera/t/galera_table_with_hyphen.inc
Normal file
48
mysql-test/suite/galera/t/galera_table_with_hyphen.inc
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# parameters:
|
||||||
|
# $fk_child - child table name
|
||||||
|
# $fk_parent - parent table name
|
||||||
|
#
|
||||||
|
--connection node_1
|
||||||
|
SET GLOBAL wsrep_slave_threads=2;
|
||||||
|
|
||||||
|
--eval CREATE TABLE `$fk_parent` ( id INT AUTO_INCREMENT PRIMARY KEY, j INT) ENGINE=InnoDB
|
||||||
|
|
||||||
|
--eval CREATE TABLE `$fk_child` (id INT AUTO_INCREMENT PRIMARY KEY, parent_id INT, j INT, FOREIGN KEY (parent_id) REFERENCES `$fk_parent`(id)) ENGINE=InnoDB
|
||||||
|
|
||||||
|
--eval INSERT INTO `$fk_parent` VALUES (23,0)
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
--let $wait_condition = SELECT COUNT(*) = 1 FROM `$fk_parent`;
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
--connection node_1a
|
||||||
|
SET GLOBAL DEBUG_DBUG='+d,wsrep_ha_write_row';
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
--eval INSERT INTO `$fk_child` VALUES (21,23,0),(22,23,0),(23,23,0)
|
||||||
|
|
||||||
|
--connection node_1a
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR wsrep_ha_write_row_reached';
|
||||||
|
|
||||||
|
--let $wsrep_received_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_received'`
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
--eval UPDATE `$fk_parent` SET j=2 WHERE id=23
|
||||||
|
|
||||||
|
--connection node_1a
|
||||||
|
--let $wait_condition = SELECT VARIABLE_VALUE = $wsrep_received_before + 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_received'
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
|
||||||
|
SET GLOBAL DEBUG_DBUG='-d,wsrep_ha_write_row';
|
||||||
|
SET DEBUG_SYNC='now SIGNAL wsrep_ha_write_row_continue';
|
||||||
|
|
||||||
|
SET GLOBAL DEBUG_DBUG="RESET";
|
||||||
|
SET DEBUG_SYNC = 'RESET';
|
||||||
|
|
||||||
|
SET GLOBAL wsrep_slave_threads=DEFAULT;
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
--eval drop table `$fk_child`
|
||||||
|
--eval drop table `$fk_parent`
|
||||||
|
|
34
mysql-test/suite/galera/t/galera_table_with_hyphen.test
Normal file
34
mysql-test/suite/galera/t/galera_table_with_hyphen.test
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
--source include/galera_cluster.inc
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# Testing how tables and databases with special characters
|
||||||
|
# are treated in certification
|
||||||
|
#
|
||||||
|
# The test creates two tables having foreign key constraint
|
||||||
|
# reference and executes two transactions which modify
|
||||||
|
# same rows. The same test is executed with different names
|
||||||
|
# containin special characters to see if the certification
|
||||||
|
# can detect the conflicts
|
||||||
|
#
|
||||||
|
# Actual test is in include file galera_table_with_hyphen.inc
|
||||||
|
# It create the test tables from parameters $fk_child and
|
||||||
|
# $fk_parent
|
||||||
|
#
|
||||||
|
--connection node_1
|
||||||
|
set wsrep_sync_wait=0;
|
||||||
|
|
||||||
|
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
|
||||||
|
SET SESSION wsrep_sync_wait = 0;
|
||||||
|
|
||||||
|
--let $fk_child = child
|
||||||
|
--let $fk_parent = par-ent
|
||||||
|
|
||||||
|
--source galera_table_with_hyphen.inc
|
||||||
|
|
||||||
|
--let $fk_child = c-hild
|
||||||
|
--let $fk_parent = p-arent-
|
||||||
|
|
||||||
|
--source galera_table_with_hyphen.inc
|
@@ -7270,7 +7270,16 @@ int handler::ha_write_row(const uchar *buf)
|
|||||||
m_lock_type == F_WRLCK);
|
m_lock_type == F_WRLCK);
|
||||||
DBUG_ENTER("handler::ha_write_row");
|
DBUG_ENTER("handler::ha_write_row");
|
||||||
DEBUG_SYNC_C("ha_write_row_start");
|
DEBUG_SYNC_C("ha_write_row_start");
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
DBUG_EXECUTE_IF("wsrep_ha_write_row",
|
||||||
|
{
|
||||||
|
const char act[]=
|
||||||
|
"now "
|
||||||
|
"SIGNAL wsrep_ha_write_row_reached "
|
||||||
|
"WAIT_FOR wsrep_ha_write_row_continue";
|
||||||
|
DBUG_ASSERT(!debug_sync_set_action(ha_thd(), STRING_WITH_LEN(act)));
|
||||||
|
});
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
if ((error= ha_check_overlaps(NULL, buf)))
|
if ((error= ha_check_overlaps(NULL, buf)))
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
|
||||||
|
@@ -9786,7 +9786,8 @@ wsrep_append_foreign_key(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ulint rcode = DB_SUCCESS;
|
ulint rcode = DB_SUCCESS;
|
||||||
char cache_key[513] = {'\0'};
|
char cache_key[MAX_FULL_NAME_LEN] = {'\0'};
|
||||||
|
char db_name[MAX_DATABASE_NAME_LEN+1] = {'\0'};
|
||||||
size_t cache_key_len = 0;
|
size_t cache_key_len = 0;
|
||||||
|
|
||||||
if ( !((referenced) ?
|
if ( !((referenced) ?
|
||||||
@@ -9871,14 +9872,38 @@ wsrep_append_foreign_key(
|
|||||||
return DB_ERROR;
|
return DB_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(cache_key,
|
char * fk_table =
|
||||||
(wsrep_protocol_version > 1) ?
|
(wsrep_protocol_version > 1) ?
|
||||||
((referenced) ?
|
((referenced) ?
|
||||||
foreign->referenced_table->name.m_name :
|
foreign->referenced_table->name.m_name :
|
||||||
foreign->foreign_table->name.m_name) :
|
foreign->foreign_table->name.m_name) :
|
||||||
foreign->foreign_table->name.m_name, sizeof(cache_key) - 1);
|
foreign->foreign_table->name.m_name;
|
||||||
cache_key_len = strlen(cache_key);
|
|
||||||
|
|
||||||
|
/* convert db and table name parts separately to system charset */
|
||||||
|
ulint db_name_len = dict_get_db_name_len(fk_table);
|
||||||
|
strmake(db_name, fk_table, db_name_len);
|
||||||
|
uint errors;
|
||||||
|
cache_key_len= innobase_convert_to_system_charset(cache_key,
|
||||||
|
db_name, sizeof(cache_key), &errors);
|
||||||
|
if (errors) {
|
||||||
|
WSREP_WARN("unexpected foreign key table %s %s",
|
||||||
|
foreign->referenced_table->name.m_name,
|
||||||
|
foreign->foreign_table->name.m_name);
|
||||||
|
return DB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* after db name adding 0 and then converted table name */
|
||||||
|
cache_key[db_name_len]= '\0';
|
||||||
|
cache_key_len++;
|
||||||
|
|
||||||
|
cache_key_len+= innobase_convert_to_system_charset(cache_key+cache_key_len,
|
||||||
|
fk_table+db_name_len+1, sizeof(cache_key), &errors);
|
||||||
|
if (errors) {
|
||||||
|
WSREP_WARN("unexpected foreign key table %s %s",
|
||||||
|
foreign->referenced_table->name.m_name,
|
||||||
|
foreign->foreign_table->name.m_name);
|
||||||
|
return DB_ERROR;
|
||||||
|
}
|
||||||
#ifdef WSREP_DEBUG_PRINT
|
#ifdef WSREP_DEBUG_PRINT
|
||||||
ulint j;
|
ulint j;
|
||||||
fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
|
fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
|
||||||
@@ -9888,16 +9913,6 @@ wsrep_append_foreign_key(
|
|||||||
}
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
#endif
|
#endif
|
||||||
char *p = strchr(cache_key, '/');
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
*p = '\0';
|
|
||||||
} else {
|
|
||||||
WSREP_WARN("unexpected foreign key table %s %s",
|
|
||||||
foreign->referenced_table->name.m_name,
|
|
||||||
foreign->foreign_table->name.m_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
wsrep_buf_t wkey_part[3];
|
wsrep_buf_t wkey_part[3];
|
||||||
wsrep_key_t wkey = {wkey_part, 3};
|
wsrep_key_t wkey = {wkey_part, 3};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user