diff options
-rw-r--r-- | innobase/dict/dict0dict.c | 75 | ||||
-rw-r--r-- | mysql-test/r/innodb.result | 3 | ||||
-rw-r--r-- | mysql-test/t/innodb.test | 9 | ||||
-rw-r--r-- | sql/sql_class.cc | 22 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 15 |
6 files changed, 87 insertions, 41 deletions
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index a576a886b97..dc7acfcba36 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2138,19 +2138,37 @@ dict_scan_col( return(ptr); } - if (*ptr == '`') { - ptr++; - } - - old_ptr = ptr; + if (*ptr == '`' || *ptr == '"') { + /* + The identifier is quoted. Search for end quote. + We can't use the general code here as the name may contain + special characters like space. + */ + char quote= *ptr++; + + old_ptr= ptr; + /* + The colum name should always end with 'quote' but we check for + end zero just to be safe if this is called outside of MySQL + */ + while (*ptr && *ptr != quote) + ptr++; + *column_name_len = (ulint)(ptr - old_ptr); + + if (*ptr) /* Skip end quote */ + ptr++; + } + else + { + old_ptr = ptr; - while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' && *ptr != '`' - && *ptr != '\0') { - + while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' + && *ptr != '\0') { ptr++; + } + *column_name_len = (ulint)(ptr - old_ptr); } - *column_name_len = (ulint)(ptr - old_ptr); if (table == NULL) { *success = TRUE; @@ -2161,9 +2179,9 @@ dict_scan_col( col = dict_table_get_nth_col(table, i); - if (ut_strlen(col->name) == (ulint)(ptr - old_ptr) + if (ut_strlen(col->name) == *column_name_len && 0 == ut_cmp_in_lower_case(col->name, old_ptr, - (ulint)(ptr - old_ptr))) { + *column_name_len)) { /* Found */ *success = TRUE; @@ -2175,10 +2193,6 @@ dict_scan_col( } } - if (*ptr == '`') { - ptr++; - } - return(ptr); } @@ -2200,6 +2214,7 @@ dict_scan_table_name( char* dot_ptr = NULL; char* old_ptr; ulint i; + char quote = 0; *success = FALSE; *table = NULL; @@ -2213,14 +2228,16 @@ dict_scan_table_name( return(ptr); } - if (*ptr == '`') { - ptr++; + if (*ptr == '`' || *ptr == '"') { + quote= *ptr++; } old_ptr = ptr; - while (!isspace(*ptr) && *ptr != '(' && *ptr != '`' && *ptr != '\0') { - if (*ptr == '.') { + while (*ptr != quote && + (quote || (!isspace(*ptr) && *ptr != '(')) && + *ptr != '\0') { + if (!quote && *ptr == '.') { dot_ptr = ptr; } @@ -2273,7 +2290,7 @@ dict_scan_table_name( *table = dict_table_get_low(second_table_name); - if (*ptr == '`') { + if (*ptr && *ptr == quote) { ptr++; } @@ -2293,7 +2310,7 @@ dict_scan_id( scannable */ ulint* len) /* out: length of the id */ { - ibool scanned_backquote = FALSE; + char quote = 0; *start = NULL; @@ -2306,23 +2323,23 @@ dict_scan_id( return(ptr); } - if (*ptr == '`') { - scanned_backquote = TRUE; - ptr++; + if (*ptr == '`' || *ptr == '"') { + quote = *ptr++; } *start = ptr; - while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')' - && *ptr != '\0' && *ptr != '`') { - + while (*ptr != quote && + (!quote || (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && + *ptr != ')')) + && *ptr != '\0') { ptr++; } *len = (ulint) (ptr - *start); - if (scanned_backquote) { - if (*ptr == '`') { + if (quote) { + if (*ptr == quote) { ptr++; } else { /* Syntax error */ diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index ce5491a718f..ca4a49fea4e 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1243,3 +1243,6 @@ a 3 4 drop table t1; +CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) TYPE=INNODB; +CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) TYPE=INNODB; +drop table t1,t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 7cc509caf74..51fadccdc1c 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -869,3 +869,12 @@ truncate table t1; insert into t1 (a) values (NULL),(NULL); SELECT * from t1; drop table t1; + +# +# Test dictionary handling with spaceand quoting +# + +CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) TYPE=INNODB; +CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) TYPE=INNODB; +#show create table t2; +drop table t1,t2; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3ea61da28fc..fc83131e98a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -538,7 +538,6 @@ select_export::~select_export() int select_export::prepare(List<Item> &list) { - char path[FN_REFLEN]; uint option=4; bool blob_flag=0; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS @@ -739,9 +738,13 @@ err: void select_export::send_error(uint errcode,const char *err) { ::send_error(&thd->net,errcode,err); - (void) end_io_cache(&cache); - (void) my_close(file,MYF(0)); - file= -1; + if (file > 0) + { + (void) end_io_cache(&cache); + (void) my_close(file,MYF(0)); + (void) my_delete(path,MYF(0)); // Delete file on error + file= -1; + } } @@ -849,10 +852,13 @@ err: void select_dump::send_error(uint errcode,const char *err) { ::send_error(&thd->net,errcode,err); - (void) end_io_cache(&cache); - (void) my_close(file,MYF(0)); - (void) my_delete(path,MYF(0)); // Delete file on error - file= -1; + if (file > 0) + { + (void) end_io_cache(&cache); + (void) my_close(file,MYF(0)); + (void) my_delete(path,MYF(0)); // Delete file on error + file= -1; + } } diff --git a/sql/sql_class.h b/sql/sql_class.h index f4fc7b4770f..d96c6bb53cc 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -665,11 +665,13 @@ class select_export :public select_result { File file; IO_CACHE cache; ha_rows row_count; + char path[FN_REFLEN]; uint field_term_length; int field_sep_char,escape_char,line_sep_char; bool fixed_row_size; public: - select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {} + select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) + { path[0]=0; } ~select_export(); int prepare(List<Item> &list); bool send_fields(List<Item> &list, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e3bd3c8b570..36ef97cbf30 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1912,7 +1912,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, read_time+=record_count/(double) TIME_FOR_COMPARE; if (join->sort_by_table && - join->sort_by_table != join->positions[join->const_tables].table->table) + join->sort_by_table != + join->positions[join->const_tables].table->table) read_time+=record_count; // We have to make a temp table if (read_time < join->best_read) { @@ -1946,7 +1947,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, uint max_key_part=0; /* Test how we can use keys */ - rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; /* Assumed records/key */ + rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key for (keyuse=s->keyuse ; keyuse->table == table ;) { key_map found_part=0; @@ -2085,7 +2086,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, will match */ if (table->quick_keys & ((key_map) 1 << key) && - table->quick_key_parts[key] <= max_key_part) + table->quick_key_parts[key] == max_key_part) tmp=records= (double) table->quick_rows[key]; else { @@ -2127,6 +2128,14 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, } records=(ulong) tmp; } + /* + If quick_select was used on a part of this key, we know + the maximum number of rows that the key can match. + */ + if (table->quick_keys & ((key_map) 1 << key) && + table->quick_key_parts[key] <= max_key_part && + records > (double) table->quick_rows[key]) + tmp= records= (double) table->quick_rows[key]; } /* Limit the number of matched rows */ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); |