Commit 85ccc78f authored by marko's avatar marko

Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.

ut_print_name(), ut_print_namel(): Add parameter table_id for distinguishing
names of tables from other identifiers (names of indexes, columns and
constraints).

innobase_convert_from_table_id(), innobase_convert_from_id(),
innobase_convert_from_filename(), innobase_get_charset(): New functions.

dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
dict_skip_word(), dict_create_foreign_constraints_low():
Add parameter "cs", so that isspace() can be replaced with my_isspace(),
whose operation depends on the connection character set.

dict_scan_id(): Convert the identifier to UTF-8.

dict_str_starts_with_keyword(): New extern function, to replace dict_accept()
in row_search_for_mysql().

mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().

ha_innobase::create(): Remove the thd->convert_string() call.
Pass the statement to InnoDB in the connection character set
and let InnoDB convert the identifiers to UTF-8.
parent 5fbd0192
......@@ -605,9 +605,9 @@ btr_page_get_father_for_rec(
buf_page_print(buf_frame_align(node_ptr));
fputs("InnoDB: Corruption of an index tree: table ", stderr);
ut_print_name(stderr, NULL, index->table_name);
ut_print_name(stderr, NULL, TRUE, index->table_name);
fputs(", index ", stderr);
ut_print_name(stderr, NULL, index->name);
ut_print_name(stderr, NULL, FALSE, index->name);
fprintf(stderr, ",\n"
"InnoDB: father ptr page no %lu, child page no %lu\n",
(ulong)
......
......@@ -1250,9 +1250,9 @@ dict_foreign_eval_sql(
ut_print_timestamp(ef);
fputs(" Error in foreign key constraint creation for table ",
ef);
ut_print_name(ef, trx, table->name);
ut_print_name(ef, trx, TRUE, table->name);
fputs(".\nA foreign key constraint of name ", ef);
ut_print_name(ef, trx, foreign->id);
ut_print_name(ef, trx, FALSE, foreign->id);
fputs("\nalready exists."
" (Note that internally InnoDB adds 'databasename/'\n"
"in front of the user-defined constraint name).\n",
......@@ -1280,7 +1280,7 @@ dict_foreign_eval_sql(
ut_print_timestamp(ef);
fputs(" Internal error in foreign key constraint creation"
" for table ", ef);
ut_print_name(ef, trx, table->name);
ut_print_name(ef, trx, TRUE, table->name);
fputs(".\n"
"See the MySQL .err log in the datadir for more information.\n", ef);
mutex_exit(&dict_foreign_err_mutex);
......
This diff is collapsed.
......@@ -184,7 +184,7 @@ dict_print(void)
if (table == NULL) {
fputs("InnoDB: Failed to load table ", stderr);
ut_print_namel(stderr, NULL, (char*) field, len);
ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
putc('\n', stderr);
} else {
/* The table definition was corrupt if there
......
......@@ -706,6 +706,61 @@ innobase_get_cset_width(
}
}
/**********************************************************************
Converts an identifier to a table name.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_table_id(
/*===========================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
strconvert(current_thd->charset(), from,
&my_charset_filename, to, len, &errors);
}
/**********************************************************************
Converts an identifier to UTF-8.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_id(
/*=====================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
strconvert(current_thd->charset(), from,
system_charset_info, to, len, &errors);
}
/**********************************************************************
Removes the filename encoding of a table or database name.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_filename(
/*===========================*/
char* s) /* in: identifier; out: decoded identifier */
{
uint errors;
strconvert(&my_charset_filename, s,
system_charset_info, s, strlen(s), &errors);
}
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
......@@ -736,6 +791,21 @@ innobase_casedn_str(
my_casedn_str(system_charset_info, a);
}
/**************************************************************************
Determines the connection character set.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
struct charset_info_st*
innobase_get_charset(
/*=================*/
/* out: connection character set */
void* mysql_thd) /* in: MySQL thread handle */
{
return(((THD*) mysql_thd)->charset());
}
/*************************************************************************
Creates a temporary file. */
extern "C"
......@@ -1135,23 +1205,70 @@ innobase_invalidate_query_cache(
}
/*********************************************************************
Get the quote character to be used in SQL identifiers.
Display an SQL identifier.
This definition must match the one in innobase/ut/ut0ut.c! */
extern "C"
int
mysql_get_identifier_quote_char(
/*============================*/
/* out: quote character to be
used in SQL identifiers; EOF if none */
void
innobase_print_identifier(
/*======================*/
FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */
ulint namelen)/* in: length of name */
{
const char* s = name;
char* qname = NULL;
int q;
if (table_id) {
/* Decode the table name. The filename_to_tablename()
function expects a NUL-terminated string. The input and
output strings buffers must not be shared. The function
only produces more output when the name contains other
characters than [0-9A-Z_a-z]. */
char* temp_name = my_malloc(namelen + 1, MYF(MY_WME));
uint qnamelen = namelen
+ (1 + sizeof srv_mysql50_table_name_prefix);
if (temp_name) {
qname = my_malloc(qnamelen, MYF(MY_WME));
if (qname) {
memcpy(temp_name, name, namelen);
temp_name[namelen] = 0;
s = qname;
namelen = filename_to_tablename(temp_name,
qname, qnamelen);
}
my_free(temp_name, MYF(0));
}
}
if (!trx || !trx->mysql_thd) {
return(EOF);
q = '"';
} else {
/* TODO: convert from UTF-8 to trx->mysql_thd->charset() ? */
q = get_quote_char_for_identifier((THD*) trx->mysql_thd,
s, (int) namelen);
}
return(get_quote_char_for_identifier((THD*) trx->mysql_thd,
name, (int) namelen));
if (q == EOF) {
fwrite(s, 1, namelen, f);
} else {
const char* e = s + namelen;
putc(q, f);
while (s < e) {
int c = *s++;
if (c == q) {
putc(c, f);
}
putc(c, f);
}
putc(q, f);
}
my_free(qname, MYF(MY_ALLOW_ZERO_PTR));
}
/**************************************************************************
......@@ -1267,6 +1384,24 @@ innobase_init(void)
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
#ifdef UNIV_DEBUG
static const char test_filename[] = "-@";
char test_tablename[sizeof test_filename
+ sizeof srv_mysql50_table_name_prefix];
if ((sizeof test_tablename) - 1
!= filename_to_tablename(test_filename, test_tablename,
sizeof test_tablename)
|| strncmp(test_tablename,
srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix)
|| strcmp(test_tablename
+ sizeof srv_mysql50_table_name_prefix,
test_filename)) {
sql_print_error("tablename encoding has been changed");
goto error;
}
#endif /* UNIV_DEBUG */
/* Check that values don't overflow on 32-bit systems. */
if (sizeof(ulint) == 4) {
if (innobase_buffer_pool_size > UINT_MAX32) {
......@@ -4690,7 +4825,7 @@ ha_innobase::create(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
......@@ -4786,20 +4921,9 @@ ha_innobase::create(
}
}
if (current_thd->query != NULL) {
LEX_STRING q;
if (thd->convert_string(&q, system_charset_info,
current_thd->query,
current_thd->query_length,
current_thd->charset())) {
error = HA_ERR_OUT_OF_MEM;
goto cleanup;
}
if (thd->query != NULL) {
error = row_table_add_foreign_constraints(trx,
q.str, norm_name,
thd->query, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE);
error = convert_error_code_to_mysql(error, NULL);
......@@ -4955,7 +5079,7 @@ ha_innobase::delete_table(
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
......
......@@ -44,18 +44,6 @@ dict_get_db_name_len(
/* out: database name length */
const char* name); /* in: table name in the form
dbname '/' tablename */
/*************************************************************************
Accepts a specified string. Comparisons are case-insensitive. */
const char*
dict_accept(
/*========*/
/* out: if string was accepted, the pointer
is moved after that, else ptr is returned */
const char* ptr, /* in: scan from this */
const char* string, /* in: accept only this string as the next
non-whitespace string */
ibool* success);/* out: TRUE if accepted */
/************************************************************************
Decrements the count of open MySQL handles to a table. */
......@@ -219,6 +207,17 @@ dict_table_referenced_by_foreign_key(
/* out: TRUE if table is referenced by a
foreign key */
dict_table_t* table); /* in: InnoDB table */
/**************************************************************************
Determines whether a string starts with the specified keyword. */
ibool
dict_str_starts_with_keyword(
/*=========================*/
/* out: TRUE if str starts
with keyword */
void* mysql_thd, /* in: MySQL thread handle */
const char* str, /* in: string to scan for keyword */
const char* keyword); /* in: keyword to look for */
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
......
......@@ -18,6 +18,9 @@ Created 10/10/1995 Heikki Tuuri
extern const char* srv_main_thread_op_info;
/* Prefix used by MySQL to indicate pre-5.1 table name encoding */
extern const char srv_mysql50_table_name_prefix[9];
/* When this event is set the lock timeout and InnoDB monitor
thread starts running */
extern os_event_t srv_lock_timeout_thread_event;
......
......@@ -224,6 +224,7 @@ ut_print_name(
/*==========*/
FILE* f, /* in: output stream */
struct trx_struct*trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name); /* in: name to print */
/**************************************************************************
......@@ -234,6 +235,7 @@ ut_print_namel(
/*===========*/
FILE* f, /* in: output stream */
struct trx_struct*trx, /* in: transaction (NULL=no quotes) */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */
ulint namelen);/* in: length of name */
......
......@@ -1860,7 +1860,7 @@ lock_rec_enqueue_waiting(
fputs(
" InnoDB: Error: a record lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr);
ut_print_name(stderr, trx, index->table_name);
ut_print_name(stderr, trx, TRUE, index->table_name);
fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr);
......@@ -1899,7 +1899,7 @@ lock_rec_enqueue_waiting(
if (lock_print_waits) {
fprintf(stderr, "Lock wait for trx %lu in index ",
(ulong) ut_dulint_get_low(trx->id));
ut_print_name(stderr, trx, index->name);
ut_print_name(stderr, trx, FALSE, index->name);
}
#endif /* UNIV_DEBUG */
......@@ -3555,7 +3555,7 @@ lock_table_enqueue_waiting(
fputs(
" InnoDB: Error: a table lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr);
ut_print_name(stderr, trx, table->name);
ut_print_name(stderr, trx, TRUE, table->name);
fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr);
......@@ -4074,7 +4074,8 @@ lock_table_print(
ut_a(lock_get_type(lock) == LOCK_TABLE);
fputs("TABLE LOCK table ", file);
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
ut_print_name(file, lock->trx, TRUE,
lock->un_member.tab_lock.table->name);
fprintf(file, " trx id %lu %lu",
(ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low);
......
......@@ -601,7 +601,7 @@ row_ins_set_detailed(
rewind(srv_misc_tmpfile);
if (os_file_set_eof(srv_misc_tmpfile)) {
ut_print_name(srv_misc_tmpfile, trx,
ut_print_name(srv_misc_tmpfile, trx, TRUE,
foreign->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format(
srv_misc_tmpfile,
......@@ -643,22 +643,22 @@ row_ins_foreign_report_err(
trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
TRUE);
putc('\n', ef);
fputs(errstr, ef);
fputs(" in parent table, in index ", ef);
ut_print_name(ef, trx, foreign->referenced_index->name);
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
if (entry) {
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
}
fputs("\nBut in child table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(", in index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name);
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
if (rec) {
fputs(", there is a record:\n", ef);
rec_print(ef, rec, foreign->foreign_index);
......@@ -696,20 +696,20 @@ row_ins_foreign_report_add_err(
fputs(" Transaction:\n", ef);
trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
TRUE);
fputs("\nTrying to add in child table, in index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name);
ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
if (entry) {
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
}
fputs("\nBut in parent table ", ef);
ut_print_name(ef, trx, foreign->referenced_table_name);
ut_print_name(ef, trx, TRUE, foreign->referenced_table_name);
fputs(", in index ", ef);
ut_print_name(ef, trx, foreign->referenced_index->name);
ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
fputs(",\nthe closest match we can find is record:\n", ef);
if (rec && page_rec_is_supremum(rec)) {
/* If the cursor ended on a supremum record, it is better
......@@ -1277,16 +1277,19 @@ row_ins_check_foreign_constraint(
fputs(" Transaction:\n", ef);
trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
ut_print_name(ef, trx, TRUE,
foreign->foreign_table_name);
fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef,
trx, foreign, TRUE);
fputs("\nTrying to add to index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name);
ut_print_name(ef, trx, FALSE,
foreign->foreign_index->name);
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
fputs("\nBut the parent table ", ef);
ut_print_name(ef, trx, foreign->referenced_table_name);
ut_print_name(ef, trx, TRUE,
foreign->referenced_table_name);
fputs("\nor its .ibd file does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex);
......
This diff is collapsed.
......@@ -480,12 +480,12 @@ row_build_row_ref_in_tuple(
ut_a(ref && index && rec);
if (!index->table) {
if (UNIV_UNLIKELY(!index->table)) {
fputs("InnoDB: table ", stderr);
notfound:
ut_print_name(stderr, trx, index->table_name);
ut_print_name(stderr, trx, TRUE, index->table_name);
fputs(" for index ", stderr);
ut_print_name(stderr, trx, index->name);
ut_print_name(stderr, trx, FALSE, index->name);
fputs(" not found\n", stderr);
ut_error;
}
......
......@@ -3248,7 +3248,7 @@ row_search_for_mysql(
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name ",
(ulong) prebuilt->magic_n);
ut_print_name(stderr, trx, prebuilt->table->name);
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption(prebuilt);
......@@ -3534,15 +3534,13 @@ stderr);
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& prebuilt->select_lock_type != LOCK_NONE
&& trx->mysql_query_str) {
&& trx->mysql_query_str && trx->mysql_thd) {
/* Scan the MySQL query string; check if SELECT is the first
word there */
ibool success;
dict_accept(*trx->mysql_query_str, "SELECT", &success);
if (success) {
if (dict_str_starts_with_keyword(trx->mysql_thd,
*trx->mysql_query_str, "SELECT")) {
/* It is a plain locking SELECT and the isolation
level is low: do not lock gaps */
......
......@@ -68,6 +68,9 @@ ibool srv_error_monitor_active = FALSE;
const char* srv_main_thread_op_info = "";
/* Prefix used by MySQL to indicate pre-5.1 table name encoding */
const char srv_mysql50_table_name_prefix[9] = "#mysql50#";
/* Server parameters which are read from the initfile */
/* The following three are dir paths which are catenated before file
......
......@@ -843,7 +843,7 @@ trx_undo_update_rec_get_update(
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n"
"InnoDB: Run also CHECK TABLE ",
(ulong) dict_index_get_n_fields(index));
ut_print_name(stderr, trx, index->table_name);
ut_print_name(stderr, trx, TRUE, index->table_name);
fprintf(stderr, "\n"
"InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
(ulong) n_fields, (ulong) i, ptr);
......
......@@ -241,7 +241,7 @@ trx_rollback_to_savepoint_for_mysql(
if (trx->conc_state == TRX_NOT_STARTED) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: transaction has a savepoint ", stderr);
ut_print_name(stderr, trx, savep->name);
ut_print_name(stderr, trx, FALSE, savep->name);
fputs(" though it is not started\n", stderr);
return(DB_ERROR);
}
......@@ -544,7 +544,7 @@ trx_rollback_or_clean_all_without_sess(
if (table) {
fputs("InnoDB: Table found: dropping table ", stderr);
ut_print_name(stderr, trx, table->name);
ut_print_name(stderr, trx, TRUE, table->name);
fputs(" in recovery\n", stderr);
err = row_drop_table_for_mysql(table->name, trx, TRUE);
......
......@@ -20,18 +20,20 @@ Created 5/11/1994 Heikki Tuuri
ibool ut_always_false = FALSE;
#ifndef UNIV_HOTBACKUP
/*********************************************************************
Get the quote character to be used in SQL identifiers.
Display an SQL identifier.
This definition must match the one in sql/ha_innodb.cc! */
extern
int
mysql_get_identifier_quote_char(
/*============================*/
/* out: quote character to be
used in SQL identifiers; EOF if none */
void
innobase_print_identifier(
/*======================*/
FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */
ulint namelen);/* in: length of name */
#endif /* !UNIV_HOTBACKUP */
/************************************************************
Gets the high 32 bits in a ulint. That is makes a shift >> 32,
......@@ -398,9 +400,10 @@ ut_print_name(
/*==========*/
FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name) /* in: name to print */
{
ut_print_namel(f, trx, name, strlen(name));
ut_print_namel(f, trx, table_id, name, strlen(name));
}
/**************************************************************************
......@@ -411,29 +414,27 @@ ut_print_namel(
/*===========*/
FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction (NULL=no quotes) */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */
ulint namelen)/* in: length of name */
{
const char* s = name;
const char* e = s + namelen;
#ifdef UNIV_HOTBACKUP
int q = '"';
fwrite(name, 1, namelen, f);
#else
int q = mysql_get_identifier_quote_char(trx, name, namelen);
#endif
if (q == EOF) {
fwrite(name, 1, namelen, f);
return;
char* slash = strchr(name, '/');
if (UNIV_LIKELY_NULL(slash)) {
/* Print the database name and table name separately. */
ut_ad(table_id);
innobase_print_identifier(f, trx, TRUE, name, slash - name);
putc('.', f);
innobase_print_identifier(f, trx, TRUE, slash + 1,
namelen - (slash - name) - 1);
} else {
innobase_print_identifier(f, trx, table_id, name, namelen);
}
putc(q, f);
while (s < e) {
int c = *s++;
if (c == q) {
putc(c, f);
}
putc(c, f);
}
putc(q, f);
#endif
}
/**************************************************************************
......
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