diff options
author | msvensson@pilot.mysql.com <> | 2007-02-06 14:48:22 +0100 |
---|---|---|
committer | msvensson@pilot.mysql.com <> | 2007-02-06 14:48:22 +0100 |
commit | d018030b20c8b4ca57d20322619de2fd670a05bc (patch) | |
tree | 11ccd2413b305f3797da63237ce98b416af8dd84 /sql | |
parent | 61686e85566876159de6bf7d5a92ee8a3dfedaeb (diff) | |
parent | ede3afe470a88bf1d4bc96d8ee5bce069569d10f (diff) | |
download | mariadb-git-d018030b20c8b4ca57d20322619de2fd670a05bc.tar.gz |
Merge 192.168.0.10:mysql/mysql-5.0-maint
into pilot.mysql.com:/home/msvensson/mysql/mysql-5.0-maint
Diffstat (limited to 'sql')
-rw-r--r-- | sql/examples/ha_tina.cc | 1 | ||||
-rw-r--r-- | sql/filesort.cc | 6 | ||||
-rw-r--r-- | sql/gen_lex_hash.cc | 22 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 502 | ||||
-rw-r--r-- | sql/ha_myisammrg.cc | 39 | ||||
-rw-r--r-- | sql/item.cc | 5 | ||||
-rw-r--r-- | sql/item_subselect.cc | 4 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 9 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/mysqld.cc | 34 | ||||
-rw-r--r-- | sql/mysqld.cc.rej | 161 | ||||
-rw-r--r-- | sql/opt_range.cc | 12 | ||||
-rw-r--r-- | sql/opt_sum.cc | 10 | ||||
-rw-r--r-- | sql/sql_base.cc | 51 | ||||
-rw-r--r-- | sql/sql_delete.cc | 6 | ||||
-rw-r--r-- | sql/sql_lex.h | 14 | ||||
-rw-r--r-- | sql/sql_parse.cc | 13 | ||||
-rw-r--r-- | sql/sql_select.cc | 60 | ||||
-rw-r--r-- | sql/sql_show.cc | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 16 | ||||
-rw-r--r-- | sql/table.cc | 1 |
21 files changed, 714 insertions, 256 deletions
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index f328a631d10..00f927aa7b7 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -276,6 +276,7 @@ bool tina_end() return FALSE; } + /* Finds the end of a line. Currently only supports files written on a UNIX OS. diff --git a/sql/filesort.cc b/sql/filesort.cc index 81600ce8a93..73f480aad02 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -428,7 +428,8 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH]; my_off_t record; TABLE *sort_form; - volatile THD::killed_state *killed= ¤t_thd->killed; + THD *thd= current_thd; + volatile THD::killed_state *killed= &thd->killed; handler *file; DBUG_ENTER("find_all_keys"); DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row"))); @@ -525,6 +526,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, } else file->unlock_row(); + /* It does not make sense to read more keys in case of a fatal error */ + if (thd->net.report_error) + DBUG_RETURN(HA_POS_ERROR); } if (quick_select) { diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 7abdb5f488c..2d78999017a 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -445,10 +445,24 @@ int main(int argc,char **argv) /* Broken up to indicate that it's not advice to you, gentle reader. */ printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n"); - printf("/* Copyright (C) 2001-2004 MySQL AB\n\ - This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ - and you are welcome to modify and redistribute it under the GPL license\n\ - \n*/\n\n"); + printf("\ +/* Copyright (C) 2001-2004 MySQL AB\n\ +\n\ + This program is free software; you can redistribute it and/or modify\n\ + it under the terms of the GNU General Public License as published by\n\ + the Free Software Foundation; version 2 of the License.\n\ +\n\ + This program is distributed in the hope that it will be useful,\n\ + but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ + GNU General Public License for more details.\n\ +\n\ + You should have received a copy of the GNU General Public License\n\ + along with this program; see the file COPYING. If not, write to the\n\ + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston\n\ + MA 02110-1301 USA. */\n\ +\n\ +"); /* Broken up to indicate that it's not advice to you, gentle reader. */ printf("/* Do " "not " "edit " "this " "file! This is generated by " diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 495c3f4f78f..39f8894ae89 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -120,6 +120,305 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, return; } + +/* + Convert TABLE object to MyISAM key and column definition + + SYNOPSIS + table2myisam() + table_arg in TABLE object. + keydef_out out MyISAM key definition. + recinfo_out out MyISAM column definition. + records_out out Number of fields. + + DESCRIPTION + This function will allocate and initialize MyISAM key and column + definition for further use in mi_create or for a check for underlying + table conformance in merge engine. + + RETURN VALUE + 0 OK + !0 error code +*/ + +int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, + MI_COLUMNDEF **recinfo_out, uint *records_out) +{ + uint i, j, recpos, minpos, fieldpos, temp_length, length; + enum ha_base_keytype type= HA_KEYTYPE_BINARY; + KEY *pos; + MI_KEYDEF *keydef; + MI_COLUMNDEF *recinfo, *recinfo_pos; + HA_KEYSEG *keyseg; + TABLE_SHARE *share= table_arg->s; + uint options= share->db_options_in_use; + DBUG_ENTER("table2myisam"); + if (!(my_multi_malloc(MYF(MY_WME), + recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF), + keydef_out, share->keys * sizeof(MI_KEYDEF), + &keyseg, + (share->key_parts + share->keys) * sizeof(HA_KEYSEG), + NullS))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */ + keydef= *keydef_out; + recinfo= *recinfo_out; + pos= table_arg->key_info; + for (i= 0; i < share->keys; i++, pos++) + { + keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL)); + keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? + (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) : + pos->algorithm; + keydef[i].seg= keyseg; + keydef[i].keysegs= pos->key_parts; + for (j= 0; j < pos->key_parts; j++) + { + Field *field= pos->key_part[j].field; + type= field->key_type(); + keydef[i].seg[j].flag= pos->key_part[j].key_part_flag; + + if (options & HA_OPTION_PACK_KEYS || + (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | + HA_SPACE_PACK_USED))) + { + if (pos->key_part[j].length > 8 && + (type == HA_KEYTYPE_TEXT || + type == HA_KEYTYPE_NUM || + (type == HA_KEYTYPE_BINARY && !field->zero_pack()))) + { + /* No blobs here */ + if (j == 0) + keydef[i].flag|= HA_PACK_KEY; + if (!(field->flags & ZEROFILL_FLAG) && + (field->type() == MYSQL_TYPE_STRING || + field->type() == MYSQL_TYPE_VAR_STRING || + ((int) (pos->key_part[j].length - field->decimals())) >= 4)) + keydef[i].seg[j].flag|= HA_SPACE_PACK; + } + else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16)) + keydef[i].flag|= HA_BINARY_PACK_KEY; + } + keydef[i].seg[j].type= (int) type; + keydef[i].seg[j].start= pos->key_part[j].offset; + keydef[i].seg[j].length= pos->key_part[j].length; + keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end= + keydef[i].seg[j].bit_length= 0; + keydef[i].seg[j].bit_pos= 0; + keydef[i].seg[j].language= field->charset()->number; + + if (field->null_ptr) + { + keydef[i].seg[j].null_bit= field->null_bit; + keydef[i].seg[j].null_pos= (uint) (field->null_ptr- + (uchar*) table_arg->record[0]); + } + else + { + keydef[i].seg[j].null_bit= 0; + keydef[i].seg[j].null_pos= 0; + } + if (field->type() == FIELD_TYPE_BLOB || + field->type() == FIELD_TYPE_GEOMETRY) + { + keydef[i].seg[j].flag|= HA_BLOB_PART; + /* save number of bytes used to pack length */ + keydef[i].seg[j].bit_start= (uint) (field->pack_length() - + share->blob_ptr_size); + } + else if (field->type() == FIELD_TYPE_BIT) + { + keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len; + keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs; + keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr - + (uchar*) table_arg->record[0]); + } + } + keyseg+= pos->key_parts; + } + if (table_arg->found_next_number_field) + keydef[share->next_number_index].flag|= HA_AUTO_KEY; + recpos= 0; + recinfo_pos= recinfo; + while (recpos < (uint) share->reclength) + { + Field **field, *found= 0; + minpos= share->reclength; + length= 0; + + for (field= table_arg->field; *field; field++) + { + if ((fieldpos= (*field)->offset()) >= recpos && + fieldpos <= minpos) + { + /* skip null fields */ + if (!(temp_length= (*field)->pack_length_in_rec())) + continue; /* Skip null-fields */ + if (! found || fieldpos < minpos || + (fieldpos == minpos && temp_length < length)) + { + minpos= fieldpos; + found= *field; + length= temp_length; + } + } + } + DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d", + (long) found, recpos, minpos, length)); + if (recpos != minpos) + { // Reserved space (Null bits?) + bzero((char*) recinfo_pos, sizeof(*recinfo_pos)); + recinfo_pos->type= (int) FIELD_NORMAL; + recinfo_pos++->length= (uint16) (minpos - recpos); + } + if (!found) + break; + + if (found->flags & BLOB_FLAG) + recinfo_pos->type= (int) FIELD_BLOB; + else if (found->type() == MYSQL_TYPE_VARCHAR) + recinfo_pos->type= FIELD_VARCHAR; + else if (!(options & HA_OPTION_PACK_RECORD)) + recinfo_pos->type= (int) FIELD_NORMAL; + else if (found->zero_pack()) + recinfo_pos->type= (int) FIELD_SKIP_ZERO; + else + recinfo_pos->type= (int) ((length <= 3 || + (found->flags & ZEROFILL_FLAG)) ? + FIELD_NORMAL : + found->type() == MYSQL_TYPE_STRING || + found->type() == MYSQL_TYPE_VAR_STRING ? + FIELD_SKIP_ENDSPACE : + FIELD_SKIP_PRESPACE); + if (found->null_ptr) + { + recinfo_pos->null_bit= found->null_bit; + recinfo_pos->null_pos= (uint) (found->null_ptr - + (uchar*) table_arg->record[0]); + } + else + { + recinfo_pos->null_bit= 0; + recinfo_pos->null_pos= 0; + } + (recinfo_pos++)->length= (uint16) length; + recpos= minpos + length; + DBUG_PRINT("loop", ("length: %d type: %d", + recinfo_pos[-1].length,recinfo_pos[-1].type)); + } + *records_out= (uint) (recinfo_pos - recinfo); + DBUG_RETURN(0); +} + + +/* + Check for underlying table conformance + + SYNOPSIS + check_definition() + t1_keyinfo in First table key definition + t1_recinfo in First table record definition + t1_keys in Number of keys in first table + t1_recs in Number of records in first table + t2_keyinfo in Second table key definition + t2_recinfo in Second table record definition + t2_keys in Number of keys in second table + t2_recs in Number of records in second table + strict in Strict check switch + + DESCRIPTION + This function compares two MyISAM definitions. By intention it was done + to compare merge table definition against underlying table definition. + It may also be used to compare dot-frm and MYI definitions of MyISAM + table as well to compare different MyISAM table definitions. + + For merge table it is not required that number of keys in merge table + must exactly match number of keys in underlying table. When calling this + function for underlying table conformance check, 'strict' flag must be + set to false, and converted merge definition must be passed as t1_*. + + Otherwise 'strict' flag must be set to 1 and it is not required to pass + converted dot-frm definition as t1_*. + + RETURN VALUE + 0 - Equal definitions. + 1 - Different definitions. +*/ + +int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, + uint t1_keys, uint t1_recs, + MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo, + uint t2_keys, uint t2_recs, bool strict) +{ + uint i, j; + DBUG_ENTER("check_definition"); + if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys)) + { + DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u", + t1_keys, t2_keys)); + DBUG_RETURN(1); + } + if (t1_recs != t2_recs) + { + DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u", + t1_recs, t2_recs)); + DBUG_RETURN(1); + } + for (i= 0; i < t1_keys; i++) + { + HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg; + HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg; + if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs || + t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) + { + DBUG_PRINT("error", ("Key %d has different definition", i)); + DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d", + t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg)); + DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d", + t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg)); + DBUG_RETURN(1); + } + for (j= t1_keyinfo[i].keysegs; j--;) + { + if (t1_keysegs[j].type != t2_keysegs[j].type || + t1_keysegs[j].language != t2_keysegs[j].language || + t1_keysegs[j].null_bit != t2_keysegs[j].null_bit || + t1_keysegs[j].length != t2_keysegs[j].length) + { + DBUG_PRINT("error", ("Key segment %d (key %d) has different " + "definition", j, i)); + DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, " + "t1_length=%d", + t1_keysegs[j].type, t1_keysegs[j].language, + t1_keysegs[j].null_bit, t1_keysegs[j].length)); + DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, " + "t2_length=%d", + t2_keysegs[j].type, t2_keysegs[j].language, + t2_keysegs[j].null_bit, t2_keysegs[j].length)); + + DBUG_RETURN(1); + } + } + } + for (i= 0; i < t1_recs; i++) + { + MI_COLUMNDEF *t1_rec= &t1_recinfo[i]; + MI_COLUMNDEF *t2_rec= &t2_recinfo[i]; + if (t1_rec->type != t2_rec->type || + t1_rec->length != t2_rec->length || + t1_rec->null_bit != t2_rec->null_bit) + { + DBUG_PRINT("error", ("Field %d has different definition", i)); + DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d", + t1_rec->type, t1_rec->length, t1_rec->null_bit)); + DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d", + t2_rec->type, t2_rec->length, t2_rec->null_bit)); + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} + + extern "C" { volatile int *killed_ptr(MI_CHECK *param) @@ -1429,192 +1728,31 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, HA_CREATE_INFO *info) { int error; - uint i,j,recpos,minpos,fieldpos,temp_length,length, create_flags= 0; - bool found_real_auto_increment=0; - enum ha_base_keytype type; + uint create_flags= 0, records; char buff[FN_REFLEN]; - KEY *pos; MI_KEYDEF *keydef; - MI_COLUMNDEF *recinfo,*recinfo_pos; - HA_KEYSEG *keyseg; + MI_COLUMNDEF *recinfo; + MI_CREATE_INFO create_info; TABLE_SHARE *share= table->s; uint options= share->db_options_in_use; DBUG_ENTER("ha_myisam::create"); - - type=HA_KEYTYPE_BINARY; // Keep compiler happy - if (!(my_multi_malloc(MYF(MY_WME), - &recinfo,(share->fields*2+2)* - sizeof(MI_COLUMNDEF), - &keydef, share->keys*sizeof(MI_KEYDEF), - &keyseg, - ((share->key_parts + share->keys) * - sizeof(HA_KEYSEG)), - NullS))) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - - pos=table_arg->key_info; - for (i=0; i < share->keys ; i++, pos++) - { - keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL)); - keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? - (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) : - pos->algorithm; - keydef[i].seg=keyseg; - keydef[i].keysegs=pos->key_parts; - for (j=0 ; j < pos->key_parts ; j++) - { - Field *field=pos->key_part[j].field; - type=field->key_type(); - keydef[i].seg[j].flag=pos->key_part[j].key_part_flag; - - if (options & HA_OPTION_PACK_KEYS || - (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | - HA_SPACE_PACK_USED))) - { - if (pos->key_part[j].length > 8 && - (type == HA_KEYTYPE_TEXT || - type == HA_KEYTYPE_NUM || - (type == HA_KEYTYPE_BINARY && !field->zero_pack()))) - { - /* No blobs here */ - if (j == 0) - keydef[i].flag|=HA_PACK_KEY; - if (!(field->flags & ZEROFILL_FLAG) && - (field->type() == MYSQL_TYPE_STRING || - field->type() == MYSQL_TYPE_VAR_STRING || - ((int) (pos->key_part[j].length - field->decimals())) - >= 4)) - keydef[i].seg[j].flag|=HA_SPACE_PACK; - } - else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16)) - keydef[i].flag|= HA_BINARY_PACK_KEY; - } - keydef[i].seg[j].type= (int) type; - keydef[i].seg[j].start= pos->key_part[j].offset; - keydef[i].seg[j].length= pos->key_part[j].length; - keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end= - keydef[i].seg[j].bit_length= 0; - keydef[i].seg[j].bit_pos= 0; - keydef[i].seg[j].language= field->charset()->number; - - if (field->null_ptr) - { - keydef[i].seg[j].null_bit=field->null_bit; - keydef[i].seg[j].null_pos= (uint) (field->null_ptr- - (uchar*) table_arg->record[0]); - } - else - { - keydef[i].seg[j].null_bit=0; - keydef[i].seg[j].null_pos=0; - } - if (field->type() == FIELD_TYPE_BLOB || - field->type() == FIELD_TYPE_GEOMETRY) - { - keydef[i].seg[j].flag|=HA_BLOB_PART; - /* save number of bytes used to pack length */ - keydef[i].seg[j].bit_start= (uint) (field->pack_length() - - share->blob_ptr_size); - } - else if (field->type() == FIELD_TYPE_BIT) - { - keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len; - keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs; - keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr - - (uchar*) table_arg->record[0]); - } - } - keyseg+=pos->key_parts; - } - - if (table_arg->found_next_number_field) - { - keydef[share->next_number_index].flag|= HA_AUTO_KEY; - found_real_auto_increment= share->next_number_key_offset == 0; - } - - recpos=0; recinfo_pos=recinfo; - while (recpos < (uint) share->reclength) - { - Field **field,*found=0; - minpos= share->reclength; - length=0; - - for (field=table_arg->field ; *field ; field++) - { - if ((fieldpos=(*field)->offset()) >= recpos && - fieldpos <= minpos) - { - /* skip null fields */ - if (!(temp_length= (*field)->pack_length_in_rec())) - continue; /* Skip null-fields */ - if (! found || fieldpos < minpos || - (fieldpos == minpos && temp_length < length)) - { - minpos=fieldpos; found= *field; length=temp_length; - } - } - } - DBUG_PRINT("loop",("found: 0x%lx recpos: %d minpos: %d length: %d", - (long) found, recpos, minpos, length)); - if (recpos != minpos) - { // Reserved space (Null bits?) - bzero((char*) recinfo_pos,sizeof(*recinfo_pos)); - recinfo_pos->type=(int) FIELD_NORMAL; - recinfo_pos++->length= (uint16) (minpos-recpos); - } - if (! found) - break; - - if (found->flags & BLOB_FLAG) - recinfo_pos->type= (int) FIELD_BLOB; - else if (found->type() == MYSQL_TYPE_VARCHAR) - recinfo_pos->type= FIELD_VARCHAR; - else if (!(options & HA_OPTION_PACK_RECORD)) - recinfo_pos->type= (int) FIELD_NORMAL; - else if (found->zero_pack()) - recinfo_pos->type= (int) FIELD_SKIP_ZERO; - else - recinfo_pos->type= (int) ((length <= 3 || - (found->flags & ZEROFILL_FLAG)) ? - FIELD_NORMAL : - found->type() == MYSQL_TYPE_STRING || - found->type() == MYSQL_TYPE_VAR_STRING ? - FIELD_SKIP_ENDSPACE : - FIELD_SKIP_PRESPACE); - if (found->null_ptr) - { - recinfo_pos->null_bit=found->null_bit; - recinfo_pos->null_pos= (uint) (found->null_ptr- - (uchar*) table_arg->record[0]); - } - else - { - recinfo_pos->null_bit=0; - recinfo_pos->null_pos=0; - } - (recinfo_pos++)->length= (uint16) length; - recpos=minpos+length; - DBUG_PRINT("loop",("length: %d type: %d", - recinfo_pos[-1].length,recinfo_pos[-1].type)); - - } - MI_CREATE_INFO create_info; - bzero((char*) &create_info,sizeof(create_info)); + if ((error= table2myisam(table_arg, &keydef, &recinfo, &records))) + DBUG_RETURN(error); /* purecov: inspected */ + bzero((char*) &create_info, sizeof(create_info)); create_info.max_rows= share->max_rows; create_info.reloc_rows= share->min_rows; - create_info.with_auto_increment=found_real_auto_increment; - create_info.auto_increment=(info->auto_increment_value ? - info->auto_increment_value -1 : - (ulonglong) 0); + create_info.with_auto_increment= share->next_number_key_offset == 0; + create_info.auto_increment= (info->auto_increment_value ? + info->auto_increment_value -1 : + (ulonglong) 0); create_info.data_file_length= ((ulonglong) share->max_rows * - share->avg_row_length); - create_info.raid_type=info->raid_type; + share->avg_row_length); + create_info.raid_type= info->raid_type; create_info.raid_chunks= (info->raid_chunks ? info->raid_chunks : - RAID_DEFAULT_CHUNKS); + RAID_DEFAULT_CHUNKS); create_info.raid_chunksize= (info->raid_chunksize ? info->raid_chunksize : RAID_DEFAULT_CHUNKSIZE); - create_info.data_file_name= info->data_file_name; + create_info.data_file_name= info->data_file_name; create_info.index_file_name= info->index_file_name; if (info->options & HA_LEX_CREATE_TMP_TABLE) @@ -1627,13 +1765,13 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, create_flags|= HA_CREATE_DELAY_KEY_WRITE; /* TODO: Check that the following fn_format is really needed */ - error=mi_create(fn_format(buff,name,"","",2+4), - share->keys,keydef, - (uint) (recinfo_pos-recinfo), recinfo, - 0, (MI_UNIQUEDEF*) 0, - &create_info, create_flags); - - my_free((gptr) recinfo,MYF(0)); + error= mi_create(fn_format(buff, name, "", "", + MY_UNPACK_FILENAME|MY_REPLACE_EXT), + share->keys, keydef, + records, recinfo, + 0, (MI_UNIQUEDEF*) 0, + &create_info, create_flags); + my_free((gptr) recinfo, MYF(0)); DBUG_RETURN(error); } diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 09445f775de..8e24164abc9 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -66,6 +66,12 @@ static const char *ha_myisammrg_exts[] = { ".MRG", NullS }; +extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, + MI_COLUMNDEF **recinfo_out, uint *records_out); +extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, + uint t1_keys, uint t1_recs, + MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo, + uint t2_keys, uint t2_recs, bool strict); const char **ha_myisammrg::bas_ext() const { @@ -87,6 +93,12 @@ const char *ha_myisammrg::index_type(uint key_number) int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) { + MI_KEYDEF *keyinfo; + MI_COLUMNDEF *recinfo; + MYRG_TABLE *u_table; + uint recs; + uint keys= table->s->keys; + int error; char name_buff[FN_REFLEN]; DBUG_PRINT("info", ("ha_myisammrg::open")); @@ -109,18 +121,43 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) { DBUG_PRINT("error",("reclength: %lu mean_rec_length: %lu", table->s->reclength, mean_rec_length)); + error= HA_ERR_WRONG_MRG_TABLE_DEF; goto err; } + if ((error= table2myisam(table, &keyinfo, &recinfo, &recs))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM " + "key and column definition")); + goto err; + /* purecov: end */ + } + for (u_table= file->open_tables; u_table < file->end_table; u_table++) + { + if (check_definition(keyinfo, recinfo, keys, recs, + u_table->table->s->keyinfo, u_table->table->s->rec, + u_table->table->s->base.keys, + u_table->table->s->base.fields, false)) + { + my_free((gptr) recinfo, MYF(0)); + error= HA_ERR_WRONG_MRG_TABLE_DEF; + goto err; + } + } + my_free((gptr) recinfo, MYF(0)); #if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4 /* Merge table has more than 2G rows */ if (table->s->crashed) + { + error= HA_ERR_WRONG_MRG_TABLE_DEF; goto err; + } #endif return (0); err: myrg_close(file); file=0; - return (my_errno= HA_ERR_WRONG_MRG_TABLE_DEF); + return (my_errno= error); } int ha_myisammrg::close(void) diff --git a/sql/item.cc b/sql/item.cc index 0017b64ba0d..9a55eb25e2c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1242,7 +1242,10 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, if (type() == SUM_FUNC_ITEM && skip_registered && ((Item_sum *) this)->ref_by) return; - if (type() != SUM_FUNC_ITEM && with_sum_func) + if ((type() != SUM_FUNC_ITEM && with_sum_func) || + (type() == FUNC_ITEM && + (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC || + ((Item_func *) this)->functype() == Item_func::TRIG_COND_FUNC))) { /* Will split complicated items and ignore simple ones */ split_sum_func(thd, ref_pointer_array, fields); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e19815960a6..d61bb25e9b7 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -195,6 +195,10 @@ bool Item_subselect::exec() { int res; + if (thd->net.report_error) + /* Do not execute subselect in case of a fatal error */ + return 1; + res= engine->exec(); if (engine_changed) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 05498018386..737064a9713 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1054,7 +1054,8 @@ longlong Item_func_quarter::val_int() { DBUG_ASSERT(fixed == 1); TIME ltime; - (void) get_arg0_date(<ime, TIME_FUZZY_DATE); + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) + return 0; return (longlong) ((ltime.month+2)/3); } @@ -1668,6 +1669,7 @@ String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); TIME ltime; + longlong arg_val= args[0]->val_int(); if ((null_value=args[0]->null_value) || str->alloc(19)) { @@ -1675,7 +1677,7 @@ String *Item_func_sec_to_time::val_str(String *str) return (String*) 0; } - sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + sec_to_time(arg_val, args[0]->unsigned_flag, <ime); make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; @@ -1686,11 +1688,12 @@ longlong Item_func_sec_to_time::val_int() { DBUG_ASSERT(fixed == 1); TIME ltime; + longlong arg_val= args[0]->val_int(); if ((null_value=args[0]->null_value)) return 0; - sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + sec_to_time(arg_val, args[0]->unsigned_flag, <ime); return (ltime.neg ? -1 : 1) * ((ltime.hour)*10000 + ltime.minute*100 + ltime.second); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 899227fb0a6..1bde8306072 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -992,7 +992,8 @@ bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); void add_join_on(TABLE_LIST *b,Item *expr); -void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields); +void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, + SELECT_LEX *lex); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); void update_non_unique_table_error(TABLE_LIST *update, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9d13ef85aef..5a805b586fd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -198,12 +198,6 @@ inline void reset_floating_point_exceptions() } /* cplusplus */ - -#if defined(HAVE_LINUXTHREADS) -#define THR_KILL_SIGNAL SIGINT -#else -#define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads -#endif #define MYSQL_KILL_SIGNAL SIGTERM #ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R @@ -524,6 +518,7 @@ rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; pthread_cond_t COND_refresh,COND_thread_count, COND_global_read_lock; pthread_t signal_thread; pthread_attr_t connection_attrib; +static uint thr_kill_signal; File_parser_dummy_hook file_parser_dummy_hook; @@ -699,7 +694,7 @@ static void close_connections(void) DBUG_PRINT("info",("Waiting for select thread")); #ifndef DONT_USE_THR_ALARM - if (pthread_kill(select_thread,THR_CLIENT_ALARM)) + if (pthread_kill(select_thread, thr_client_alarm)) break; // allready dead #endif set_timespec(abstime, 2); @@ -2155,7 +2150,9 @@ static void init_signals(void) DBUG_ENTER("init_signals"); if (test_flags & TEST_SIGINT) - my_sigset(THR_KILL_SIGNAL,end_thread_signal); + { + my_sigset(thr_kill_signal, end_thread_signal); + } my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) @@ -2212,8 +2209,12 @@ static void init_signals(void) #endif sigaddset(&set,THR_SERVER_ALARM); if (test_flags & TEST_SIGINT) - sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT - sigdelset(&set,THR_CLIENT_ALARM); // For alarms + { + // May be SIGINT + sigdelset(&set, thr_kill_signal); + } + // For alarms + sigdelset(&set, thr_client_alarm); sigprocmask(SIG_SETMASK,&set,NULL); pthread_sigmask(SIG_SETMASK,&set,NULL); DBUG_VOID_RETURN; @@ -2277,24 +2278,20 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) */ init_thr_alarm(max_connections + global_system_variables.max_insert_delayed_threads + 10); -#if SIGINT != THR_KILL_SIGNAL - if (test_flags & TEST_SIGINT) + if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT)) { (void) sigemptyset(&set); // Setup up SIGINT for debug (void) sigaddset(&set,SIGINT); // For debugging (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL); } -#endif (void) sigemptyset(&set); // Setup up SIGINT for debug #ifdef USE_ONE_SIGNAL_HAND (void) sigaddset(&set,THR_SERVER_ALARM); // For alarms #endif #ifndef IGNORE_SIGHUP_SIGQUIT (void) sigaddset(&set,SIGQUIT); -#if THR_CLIENT_ALARM != SIGHUP (void) sigaddset(&set,SIGHUP); #endif -#endif (void) sigaddset(&set,SIGTERM); (void) sigaddset(&set,SIGTSTP); @@ -3352,6 +3349,13 @@ int main(int argc, char **argv) DEBUGGER_OFF; + /* Set signal used to kill MySQL */ +#if defined(SIGUSR2) + thr_kill_signal= thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2; +#else + thr_kill_signal= SIGINT; +#endif + #ifdef _CUSTOMSTARTUPCONFIG_ if (_cust_check_startup()) { diff --git a/sql/mysqld.cc.rej b/sql/mysqld.cc.rej new file mode 100644 index 00000000000..bd7338143ae --- /dev/null +++ b/sql/mysqld.cc.rej @@ -0,0 +1,161 @@ +*************** +*** 177,188 **** + } /* cplusplus */ + + +- #if defined(HAVE_LINUXTHREADS) +- #define THR_KILL_SIGNAL SIGINT +- #else +- #define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads +- #endif +- + #ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R + #include <sys/types.h> + #else +--- 177,182 ---- + } /* cplusplus */ + + + #ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R + #include <sys/types.h> + #else +*************** +*** 505,510 **** + static void clean_up_mutexes(void); + static int test_if_case_insensitive(const char *dir_name); + static void create_pid_file(); + + /**************************************************************************** + ** Code to end mysqld +--- 499,505 ---- + static void clean_up_mutexes(void); + static int test_if_case_insensitive(const char *dir_name); + static void create_pid_file(); ++ static uint get_thread_lib(void); + + /**************************************************************************** + ** Code to end mysqld +*************** +*** 544,550 **** + DBUG_PRINT("info",("Waiting for select_thread")); + + #ifndef DONT_USE_THR_ALARM +! if (pthread_kill(select_thread,THR_CLIENT_ALARM)) + break; // allready dead + #endif + set_timespec(abstime, 2); +--- 539,546 ---- + DBUG_PRINT("info",("Waiting for select_thread")); + + #ifndef DONT_USE_THR_ALARM +! if (pthread_kill(select_thread, +! thd_lib_detected == THD_LIB_LT ? SIGALRM : SIGUSR1)) + break; // allready dead + #endif + set_timespec(abstime, 2); +*************** +*** 844,850 **** + sig,my_thread_id()); + } + #ifdef DONT_REMEMBER_SIGNAL +! sigset(sig,print_signal_warning); /* int. thread system calls */ + #endif + #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) + if (sig == SIGALRM) +--- 840,846 ---- + sig,my_thread_id()); + } + #ifdef DONT_REMEMBER_SIGNAL +! my_sigset(sig, print_signal_warning); /* int. thread system calls */ + #endif + #if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) + if (sig == SIGALRM) +*************** +*** 1841,1848 **** + DBUG_ENTER("init_signals"); + + if (test_flags & TEST_SIGINT) +! sigset(THR_KILL_SIGNAL,end_thread_signal); +! sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! + + if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) + { +--- 1837,1847 ---- + DBUG_ENTER("init_signals"); + + if (test_flags & TEST_SIGINT) +! { +! my_sigset(thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2, +! end_thread_signal); +! } +! my_sigset(THR_SERVER_ALARM, print_signal_warning); // Should never be called! + + if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) + { +*************** +*** 1877,1883 **** + #endif + (void) sigemptyset(&set); + #ifdef THREAD_SPECIFIC_SIGPIPE +! sigset(SIGPIPE,abort_thread); + sigaddset(&set,SIGPIPE); + #else + (void) signal(SIGPIPE,SIG_IGN); // Can't know which thread +--- 1876,1882 ---- + #endif + (void) sigemptyset(&set); + #ifdef THREAD_SPECIFIC_SIGPIPE +! my_sigset(SIGPIPE, abort_thread); + sigaddset(&set,SIGPIPE); + #else + (void) signal(SIGPIPE,SIG_IGN); // Can't know which thread +*************** +*** 2237,2244 **** + MY_INIT(argv[0]); // init my_sys library & pthreads + tzset(); // Set tzname + + start_time=time((time_t*) 0); +- + #ifdef OS2 + { + // fix timezone for daylight saving +--- 2236,2243 ---- + MY_INIT(argv[0]); // init my_sys library & pthreads + tzset(); // Set tzname + ++ thd_lib_detected= get_thread_lib(); + start_time=time((time_t*) 0); + #ifdef OS2 + { + // fix timezone for daylight saving +*************** +*** 5547,5552 **** + (void) my_write(file, (byte*) buff, (uint) (end-buff),MYF(MY_WME)); + (void) my_close(file, MYF(0)); + } + } + + +--- 5546,5567 ---- + (void) my_write(file, (byte*) buff, (uint) (end-buff),MYF(MY_WME)); + (void) my_close(file, MYF(0)); + } ++ } ++ ++ ++ static uint get_thread_lib(void) ++ { ++ char buff[64]; ++ ++ #ifdef _CS_GNU_LIBPTHREAD_VERSION ++ confstr(_CS_GNU_LIBPTHREAD_VERSION, buff, sizeof(buff)); ++ ++ if (!strncasecmp(buff, "NPTL", 4)) ++ return THD_LIB_NPTL; ++ else if (!strncasecmp(buff, "linuxthreads", 12)) ++ return THD_LIB_LT; ++ #endif ++ return THD_LIB_OTHER; + } + + diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 04bc24b718a..f0af4b7db2a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -193,6 +193,8 @@ public: } inline void merge_flags(SEL_ARG *arg) { maybe_flag|=arg->maybe_flag; } inline void maybe_smaller() { maybe_flag=1; } + /* Return true iff it's a single-point null interval */ + inline bool is_null_interval() { return maybe_null && max_value[0] == 1; } inline int cmp_min_to_min(SEL_ARG* arg) { return sel_cmp(field,min_value, arg->min_value, min_flag, arg->min_flag); @@ -452,6 +454,7 @@ typedef struct st_qsel_param { bool is_ror_scan; /* Number of ranges in the last checked tree->key */ uint n_ranges; + uint8 first_null_comp; /* first null component if any, 0 - otherwise */ } PARAM; class TABLE_READ_PLAN; @@ -5619,6 +5622,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) DBUG_ENTER("check_quick_select"); param->is_ror_scan= FALSE; + param->first_null_comp= 0; if (!tree) DBUG_RETURN(HA_POS_ERROR); // Can't use it @@ -5710,6 +5714,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, ha_rows records=0, tmp; uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length; char *tmp_min_key, *tmp_max_key; + uint8 save_first_null_comp= param->first_null_comp; param->max_key_part=max(param->max_key_part,key_tree->part); if (key_tree->left != &null_element) @@ -5747,6 +5752,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, param->is_ror_scan= FALSE; } + if (!param->first_null_comp && key_tree->is_null_interval()) + param->first_null_comp= key_tree->part+1; + if (key_tree->next_key_part && key_tree->next_key_part->part == key_tree->part+1 && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) @@ -5790,7 +5798,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME && min_key_length == max_key_length && - !memcmp(param->min_key,param->max_key,min_key_length)) + !memcmp(param->min_key,param->max_key,min_key_length) && + !param->first_null_comp) { tmp=1; // Max one record param->n_ranges++; @@ -5865,6 +5874,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, return tmp; records+=tmp; } + param->first_null_comp= save_first_null_comp; return records; } diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index e8bc15a93f1..9222e15ff91 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -67,9 +67,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond); GROUP BY part. RETURN VALUES - 0 No errors - 1 if all items were resolved - -1 on impossible conditions + 0 no errors + 1 if all items were resolved + HA_ERR_KEY_NOT_FOUND on impossible conditions OR an error number from my_base.h HA_ERR_... if a deadlock or a lock wait timeout happens, for example */ @@ -224,7 +224,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (error) { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) - return -1; // No rows matching WHERE + return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE /* HA_ERR_LOCK_DEADLOCK or some other error */ table->file->print_error(error, MYF(0)); return(error); @@ -311,7 +311,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (error) { if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) - return -1; // No rows matching WHERE + return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE /* HA_ERR_LOCK_DEADLOCK or some other error */ table->file->print_error(error, MYF(0)); return(error); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0949d4aa331..ad9cd5985d1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2945,7 +2945,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { List_iterator_fast<Natural_join_column> field_it(*(table_ref->join_columns)); - Natural_join_column *nj_col; + Natural_join_column *nj_col, *curr_nj_col; Field *found_field; Query_arena *arena, backup; DBUG_ENTER("find_field_in_natural_join"); @@ -2956,14 +2956,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, LINT_INIT(found_field); - for (;;) + for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col; + curr_nj_col= field_it++) { - if (!(nj_col= field_it++)) - DBUG_RETURN(NULL); - - if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) - break; + if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) + { + if (nj_col) + { + my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); + DBUG_RETURN(NULL); + } + nj_col= curr_nj_col; + } } + if (!nj_col) + DBUG_RETURN(NULL); if (nj_col->view_field) { @@ -3774,9 +3781,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { bool found= FALSE; const char *field_name_1; + /* true if field_name_1 is a member of using_fields */ + bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) goto err; field_name_1= nj_col_1->name(); + is_using_column_1= using_fields && + test_if_string_in_list(field_name_1, using_fields); + DBUG_PRINT ("info", ("field_name_1=%s.%s", + nj_col_1->table_name() ? nj_col_1->table_name() : "", + field_name_1)); /* Find a field with the same name in table_ref_2. @@ -3793,6 +3807,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); + DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", + cur_nj_col_2->table_name() ? + cur_nj_col_2->table_name() : "", + cur_field_name_2)); /* Compare the two columns and check for duplicate common fields. @@ -3800,10 +3818,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, table_ref_2 (then found == TRUE), or if a field in table_ref_2 was already matched by some previous field in table_ref_1 (then cur_nj_col_2->is_common == TRUE). + Note that it is too early to check the columns outside of the + USING list for ambiguity because they are not actually "referenced" + here. These columns must be checked only on unqualified reference + by name (e.g. in SELECT list). */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { - if (found || cur_nj_col_2->is_common) + DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); + if (cur_nj_col_2->is_common || + (found && (!using_fields || is_using_column_1))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; @@ -3829,9 +3853,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, clause (if present), mark them as common fields, and add a new equi-join condition to the ON clause. */ - if (nj_col_2 && - (!using_fields || - test_if_string_in_list(field_name_1, using_fields))) + if (nj_col_2 && (!using_fields ||is_using_column_1)) { Item *item_1= nj_col_1->create_item(thd); Item *item_2= nj_col_2->create_item(thd); @@ -3886,6 +3908,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; + DBUG_PRINT ("info", ("%s.%s and %s.%s are common", + nj_col_1->table_name() ? + nj_col_1->table_name() : "", + nj_col_1->name(), + nj_col_2->table_name() ? + nj_col_2->table_name() : "", + nj_col_2->name())); if (field_1) { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e8291edda5d..94d753eb703 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -75,10 +75,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, Test if the user wants to delete all rows and deletion doesn't have any side-effects (because of triggers), so we can use optimized handler::delete_all_rows() method. + We implement fast TRUNCATE for InnoDB even if triggers are present. + TRUNCATE ignores triggers. */ if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !(table->triggers && table->triggers->has_delete_triggers())) + (thd->lex->sql_command == SQLCOM_TRUNCATE || + !(table->triggers && table->triggers->has_delete_triggers())) + ) { deleted= table->file->records; if (!(error=table->file->delete_all_rows())) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d9dbc80e9a7..ae2b0d30a9c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -586,6 +586,20 @@ public: int cur_pos_in_select_list; List<udf_func> udf_list; /* udf function calls stack */ + /* + This is a copy of the original JOIN USING list that comes from + the parser. The parser : + 1. Sets the natural_join of the second TABLE_LIST in the join + and the st_select_lex::prev_join_using. + 2. Makes a parent TABLE_LIST and sets its is_natural_join/ + join_using_fields members. + 3. Uses the wrapper TABLE_LIST as a table in the upper level. + We cannot assign directly to join_using_fields in the parser because + at stage (1.) the parent TABLE_LIST is not constructed yet and + the assignment will override the JOIN USING fields of the lower level + joins on the right. + */ + List<String> *prev_join_using; void init_query(); void init_select(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fe511957bec..affa6e130dc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6444,11 +6444,8 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) If this is a JOIN ... USING, move the list of joined fields to the table reference that describes the join. */ - if (table->join_using_fields) - { - ptr->join_using_fields= table->join_using_fields; - table->join_using_fields= NULL; - } + if (prev_join_using) + ptr->join_using_fields= prev_join_using; } } join_list->push_front(ptr); @@ -6704,6 +6701,7 @@ void add_join_on(TABLE_LIST *b, Item *expr) a Left join argument b Right join argument using_fields Field names from USING clause + lex The current st_select_lex IMPLEMENTATION This function marks that table b should be joined with a either via @@ -6732,10 +6730,11 @@ void add_join_on(TABLE_LIST *b, Item *expr) None */ -void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields) +void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, + SELECT_LEX *lex) { b->natural_join= a; - b->join_using_fields= using_fields; + lex->prev_join_using= using_fields; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 981f7206263..c9f0108f6bf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -707,11 +707,20 @@ JOIN::optimize() { int res; /* - opt_sum_query() returns -1 if no rows match to the WHERE conditions, - or 1 if all items were resolved, or 0, or an error number HA_ERR_... + opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match + to the WHERE conditions, + or 1 if all items were resolved, + or 0, or an error number HA_ERR_... */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { + if (res == HA_ERR_KEY_NOT_FOUND) + { + DBUG_PRINT("info",("No matching min/max row")); + zero_result_cause= "No matching min/max row"; + error=0; + DBUG_RETURN(0); + } if (res > 1) { thd->fatal_error(); @@ -719,13 +728,6 @@ JOIN::optimize() DBUG_PRINT("error",("Error from opt_sum_query")); DBUG_RETURN(1); } - if (res < 0) - { - DBUG_PRINT("info",("No matching min/max row")); - zero_result_cause= "No matching min/max row"; - error=0; - DBUG_RETURN(0); - } DBUG_PRINT("info",("Select tables optimized away")); zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved @@ -855,6 +857,13 @@ JOIN::optimize() { ORDER *org_order= order; order=remove_const(this, order,conds,1, &simple_order); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } + /* If we are using ORDER BY NULL or ORDER BY const_expression, return result in any order (even if we are using a GROUP BY) @@ -864,10 +873,11 @@ JOIN::optimize() } /* Check if we can optimize away GROUP BY/DISTINCT. - We can do that if there are no aggregate functions and the + We can do that if there are no aggregate functions, the fields in DISTINCT clause (if present) and/or columns in GROUP BY (if present) contain direct references to all key parts of - an unique index (in whatever order). + an unique index (in whatever order) and if the key parts of the + unique index cannot contain NULLs. Note that the unique keys for DISTINCT and GROUP BY should not be the same (as long as they are unique). @@ -962,6 +972,12 @@ JOIN::optimize() group_list= remove_const(this, (old_group_list= group_list), conds, rollup.state == ROLLUP::STATE_NONE, &simple_group); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } if (old_group_list && !group_list) select_distinct= 0; } @@ -978,6 +994,12 @@ JOIN::optimize() { group_list= procedure->group= remove_const(this, procedure->group, conds, 1, &simple_group); + if (thd->net.report_error) + { + error= 1; + DBUG_PRINT("error",("Error from remove_const")); + DBUG_RETURN(1); + } calc_group_buffer(this, group_list); } @@ -6415,6 +6437,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, *simple_order=0; // Must do a temp table to sort else if (!(order_tables & not_const_tables)) { + if (order->item[0]->with_subselect) + order->item[0]->val_str(&order->item[0]->str_value); DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; // skip const item } @@ -11875,7 +11899,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, /* - Check if GROUP BY/DISTINCT can be optimized away because the set is + Check if GROUP BY/DISTINCT can be optimized away because the set is already known to be distinct. SYNOPSIS @@ -11883,7 +11907,7 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, table The table to operate on. find_func function to iterate over the list and search for a field - + DESCRIPTION Used in removing the GROUP BY/DISTINCT of the following types of statements: @@ -11894,12 +11918,13 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, then <any combination of a,b,c>,{whatever} is also distinct This function checks if all the key parts of any of the unique keys - of the table are referenced by a list : either the select list + of the table are referenced by a list : either the select list through find_field_in_item_list or GROUP BY list through find_field_in_order_list. - If the above holds then we can safely remove the GROUP BY/DISTINCT, + If the above holds and the key parts cannot contain NULLs then we + can safely remove the GROUP BY/DISTINCT, as no result set can be more distinct than an unique key. - + RETURN VALUE 1 found 0 not found. @@ -11922,7 +11947,8 @@ list_contains_unique_index(TABLE *table, key_part < key_part_end; key_part++) { - if (!find_func(key_part->field, data)) + if (key_part->field->maybe_null() || + !find_func(key_part->field, data)) break; } if (key_part == key_part_end) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 21a5ead90af..23059ac545a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3973,6 +3973,7 @@ bool get_schema_tables_result(JOIN *join) if (is_subselect) // is subselect { + table_list->table->file->extra(HA_EXTRA_NO_CACHE); table_list->table->file->extra(HA_EXTRA_RESET_STATE); table_list->table->file->delete_all_rows(); free_io_cache(table_list->table); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0f29c3e1028..b4147d2905c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5466,11 +5466,11 @@ join_table: YYERROR_UNLESS($1 && $3); } '(' using_list ')' - { add_join_natural($1,$3,$7); $$=$3; } + { add_join_natural($1,$3,$7,Select); $$=$3; } | table_ref NATURAL JOIN_SYM table_factor { YYERROR_UNLESS($1 && ($$=$4)); - add_join_natural($1,$4,NULL); + add_join_natural($1,$4,NULL,Select); } /* LEFT JOIN variants */ @@ -5497,11 +5497,15 @@ join_table: YYERROR_UNLESS($1 && $5); } USING '(' using_list ')' - { add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } + { + add_join_natural($1,$5,$9,Select); + $5->outer_join|=JOIN_TYPE_LEFT; + $$=$5; + } | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($1,$6,NULL); + add_join_natural($1,$6,NULL,Select); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } @@ -5535,12 +5539,12 @@ join_table: LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; - add_join_natural($$,$5,$9); + add_join_natural($$,$5,$9,Select); } | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor { YYERROR_UNLESS($1 && $6); - add_join_natural($6,$1,NULL); + add_join_natural($6,$1,NULL,Select); LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; diff --git a/sql/table.cc b/sql/table.cc index 5c72ac6ccbf..4f1477355b1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2630,6 +2630,7 @@ Field *Natural_join_column::field() const char *Natural_join_column::table_name() { + DBUG_ASSERT(table_ref); return table_ref->alias; } |