summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authormsvensson@pilot.mysql.com <>2007-02-06 14:48:22 +0100
committermsvensson@pilot.mysql.com <>2007-02-06 14:48:22 +0100
commitd018030b20c8b4ca57d20322619de2fd670a05bc (patch)
tree11ccd2413b305f3797da63237ce98b416af8dd84 /sql
parent61686e85566876159de6bf7d5a92ee8a3dfedaeb (diff)
parentede3afe470a88bf1d4bc96d8ee5bce069569d10f (diff)
downloadmariadb-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.cc1
-rw-r--r--sql/filesort.cc6
-rw-r--r--sql/gen_lex_hash.cc22
-rw-r--r--sql/ha_myisam.cc502
-rw-r--r--sql/ha_myisammrg.cc39
-rw-r--r--sql/item.cc5
-rw-r--r--sql/item_subselect.cc4
-rw-r--r--sql/item_timefunc.cc9
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/mysqld.cc34
-rw-r--r--sql/mysqld.cc.rej161
-rw-r--r--sql/opt_range.cc12
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/sql_base.cc51
-rw-r--r--sql/sql_delete.cc6
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc13
-rw-r--r--sql/sql_select.cc60
-rw-r--r--sql/sql_show.cc1
-rw-r--r--sql/sql_yacc.yy16
-rw-r--r--sql/table.cc1
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= &current_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(&ltime, TIME_FUZZY_DATE);
+ if (get_arg0_date(&ltime, 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, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
make_time((DATE_TIME_FORMAT *) 0, &ltime, 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, &ltime);
+ sec_to_time(arg_val, args[0]->unsigned_flag, &ltime);
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;
}