mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fixed parsing of column names and foreign key constraints in Innobase to handle quoted identifiers and identifiers with space. (Bug #1725)
Fix optimizer tuning bug when first used key part was a constant. (Bug #1679)
This commit is contained in:
@ -2138,19 +2138,37 @@ dict_scan_col(
|
|||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`' || *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;
|
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 != '`'
|
while (!isspace(*ptr) && *ptr != ',' && *ptr != ')'
|
||||||
&& *ptr != '\0') {
|
&& *ptr != '\0') {
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
|
}
|
||||||
|
*column_name_len = (ulint)(ptr - old_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
*column_name_len = (ulint)(ptr - old_ptr);
|
|
||||||
|
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
*success = TRUE;
|
*success = TRUE;
|
||||||
@ -2161,9 +2179,9 @@ dict_scan_col(
|
|||||||
|
|
||||||
col = dict_table_get_nth_col(table, i);
|
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,
|
&& 0 == ut_cmp_in_lower_case(col->name, old_ptr,
|
||||||
(ulint)(ptr - old_ptr))) {
|
*column_name_len)) {
|
||||||
/* Found */
|
/* Found */
|
||||||
|
|
||||||
*success = TRUE;
|
*success = TRUE;
|
||||||
@ -2175,10 +2193,6 @@ dict_scan_col(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2200,6 +2214,7 @@ dict_scan_table_name(
|
|||||||
char* dot_ptr = NULL;
|
char* dot_ptr = NULL;
|
||||||
char* old_ptr;
|
char* old_ptr;
|
||||||
ulint i;
|
ulint i;
|
||||||
|
char quote = 0;
|
||||||
|
|
||||||
*success = FALSE;
|
*success = FALSE;
|
||||||
*table = NULL;
|
*table = NULL;
|
||||||
@ -2213,14 +2228,16 @@ dict_scan_table_name(
|
|||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`' || *ptr == '"') {
|
||||||
ptr++;
|
quote= *ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_ptr = ptr;
|
old_ptr = ptr;
|
||||||
|
|
||||||
while (!isspace(*ptr) && *ptr != '(' && *ptr != '`' && *ptr != '\0') {
|
while (*ptr != quote &&
|
||||||
if (*ptr == '.') {
|
(quote || (!isspace(*ptr) && *ptr != '(')) &&
|
||||||
|
*ptr != '\0') {
|
||||||
|
if (!quote && *ptr == '.') {
|
||||||
dot_ptr = ptr;
|
dot_ptr = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2273,7 +2290,7 @@ dict_scan_table_name(
|
|||||||
|
|
||||||
*table = dict_table_get_low(second_table_name);
|
*table = dict_table_get_low(second_table_name);
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr && *ptr == quote) {
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2293,7 +2310,7 @@ dict_scan_id(
|
|||||||
scannable */
|
scannable */
|
||||||
ulint* len) /* out: length of the id */
|
ulint* len) /* out: length of the id */
|
||||||
{
|
{
|
||||||
ibool scanned_backquote = FALSE;
|
char quote = 0;
|
||||||
|
|
||||||
*start = NULL;
|
*start = NULL;
|
||||||
|
|
||||||
@ -2306,23 +2323,23 @@ dict_scan_id(
|
|||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`' || *ptr == '"') {
|
||||||
scanned_backquote = TRUE;
|
quote = *ptr++;
|
||||||
ptr++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*start = ptr;
|
*start = ptr;
|
||||||
|
|
||||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')'
|
while (*ptr != quote &&
|
||||||
&& *ptr != '\0' && *ptr != '`') {
|
(!quote || (!isspace(*ptr) && *ptr != ',' && *ptr != '(' &&
|
||||||
|
*ptr != ')'))
|
||||||
|
&& *ptr != '\0') {
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*len = (ulint) (ptr - *start);
|
*len = (ulint) (ptr - *start);
|
||||||
|
|
||||||
if (scanned_backquote) {
|
if (quote) {
|
||||||
if (*ptr == '`') {
|
if (*ptr == quote) {
|
||||||
ptr++;
|
ptr++;
|
||||||
} else {
|
} else {
|
||||||
/* Syntax error */
|
/* Syntax error */
|
||||||
|
@ -1243,3 +1243,6 @@ a
|
|||||||
3
|
3
|
||||||
4
|
4
|
||||||
drop table t1;
|
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;
|
||||||
|
@ -869,3 +869,12 @@ truncate table t1;
|
|||||||
insert into t1 (a) values (NULL),(NULL);
|
insert into t1 (a) values (NULL),(NULL);
|
||||||
SELECT * from t1;
|
SELECT * from t1;
|
||||||
drop table 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;
|
||||||
|
@ -538,7 +538,6 @@ select_export::~select_export()
|
|||||||
int
|
int
|
||||||
select_export::prepare(List<Item> &list)
|
select_export::prepare(List<Item> &list)
|
||||||
{
|
{
|
||||||
char path[FN_REFLEN];
|
|
||||||
uint option=4;
|
uint option=4;
|
||||||
bool blob_flag=0;
|
bool blob_flag=0;
|
||||||
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
|
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
|
||||||
@ -739,9 +738,13 @@ err:
|
|||||||
void select_export::send_error(uint errcode,const char *err)
|
void select_export::send_error(uint errcode,const char *err)
|
||||||
{
|
{
|
||||||
::send_error(&thd->net,errcode,err);
|
::send_error(&thd->net,errcode,err);
|
||||||
(void) end_io_cache(&cache);
|
if (file > 0)
|
||||||
(void) my_close(file,MYF(0));
|
{
|
||||||
file= -1;
|
(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)
|
void select_dump::send_error(uint errcode,const char *err)
|
||||||
{
|
{
|
||||||
::send_error(&thd->net,errcode,err);
|
::send_error(&thd->net,errcode,err);
|
||||||
(void) end_io_cache(&cache);
|
if (file > 0)
|
||||||
(void) my_close(file,MYF(0));
|
{
|
||||||
(void) my_delete(path,MYF(0)); // Delete file on error
|
(void) end_io_cache(&cache);
|
||||||
file= -1;
|
(void) my_close(file,MYF(0));
|
||||||
|
(void) my_delete(path,MYF(0)); // Delete file on error
|
||||||
|
file= -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -665,11 +665,13 @@ class select_export :public select_result {
|
|||||||
File file;
|
File file;
|
||||||
IO_CACHE cache;
|
IO_CACHE cache;
|
||||||
ha_rows row_count;
|
ha_rows row_count;
|
||||||
|
char path[FN_REFLEN];
|
||||||
uint field_term_length;
|
uint field_term_length;
|
||||||
int field_sep_char,escape_char,line_sep_char;
|
int field_sep_char,escape_char,line_sep_char;
|
||||||
bool fixed_row_size;
|
bool fixed_row_size;
|
||||||
public:
|
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();
|
~select_export();
|
||||||
int prepare(List<Item> &list);
|
int prepare(List<Item> &list);
|
||||||
bool send_fields(List<Item> &list,
|
bool send_fields(List<Item> &list,
|
||||||
|
@ -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;
|
read_time+=record_count/(double) TIME_FOR_COMPARE;
|
||||||
if (join->sort_by_table &&
|
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
|
read_time+=record_count; // We have to make a temp table
|
||||||
if (read_time < join->best_read)
|
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;
|
uint max_key_part=0;
|
||||||
|
|
||||||
/* Test how we can use keys */
|
/* 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 ;)
|
for (keyuse=s->keyuse ; keyuse->table == table ;)
|
||||||
{
|
{
|
||||||
key_map found_part=0;
|
key_map found_part=0;
|
||||||
@ -2085,7 +2086,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||||||
will match
|
will match
|
||||||
*/
|
*/
|
||||||
if (table->quick_keys & ((key_map) 1 << key) &&
|
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];
|
tmp=records= (double) table->quick_rows[key];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2127,6 +2128,14 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||||||
}
|
}
|
||||||
records=(ulong) tmp;
|
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 */
|
/* Limit the number of matched rows */
|
||||||
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
|
||||||
|
Reference in New Issue
Block a user