diff options
Diffstat (limited to 'sql')
41 files changed, 856 insertions, 414 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index 5e023a68de9..606cc3ec7c0 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -98,16 +98,6 @@ BUILT_SOURCES = sql_yacc.cc sql_yacc.h EXTRA_DIST = udf_example.cc $(BUILT_SOURCES) YFLAGS = -d -OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\ - __math.h time.h __time.h unistd.h __unistd.h types.h \ - xtypes.h ac-types.h posix.h string.h __string.h \ - errno.h socket.h inet.h dirent.h netdb.h \ - cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \ - prio_queue.h pthread_attr.h pthread_once.h queue.h\ - sleep.h specific.h version.h pwd.h timers.h uio.h \ - cdefs.h machdep.h signal.h __signal.h util.h lex.h \ - wait.h - link_sources: rm -f mini_client_errors.c @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c diff --git a/sql/field.cc b/sql/field.cc index ba84de07afb..205e98698fe 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3831,7 +3831,9 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr) if (binary_flag) return memcmp(a_ptr,b_ptr,field_length); else - return my_sortcmp(field_charset,a_ptr,b_ptr,field_length); + return my_strnncoll(field_charset, + (const uchar*)a_ptr,field_length, + (const uchar*)b_ptr,field_length); } void Field_string::sort_string(char *to,uint length) @@ -3841,7 +3843,7 @@ void Field_string::sort_string(char *to,uint length) else { #ifdef USE_STRCOLL - if (use_strcoll(field_charset)) { + if (use_strnxfrm(field_charset)) { uint tmp=my_strnxfrm(field_charset, (unsigned char *)to, length, (unsigned char *) ptr, field_length); @@ -3907,7 +3909,9 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length) int cmp= memcmp(a,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, a,a_length, b,b_length); + return my_strnncoll(field_charset, + (const uchar*)a,a_length, + (const uchar*)b,b_length); } @@ -3924,7 +3928,9 @@ int Field_string::pack_cmp(const char *b, uint length) int cmp= memcmp(ptr,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, ptr,a_length, b, b_length); + return my_strnncoll(field_charset, + (const uchar*)ptr,a_length, + (const uchar*)b, b_length); } @@ -4033,7 +4039,9 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr) if (binary_flag) diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length)); else - diff=my_sortcmp(field_charset, a_ptr+2,b_ptr+2,min(a_length,b_length)); + diff=my_strnncoll(field_charset, + (const uchar*)a_ptr+2,min(a_length,b_length), + (const uchar*)b_ptr+2,min(a_length,b_length)); return diff ? diff : (int) (a_length - b_length); } @@ -4045,7 +4053,7 @@ void Field_varstring::sort_string(char *to,uint length) else { #ifdef USE_STRCOLL - if (use_strcoll(field_charset)) + if (use_strnxfrm(field_charset)) tot_length=my_strnxfrm(field_charset, (unsigned char *) to, length, (unsigned char *)ptr+2, tot_length); @@ -4134,7 +4142,9 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length) int cmp= memcmp(a,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, a,a_length, b,b_length); + return my_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } int Field_varstring::pack_cmp(const char *b, uint key_length) @@ -4155,7 +4165,9 @@ int Field_varstring::pack_cmp(const char *b, uint key_length) int cmp= memcmp(a,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, a,a_length, b,b_length); + return my_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } uint Field_varstring::packed_col_length(const char *ptr, uint length) @@ -4382,7 +4394,9 @@ int Field_blob::cmp(const char *a,uint32 a_length, const char *b, if (binary_flag) diff=memcmp(a,b,min(a_length,b_length)); else - diff=my_sortcmp(field_charset, a,b,min(a_length,b_length)); + diff=my_strnncoll(field_charset, + (const uchar*)a,min(a_length,b_length), + (const uchar*)b,min(a_length,b_length)); return diff ? diff : (int) (a_length - b_length); } @@ -4543,7 +4557,7 @@ void Field_blob::sort_string(char *to,uint length) else { #ifdef USE_STRCOLL - if (use_strcoll(field_charset)) + if (use_strnxfrm(field_charset)) { blob_length=my_strnxfrm(field_charset, (unsigned char *)to, length, @@ -4638,7 +4652,9 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length) int cmp= memcmp(a,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, a,a_length, b,b_length); + return my_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } @@ -4664,7 +4680,9 @@ int Field_blob::pack_cmp(const char *b, uint key_length) int cmp= memcmp(a,b,min(a_length,b_length)); return cmp ? cmp : (int) (a_length - b_length); } - return my_sortncmp(field_charset, a,a_length, b,b_length); + return my_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } /* Create a packed key that will be used for storage from a MySQL row */ diff --git a/sql/field.h b/sql/field.h index 127b3a069cb..8d63b0ef3f1 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1096,6 +1096,7 @@ Field *make_field(char *ptr, uint32 field_length, uint pack_length_to_packflag(uint type); uint32 calc_pack_length(enum_field_types type,uint32 length); bool set_field_to_null(Field *field); +bool set_field_to_null_with_conversions(Field *field); uint find_enum(TYPELIB *typelib,const char *x, uint length); ulonglong find_set(TYPELIB *typelib,const char *x, uint length); bool test_if_int(const char *str,int length); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index da7a1187a47..efb7401779c 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -112,35 +112,52 @@ static void do_outer_field_to_null_str(Copy_field *copy) bool set_field_to_null(Field *field) { - if (field->maybe_null()) + if (field->real_maybe_null()) { field->set_null(); field->reset(); + return 0; } - else + return 1; +} + + +bool +set_field_to_null_with_conversions(Field *field) +{ + if (field->real_maybe_null()) { - if (field->type() == FIELD_TYPE_TIMESTAMP) - { - ((Field_timestamp*) field)->set_time(); - return 0; // Ok to set time to NULL - } + field->set_null(); field->reset(); - if (field == field->table->next_number_field) - return 0; // field is set in handler.cc - if (current_thd->count_cuted_fields) - { - current_thd->cuted_fields++; // Increment error counter - return 0; - } - if (!current_thd->no_errors) - my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0), - field->field_name); - return 1; + return 0; + } + + /* + Check if this is a special type, which will get a special walue + when set to NULL + */ + if (field->type() == FIELD_TYPE_TIMESTAMP) + { + ((Field_timestamp*) field)->set_time(); + return 0; // Ok to set time to NULL + } + field->reset(); + if (field == field->table->next_number_field) + return 0; // field is set in handler.cc + if (current_thd->count_cuted_fields) + { + current_thd->cuted_fields++; // Increment error counter + return 0; } - return 0; + if (!current_thd->no_errors) + my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0), + field->field_name); + return 1; } + + static void do_skip(Copy_field *copy __attribute__((unused))) { } diff --git a/sql/filesort.cc b/sql/filesort.cc index 4d877c92dba..e1c673aca0b 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -63,24 +63,21 @@ static uint sortlength(SORT_FIELD *sortorder,uint length); table->record_pointers */ -ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, - SQL_SELECT *select, ha_rows special, ha_rows max_rows, - ha_rows *examined_rows) +ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, + SQL_SELECT *select, ha_rows max_rows, ha_rows *examined_rows) { int error; ulong memavl; uint maxbuffer; + uint i; BUFFPEK *buffpek; ha_rows records; uchar **sort_keys; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; - THD *thd= current_thd; - - DBUG_ENTER("filesort"); - DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length,special);); CHARSET_INFO *charset=table->table_charset; - uint i; + DBUG_ENTER("filesort"); + DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length);); #ifdef SKIP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif @@ -111,27 +108,15 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, { statistic_increment(filesort_scan_count, &LOCK_status); } - if (select && my_b_inited(&select->file)) - { - records=special=select->records; /* purecov: deadcode */ - selected_records_file= &select->file; /* purecov: deadcode */ - reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */ - } - else if (special) - { - records=special; /* purecov: deadcode */ - selected_records_file= outfile; /* purecov: deadcode */ - reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */ - } #ifdef CAN_TRUST_RANGE - else if (select && select->quick && select->quick->records > 0L) + if (select && select->quick && select->quick->records > 0L) { records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2), table->file->records)+EXTRA_RECORDS; selected_records_file=0; } -#endif else +#endif { records=table->file->estimate_number_of_rows(); selected_records_file= 0; @@ -140,7 +125,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, records=param.max_rows; /* purecov: inspected */ #ifdef USE_STRCOLL - if (use_strcoll(charset) && + if (use_strnxfrm(charset) && !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME)))) goto err; #endif @@ -511,7 +496,7 @@ static void make_sortkey(register SORTPARAM *param, length=sort_field->length; } #ifdef USE_STRCOLL - if(use_strcoll(cs)) + if(use_strnxfrm(cs)) { if (item->binary) { @@ -541,7 +526,7 @@ static void make_sortkey(register SORTPARAM *param, memcpy(to,res->ptr(),length); bzero((char *)to+length,diff); if (!item->binary) - case_sort(cs, (char*) to,length); + my_tosort(cs, (char*) to,length); #ifdef USE_STRCOLL } #endif @@ -946,7 +931,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length) if (!sortorder->field->binary()) { CHARSET_INFO *cs=((Field_str*)(sortorder->field))->charset(); - if (use_strcoll(cs)) + if (use_strnxfrm(cs)) sortorder->length= sortorder->length*cs->strxfrm_multiply; } #endif @@ -966,7 +951,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length) if (!sortorder->item->binary) { CHARSET_INFO *cs=sortorder->item->str_value.charset(); - if (use_strcoll(cs)) + if (use_strnxfrm(cs)) sortorder->length= sortorder->length*cs->strxfrm_multiply; } #endif diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 5c314462666..6cfd3c881cc 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -35,7 +35,9 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked) { if (!(file= heap_open(name, mode)) && my_errno == ENOENT) { - if (!create(name, table, NULL)) + HA_CREATE_INFO create_info; + bzero(&create_info, sizeof(create_info)); + if (!create(name, table, &create_info)) file= heap_open(name, mode); } return (file ? 0 : 1); @@ -51,6 +53,8 @@ int ha_heap::write_row(byte * buf) statistic_increment(ha_write_count,&LOCK_status); if (table->time_stamp) update_timestamp(buf+table->time_stamp-1); + if (table->next_number_field && buf == table->record[0]) + update_auto_increment(); return heap_write(file,buf); } @@ -161,6 +165,8 @@ void ha_heap::info(uint flag) index_file_length=info.index_length; max_data_file_length= info.max_records* info.reclength; delete_length= info.deleted * info.reclength; + if (flag & HA_STATUS_AUTO) + auto_increment_value= info.auto_increment; } int ha_heap::extra(enum ha_extra_function operation) @@ -234,11 +240,11 @@ ha_rows ha_heap::records_in_range(int inx, } } - int ha_heap::create(const char *name, TABLE *table, HA_CREATE_INFO *create_info) { uint key, parts, mem_per_row= 0; + uint auto_key= 0, auto_key_type= 0; ulong max_rows; HP_KEYDEF *keydef; HA_KEYSEG *seg; @@ -296,19 +302,42 @@ int ha_heap::create(const char *name, TABLE *table, seg->null_bit= 0; seg->null_pos= 0; } + if (field->flags & AUTO_INCREMENT_FLAG) + { + auto_key= key + 1; + auto_key_type= field->key_type(); + } } } mem_per_row+= MY_ALIGN(table->reclength + 1, sizeof(char*)); max_rows = (ulong) (current_thd->variables.max_heap_table_size / mem_per_row); + HP_CREATE_INFO hp_create_info; + hp_create_info.auto_key= auto_key; + hp_create_info.auto_key_type= auto_key_type; + hp_create_info.auto_increment= (create_info->auto_increment_value ? + create_info->auto_increment_value - 1 : 0); error= heap_create(fn_format(buff,name,"","",4+2), table->keys,keydef, table->reclength, ((table->max_rows < max_rows && table->max_rows) ? table->max_rows : max_rows), - table->min_rows); + table->min_rows, &hp_create_info); my_free((gptr) keydef, MYF(0)); if (file) info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE); ref_length= sizeof(HEAP_PTR); return (error); } + +void ha_heap::update_create_info(HA_CREATE_INFO *create_info) +{ + table->file->info(HA_STATUS_AUTO); + if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) + create_info->auto_increment_value= auto_increment_value; +} + +longlong ha_heap::get_auto_increment() +{ + ha_heap::info(HA_STATUS_AUTO); + return auto_increment_value; +} diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 504f5262bf3..f82a1a460d8 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -40,8 +40,7 @@ class ha_heap: public handler ulong table_flags() const { return (HA_READ_RND_SAME | HA_NO_INDEX | HA_KEYPOS_TO_RNDPOS | - HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ | - HA_NO_AUTO_INCREMENT); + HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ); } ulong index_flags(uint inx) const { @@ -63,6 +62,7 @@ class ha_heap: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); + longlong get_auto_increment(); int index_read(byte * buf, const byte * key, uint key_len, enum ha_rkey_function find_flag); int index_read_idx(byte * buf, uint idx, const byte * key, @@ -87,6 +87,7 @@ class ha_heap: public handler int delete_table(const char *from); int rename_table(const char * from, const char * to); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); + void update_create_info(HA_CREATE_INFO *create_info); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b684d9dd4dd..2a7990a18ee 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1366,9 +1366,9 @@ innobase_mysql_cmp( case FIELD_TYPE_VAR_STRING: // BAR TODO: Discuss with heikki.tuuri@innodb.com // so that he sends CHARSET_INFO for the field to this function. - ret = my_sortncmp(default_charset_info, - (const char*) a, a_length, - (const char*) b, b_length); + ret = my_strnncoll(default_charset_info, + a, a_length, + b, b_length); if (ret < 0) { return(-1); } else if (ret > 0) { @@ -2181,16 +2181,8 @@ convert_search_mode_to_innobase( case HA_READ_AFTER_KEY: return(PAGE_CUR_G); case HA_READ_BEFORE_KEY: return(PAGE_CUR_L); case HA_READ_PREFIX: return(PAGE_CUR_GE); - case HA_READ_PREFIX_LAST: - /* ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: Using HA_READ_PREFIX_LAST\n"); */ - return(PAGE_CUR_LE); - - /* InnoDB does not yet support ..PREFIX_LAST! - We have to add a new search flag - PAGE_CUR_LE_OR_PREFIX to InnoDB. */ - + case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE); + /* HA_READ_PREFIX_LAST does not yet work in InnoDB! */ /* the above PREFIX flags mean that the last field in the key value may just be a prefix of the complete fixed length field */ @@ -3155,8 +3147,8 @@ innobase_drop_database( memcpy(namebuf, ptr, len); namebuf[len] = '/'; namebuf[len + 1] = '\0'; -#ifdef __WIN__ - casedn_str(namebuf); +#ifdef FN_NO_CASE_SENCE + my_casedn_str(system_charset_info, namebuf); #endif trx = trx_allocate_for_mysql(); @@ -3264,7 +3256,7 @@ ha_innobase::records_in_range( MYF(MY_WME)); dtuple_t* range_start; dtuple_t* range_end; - ulint n_rows; + ib_longlong n_rows; ulint mode1; ulint mode2; void* heap1; @@ -3649,6 +3641,7 @@ ha_innobase::reset(void) return(0); } + /********************************************************************** When we create a temporary table inside MySQL LOCK TABLES, MySQL will not call external_lock for the temporary table when it uses it. Instead, @@ -3787,6 +3780,14 @@ innodb_show_status( DBUG_ENTER("innodb_show_status"); + if (innodb_skip) { + + fprintf(stderr, + "Cannot call SHOW INNODB STATUS because skip-innodb is defined\n"); + + DBUG_RETURN(-1); + } + /* We let the InnoDB Monitor to output at most 100 kB of text, add a safety margin of 10 kB for buffer overruns */ diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index a26c2e02db8..43a351101b3 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -559,7 +559,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) param.tmpfile_createflag = O_RDWR | O_TRUNC; param.using_global_keycache = 1; param.thd=thd; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; param.out_flag=0; strmov(fixed_name,file->filename); @@ -718,7 +718,7 @@ bool ha_myisam::activate_all_index(THD *thd) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; error=repair(thd,param,0) != HA_ADMIN_OK; thd->proc_info=save_proc_info; } diff --git a/sql/init.cc b/sql/init.cc index 052ee16925e..8834fd3a89c 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -24,7 +24,6 @@ void unireg_init(ulong options) { uint i; double nr; - CHARSET_INFO *cs; DBUG_ENTER("unireg_init"); MYSYS_PROGRAM_DONT_USE_CURSES(); diff --git a/sql/item.cc b/sql/item.cc index 394833b396a..38ec7e80898 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -432,7 +432,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (!field) // If field is not checked { Field *tmp; - if (!(tmp=find_field_in_tables(thd, this, tables, 0))) + if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field) { /* We can't find table field in table list of current select, @@ -448,14 +448,18 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) thd->net.last_errno= 0; #endif for (SELECT_LEX *sl= thd->lex.select->outer_select(); - sl && !tmp; + sl; sl= sl->outer_select()) - tmp=find_field_in_tables(thd, this, - (TABLE_LIST*)(last= sl)->table_list.first, - 0); + if ((tmp= find_field_in_tables(thd, this, + (TABLE_LIST*) + (last= sl)->table_list.first, + 0)) != not_found_field) + break; if (!tmp) + return -1; + else if (tmp == not_found_field) { - // Call to produce appropriate error message + // call to return error code find_field_in_tables(thd, this, tables, 1); return -1; } @@ -481,7 +485,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) tbl->shared= 1; } } - } + } + else if (!tmp) + return -1; + set_field(tmp); } else if (thd && thd->set_query_id && field->query_id != thd->query_id) @@ -591,7 +598,7 @@ void Item_field::save_org_in_field(Field *to) if (field->is_null()) { null_value=1; - set_field_to_null(to); + set_field_to_null_with_conversions(to); } else { @@ -606,7 +613,7 @@ int Item_field::save_in_field(Field *to) if (result_field->is_null()) { null_value=1; - return set_field_to_null(to); + return set_field_to_null_with_conversions(to); } else { @@ -618,8 +625,42 @@ int Item_field::save_in_field(Field *to) } +/* + Store null in field + + SYNOPSIS + save_in_field() + field Field where we want to store NULL + + DESCRIPTION + This is used on INSERT. + Allow NULL to be inserted in timestamp and auto_increment values + + RETURN VALUES + 0 ok + 1 Field doesn't support NULL values and can't handle 'field = NULL' +*/ + int Item_null::save_in_field(Field *field) { + return set_field_to_null_with_conversions(field); +} + + +/* + Store null in field + + SYNOPSIS + save_safe_in_field() + field Field where we want to store NULL + + RETURN VALUES + 0 ok + 1 Field doesn't support NULL values +*/ + +int Item_null::save_safe_in_field(Field *field) +{ return set_field_to_null(field); } @@ -637,7 +678,7 @@ int Item::save_in_field(Field *field) str_value.set_quick(buff,sizeof(buff),cs); result=val_str(&str_value); if (null_value) - return set_field_to_null(field); + return set_field_to_null_with_conversions(field); field->set_notnull(); error=field->store(result->ptr(),result->length(),cs); str_value.set_quick(0, 0, cs); @@ -654,7 +695,7 @@ int Item::save_in_field(Field *field) { longlong nr=val_int(); if (null_value) - return set_field_to_null(field); + return set_field_to_null_with_conversions(field); field->set_notnull(); error=field->store(nr); } @@ -789,7 +830,9 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { if (!ref) { - if (!(ref= find_item_in_list(this, thd->lex.select->item_list, 0))) + if ((ref= find_item_in_list(this, thd->lex.select->item_list, + REPORT_EXCEPT_NOT_FOUND)) == + (Item **)not_found_item) { /* We can't find table field in table list of current select, @@ -798,17 +841,25 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) of view rules. For example if both tables (outer & current) have field 'field' it is not mistake to refer to this field without mention of table name, but if we join tables in one list it will - cause error ER_NON_UNIQ_ERROR in find_field_in_tables. + cause error ER_NON_UNIQ_ERROR in find_item_in_list. */ SELECT_LEX *last=0; for (SELECT_LEX *sl= thd->lex.select->outer_select(); - sl && !ref; + sl; sl= sl->outer_select()) - ref= find_item_in_list(this, (last= sl)->item_list, 0); + if((ref= find_item_in_list(this, (last= sl)->item_list, + REPORT_EXCEPT_NOT_FOUND)) != + (Item **)not_found_item) + break; + if (!ref) { + return 1; + } + else if (ref == (Item **)not_found_item) + { // Call to report error - find_item_in_list(this, thd->lex.select->item_list, 1); + find_item_in_list(this, thd->lex.select->item_list, REPORT_ALL_ERRORS); return 1; } else @@ -834,6 +885,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } } } + else if (!ref) + return 1; max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; diff --git a/sql/item.h b/sql/item.h index 84182203d4c..115e9426691 100644 --- a/sql/item.h +++ b/sql/item.h @@ -56,6 +56,8 @@ public: virtual int save_in_field(Field *field); virtual void save_org_in_field(Field *field) { (void) save_in_field(field); } + virtual int save_safe_in_field(Field *field) + { return save_in_field(field); } virtual bool send(THD *thd, String *str); virtual bool eq(const Item *, bool binary_cmp) const; virtual Item_result result_type () const { return REAL_RESULT; } @@ -153,7 +155,8 @@ public: longlong val_int(); String *val_str(String *str); void make_field(Send_field *field); - int save_in_field(Field *field); + int save_in_field(Field *field); + int save_safe_in_field(Field *field); enum Item_result result_type () const { return STRING_RESULT; } bool send(THD *thd, String *str); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 99fc0bcdb67..456ce5f22ba 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -32,11 +32,22 @@ SUBSELECT TODO: #include "mysql_priv.h" #include "sql_select.h" -Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex, - select_subselect *result): +Item_subselect::Item_subselect(): Item(), engine_owner(1), value_assigned(0) { - DBUG_ENTER("Item_subselect::Item_subselect"); + assign_null(); + /* + item value is NULL if select_subselect not changed this value + (i.e. some rows will be found returned) + */ + null_value= 1; +} + +void Item_subselect::init(THD *thd, st_select_lex *select_lex, + select_subselect *result) +{ + + DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); if (select_lex->next_select()) @@ -45,12 +56,6 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex, else engine= new subselect_single_select_engine(thd, select_lex, result, this); - assign_null(); - /* - item value is NULL if select_subselect not changed this value - (i.e. some rows will be found returned) - */ - null_value= 1; DBUG_VOID_RETURN; } @@ -76,14 +81,17 @@ void Item_subselect::make_field (Send_field *tmp_field) bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - // Is it one field subselect? - if (engine->cols() > max_columns) - { - my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); - return 1; - } int res= engine->prepare(); - fix_length_and_dec(); + if (!res) + { + // Is it one field subselect? + if (engine->cols() > max_columns) + { + my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); + return 1; + } + fix_length_and_dec(); + } return res; } @@ -99,8 +107,9 @@ inline table_map Item_subselect::used_tables() const Item_singleval_subselect::Item_singleval_subselect(THD *thd, st_select_lex *select_lex): - Item_subselect(thd, select_lex, new select_singleval_subselect(this)) + Item_subselect() { + init(thd, select_lex, new select_singleval_subselect(this)); max_columns= 1; maybe_null= 1; } @@ -119,28 +128,38 @@ Item::Type Item_subselect::type() const double Item_singleval_subselect::val () { if (engine->exec()) + { + assign_null(); return 0; + } return real_value; } longlong Item_singleval_subselect::val_int () { if (engine->exec()) + { + assign_null(); return 0; + } return int_value; } String *Item_singleval_subselect::val_str (String *str) { if (engine->exec() || null_value) + { + assign_null(); return 0; - return &str_value; + } + return &string_value; } Item_exists_subselect::Item_exists_subselect(THD *thd, st_select_lex *select_lex): - Item_subselect(thd, select_lex, new select_exists_subselect(this)) + Item_subselect() { + init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; null_value= 0; //can't be NULL maybe_null= 0; //can't be NULL @@ -157,21 +176,30 @@ void Item_exists_subselect::fix_length_and_dec() double Item_exists_subselect::val () { if (engine->exec()) + { + assign_null(); return 0; + } return (double) value; } longlong Item_exists_subselect::val_int () { if (engine->exec()) + { + assign_null(); return 0; + } return value; } String *Item_exists_subselect::val_str(String *str) { if (engine->exec()) + { + assign_null(); return 0; + } str->set(value); return str; } @@ -182,7 +210,7 @@ subselect_single_select_engine::subselect_single_select_engine(THD *thd, select_subselect *result, Item_subselect *item): subselect_engine(thd, item, result), - executed(0), optimized(0) + prepared(0), optimized(0), executed(0) { select_lex= select; SELECT_LEX_UNIT *unit= select_lex->master_unit(); @@ -221,6 +249,9 @@ subselect_union_engine::subselect_union_engine(THD *thd, int subselect_single_select_engine::prepare() { + if (prepared) + return 0; + prepared= 1; SELECT_LEX *save_select= thd->lex.select; thd->lex.select= select_lex; if(join->prepare((TABLE_LIST*) select_lex->table_list.first, diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 92839eb0e5f..33f82982708 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -39,8 +39,7 @@ protected: uint max_columns; public: - Item_subselect(THD *thd, st_select_lex *select_lex, - select_subselect* result); + Item_subselect(); Item_subselect(Item_subselect *item) { null_value= item->null_value; @@ -50,6 +49,14 @@ public: engine_owner= 0; name= item->name; } + + /* + We need this method, because some compilers do not allow 'this' + pointer in constructor initialization list, but we need pass pointer + to subselect Item class to select_subselect classes constructor. + */ + void init (THD *thd, st_select_lex *select_lex, select_subselect *result); + ~Item_subselect(); virtual void assign_null() { @@ -73,10 +80,16 @@ public: class Item_singleval_subselect :public Item_subselect { protected: - longlong int_value; /* here stored integer value of this item */ - double real_value; /* here stored real value of this item */ + longlong int_value; /* Here stored integer value of this item */ + double real_value; /* Here stored real value of this item */ + /* + Here stored string value of this item. + (str_value used only as temporary buffer, because it can be changed + by Item::save_field) + */ + String string_value; enum Item_result res_type; /* type of results */ - + public: Item_singleval_subselect(THD *thd, st_select_lex *select_lex); Item_singleval_subselect(Item_singleval_subselect *item): @@ -84,6 +97,7 @@ public: { int_value= item->int_value; real_value= item->real_value; + string_value.set(item->string_value, 0, item->string_value.length()); max_length= item->max_length; decimals= item->decimals; res_type= item->res_type; @@ -165,8 +179,9 @@ public: class subselect_single_select_engine: public subselect_engine { - my_bool executed; /* simple subselect is executed */ + my_bool prepared; /* simple subselect is prepared */ my_bool optimized; /* simple subselect is optimized */ + my_bool executed; /* simple subselect is executed */ st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 93ced79005f..4d25098bb88 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -866,7 +866,9 @@ static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2) static int simple_str_key_cmp(void* arg, byte* key1, byte* key2) { /* BAR TODO: remove default_charset_info */ - return my_sortcmp(default_charset_info,(char*) key1, (char*) key2, *(uint*) arg); + return my_strnncoll(default_charset_info, + (const uchar*) key1, *(uint*) arg, + (const uchar*) key2, *(uint*) arg); } /* diff --git a/sql/key.cc b/sql/key.cc index fa09a0a6d44..84669808b92 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -193,8 +193,9 @@ int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length) FIELDFLAG_PACK))) { /* BAR TODO: I'm not sure this should be system_charset_info */ - if (my_sortcmp(system_charset_info,(char*) key, - (char*) table->record[0]+key_part->offset,length)) + if (my_strnncoll(system_charset_info, + (const uchar*) key, length, + (const uchar*) table->record[0]+key_part->offset,length)) return 1; } else if (memcmp(key,table->record[0]+key_part->offset,length)) diff --git a/sql/log.cc b/sql/log.cc index 59f99e3460e..91ef42e1381 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -942,8 +942,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, int error= 0; VOID(pthread_mutex_lock(&LOCK_log)); - /* Test if someone closed after the is_open test */ - if (log_type != LOG_CLOSED) + /* Test if someone closed between the is_open test and lock */ + if (is_open()) { time_t skr; ulong id; @@ -973,7 +973,6 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, last_time=skr; struct tm tm_tmp; struct tm *start; - ulong length; localtime_r(&skr,&tm_tmp); start=&tm_tmp; /* Note that my_b_write() assumes it knows the length for this */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8077d600643..bd6914363e2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -392,6 +392,8 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, bool fake_select_lex); void fix_tables_pointers(SELECT_LEX *select_lex); +int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, + select_result *result); int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type, select_result *result); int mysql_union(THD *thd, LEX *lex,select_result *result); @@ -456,6 +458,7 @@ bool wait_for_tables(THD *thd); bool table_is_used(TABLE *table, bool wait_for_name_lock); bool drop_locked_tables(THD *thd,const char *db, const char *table_name); void abort_locked_tables(THD *thd,const char *db, const char *table_name); +extern const Field *not_found_field; Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, bool report_error); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, @@ -545,7 +548,11 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, int *error); -Item ** find_item_in_list(Item *item, List<Item> &items, bool report_error); +enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, + IGNORE_ERRORS}; +extern const Item **not_found_item; +Item ** find_item_in_list(Item *item, List<Item> &items, + find_item_error_report_type report_error); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it); @@ -606,7 +613,7 @@ pthread_handler_decl(handle_manager, arg); #ifndef DBUG_OFF void print_where(COND *cond,const char *info); void print_cached_tables(void); -void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special); +void TEST_filesort(SORT_FIELD *sortorder,uint s_length); #endif void mysql_print_status(THD *thd); /* key.cc */ @@ -635,8 +642,9 @@ bool open_log(MYSQL_LOG *log, const char *hostname, extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - mysql_real_data_home[], *charsets_list; -extern my_string mysql_tmpdir; + mysql_real_data_home[], *charsets_list, *opt_mysql_tmpdir; +#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) +extern MY_TMPDIR mysql_tmpdir_list; extern const char *command_name[]; extern const char *first_keyword, *localhost, *delayed_user; extern const char **errmesg; /* Error messages */ @@ -786,9 +794,9 @@ void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors); void end_read_record(READ_RECORD *info); -ha_rows filesort(TABLE *form,struct st_sort_field *sortorder, uint s_length, - SQL_SELECT *select, ha_rows special,ha_rows max_rows, - ha_rows *examined_rows); +ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder, + uint s_length, SQL_SELECT *select, + ha_rows max_rows, ha_rows *examined_rows); void change_double_for_sort(double nr,byte *to); int get_quick_record(SQL_SELECT *select); int calc_weekday(long daynr,bool sunday_first_day_of_week); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a3a82d96b2e..e6c2c198722 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -395,7 +395,8 @@ const char *myisam_recover_options_str="OFF"; const char *sql_mode_str="OFF"; ulong rpl_recovery_rank=0; -my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL, mysql_tmpdir=NULL; +my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL; +MY_TMPDIR mysql_tmpdir_list; ulong my_bind_addr; /* the address we bind to */ char *my_bind_addr_str; DATE_FORMAT dayord; @@ -852,7 +853,7 @@ void clean_up(bool print_message) if (defaults_argv) free_defaults(defaults_argv); my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); + free_tmpdir(&mysql_tmpdir_list); my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); x_free(opt_bin_logname); x_free(opt_relay_logname); @@ -1834,17 +1835,6 @@ int main(int argc, char **argv) load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv); defaults_argv=argv; - /* Get default temporary directory */ - opt_mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ -#if defined( __WIN__) || defined(OS2) - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TEMP"); - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TMP"); -#endif - if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0]) - opt_mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */ - set_options(); get_options(argc,argv); if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) @@ -2941,13 +2931,13 @@ struct my_option my_long_options[] = #endif /* HAVE_BERKELEY_DB */ {"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"big-tables", OPT_BIG_TABLES, + {"big-tables", OPT_BIG_TABLES, "Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, + {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, "Tells the master that updates to the given database should not be logged tothe binary log", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to", @@ -3316,16 +3306,23 @@ struct my_option my_long_options[] = #ifdef HAVE_OPENSSL #include "sslopt-longopts.h" #endif - {"temp-pool", OPT_TEMP_POOL, + {"temp-pool", OPT_TEMP_POOL, "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", (gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"tmpdir", 't', "Path for temporary files", (gptr*) &opt_mysql_tmpdir, + {"tmpdir", 't', + "Path for temporary files. Several paths may be specified, separated by a " +#if defined( __WIN__) || defined(OS2) + "semicolon (;)" +#else + "colon (:)" +#endif + ", in this case they are used in a round-robin fashion.", + (gptr*) &opt_mysql_tmpdir, (gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"transaction-isolation", OPT_TX_ISOLATION, - "Default transaction isolation level", 0, 0, 0, GET_NO_ARG, REQUIRED_ARG, 0, - 0, 0, 0, - 0, 0}, + "Default transaction isolation level", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, + 0, 0, 0, 0, 0}, {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -3378,7 +3375,7 @@ struct my_option my_long_options[] = (gptr*) &connect_timeout, (gptr*) &connect_timeout, 0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 }, {"delayed_insert_timeout", OPT_DELAYED_INSERT_TIMEOUT, - "Ho wlong a INSERT DELAYED thread should wait for INSERT statements before terminating.", + "How long a INSERT DELAYED thread should wait for INSERT statements before terminating.", (gptr*) &delayed_insert_timeout, (gptr*) &delayed_insert_timeout, 0, GET_ULONG, REQUIRED_ARG, DELAYED_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"delayed_insert_limit", OPT_DELAYED_INSERT_LIMIT, @@ -4174,7 +4171,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_SKIP_SHOW_DB: opt_skip_show_db=1; opt_specialflag|=SPECIAL_SKIP_SHOW_DB; - mysql_port=0; break; #ifdef ONE_THREAD case (int) OPT_ONE_THREAD: @@ -4498,9 +4494,7 @@ static void fix_paths(void) charsets_dir=mysql_charsets_dir; } - char *end=convert_dirname(buff, opt_mysql_tmpdir, NullS); - if (!(mysql_tmpdir= my_memdup((byte*) buff,(uint) (end-buff)+1, - MYF(MY_FAE)))) + if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) exit(1); if (!slave_load_tmpdir) { diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index 980f8b090a1..0fc2347bebd 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -286,12 +286,12 @@ send_eof(THD *thd, bool no_flush) { if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) { - char buff[5]; + uchar buff[5]; uint tmp= min(thd->total_warn_count, 65535); buff[0]=254; int2store(buff+1, tmp); int2store(buff+3, 0); // No flags yet - VOID(my_net_write(net,buff,5)); + VOID(my_net_write(net,(char*) buff,5)); VOID(net_flush(net)); } else diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ed5b2b0a230..2b0ac08fe95 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -978,7 +978,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, { CHARSET_INFO *charset=((Field_str*)(field))->charset(); #ifdef USE_STRCOLL - if (use_strcoll(charset)) + if (use_strnxfrm(charset)) like_error= my_like_range(charset, res->ptr(),res->length(),wild_prefix, field_length, min_str+maybe_null, diff --git a/sql/set_var.cc b/sql/set_var.cc index b221a3f98ff..72579664a3e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -541,7 +541,7 @@ struct show_var_st init_vars[]= { {"timezone", time_zone, SHOW_CHAR}, #endif {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, - {"tmpdir", (char*) &mysql_tmpdir, SHOW_CHAR_PTR}, + {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, {"version", server_version, SHOW_CHAR}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3773eca43e1..40a11d54f10 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1783,9 +1783,29 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, return field; } +// Special Field pointer for find_field_in_tables returning +const Field *not_found_field= (Field*) 0x1; +/* + Find field in table list. + + SYNOPSIS + find_field_in_tables() + thd - pointer to current thread structure + item - field item that should be found + tables - tables for scaning + report_error - if FALSE then do not report error if item not found and + return not_found_field; + + RETURN VALUES + 0 - field is not found or field is not unique, error message is + reported + not_found_field - function was called with report_error == FALSE and + field if not found, no error message reported + found field +*/ Field * -find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, +find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, bool report_error) { Field *found=0; @@ -1831,13 +1851,18 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); table_name=buff; } - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name, - thd->where); + if (report_error) + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + table_name, thd->where); + else + return (Field*) not_found_field; } else if (report_error) my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), item->full_name(),thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } bool allow_rowid= tables && !tables->next; // Only one table @@ -1852,11 +1877,10 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, return (Field*) 0; if (found) { - if (!report_error) // Returns first found + if (!thd->where) // Returns first found break; - if (report_error) - my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), - name,thd->where); + my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), + name,thd->where); return (Field*) 0; } found=field; @@ -1867,11 +1891,39 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, if (report_error) my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), item->full_name(), thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } +// Special Item pointer for find_item_in_list returning +const Item **not_found_item= (const Item**) 0x1; + +/* + Find Item in list of items (find_field_in_tables analog) + + SYNOPSIS + find_item_in_list() + find - item to find + items - list of items + report_error + REPORT_ALL_ERRORS - report errors, return 0 if error + REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0 + IGNORE_ERRORS - do not report errors, return 0 if error + + RETURN VALUES + 0 - item is not found or item is not unique, error message is + reported + not_found_item - function was called with report_error == + REPORT_EXCEPT_NOT_FOUND and item if not found, no error + message reported + found field + +*/ + Item ** -find_item_in_list(Item *find, List<Item> &items, bool report_error) +find_item_in_list(Item *find, List<Item> &items, + find_item_error_report_type report_error) { List_iterator<Item> li(items); Item **found=0,*item; @@ -1896,7 +1948,7 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error) { if ((*found)->eq(item,0)) continue; // Same field twice (Access?) - if (report_error) + if (report_error != IGNORE_ERRORS) my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), find->full_name(), current_thd->where); return (Item**) 0; @@ -1919,10 +1971,17 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error) break; } } - if (!found && report_error) - my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), - find->full_name(), current_thd->where); - return found; + if (found) + return found; + else if (report_error != REPORT_EXCEPT_NOT_FOUND) + { + if (report_error == REPORT_ALL_ERRORS) + my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), + find->full_name(), current_thd->where); + return (Item **) 0; + } + else + return (Item **) not_found_item; } /**************************************************************************** @@ -2229,30 +2288,32 @@ fill_record(Field **ptr,List<Item> &values) static void mysql_rm_tmp_tables(void) { - uint idx; - char filePath[FN_REFLEN]; + uint i, idx; + char filePath[FN_REFLEN], *tmpdir; MY_DIR *dirp; FILEINFO *file; DBUG_ENTER("mysql_rm_tmp_tables"); + for (i=0; i<=mysql_tmpdir_list.max; i++) + { + tmpdir=mysql_tmpdir_list.list[i]; /* See if the directory exists */ - if (!(dirp = my_dir(mysql_tmpdir,MYF(MY_WME | MY_DONT_SORT)))) - DBUG_VOID_RETURN; /* purecov: inspected */ + if (!(dirp = my_dir(tmpdir,MYF(MY_WME | MY_DONT_SORT)))) + continue; - /* - ** Remove all SQLxxx tables from directory - */ + /* Remove all SQLxxx tables from directory */ for (idx=2 ; idx < (uint) dirp->number_off_files ; idx++) { file=dirp->dir_entry+idx; if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length)) { - sprintf(filePath,"%s%s",mysql_tmpdir,file->name); /* purecov: inspected */ - VOID(my_delete(filePath,MYF(MY_WME))); /* purecov: inspected */ + sprintf(filePath,"%s%s",tmpdir,file->name); + VOID(my_delete(filePath,MYF(MY_WME))); } } my_dirend(dirp); + } DBUG_VOID_RETURN; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7c51cac0f3a..5bdefbaaa30 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -357,6 +357,12 @@ TODO list: #define DUMP(C) #endif +#ifdef FN_NO_CASE_SENCE +#define DB_NAME_PREPROCESS(C) tolower(C) +#else +#define DB_NAME_PREPROCESS(C) (C) +#endif + const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND",NullS }; TYPELIB query_cache_type_typelib= { @@ -1394,14 +1400,15 @@ ulong Query_cache::init_cache() VOID(hash_init(&queries,system_charset_info,def_query_hash_size, 0, 0, query_cache_query_get_key, 0, 0)); - /* - On windows we have to compare names case insensitive as for the OS - A.frm and a.frm are the same file. - */ +#ifndef FN_NO_CASE_SENCE + VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0, + query_cache_table_get_key, 0, 0)); +#else + // windows, OS/2 or other case insensitive file names work around VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0, - query_cache_table_get_key, 0, - IF_WIN((lower_case_table_names ? 0: HASH_CASE_INSENSITIVE), - 0))); + query_cache_table_get_key, 0, + (lower_case_table_names?0:HASH_CASE_INSENSITIVE))); +#endif queries_in_cache = 0; queries_blocks = 0; @@ -2447,7 +2454,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, lex->select->options, (int) thd->variables.query_cache_type)); - for (; tables_used; tables_used=tables_used->next) + for (; tables_used; tables_used= tables_used->next) { tables++; DBUG_PRINT("qcache", ("table %s, db %s, type %u", @@ -2457,10 +2464,16 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, tables_used->table->file->has_transactions()); if (tables_used->table->db_type == DB_TYPE_MRG_ISAM || - tables_used->table->tmp_table != NO_TMP_TABLE) + tables_used->table->tmp_table != NO_TMP_TABLE || + (tables_used->db_length == 5 && + DB_NAME_PREPROCESS(tables_used->db[0])=='m' && + DB_NAME_PREPROCESS(tables_used->db[1])=='y' && + DB_NAME_PREPROCESS(tables_used->db[2])=='s' && + DB_NAME_PREPROCESS(tables_used->db[3])=='q' && + DB_NAME_PREPROCESS(tables_used->db[4])=='l')) { DBUG_PRINT("qcache", - ("select not cacheable: used MRG_ISAM or temporary table(s)")); + ("select not cacheable: used MRG_ISAM, temporary or system table(s)")); DBUG_RETURN(0); } if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 763484dbba8..c4966ff1326 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -887,9 +887,14 @@ bool select_singleval_subselect::send_data(List<Item> &items) it->decimals= val_item->decimals; it->binary= val_item->binary; it->int_value= val_item->val_int(); - String *s= val_item->val_str(&it->str_value); - if (s != &it->str_value) - it->str_value.set(*s, 0, s->length()); + String *s= val_item->val_str(&it->string_value); + if (s != &it->string_value) + { + it->string_value.set(*s, 0, s->length()); + } + // TODO: remove when correct charset handling appeared for Item + it->str_value.set(*s, 0, s->length()); // store charset + it->res_type= val_item->result_type(); } it->assigned(1); @@ -910,3 +915,57 @@ bool select_exists_subselect::send_data(List<Item> &items) DBUG_RETURN(0); } + +/*************************************************************************** +** Dump of select to variables +***************************************************************************/ +int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) +{ + List_iterator_fast<Item> li(list); + List_iterator_fast<LEX_STRING> gl(var_list); + Item *item; + LEX_STRING *ls; + if (var_list.elements != list.elements) + { + my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0)); + return 1; + } + while ((item=li++)) + { + ls= gl++; + Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item); + xx->fix_fields(current_thd,(TABLE_LIST*) current_thd->lex.select_lex.table_list.first,&item); + xx->fix_length_and_dec(); + vars.push_back(xx); + } + return 0; +} +bool select_dumpvar::send_data(List<Item> &items) +{ + List_iterator_fast<Item_func_set_user_var> li(vars); + Item_func_set_user_var *xx; + DBUG_ENTER("send_data"); + + if (row_count++) + { + my_error(ER_TOO_MANY_ROWS, MYF(0)); + DBUG_RETURN(1); + } + while ((xx=li++)) + xx->update(); + DBUG_RETURN(0); +} + +bool select_dumpvar::send_eof() +{ + if (row_count) + { + ::send_ok(thd,row_count); + return 0; + } + else + { + my_error(ER_EMPTY_QUERY,MYF(0)); + return 1; + } +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 3983405e039..b625a78b867 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -973,3 +973,15 @@ public: bool send_eof(); }; +class select_dumpvar :public select_result { + ha_rows row_count; +public: + List<LEX_STRING> var_list; + List<Item_func_set_user_var> vars; + select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;} + ~select_dumpvar() {} + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); + bool send_fields(List<Item> &list, uint flag) {return 0;} + bool send_data(List<Item> &items); + bool send_eof(); +}; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 1d843b78d4e..58b12bca00d 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -69,7 +69,6 @@ static bool write_db_opt(const char *path, HA_CREATE_INFO *create) error=0; my_close(file,MYF(0)); } -exit: return error; } @@ -104,7 +103,7 @@ static bool load_db_opt(const char *path, HA_CREATE_INFO *create) IO_CACHE cache; init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)); - while ((int) (nbytes= my_b_gets(&cache, (byte*) buf, sizeof(buf))) > 0) + while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) { char *pos= buf+nbytes-1; /* Remove end space and control characters */ @@ -251,10 +250,8 @@ exit2: int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { char path[FN_REFLEN+16]; - MY_DIR *dirp; long result=1; int error = 0; - register File file; uint create_options = create_info ? create_info->options : 0; DBUG_ENTER("mysql_alter_db"); @@ -602,7 +599,7 @@ bool mysql_change_db(THD *thd, const char *name) int mysqld_show_create_db(THD *thd, const char *dbname) { - int length, db_length; + int length; char path[FN_REFLEN], *to; uint db_access; bool found_libchar; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0581e0b5a3b..cb1a9db70cd 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -117,8 +117,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, MYF(MY_FAE | MY_ZEROFILL)); if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (table->found_records = filesort(table, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + (table->found_records = filesort(thd, table, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { @@ -330,7 +330,7 @@ bool multi_delete::send_data(List<Item> &values) table->status|= STATUS_DELETED; if (!(error=table->file->delete_row(table->record[0]))) deleted++; - else + else if (!table_being_deleted->next) { table->file->print_error(error,MYF(0)); DBUG_RETURN(1); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 122ceeedc54..9f09afc78a6 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -944,7 +944,7 @@ void st_select_lex_unit::init_query() global_parameters= this; select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; - optimized= 0; + prepared= optimized= 0; item= 0; } @@ -955,6 +955,7 @@ void st_select_lex::init_query() table_list.first= 0; table_list.next= (byte**) &table_list.first; item_list.empty(); + join= 0; } void st_select_lex::init_select() @@ -973,7 +974,6 @@ void st_select_lex::init_select() ftfunc_list= &ftfunc_list_alloc; linkage= UNSPECIFIED_TYPE; depended= having_fix_field= 0; - } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index acf73f34d5d..de57e9f77a8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -210,7 +210,7 @@ private: SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group SELECT_LEXs */ -class st_lex; +struct st_lex; class st_select_lex; class THD; class select_result; @@ -227,6 +227,7 @@ protected: select_result *result; int res; bool describe, found_rows_for_union, + prepared, //prepare phase already performed for UNION (unit) optimized; // optimize phase already performed for UNION (unit) public: /* @@ -333,6 +334,7 @@ typedef struct st_lex enum SSL_type ssl_type; /* defined in violite.h */ String *wild; sql_exchange *exchange; + select_result *result; List<key_part_spec> col_list; List<key_part_spec> ref_list; @@ -376,7 +378,7 @@ typedef struct st_lex uint param_count; bool drop_primary, drop_if_exists, local_file, olap; bool in_comment, ignore_space, verbose, simple_alter; - bool derived_tables; + bool derived_tables, describe; uint slave_thd_opt; CHARSET_INFO *charset; } LEX; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 595df6b7b7d..96b48ebd1fd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1289,6 +1289,7 @@ mysql_execute_command(THD *thd) int res= 0; LEX *lex= &thd->lex; TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first; + TABLE_LIST *cursor; SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_execute_command"); @@ -1336,8 +1337,7 @@ mysql_execute_command(THD *thd) TODO: solve problem with depended derived tables in subselects */ if (lex->sql_command == SQLCOM_SELECT && - (select_lex->options & SELECT_DESCRIBE) && - lex->derived_tables) + lex->describe && lex->derived_tables) { if (!(explain_result= new select_send())) { @@ -1345,7 +1345,7 @@ mysql_execute_command(THD *thd) DBUG_VOID_RETURN; } //check rights - for (TABLE_LIST *cursor= tables; + for (cursor= tables; cursor; cursor= cursor->next) if (cursor->derived) @@ -1363,7 +1363,7 @@ mysql_execute_command(THD *thd) } thd->send_explain_fields(explain_result); // EXPLAIN derived tables - for (TABLE_LIST *cursor= tables; + for (cursor= tables; cursor; cursor= cursor->next) if (cursor->derived) @@ -1405,9 +1405,7 @@ mysql_execute_command(THD *thd) switch (lex->sql_command) { case SQLCOM_SELECT: { - select_result *result; - if (select_lex->options & SELECT_DESCRIBE) - lex->exchange=0; + select_result *result=lex->result; if (tables) { res=check_table_access(thd, @@ -1432,51 +1430,10 @@ mysql_execute_command(THD *thd) if (unit->select_limit_cnt == HA_POS_ERROR) select_lex->options&= ~OPTION_FOUND_ROWS; - if (lex->exchange) - { - if (lex->exchange->dumpfile) - { - if (!(result=new select_dump(lex->exchange))) - { - res= -1; - break; - } - } - else - { - if (!(result=new select_export(lex->exchange))) - { - res= -1; - break; - } - } - } - else if (!(result=new select_send())) - { - res= -1; -#ifdef DELETE_ITEMS - delete select_lex->having; - delete select_lex->where; -#endif - break; - } - else - { - /* - Normal select: - Change lock if we are using SELECT HIGH PRIORITY, - FOR UPDATE or IN SHARE MODE - */ - TABLE_LIST *table; - for (table = tables ; table ; table=table->next) - table->lock_type= lex->lock_option; - } - if (!(res=open_and_lock_tables(thd,tables))) { - if (select_lex->options & SELECT_DESCRIBE) + if (lex->describe) { - delete result; // we do not need it for explain if (!explain_result) if (!(explain_result= new select_send())) { @@ -1486,24 +1443,7 @@ mysql_execute_command(THD *thd) else thd->send_explain_fields(explain_result); fix_tables_pointers(select_lex); - for ( SELECT_LEX *sl= select_lex; - sl && res == 0; - sl= sl->next_select_in_list()) - { - SELECT_LEX *first= sl->master_unit()->first_select(); - res= mysql_explain_select(thd, sl, - ((select_lex==sl)? - ((sl->next_select_in_list())?"PRIMARY": - "SIMPLE"): - ((sl == first)? - ((sl->depended)?"DEPENDENT SUBSELECT": - "SUBSELECT"): - ((sl->depended)?"DEPENDENT UNION": - "UNION"))), - explain_result); - } - if (res > 0) - res= -res; // mysql_explain_select do not report error + res= mysql_explain_union(thd, &thd->lex.unit, explain_result); MYSQL_LOCK *save_lock= thd->lock; thd->lock= (MYSQL_LOCK *)0; explain_result->send_eof(); @@ -1511,12 +1451,33 @@ mysql_execute_command(THD *thd) } else { + if (!result) + { + if ((result=new select_send())) + { + /* + Normal select: + Change lock if we are using SELECT HIGH PRIORITY, + FOR UPDATE or IN SHARE MODE + */ + TABLE_LIST *table; + for (table = tables ; table ; table=table->next) + table->lock_type= lex->lock_option; + } + else + { + res= -1; +#ifdef DELETE_ITEMS + delete select_lex->having; + delete select_lex->where; +#endif + break; + } + } query_cache_store_query(thd, tables); res=handle_select(thd, lex, result); } } - else - delete result; break; } case SQLCOM_DO: @@ -2947,7 +2908,7 @@ mysql_init_query(THD *thd) thd->free_list= 0; thd->lex.union_option= 0; thd->lex.select= &thd->lex.select_lex; - thd->lex.olap=0; + thd->lex.olap=thd->lex.describe=0; thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE; thd->fatal_error= 0; // Safety thd->total_warn_count=0; // Warnings for this query @@ -2967,6 +2928,7 @@ mysql_init_select(LEX *lex) lex->thd->variables.select_limit; select_lex->olap= UNSPECIFIED_OLAP_TYPE; lex->exchange= 0; + lex->result= 0; lex->proc_list.first= 0; } @@ -3570,10 +3532,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) } if (options & REFRESH_LOG) { - mysql_log.new_file(); - mysql_update_log.new_file(); - mysql_bin_log.new_file(); - mysql_slow_log.new_file(); + mysql_log.new_file(1); + mysql_update_log.new_file(1); + mysql_bin_log.new_file(1); + mysql_slow_log.new_file(1); if (ha_flush_logs()) result=1; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a085795fa76..bd115f0fc1e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -634,7 +634,6 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { MEM_ROOT thd_root = thd->mem_root; PREP_STMT stmt; - bool error; DBUG_ENTER("mysql_stmt_prepare"); bzero((char*) &stmt, sizeof(stmt)); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f850134190d..84ffa9c6663 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -112,7 +112,10 @@ static Item* part_of_refkey(TABLE *form,Field *field); static uint find_shortest_key(TABLE *table, key_map usable_keys); static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, ha_rows select_limit, bool no_changes); -static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit); +static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, + ha_rows filesort_limit, ha_rows select_limit); +static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, + ha_rows select_limit); static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields, Item *having); static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field, @@ -171,7 +174,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) result->abort(); if (res || thd->net.report_error) { - send_error(thd, 0, MYF(0)); + send_error(thd, 0, NullS); res= 1; } delete result; @@ -213,7 +216,7 @@ JOIN::prepare(TABLE_LIST *tables_init, SELECT_LEX_UNIT *unit, bool fake_select_lex) { DBUG_ENTER("JOIN::prepare"); - + conds= conds_init; order= order_init; group_list= group_init; @@ -348,7 +351,7 @@ int JOIN::optimize() { DBUG_ENTER("JOIN::optimize"); - + #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ if (having && !group_list && ! sum_func_count) @@ -748,8 +751,8 @@ JOIN::exec() { DBUG_PRINT("info",("Sorting for group")); thd->proc_info="Sorting for group"; - if (create_sort_index(&join_tab[const_tables], group_list, - HA_POS_ERROR) || + if (create_sort_index(thd, &join_tab[const_tables], group_list, + HA_POS_ERROR, HA_POS_ERROR) || make_sum_func_list(this, all_fields) || alloc_group_fields(this, group_list)) DBUG_VOID_RETURN; @@ -763,8 +766,8 @@ JOIN::exec() { DBUG_PRINT("info",("Sorting for order")); thd->proc_info="Sorting for order"; - if (create_sort_index(&join_tab[const_tables], order, - HA_POS_ERROR)) + if (create_sort_index(thd, &join_tab[const_tables], order, + HA_POS_ERROR, HA_POS_ERROR)) DBUG_VOID_RETURN; order=0; } @@ -866,7 +869,8 @@ JOIN::exec() if (group_list) { thd->proc_info="Creating sort index"; - if (create_sort_index(join_tab, group_list, HA_POS_ERROR) || + if (create_sort_index(thd, join_tab, group_list, HA_POS_ERROR, + HA_POS_ERROR) || alloc_group_fields(this, group_list)) { free_tmp_table(thd,tmp_table2); /* purecov: inspected */ @@ -962,12 +966,33 @@ JOIN::exec() DBUG_EXECUTE("where",print_where(conds,"having after sort");); } } - if (create_sort_index(&join_tab[const_tables], - group_list ? group_list : order, - (having_list || group_list || - (select_options & OPTION_FOUND_ROWS)) ? - HA_POS_ERROR : unit->select_limit_cnt)) - DBUG_VOID_RETURN; + { + ha_rows select_limit= unit->select_limit_cnt; + if (having || group || (select_options & OPTION_FOUND_ROWS)) + select_limit= HA_POS_ERROR; + else + { + /* + We can abort sorting after thd->select_limit rows if we there is no + WHERE clause for any tables after the sorted one. + */ + JOIN_TAB *table= &join_tab[const_tables+1]; + JOIN_TAB *end_table= &join_tab[tables]; + for (; table < end_table ; table++) + { + if (table->select_cond) + { + /* We have to sort all rows */ + select_limit= HA_POS_ERROR; + break; + } + } + } + if (create_sort_index(thd, &join_tab[const_tables], + group_list ? group_list : order, + select_limit, unit->select_limit_cnt)) + DBUG_VOID_RETURN; + } } having=having_list; // Actually a parameter thd->proc_info="Sending data"; @@ -1018,36 +1043,60 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, bool fake_select_lex) { - JOIN *join = new JOIN(thd, fields, select_options, result); - DBUG_ENTER("mysql_select"); - thd->proc_info="init"; - thd->used_tables=0; // Updated by setup_fields - if (join->prepare(tables, conds, order, group, having, proc_param, - select_lex, unit, fake_select_lex)) + bool free_join= 1; + JOIN *join; + if (!fake_select_lex && select_lex->join != 0) { - DBUG_RETURN(-1); + //here is EXPLAIN of subselect or derived table + join= select_lex->join; + join->result= result; + if (!join->procedure && result->prepare(join->fields_list, unit)) + { + DBUG_RETURN(-1); + } + join->select_options= select_options; + free_join= 0; + } + else + { + join= new JOIN(thd, fields, select_options, result); + thd->proc_info="init"; + thd->used_tables=0; // Updated by setup_fields + + if (join->prepare(tables, conds, order, group, having, proc_param, + select_lex, unit, fake_select_lex)) + { + DBUG_RETURN(-1); + } } - switch (join->optimize()) { + + switch (join->optimize()) + { case 1: DBUG_RETURN(join->error); case -1: goto err; - } + } - if (join->global_optimize()) + if (free_join && join->global_optimize()) goto err; join->exec(); err: - thd->limit_found_rows = join->send_records; - thd->examined_row_count = join->examined_rows; - thd->proc_info="end"; - int error= (fake_select_lex?0:join->cleanup(thd)) || thd->net.report_error; - delete join; - DBUG_RETURN(error); + if (free_join) + { + thd->limit_found_rows = join->send_records; + thd->examined_row_count = join->examined_rows; + thd->proc_info="end"; + int error= (fake_select_lex?0:join->cleanup(thd)) || thd->net.report_error; + delete join; + DBUG_RETURN(error); + } + else + DBUG_RETURN(0); } /***************************************************************************** @@ -3605,6 +3654,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: case Item::FIELD_STD_ITEM: + case Item::SUBSELECT_ITEM: /* The following can only happen with 'CREATE TABLE ... SELECT' */ case Item::INT_ITEM: case Item::REAL_ITEM: @@ -3663,7 +3713,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, char *tmpname,path[FN_REFLEN]; byte *pos,*group_buff; uchar *null_flags; - Field **reg_field,**from_field; + Field **reg_field, **from_field, **blob_field; Copy_field *copy=0; KEY *keyinfo; KEY_PART_INFO *key_part_info; @@ -3708,8 +3758,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, hidden_field_count=param->hidden_field_count; if (!my_multi_malloc(MYF(MY_WME), &table,sizeof(*table), - ®_field,sizeof(Field*)*(field_count+1), - &from_field,sizeof(Field*)*field_count, + ®_field, sizeof(Field*)*(field_count+1), + &blob_field, sizeof(Field*)*(field_count+1), + &from_field, sizeof(Field*)*field_count, ©_func,sizeof(*copy_func)*(param->func_count+1), ¶m->keyinfo,sizeof(*param->keyinfo), &key_part_info, @@ -3738,8 +3789,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, bzero((char*) reg_field,sizeof(Field*)*(field_count+1)); bzero((char*) from_field,sizeof(Field*)*field_count); table->field=reg_field; + table->blob_field= (Field_blob**) blob_field; table->real_name=table->path=tmpname; - table->table_name=base_name(tmpname); + /* + This must be "" as field may refer to it after tempory table is dropped + */ + table->table_name= (char*) ""; table->reginfo.lock_type=TL_WRITE; /* Will be updated */ table->db_stat=HA_OPEN_KEYFILE+HA_OPEN_RNDFILE; table->blob_ptr_size=mi_portable_sizeof_char_ptr; @@ -3748,7 +3803,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->derived_select_number= 0; table->db_low_byte_first=1; // True for HEAP and MyISAM table->temp_pool_slot = temp_pool_slot; - + table->copy_blobs= 1; /* Calculate which type of fields we will store in the temporary table */ @@ -3795,7 +3850,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (!(new_field->flags & NOT_NULL_FLAG)) null_count++; if (new_field->flags & BLOB_FLAG) + { + *blob_field++= new_field; blob_count++; + } ((Item_sum*) item)->args[i]= new Item_field(new_field); } } @@ -3818,7 +3876,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (!(new_field->flags & NOT_NULL_FLAG)) null_count++; if (new_field->flags & BLOB_FLAG) + { + *blob_field++= new_field; blob_count++; + } if (item->marker == 4 && item->maybe_null) { group_null_items++; @@ -3831,6 +3892,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= (uint) (reg_field - table->field); + *blob_field= 0; // End marker /* If result table is small; use a heap */ if (blob_count || using_unique_constraint || group_null_items || @@ -4088,10 +4150,17 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (create_myisam_tmp_table(table,param,select_options)) goto err; } + /* Set table_name for easier debugging */ + table->table_name= base_name(tmpname); if (!open_tmp_table(table)) DBUG_RETURN(table); err: + /* + Hack to ensure that free_blobs() doesn't fail if blob_field is not yet + complete + */ + *table->blob_field= 0; free_tmp_table(thd,table); /* purecov: inspected */ bitmap_clear_bit(&temp_pool, temp_pool_slot); DBUG_RETURN(NULL); /* purecov: inspected */ @@ -4236,6 +4305,7 @@ free_tmp_table(THD *thd, TABLE *entry) save_proc_info=thd->proc_info; thd->proc_info="removing tmp table"; + free_blobs(entry); if (entry->db_stat && entry->file) { (void) entry->file->close(); @@ -5797,7 +5867,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, *****************************************************************************/ static int -create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) +create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, + ha_rows filesort_limit, ha_rows select_limit) { SORT_FIELD *sortorder; uint length; @@ -5841,8 +5912,8 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit) } if (table->tmp_table) table->file->info(HA_STATUS_VARIABLE); // Get record count - table->found_records=filesort(table,sortorder,length, - select, 0L, select_limit, &examined_rows); + table->found_records=filesort(thd, table,sortorder, length, + select, filesort_limit, &examined_rows); tab->records=table->found_records; // For SQL_CALC_ROWS delete select; // filesort did select tab->select=0; @@ -5940,7 +6011,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) int error; ulong reclength,offset; uint field_count; - THD *thd= current_thd; + THD *thd= join->thd; DBUG_ENTER("remove_duplicates"); entry->reginfo.lock_type=TL_WRITE; @@ -6490,7 +6561,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, order->in_field_list=1; return 0; } - Item **item=find_item_in_list(*order->item, fields, 0); + Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS); if (item) { order->item=item; // use it @@ -6590,7 +6661,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, thd->set_query_id=1; // Not really needed, but... for (; new_field ; new_field= new_field->next) { - if ((item= find_item_in_list(*new_field->item, fields, 0))) + if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS))) new_field->item=item; /* Change to shared Item */ else { @@ -7179,7 +7250,6 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct,const char *message) { List<Item> field_list; - Item *item; List<Item> item_list; THD *thd=join->thd; SELECT_LEX *select_lex = &(join->thd->lex.select_lex); @@ -7193,7 +7263,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (message) { - item_list.push_back(new Item_int((int)thd->lex.select->select_number)); + item_list.push_back(new Item_int((int32) thd->lex.select->select_number)); item_list.push_back(new Item_string(thd->lex.select->type, strlen(thd->lex.select->type), default_charset_info)); @@ -7220,7 +7290,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, tmp2.length(0); item_list.empty(); - item_list.push_back(new Item_int((int)thd->lex.select->select_number)); + item_list.push_back(new Item_int((int32) thd->lex.select->select_number)); item_list.push_back(new Item_string(thd->lex.select->type, strlen(thd->lex.select->type), default_charset_info)); @@ -7368,9 +7438,43 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, result->send_error(0,NullS); } } + for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); + unit; + unit= unit->next_unit()) + { + if (mysql_explain_union(thd, unit, result)) + DBUG_VOID_RETURN; + } DBUG_VOID_RETURN; } +int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) +{ + int res= 0; + SELECT_LEX *first= unit->first_select(); + for (SELECT_LEX *sl= first; + sl; + sl= sl->next_select()) + { + res= mysql_explain_select(thd, sl, + (((&thd->lex.select_lex)==sl)? + ((sl->next_select_in_list())?"PRIMARY": + "SIMPLE"): + ((sl == first)? + ((sl->depended)?"DEPENDENT SUBSELECT": + "SUBSELECT"): + ((sl->depended)?"DEPENDENT UNION": + "UNION"))), + result); + if (res) + break; + + } + if (res > 0) + res= -res; // mysql_explain_select do not report error + return res; +} + int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_result *result) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 93c7c07a347..eca86a60887 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -230,7 +230,7 @@ int mysqld_show_table_types(THD *thd) const char *option_name= show_comp_option_name[(int) *types->value]; if (*types->value == SHOW_OPTION_YES && - !strcasecmp(default_type_name, types->type)) + !my_strcasecmp(system_charset_info, default_type_name, types->type)) option_name= "DEFAULT"; net_store_data(packet, option_name); net_store_data(packet, types->comment); @@ -1401,12 +1401,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) int mysqld_show_charsets(THD *thd, const char *wild) { - uint i; char buff[8192]; String packet2(buff,sizeof(buff),default_charset_info); List<Item> field_list; CONVERT *convert=thd->variables.convert_set; - CHARSET_INFO *cs; + CHARSET_INFO **cs; DBUG_ENTER("mysqld_show_charsets"); field_list.push_back(new Item_empty_string("Name",30)); @@ -1419,16 +1418,16 @@ int mysqld_show_charsets(THD *thd, const char *wild) for (cs=all_charsets ; cs < all_charsets+255 ; cs++ ) { - if (!cs->name) + if (!cs[0]) continue; if (!(wild && wild[0] && - wild_case_compare(system_charset_info,cs->name,wild))) + wild_case_compare(system_charset_info,cs[0]->name,wild))) { packet2.length(0); - net_store_data(&packet2,convert,cs->name); - net_store_data(&packet2,(uint32) cs->number); - net_store_data(&packet2,(uint32) cs->strxfrm_multiply); - net_store_data(&packet2,(uint32) cs->mbmaxlen ? cs->mbmaxlen : 1); + net_store_data(&packet2,convert,cs[0]->name); + net_store_data(&packet2,(uint32) cs[0]->number); + net_store_data(&packet2,(uint32) cs[0]->strxfrm_multiply); + net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen ? cs[0]->mbmaxlen : 1)); if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) goto err; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 6a42078cbcd..d2d14d4e7a2 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -505,7 +505,7 @@ int sortcmp(const String *x,const String *y) uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len); #ifdef USE_STRCOLL - if (use_strcoll(x->str_charset)) + if (use_strnxfrm(x->str_charset)) { #ifndef CMP_ENDSPACE while (x_len && my_isspace(x->str_charset,s[x_len-1])) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ccb7b5e5a9a..803d4102563 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2114,8 +2114,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (from->found_records = filesort(from, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + (from->found_records = filesort(thd, from, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) goto err; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index ef26a1f45fe..538417f43ea 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -97,7 +97,7 @@ void print_cached_tables(void) } -void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special) +void TEST_filesort(SORT_FIELD *sortorder,uint s_length) { char buff[256],buff2[256]; String str(buff,sizeof(buff),default_charset_info); @@ -131,8 +131,6 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special) out.append('\0'); // Purify doesn't like c_ptr() DBUG_LOCK_FILE; VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE)); - if (special) - fprintf(DBUG_FILE,"Records to sort: %ld\n",special); fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr()); DBUG_UNLOCK_FILE; DBUG_VOID_RETURN; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 1a18759eb5b..eaeec2c1e68 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -104,14 +104,19 @@ bool select_union::flush() typedef JOIN * JOIN_P; int st_select_lex_unit::prepare(THD *thd, select_result *result) { + DBUG_ENTER("st_select_lex_unit::prepare"); + + if (prepared) + DBUG_RETURN(0); + prepared= 1; + union_result=0; describe=(first_select()->options & SELECT_DESCRIBE) ? 1 : 0; res= 0; found_rows_for_union= false; TMP_TABLE_PARAM tmp_table_param; - DBUG_ENTER("st_select_lex_unit::prepare"); this->thd= thd; this->result= result; - SELECT_LEX *lex_select_save= thd->lex.select; + SELECT_LEX *lex_select_save= thd->lex.select, *sl; /* Global option */ if (((void*)(global_parameters)) == ((void*)this)) @@ -179,7 +184,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) // prepare selects joins.empty(); - for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + for (sl= first_select(); sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK | @@ -304,10 +309,12 @@ int st_select_lex_unit::exec() int st_select_lex_unit::cleanup() { DBUG_ENTER("st_select_lex_unit::cleanup"); - delete union_result; - free_tmp_table(thd,table); - table= 0; // Safety - + if (union_result) + { + delete union_result; + free_tmp_table(thd,table); + table= 0; // Safety + } List_iterator<JOIN*> j(joins); JOIN** join; while ((join= j++)) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 5d94b54f347..c146b07284f 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -190,8 +190,8 @@ int mysql_update(THD *thd, MYF(MY_FAE | MY_ZEROFILL)); if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (table->found_records = filesort(table, sortorder, length, - (SQL_SELECT *) 0, 0L, + (table->found_records = filesort(thd, table, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { @@ -776,7 +776,7 @@ bool multi_update::send_eof() thd->proc_info="updating the reference tables"; /* Does updates for the last n - 1 tables, returns 0 if ok */ - int error = do_updates(false); /* do_updates returns 0 if success */ + int error = (num_updated > 1) ? do_updates(false) : 0; /* do_updates returns 0 if success */ /* reset used flags */ #ifndef NOT_USED diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f7ab07b2da3..4f75716ff56 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -520,10 +520,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %left '^' %right NOT %right BINARY COLLATE_SYM +/* These don't actually affect the way the query is really evaluated, but + they silence a few warnings for shift/reduce conflicts. */ +%left ',' +%left STRAIGHT_JOIN JOIN_SYM +%nonassoc CROSS INNER_SYM NATURAL LEFT RIGHT %type <lex_str> IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME - ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET + ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET %type <lex_str_ptr> opt_table_alias @@ -632,7 +637,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild union union_list precision union_option opt_on_delete_item subselect_start opt_and - subselect_end + subselect_end select_var_list select_var_list_init END_OF_INPUT %type <NONE> @@ -754,7 +759,8 @@ master_def: RELAY_LOG_POS_SYM EQ ULONG_NUM { Lex->mi.relay_log_pos = $3; - }; + } + ; /* create a table */ @@ -819,11 +825,13 @@ create: LEX *lex=Lex; lex->udf.returns=(Item_result) $7; lex->udf.dl=$9.str; - }; + } + ; create2: '(' field_list ')' opt_create_table_options create3 {} - | opt_create_table_options create3 {}; + | opt_create_table_options create3 {} + ; create3: /* empty */ {} @@ -833,7 +841,8 @@ create3: lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; mysql_init_select(lex); } - select_options select_item_list opt_select_from union {}; + select_options select_item_list opt_select_from union {} + ; opt_as: /* empty */ {} @@ -1544,6 +1553,7 @@ select_part2: select_into: limit_clause {} | select_from + | opt_into | opt_into select_from | select_from opt_into; @@ -2209,11 +2219,12 @@ opt_pad: join_table_list: '(' join_table_list ')' { $$=$2; } | join_table { $$=$1; } - | join_table_list normal_join join_table { $$=$3; } - | join_table_list STRAIGHT_JOIN join_table { $$=$3 ; $$->straight=1; } - | join_table_list INNER_SYM JOIN_SYM join_table ON expr + | join_table_list normal_join join_table_list { $$=$3; } + | join_table_list STRAIGHT_JOIN join_table_list + { $$=$3 ; $$->straight=1; } + | join_table_list INNER_SYM JOIN_SYM join_table_list ON expr { add_join_on($4,$6); $$=$4; } - | join_table_list INNER_SYM JOIN_SYM join_table + | join_table_list INNER_SYM JOIN_SYM join_table_list { SELECT_LEX *sel=Select; sel->db1=$1->db; sel->table1=$1->alias; @@ -2221,9 +2232,9 @@ join_table_list: } USING '(' using_list ')' { add_join_on($4,$8); $$=$4; } - | join_table_list LEFT opt_outer JOIN_SYM join_table ON expr + | join_table_list LEFT opt_outer JOIN_SYM join_table_list ON expr { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } - | join_table_list LEFT opt_outer JOIN_SYM join_table + | join_table_list LEFT opt_outer JOIN_SYM join_table_list { SELECT_LEX *sel=Select; sel->db1=$1->db; sel->table1=$1->alias; @@ -2231,11 +2242,11 @@ join_table_list: } USING '(' using_list ')' { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } - | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table + | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list { add_join_natural($1,$6); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } - | join_table_list RIGHT opt_outer JOIN_SYM join_table ON expr + | join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } - | join_table_list RIGHT opt_outer JOIN_SYM join_table + | join_table_list RIGHT opt_outer JOIN_SYM join_table_list { SELECT_LEX *sel=Select; sel->db1=$1->db; sel->table1=$1->alias; @@ -2243,9 +2254,9 @@ join_table_list: } USING '(' using_list ')' { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } - | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table + | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list { add_join_natural($6,$1); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } - | join_table_list NATURAL JOIN_SYM join_table + | join_table_list NATURAL JOIN_SYM join_table_list { add_join_natural($1,$4); $$=$4; }; normal_join: @@ -2287,11 +2298,11 @@ select_part3: mysql_init_select(lex); lex->select->linkage= DERIVED_TABLE_TYPE; } - select_options select_item_list select_intoto + select_options select_item_list select_intoto; select_intoto: limit_clause {} - | select_from + | select_from; opt_outer: /* empty */ {} @@ -2542,20 +2553,61 @@ procedure_item: YYABORT; if (!$2->name) $2->set_name($1,(uint) ((char*) Lex->tok_end - $1)); - }; + } + ; + + +select_var_list_init: + { + LEX *lex=Lex; + if (!lex->describe && (!(lex->result= new select_dumpvar()))) + YYABORT; + } + select_var_list + ; + +select_var_list: + select_var_list ',' select_var_ident + | select_var_ident {} + ; + +select_var_ident: '@' ident_or_text + { + LEX *lex=Lex; + if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)))) + YYABORT; + } + ; opt_into: - INTO OUTFILE TEXT_STRING + INTO OUTFILE TEXT_STRING { - if (!(Lex->exchange= new sql_exchange($3.str,0))) - YYABORT; + LEX *lex=Lex; + if (!lex->describe) + { + if (!(lex->exchange= new sql_exchange($3.str,0))) + YYABORT; + if (!(lex->result= new select_export(lex->exchange))) + YYABORT; + } } opt_field_term opt_line_term | INTO DUMPFILE TEXT_STRING { - if (!(Lex->exchange= new sql_exchange($3.str,1))) - YYABORT; - }; + LEX *lex=Lex; + if (!lex->describe) + { + if (!(lex->exchange= new sql_exchange($3.str,1))) + YYABORT; + if (!(lex->result= new select_dump(lex->exchange))) + YYABORT; + } + } + | INTO select_var_list_init + { + current_thd->safe_to_cache_query=0; + } + ; /* DO statement @@ -3019,7 +3071,11 @@ describe: } opt_describe_column | describe_command select - { Lex->select_lex.options|= SELECT_DESCRIBE; }; + { + LEX *lex=Lex; + lex->select_lex.options|= SELECT_DESCRIBE; + lex->describe=1; + }; describe_command: @@ -3225,7 +3281,7 @@ param_marker: yyerror("You have an error in your SQL syntax"); YYABORT; } - } + }; literal: text_literal { $$ = $1; } | NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); } @@ -3566,6 +3622,7 @@ option_value: { Lex->var_list.push_back(new set_var_password($3,$5)); } + ; internal_variable_name: ident @@ -3575,6 +3632,7 @@ internal_variable_name: YYABORT; $$=tmp; } + ; isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } @@ -3595,7 +3653,8 @@ text_or_password: make_scrambled_password(buff,$3.str); $$=buff; } - }; + } + ; set_expr_or_default: @@ -3625,16 +3684,19 @@ table_lock_list: table_lock: table_ident opt_table_alias lock_option - { if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; }; + { if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; } + ; lock_option: READ_SYM { $$=TL_READ_NO_INSERT; } | WRITE_SYM { $$=current_thd->update_lock_default; } | LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; } - | READ_SYM LOCAL_SYM { $$= TL_READ; }; + | READ_SYM LOCAL_SYM { $$= TL_READ; } + ; unlock: - UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }; + UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } + ; /* @@ -3664,15 +3726,18 @@ handler: if (!add_table_to_list($2,0,0)) YYABORT; } - handler_read_or_scan where_clause limit_clause { }; + handler_read_or_scan where_clause limit_clause { } + ; handler_read_or_scan: handler_scan_function { Lex->backup_dir= 0; } - | ident handler_rkey_function { Lex->backup_dir= $1.str; }; + | ident handler_rkey_function { Lex->backup_dir= $1.str; } + ; handler_scan_function: FIRST_SYM { Lex->ha_read_mode = RFIRST; } - | NEXT_SYM { Lex->ha_read_mode = RNEXT; }; + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + ; handler_rkey_function: FIRST_SYM { Lex->ha_read_mode = RFIRST; } @@ -3686,14 +3751,16 @@ handler_rkey_function: lex->ha_rkey_mode=$1; if (!(lex->insert_list = new List_item)) YYABORT; - } '(' values ')' { }; + } '(' values ')' { } + ; handler_rkey_mode: EQ { $$=HA_READ_KEY_EXACT; } | GE { $$=HA_READ_KEY_OR_NEXT; } | LE { $$=HA_READ_KEY_OR_PREV; } | GT_SYM { $$=HA_READ_AFTER_KEY; } - | LT { $$=HA_READ_BEFORE_KEY; }; + | LT { $$=HA_READ_BEFORE_KEY; } + ; /* GRANT / REVOKE */ @@ -3731,7 +3798,8 @@ grant: grant_privileges: grant_privilege_list {} | ALL PRIVILEGES { Lex->grant = GLOBAL_ACLS;} - | ALL { Lex->grant = GLOBAL_ACLS;}; + | ALL { Lex->grant = GLOBAL_ACLS;} + ; grant_privilege_list: grant_privilege @@ -3850,7 +3918,8 @@ opt_table: YYABORT; if (lex->grant == GLOBAL_ACLS) lex->grant = TABLE_ACLS & ~GRANT_ACL; - }; + } + ; user_list: @@ -3881,7 +3950,8 @@ grant_user: | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING { $$=$1; $1->password=$5 ; } | user - { $$=$1; $1->password.str=NullS; }; + { $$=$1; $1->password.str=NullS; } + ; opt_column_list: @@ -3914,7 +3984,8 @@ column_list_id: point->rights |= lex->which_columns; else lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns)); - }; + } + ; require_clause: /* empty */ @@ -3934,6 +4005,7 @@ require_clause: /* empty */ { Lex->ssl_type=SSL_TYPE_NONE; } + ; grant_options: /* empty */ {} @@ -3941,7 +4013,8 @@ grant_options: grant_option_list: grant_option_list grant_option {} - | grant_option {}; + | grant_option {} + ; grant_option: GRANT OPTION { Lex->grant |= GRANT_ACL;} @@ -3959,14 +4032,16 @@ grant_option: { Lex->mqh.connections=$2; Lex->mqh.bits |= 4; - }; + } + ; begin: BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work; opt_work: /* empty */ {} - | WORK_SYM {;}; + | WORK_SYM {;} + ; commit: COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}; @@ -4076,4 +4151,4 @@ subselect_end: { LEX *lex=Lex; lex->select = lex->select->outer_select(); - } + }; diff --git a/sql/table.cc b/sql/table.cc index 2cdd62001f1..122cce160b6 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -527,6 +527,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, field->field_length=key_part->length; } } + /* + If the field can be NULL, don't optimize away the test + key_part_column = expression from the WHERE clause + as we need to test for NULL = NULL. + */ + if (field->real_maybe_null()) + key_part->key_part_flag|= HA_PART_KEY; } else { // Error: shorten key |