Commit 20694fdb authored by osku's avatar osku

Use bound literals in row_rename_table_for_mysql.

parent 05963b49
...@@ -3416,6 +3416,62 @@ row_is_mysql_tmp_table_name( ...@@ -3416,6 +3416,62 @@ row_is_mysql_tmp_table_name(
return(strstr(name, "/@0023sql") != NULL); return(strstr(name, "/@0023sql") != NULL);
} }
/********************************************************************
Delete a single constraint. */
static
int
row_delete_constraint_low(
/*======================*/
/* out: error code or DB_SUCCESS */
const char* id, /* in: constraint id */
trx_t* trx) /* in: transaction handle */
{
pars_info_t* info = pars_info_create();
pars_info_add_str_literal(info, "id", id);
return(que_eval_sql(info,
"PROCEDURE DELETE_CONSTRAINT () IS\n"
"BEGIN\n"
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
"END;\n"
, trx));
}
/********************************************************************
Delete a single constraint. */
static
int
row_delete_constraint(
/*==================*/
/* out: error code or DB_SUCCESS */
const char* id, /* in: constraint id */
const char* database_name, /* in: database name, with the
trailing '/' */
mem_heap_t* heap, /* in: memory heap */
trx_t* trx) /* in: transaction handle */
{
ulint err;
/* New format constraints have ids <databasename>/<constraintname>. */
err = row_delete_constraint_low(
mem_heap_strcat(heap, database_name, id), trx);
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
/* Old format < 4.0.18 constraints have constraint ids
<number>_<number>. We only try deleting them if the
constraint name does not contain a '/' character, otherwise
deleting a new format constraint named 'foo/bar' from
database 'baz' would remove constraint 'bar' from database
'foo', if it existed. */
err = row_delete_constraint_low(id, trx);
}
return(err);
}
/************************************************************************* /*************************************************************************
Renames a table for MySQL. */ Renames a table for MySQL. */
...@@ -3428,100 +3484,13 @@ row_rename_table_for_mysql( ...@@ -3428,100 +3484,13 @@ row_rename_table_for_mysql(
trx_t* trx) /* in: transaction handle */ trx_t* trx) /* in: transaction handle */
{ {
dict_table_t* table; dict_table_t* table;
que_thr_t* thr;
que_t* graph = NULL;
ulint err; ulint err;
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system
tables in Innobase. Deleting a row from SYS_INDEXES table also
frees the file segments of the B-tree associated with the index. */
static const char str1[] =
"PROCEDURE RENAME_TABLE_PROC () IS\n"
"new_table_name CHAR;\n"
"old_table_name CHAR;\n"
"gen_constr_prefix CHAR;\n"
"new_db_name CHAR;\n"
"foreign_id CHAR;\n"
"new_foreign_id CHAR;\n"
"old_db_name_len INT;\n"
"old_t_name_len INT;\n"
"new_db_name_len INT;\n"
"id_len INT;\n"
"found INT;\n"
"BEGIN\n"
"new_table_name := '";
static const char str2[] =
"';\nold_table_name := '";
static const char str3[] =
"';\n"
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
"WHERE NAME = old_table_name;\n";
static const char str4a1[] = /* drop some constraints of tmp tables */
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = '";
static const char str4a2[] = "';\n"
"DELETE FROM SYS_FOREIGN WHERE ID = '";
static const char str4a3[] = "';\n";
static const char str4b[] = /* rename all constraints */
"found := 1;\n"
"old_db_name_len := INSTR(old_table_name, '/') - 1;\n"
"new_db_name_len := INSTR(new_table_name, '/') - 1;\n"
"new_db_name := SUBSTR(new_table_name, 0, new_db_name_len);\n"
"old_t_name_len := LENGTH(old_table_name);\n"
"gen_constr_prefix := CONCAT(old_table_name, '_ibfk_');\n"
"WHILE found = 1 LOOP\n"
" SELECT ID INTO foreign_id\n"
" FROM SYS_FOREIGN\n"
" WHERE FOR_NAME = old_table_name\n"
" AND TO_BINARY(FOR_NAME) = TO_BINARY(old_table_name);\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
" UPDATE SYS_FOREIGN\n"
" SET FOR_NAME = new_table_name\n"
" WHERE ID = foreign_id;\n"
" id_len := LENGTH(foreign_id);\n"
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
" IF (INSTR(foreign_id,\n"
" gen_constr_prefix) > 0)\n"
" THEN\n"
" new_foreign_id :=\n"
" CONCAT(new_table_name,\n"
" SUBSTR(foreign_id, old_t_name_len,\n"
" id_len - old_t_name_len));\n"
" ELSE\n"
" new_foreign_id :=\n"
" CONCAT(new_db_name,\n"
" SUBSTR(foreign_id,\n"
" old_db_name_len,\n"
" id_len - old_db_name_len));\n"
" END IF;\n"
" UPDATE SYS_FOREIGN\n"
" SET ID = new_foreign_id\n"
" WHERE ID = foreign_id;\n"
" UPDATE SYS_FOREIGN_COLS\n"
" SET ID = new_foreign_id\n"
" WHERE ID = foreign_id;\n"
" END IF;\n"
" END IF;\n"
"END LOOP;\n"
"UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n"
"WHERE REF_NAME = old_table_name\n"
" AND TO_BINARY(REF_NAME) = TO_BINARY(old_table_name);\n";
static const char str5[] =
"END;\n";
mem_heap_t* heap = NULL; mem_heap_t* heap = NULL;
const char** constraints_to_drop = NULL; const char** constraints_to_drop = NULL;
ulint n_constraints_to_drop = 0; ulint n_constraints_to_drop = 0;
ibool recovering_temp_table = FALSE; ibool recovering_temp_table = FALSE;
ibool old_is_tmp, new_is_tmp; ibool old_is_tmp, new_is_tmp;
ulint len; pars_info_t* info = NULL;
ulint i;
ibool success;
/* length of database name; 0 if not renaming to a temporary table */
ulint db_name_len;
char* sql;
char* sqlend;
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(old_name != NULL); ut_a(old_name != NULL);
...@@ -3599,13 +3568,7 @@ row_rename_table_for_mysql( ...@@ -3599,13 +3568,7 @@ row_rename_table_for_mysql(
goto funct_exit; goto funct_exit;
} }
/* calculate the length of the SQL string */
len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4
+ ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\'');
if (new_is_tmp) { if (new_is_tmp) {
db_name_len = dict_get_db_name_len(old_name) + 1;
/* MySQL is doing an ALTER TABLE command and it renames the /* MySQL is doing an ALTER TABLE command and it renames the
original table to a temporary table name. We want to preserve original table to a temporary table name. We want to preserve
the original foreign key constraint definitions despite the the original foreign key constraint definitions despite the
...@@ -3615,110 +3578,124 @@ row_rename_table_for_mysql( ...@@ -3615,110 +3578,124 @@ row_rename_table_for_mysql(
heap = mem_heap_create(100); heap = mem_heap_create(100);
err = dict_foreign_parse_drop_constraints(heap, trx, err = dict_foreign_parse_drop_constraints(heap, trx,
table, table, &n_constraints_to_drop, &constraints_to_drop);
&n_constraints_to_drop,
&constraints_to_drop);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
goto funct_exit; goto funct_exit;
} }
}
/* reserve space for all database names */ /* We use the private SQL parser of Innobase to generate the query
len += 2 * n_constraints_to_drop graphs needed in deleting the dictionary data from system tables in
* (ut_strlenq(old_name, '\'') Innobase. Deleting a row from SYS_INDEXES table also frees the file
- ut_strlenq(old_name + db_name_len, '\'')); segments of the B-tree associated with the index. */
for (i = 0; i < n_constraints_to_drop; i++) { info = pars_info_create();
ulint addlen
= 2 * ut_strlenq(constraints_to_drop[i], '\'')
+ ((sizeof str4a1) + (sizeof str4a2)
+ (sizeof str4a3) - 3);
if (!strchr(constraints_to_drop[i], '/')) {
addlen *= 2;
}
len += addlen;
}
} else {
db_name_len = 0;
len += (sizeof str4b) - 1;
}
sql = sqlend = mem_alloc(len + 1); pars_info_add_str_literal(info, "new_table_name", new_name);
memcpy(sql, str1, (sizeof str1) - 1); pars_info_add_str_literal(info, "old_table_name", old_name);
sqlend += (sizeof str1) - 1;
sqlend = ut_strcpyq(sqlend, '\'', new_name);
memcpy(sqlend, str2, (sizeof str2) - 1);
sqlend += (sizeof str2) - 1;
sqlend = ut_strcpyq(sqlend, '\'', old_name);
memcpy(sqlend, str3, (sizeof str3) - 1);
sqlend += (sizeof str3) - 1;
if (db_name_len) { err = que_eval_sql(info,
/* Internally, old format < 4.0.18 constraints have as the "PROCEDURE RENAME_TABLE () IS\n"
constraint id <number>_<number>, while new format constraints "BEGIN\n"
have <databasename>/<constraintname>. */ "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
" WHERE NAME = :old_table_name;\n"
"END;\n"
, trx);
for (i = 0; i < n_constraints_to_drop; i++) { if (err != DB_SUCCESS) {
memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
sqlend += (sizeof str4a1) - 1;
sqlend = ut_memcpyq(sqlend, '\'',
old_name, db_name_len);
sqlend = ut_strcpyq(sqlend, '\'',
constraints_to_drop[i]);
memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
sqlend += (sizeof str4a2) - 1;
sqlend = ut_memcpyq(sqlend, '\'',
old_name, db_name_len);
sqlend = ut_strcpyq(sqlend, '\'',
constraints_to_drop[i]);
memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
sqlend += (sizeof str4a3) - 1;
if (!strchr(constraints_to_drop[i], '/')) {
/* If this happens to be an old format
constraint, let us delete it. Since all new
format constraints contain '/', it does no
harm to run these DELETEs anyway. */
memcpy(sqlend, str4a1, (sizeof str4a1) - 1);
sqlend += (sizeof str4a1) - 1;
sqlend = ut_strcpyq(sqlend, '\'',
constraints_to_drop[i]);
memcpy(sqlend, str4a2, (sizeof str4a2) - 1);
sqlend += (sizeof str4a2) - 1;
sqlend = ut_strcpyq(sqlend, '\'',
constraints_to_drop[i]);
memcpy(sqlend, str4a3, (sizeof str4a3) - 1);
sqlend += (sizeof str4a3) - 1;
}
}
}
else {
memcpy(sqlend, str4b, (sizeof str4b) - 1);
sqlend += (sizeof str4b) - 1;
}
memcpy(sqlend, str5, sizeof str5); goto end;
sqlend += sizeof str5; }
ut_a(sqlend == sql + len + 1); if (!new_is_tmp) {
/* Rename all constraints. */
graph = pars_sql(NULL, sql); info = pars_info_create();
ut_a(graph); pars_info_add_str_literal(info, "new_table_name", new_name);
mem_free(sql); pars_info_add_str_literal(info, "old_table_name", old_name);
graph->trx = trx; err = que_eval_sql(info,
trx->graph = NULL; "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
"gen_constr_prefix CHAR;\n"
"new_db_name CHAR;\n"
"foreign_id CHAR;\n"
"new_foreign_id CHAR;\n"
"old_db_name_len INT;\n"
"old_t_name_len INT;\n"
"new_db_name_len INT;\n"
"id_len INT;\n"
"found INT;\n"
"BEGIN\n"
"found := 1;\n"
"old_db_name_len := INSTR(:old_table_name, '/') - 1;\n"
"new_db_name_len := INSTR(:new_table_name, '/') - 1;\n"
"new_db_name := SUBSTR(:new_table_name, 0, new_db_name_len);\n"
"old_t_name_len := LENGTH(:old_table_name);\n"
"gen_constr_prefix := CONCAT(:old_table_name, '_ibfk_');\n"
"WHILE found = 1 LOOP\n"
" SELECT ID INTO foreign_id\n"
" FROM SYS_FOREIGN\n"
" WHERE FOR_NAME = :old_table_name\n"
" AND TO_BINARY(FOR_NAME) = TO_BINARY(:old_table_name);\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
" UPDATE SYS_FOREIGN\n"
" SET FOR_NAME = :new_table_name\n"
" WHERE ID = foreign_id;\n"
" id_len := LENGTH(foreign_id);\n"
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
" IF (INSTR(foreign_id,\n"
" gen_constr_prefix) > 0)\n"
" THEN\n"
" new_foreign_id :=\n"
" CONCAT(:new_table_name,\n"
" SUBSTR(foreign_id, old_t_name_len,\n"
" id_len - old_t_name_len));\n"
" ELSE\n"
" new_foreign_id :=\n"
" CONCAT(new_db_name,\n"
" SUBSTR(foreign_id,\n"
" old_db_name_len,\n"
" id_len - old_db_name_len));\n"
" END IF;\n"
" UPDATE SYS_FOREIGN\n"
" SET ID = new_foreign_id\n"
" WHERE ID = foreign_id;\n"
" UPDATE SYS_FOREIGN_COLS\n"
" SET ID = new_foreign_id\n"
" WHERE ID = foreign_id;\n"
" END IF;\n"
" END IF;\n"
"END LOOP;\n"
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
"WHERE REF_NAME = :old_table_name\n"
" AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n"
"END;\n"
, trx);
graph->fork_type = QUE_FORK_MYSQL_INTERFACE; } else if (n_constraints_to_drop > 0) {
/* Drop some constraints of tmp tables. */
ut_a(thr = que_fork_start_command(graph)); ulint db_name_len = dict_get_db_name_len(old_name) + 1;
char* db_name = mem_heap_strdupl(heap, old_name,
db_name_len);
ulint i;
que_run_threads(thr); for (i = 0; i < n_constraints_to_drop; i++) {
err = row_delete_constraint(constraints_to_drop[i],
db_name, heap, trx);
err = trx->error_state; if (err != DB_SUCCESS) {
break;
}
}
}
end:
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
if (err == DB_DUPLICATE_KEY) { if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
...@@ -3755,8 +3732,9 @@ row_rename_table_for_mysql( ...@@ -3755,8 +3732,9 @@ row_rename_table_for_mysql(
/* The following call will also rename the .ibd data file if /* The following call will also rename the .ibd data file if
the table is stored in a single-table tablespace */ the table is stored in a single-table tablespace */
success = dict_table_rename_in_cache(table, new_name, ibool success = dict_table_rename_in_cache(table, new_name,
!new_is_tmp); !new_is_tmp);
if (!success) { if (!success) {
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL); trx_general_rollback_for_mysql(trx, FALSE, NULL);
...@@ -3804,20 +3782,16 @@ row_rename_table_for_mysql( ...@@ -3804,20 +3782,16 @@ row_rename_table_for_mysql(
ut_a(dict_table_rename_in_cache(table, ut_a(dict_table_rename_in_cache(table,
old_name, FALSE)); old_name, FALSE));
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, trx_general_rollback_for_mysql(trx, FALSE, NULL);
NULL);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
} }
funct_exit: funct_exit:
if (!recovering_temp_table) { if (!recovering_temp_table) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
} }
if (graph) {
que_graph_free(graph);
}
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment