diff options
author | Sergei Golubchik <sergii@pisem.net> | 2010-10-28 19:04:23 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2010-10-28 19:04:23 +0200 |
commit | 8e7ebfbce89a472b3c5a6c30e6de101e567a8218 (patch) | |
tree | 9f9950feb45222c7df4f37c841f4af593ec75ee5 /sql | |
parent | 3bdede3c67032345ca5f71dd53ca308377dc2398 (diff) | |
parent | 7c24e8d54d1d41374b7836e3273e7e5eaf22e2c4 (diff) | |
download | mariadb-git-8e7ebfbce89a472b3c5a6c30e6de101e567a8218.tar.gz |
5.2 merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 4 | ||||
-rw-r--r-- | sql/ha_partition.cc | 7 | ||||
-rw-r--r-- | sql/handler.cc | 42 | ||||
-rw-r--r-- | sql/handler.h | 11 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 2 | ||||
-rw-r--r-- | sql/item_func.cc | 24 | ||||
-rw-r--r-- | sql/item_func.h | 1 | ||||
-rw-r--r-- | sql/item_geofunc.h | 15 | ||||
-rw-r--r-- | sql/item_sum.cc | 26 | ||||
-rw-r--r-- | sql/item_sum.h | 1 | ||||
-rw-r--r-- | sql/item_timefunc.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 118 | ||||
-rw-r--r-- | sql/multi_range_read.cc | 6 | ||||
-rw-r--r-- | sql/mysqld.cc | 21 | ||||
-rw-r--r-- | sql/opt_range.cc | 15 | ||||
-rw-r--r-- | sql/opt_subselect.h | 2 | ||||
-rw-r--r-- | sql/spatial.cc | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 8 | ||||
-rw-r--r-- | sql/sql_insert.cc | 125 | ||||
-rw-r--r-- | sql/sql_lex.h | 17 | ||||
-rw-r--r-- | sql/sql_load.cc | 8 | ||||
-rw-r--r-- | sql/sql_parse.cc | 19 | ||||
-rw-r--r-- | sql/sql_select.cc | 108 | ||||
-rw-r--r-- | sql/sql_select.h | 5 | ||||
-rw-r--r-- | sql/sql_show.cc | 67 | ||||
-rw-r--r-- | sql/sql_string.cc | 4 | ||||
-rw-r--r-- | sql/sql_string.h | 16 | ||||
-rw-r--r-- | sql/sql_update.cc | 69 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 46 | ||||
-rw-r--r-- | sql/tztime.cc | 2 |
30 files changed, 518 insertions, 279 deletions
diff --git a/sql/field.cc b/sql/field.cc index 56f45158b7f..bf496406fd6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1536,7 +1536,7 @@ void Field::make_field(Send_field *field) } else field->org_table_name= field->db_name= ""; - if (orig_table) + if (orig_table && orig_table->alias) { field->table_name= orig_table->alias; field->org_col_name= field_name; @@ -4568,7 +4568,7 @@ String *Field_double::val_str(String *val_buffer, #endif doubleget(nr,ptr); - uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE); + uint to_length= DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE; val_buffer->alloc(to_length); char *to=(char*) val_buffer->ptr(); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e76b3607249..b777b26bab0 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2406,9 +2406,14 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) tot_partition_words= (m_tot_parts + 3) / 4; engine_array= (handlerton **) my_alloca(m_tot_parts * sizeof(handlerton*)); for (i= 0; i < m_tot_parts; i++) + { engine_array[i]= ha_resolve_by_legacy_type(ha_thd(), (enum legacy_db_type) - *(uchar *) ((file_buffer) + 12 + i)); + *(uchar *) ((file_buffer) + + 12 + i)); + if (!engine_array[i]) + goto err3; + } address_tot_name_len= file_buffer + 12 + 4 * tot_partition_words; tot_name_words= (uint4korr(address_tot_name_len) + 3) / 4; if (len_words != (tot_partition_words + tot_name_words + 4)) diff --git a/sql/handler.cc b/sql/handler.cc index 94e16499c59..1fcd9555221 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2049,6 +2049,21 @@ handler *handler::clone(MEM_ROOT *mem_root) return new_handler; } +double handler::keyread_time(uint index, uint ranges, ha_rows rows) +{ + /* + It is assumed that we will read trough the whole key range and that all + key blocks are half full (normally things are much better). It is also + assumed that each time we read the next key from the index, the handler + performs a random seek, thus the cost is proportional to the number of + blocks read. This model does not take into account clustered indexes - + engines that support that (e.g. InnoDB) may want to overwrite this method. + */ + double keys_per_block= (stats.block_size/2.0/ + (table->key_info[index].key_length + + ref_length) + 1); + return (rows + keys_per_block - 1)/ keys_per_block; +} void **handler::ha_data(THD *thd) const { @@ -3122,33 +3137,6 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) return update_frm_version(table); } -/* - Calculate cost of 'index only' scan for given index and number of records. - - SYNOPSIS - handler->keyread_read_time() - index key to read - ranges number of ranges - rows #of records to read - - NOTES - It is assumed that we will read trough all key ranges and that all - key blocks are half full (normally things are much better). It is also - assumed that each time we read the next key from the index, the handler - performs a random seek, thus the cost is proportional to the number of - blocks read. -*/ - -double handler::keyread_read_time(uint index, uint ranges, ha_rows rows) -{ - double read_time; - uint keys_per_block= (stats.block_size/2/ - (table->key_info[index].key_length + ref_length) + 1); - read_time=((double) (rows+keys_per_block-1)/ (double) keys_per_block); - return read_time; -} - - /** A helper function to mark a transaction read-write, if it is started. diff --git a/sql/handler.h b/sql/handler.h index 6eb496a38cc..f76580b7082 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1653,7 +1653,16 @@ public: { return ulonglong2double(stats.data_file_length) / IO_SIZE + 2; } virtual double read_time(uint index, uint ranges, ha_rows rows) { return rows2double(ranges+rows); } - virtual double keyread_read_time(uint index, uint ranges, ha_rows rows); + + /** + Calculate cost of 'keyread' scan for given index and number of records. + + @param index index to read + @param ranges #of ranges to read + @param rows #of records to read + */ + virtual double keyread_time(uint index, uint ranges, ha_rows rows); + virtual const key_map *keys_to_use_for_scanning() { return &key_map_empty; } bool has_transactions() { return (ha_table_flags() & HA_NO_TRANSACTIONS) == 0; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 288fa439fad..2b331fd4bf3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4778,7 +4778,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return TRUE; } - if (escape_item->const_item()) + if (escape_item->const_item() && !thd->lex->view_prepare_mode) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&cmp.value1); diff --git a/sql/item_func.cc b/sql/item_func.cc index f0ed8110b79..c4eb6cdc2aa 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2289,7 +2289,7 @@ void Item_func_min_max::fix_length_and_dec() stored to the value pointer, if latter is provided. RETURN - 0 If one of arguments is NULL + 0 If one of arguments is NULL or there was a execution error # index of the least/greatest argument */ @@ -2303,6 +2303,14 @@ uint Item_func_min_max::cmp_datetimes(ulonglong *value) Item **arg= args + i; bool is_null; longlong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null); + + /* Check if we need to stop (because of error or KILL) and stop the loop */ + if (thd->is_error()) + { + null_value= 1; + return 0; + } + if ((null_value= args[i]->null_value)) return 0; if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) @@ -2331,6 +2339,12 @@ String *Item_func_min_max::val_str(String *str) if (null_value) return 0; str_res= args[min_max_idx]->val_str(str); + if (args[min_max_idx]->null_value) + { + // check if the call to val_str() above returns a NULL value + null_value= 1; + return NULL; + } str_res->set_charset(collation.collation); return str_res; } @@ -4331,6 +4345,14 @@ longlong Item_func_set_user_var::val_int_result() return entry->val_int(&null_value); } +bool Item_func_set_user_var::val_bool_result() +{ + DBUG_ASSERT(fixed == 1); + check(TRUE); + update(); // Store expression + return entry->val_int(&null_value) != 0; +} + String *Item_func_set_user_var::str_result(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_func.h b/sql/item_func.h index 1aa8433b6dc..b6f516cf431 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1407,6 +1407,7 @@ public: my_decimal *val_decimal(my_decimal *); double val_result(); longlong val_int_result(); + bool val_bool_result(); String *str_result(String *str); my_decimal *val_decimal_result(my_decimal *); bool is_null_result(); diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index edbe104e307..b3ecbc39933 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -175,6 +175,21 @@ public: item_type=it; } String *val_str(String *); + void fix_length_and_dec() + { + for (unsigned int i= 0; i < arg_count; ++i) + { + if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) + { + String str; + args[i]->print(&str, QT_ORDINARY); + str.append('\0'); + my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "non geometric", + str.ptr()); + } + } + } + const char *func_name() const { return "multipoint"; } }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index f21d96a717a..ac6268d6acb 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -418,26 +418,6 @@ void Item_sum::mark_as_sum_func() } -void Item_sum::make_field(Send_field *tmp_field) -{ - if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) - { - ((Item_field*) args[0])->field->make_field(tmp_field); - /* For expressions only col_name should be non-empty string. */ - char *empty_string= (char*)""; - tmp_field->db_name= empty_string; - tmp_field->org_table_name= empty_string; - tmp_field->table_name= empty_string; - tmp_field->org_col_name= empty_string; - tmp_field->col_name= name; - if (maybe_null) - tmp_field->flags&= ~NOT_NULL_FLAG; - } - else - init_make_field(tmp_field, field_type()); -} - - void Item_sum::print(String *str, enum_query_type query_type) { /* orig_args is not filled with valid values until fix_fields() */ @@ -2566,7 +2546,8 @@ bool Item_sum_count_distinct::add() if (always_null) return 0; copy_fields(tmp_table_param); - copy_funcs(tmp_table_param->items_to_copy); + if (copy_funcs(tmp_table_param->items_to_copy, table->in_use)) + return TRUE; for (Field **field=table->field ; *field ; field++) if ((*field)->is_real_null(0)) @@ -3168,7 +3149,8 @@ bool Item_func_group_concat::add() if (always_null) return 0; copy_fields(tmp_table_param); - copy_funcs(tmp_table_param->items_to_copy); + if (copy_funcs(tmp_table_param->items_to_copy, table->in_use)) + return TRUE; for (uint i= 0; i < arg_count_field; i++) { diff --git a/sql/item_sum.h b/sql/item_sum.h index a47939187dd..b5516792676 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -354,7 +354,6 @@ public: forced_const= TRUE; } virtual bool const_item() const { return forced_const; } - void make_field(Send_field *field); virtual void print(String *str, enum_query_type query_type); void fix_num_length_and_dec(); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index e11449c200e..22df9f34926 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -917,6 +917,8 @@ public: { decimals=0; max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; + /* It returns NULL when the second argument is less or equal to 0 */ + maybe_null= 1; } longlong val_int(); }; diff --git a/sql/log.cc b/sql/log.cc index 8173b44c21f..07d9890ff78 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5139,71 +5139,93 @@ void sql_perror(const char *message) } +#ifdef __WIN__ +extern "C" my_bool reopen_fstreams(const char *filename, + FILE *outstream, FILE *errstream) +{ + int handle_fd; + int stream_fd; + HANDLE osfh; + + DBUG_ASSERT(filename && (outstream || errstream)); + + if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) + return TRUE; + + if ((handle_fd= _open_osfhandle((intptr_t)osfh, + _O_APPEND | _O_TEXT)) == -1) + { + CloseHandle(osfh); + return TRUE; + } + + if (outstream) + { + stream_fd= _fileno(outstream); + if (_dup2(handle_fd, stream_fd) < 0) + { + CloseHandle(osfh); + return TRUE; + } + } + + if (errstream) + { + stream_fd= _fileno(errstream); + if (_dup2(handle_fd, stream_fd) < 0) + { + CloseHandle(osfh); + return TRUE; + } + } + + _close(handle_fd); + return FALSE; +} +#else +extern "C" my_bool reopen_fstreams(const char *filename, + FILE *outstream, FILE *errstream) +{ + if (outstream && !freopen(filename, "a+", outstream)) + return TRUE; + + if (errstream && !freopen(filename, "a+", errstream)) + return TRUE; + + return FALSE; +} +#endif + + /* Unfortunately, there seems to be no good way to restore the original streams upon failure. */ static bool redirect_std_streams(const char *file) { - if (freopen(file, "a+", stdout) && freopen(file, "a+", stderr)) - { - setbuf(stderr, NULL); - return FALSE; - } + if (reopen_fstreams(file, stdout, stderr)) + return TRUE; - return TRUE; + setbuf(stderr, NULL); + return FALSE; } bool flush_error_log() { - bool result=0; + bool result= 0; if (opt_error_log) { - char err_renamed[FN_REFLEN], *end; - end= strmake(err_renamed,log_error_file,FN_REFLEN-5); - strmov(end, "-old"); VOID(pthread_mutex_lock(&LOCK_error_log)); -#ifdef __WIN__ - char err_temp[FN_REFLEN+5]; - /* - On Windows is necessary a temporary file for to rename - the current error file. - */ - strxmov(err_temp, err_renamed,"-tmp",NullS); - (void) my_delete(err_temp, MYF(0)); - if (freopen(err_temp,"a+",stdout)) - { - int fd; - size_t bytes; - uchar buf[IO_SIZE]; - - if (!freopen(err_temp,"a+",stderr)) - sql_print_error("Couldn't reopen stderr"); - setbuf(stderr, NULL); - (void) my_delete(err_renamed, MYF(0)); - my_rename(log_error_file,err_renamed,MYF(0)); - redirect_std_streams(log_error_file); - - if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0) - { - while ((bytes= my_read(fd, buf, IO_SIZE, MYF(0))) && - bytes != MY_FILE_ERROR) - my_fwrite(stderr, buf, bytes, MYF(0)); - my_close(fd, MYF(0)); - } - (void) my_delete(err_temp, MYF(0)); - } - else - result= 1; -#else - my_rename(log_error_file,err_renamed,MYF(0)); - if (redirect_std_streams(log_error_file)) - result= 1; -#endif + if (redirect_std_streams(log_error_file)) + result= 1; VOID(pthread_mutex_unlock(&LOCK_error_log)); } - return result; + return result; } void MYSQL_BIN_LOG::signal_update() diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index efb7ceff05f..53699c47688 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -92,7 +92,7 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, cost->zero(); cost->avg_io_cost= 1; /* assume random seeks */ if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2) - cost->io_count= keyread_read_time(keyno, n_ranges, (uint)total_rows); + cost->io_count= keyread_time(keyno, n_ranges, (uint)total_rows); else cost->io_count= read_time(keyno, n_ranges, total_rows); cost->cpu_cost= (double) total_rows / TIME_FOR_COMPARE + 0.01; @@ -147,7 +147,7 @@ ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows, /* Produce the same cost as non-MRR code does */ if (*flags & HA_MRR_INDEX_ONLY) - cost->io_count= keyread_read_time(keyno, n_ranges, n_rows); + cost->io_count= keyread_time(keyno, n_ranges, n_rows); else cost->io_count= read_time(keyno, n_ranges, n_rows); return 0; @@ -820,7 +820,7 @@ bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags, cost->mem_cost= (double)rows_in_last_step * elem_size; /* Total cost of all index accesses */ - index_read_cost= h->keyread_read_time(keynr, 1, (double)rows); + index_read_cost= h->keyread_time(keynr, 1, (double)rows); cost->add_io(index_read_cost, 1 /* Random seeks */); return FALSE; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 538467fd796..763515c9e9c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -197,6 +197,9 @@ typedef fp_except fp_except_t; # endif #endif +extern "C" my_bool reopen_fstreams(const char *filename, + FILE *outstream, FILE *errstream); + inline void setup_fpu() { #if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H) @@ -4027,14 +4030,15 @@ static int init_server_components() opt_error_log= 1; // Too long file name else { + my_bool res; #ifndef EMBEDDED_LIBRARY - if (freopen(log_error_file, "a+", stdout)) + res= reopen_fstreams(log_error_file, stdout, stderr); +#else + res= reopen_fstreams(log_error_file, NULL, stderr); #endif - { - if (!(freopen(log_error_file, "a+", stderr))) - sql_print_warning("Couldn't reopen stderr"); + + if (!res) setbuf(stderr, NULL); - } } } @@ -4689,11 +4693,8 @@ we force server id to 2, but this MySQL server will not act as a slave."); #ifdef __WIN__ if (!opt_console) { - if (!freopen(log_error_file,"a+",stdout) || - !freopen(log_error_file,"a+",stderr)) - { - sql_print_warning("Couldn't reopen stdout or stderr"); - } + if (reopen_fstreams(log_error_file, stdout, stderr)) + unireg_abort(1); setbuf(stderr, NULL); FreeConsole(); // Remove window } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fd81236b343..d77893bdb1c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2384,9 +2384,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, if (!head->covering_keys.is_clear_all()) { int key_for_use= find_shortest_key(head, &head->covering_keys); - double key_read_time= param.table->file->keyread_read_time(key_for_use, - 1, records) + - (double) records / TIME_FOR_COMPARE; + double key_read_time= head->file->keyread_time(key_for_use, 1, records) + + (double) records / TIME_FOR_COMPARE; DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, " "read time %g", key_for_use, key_read_time)); if (key_read_time < read_time) @@ -4007,7 +4006,6 @@ skip_to_ror_scan: DBUG_RETURN(imerge_trp); } - typedef struct st_ror_scan_info { uint idx; /* # of used key in param->keys */ @@ -4083,9 +4081,9 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) if (bitmap_is_set(¶m->needed_fields, key_part->fieldnr-1)) bitmap_set_bit(&ror_scan->covered_fields, key_part->fieldnr-1); } - double rows= rows2double(param->table->quick_rows[ror_scan->keynr]); ror_scan->index_read_cost= - param->table->file->keyread_read_time(ror_scan->keynr, 1, rows); + param->table->file->keyread_time(ror_scan->keynr, 1, + param->table->quick_rows[ror_scan->keynr]); DBUG_RETURN(ror_scan); } @@ -4915,7 +4913,6 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, } if (found_records != HA_POS_ERROR && read_time > (found_read_time= cost.total_cost())) - { read_time= found_read_time; best_records= found_records; @@ -5551,7 +5548,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, field_item, (Item*)(intptr)i, inv); if (inv) + { tree= !tree ? tmp : tree_or(param, tree, tmp); + if (tree == NULL) + break; + } else tree= tree_and(param, tree, tmp); } diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index e9b93085aea..d0206b0fd05 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -199,7 +199,7 @@ public: double records= rows2double(s->table->file->stats.records); /* The cost is entire index scan cost (divided by 2) */ - double read_time= s->table->file->keyread_read_time(key, 1, records); + double read_time= s->table->file->keyread_time(key, 1, records); /* Now find out how many different keys we will get (for now we diff --git a/sql/spatial.cc b/sql/spatial.cc index 2305a8eb97d..8b869a5b1ca 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -528,7 +528,7 @@ uint Gis_line_string::init_from_wkb(const char *wkb, uint len, n_points= wkb_get_uint(wkb, bo); proper_length= 4 + n_points * POINT_DATA_SIZE; - if (len < proper_length || res->reserve(proper_length)) + if (!n_points || len < proper_length || res->reserve(proper_length)) return 0; res->q_append(n_points); @@ -746,7 +746,9 @@ uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, if (len < 4) return 0; - n_linear_rings= wkb_get_uint(wkb, bo); + if (!(n_linear_rings= wkb_get_uint(wkb, bo))) + return 0; + if (res->reserve(4, 512)) return 0; wkb+= 4; diff --git a/sql/sql_class.h b/sql/sql_class.h index fc5b15b3916..b3d78c4c801 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2792,7 +2792,9 @@ public: class select_insert :public select_result_interceptor { - public: +protected: + virtual int write_to_binlog(bool is_trans, int errcode); +public: TABLE_LIST *table_list; TABLE *table; List<Item> *fields; @@ -2828,6 +2830,8 @@ class select_create: public select_insert { MYSQL_LOCK *m_lock; /* m_lock or thd->extra_lock */ MYSQL_LOCK **m_plock; + + virtual int write_to_binlog(bool is_trans, int errcode); public: select_create (TABLE_LIST *table_arg, HA_CREATE_INFO *create_info_par, @@ -2843,7 +2847,7 @@ public: {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - int binlog_show_create_table(TABLE **tables, uint count); + int binlog_show_create_table(TABLE **tables, uint count, int errcode); void store_values(List<Item> &values); void send_error(uint errcode,const char *err); bool send_eof(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bab92ca7368..3c2f90e8080 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3004,6 +3004,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) we are fixing fields from insert list. */ lex->current_select= &lex->select_lex; + + /* Errors during check_insert_fields() should not be ignored. */ + lex->current_select->no_error= FALSE; res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) || check_insert_fields(thd, table_list, *fields, values, !insert_into_view, 1, &map)); @@ -3307,7 +3310,7 @@ bool select_insert::send_eof() /* Write to binlog before commiting transaction. No statement will - be written by the binlog_query() below in RBR mode. All the + be written by the write_to_binlog() below in RBR mode. All the events are in the transaction cache and will be written when ha_autocommit_or_rollback() is issued below. */ @@ -3319,9 +3322,8 @@ bool select_insert::send_eof() thd->clear_error(); else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); - if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query(), thd->query_length(), - trans_table, FALSE, errcode)) + + if (write_to_binlog(trans_table, errcode)) { table->file->ha_release_auto_increment(); DBUG_RETURN(1); @@ -3395,9 +3397,7 @@ void select_insert::abort() { { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); /* error of writing binary log is ignored */ - (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), - thd->query_length(), - transactional_table, FALSE, errcode); + write_to_binlog(transactional_table, errcode); } if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; @@ -3412,6 +3412,103 @@ void select_insert::abort() { DBUG_VOID_RETURN; } +int select_insert::write_to_binlog(bool is_trans, int errcode) +{ + /* It is only for statement mode */ + if (thd->current_stmt_binlog_row_based) + return 0; + + return thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query(), thd->query_length(), + is_trans, FALSE, errcode); +} + +/* Override the select_insert::write_to_binlog */ +int select_create::write_to_binlog(bool is_trans, int errcode) +{ + /* It is only for statement mode */ + if (thd->current_stmt_binlog_row_based) + return 0; + + /* + WL#5370 Keep the compatibility between 5.1 master and 5.5 slave. + Binlog a 'INSERT ... SELECT' statement only when it has the option + 'IF NOT EXISTS' and the table already exists as a base table. + */ + if ((create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) && + create_info->table_existed) + { + String query; + int result; + + thd->binlog_start_trans_and_stmt(); + /* Binlog the CREATE TABLE IF NOT EXISTS statement */ + result= binlog_show_create_table(&table, 1, 0); + if (result) + return result; + + uint db_len= strlen(create_table->db); + uint table_len= strlen(create_info->alias); + uint select_len= thd->query_length() - thd->lex->create_select_pos; + uint field_len= (table->s->fields - (field - table->field)) * + (MAX_FIELD_NAME + 3); + + /* + pre-allocating memory reduces the times of reallocating memory, + when calling query.appen(). + 40bytes is enough for other words("INSERT IGNORE INTO", etc.). + */ + if (query.real_alloc(40 + db_len + table_len + field_len + select_len)) + return 1; + + if (thd->lex->create_select_in_comment) + query.append(STRING_WITH_LEN("/*! ")); + if (thd->lex->ignore) + query.append(STRING_WITH_LEN("INSERT IGNORE INTO `")); + else if (thd->lex->duplicates == DUP_REPLACE) + query.append(STRING_WITH_LEN("REPLACE INTO `")); + else + query.append(STRING_WITH_LEN("INSERT INTO `")); + + query.append(create_table->db, db_len); + query.append(STRING_WITH_LEN("`.`")); + query.append(create_info->alias, table_len); + query.append(STRING_WITH_LEN("` ")); + + /* + The insert items. + Field is the the rightmost columns that the rows are inster in. + */ + query.append(STRING_WITH_LEN("(")); + for (Field **f= field ; *f ; f++) + { + if (f != field) + query.append(STRING_WITH_LEN(",")); + + query.append(STRING_WITH_LEN("`")); + query.append((*f)->field_name, strlen((*f)->field_name)); + query.append(STRING_WITH_LEN("`")); + } + query.append(STRING_WITH_LEN(") ")); + + /* The SELECT clause*/ + DBUG_ASSERT(thd->lex->create_select_pos); + if (thd->lex->create_select_start_with_brace) + query.append(STRING_WITH_LEN("(")); + if (query.append(thd->query() + thd->lex->create_select_pos, select_len)) + return 1; + + /* + Avoid to use thd->binlog_query() twice, otherwise it will print the unsafe + warning twice. + */ + Query_log_event ev(thd, query.c_ptr_safe(), query.length(), is_trans, + FALSE, errcode); + return mysql_bin_log.write(&ev); + } + else + return select_insert::write_to_binlog(is_trans, errcode); +} /*************************************************************************** CREATE TABLE (SELECT) ... @@ -3662,7 +3759,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) !table->s->tmp_table && !ptr->get_create_info()->table_existed) { - if (int error= ptr->binlog_show_create_table(tables, count)) + int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + if (int error= ptr->binlog_show_create_table(tables, count, errcode)) return error; } return 0; @@ -3703,7 +3801,10 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), create_table->table_name); if (thd->current_stmt_binlog_row_based) - binlog_show_create_table(&(create_table->table), 1); + { + int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + binlog_show_create_table(&(create_table->table), 1, errcode); + } table= create_table->table; } else @@ -3771,10 +3872,10 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) } int -select_create::binlog_show_create_table(TABLE **tables, uint count) +select_create::binlog_show_create_table(TABLE **tables, uint count, int errcode) { /* - Note 1: In RBR mode, we generate a CREATE TABLE statement for the + Note 1: We generate a CREATE TABLE statement for the created table by calling store_create_info() (behaves as SHOW CREATE TABLE). In the event of an error, nothing should be written to the binary log, even if the table is non-transactional; @@ -3790,7 +3891,6 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) schema that will do a close_thread_tables(), destroying the statement transaction cache. */ - DBUG_ASSERT(thd->current_stmt_binlog_row_based); DBUG_ASSERT(tables && *tables && count > 0); char buf[2048]; @@ -3808,7 +3908,6 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) if (mysql_bin_log.is_open()) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); result= thd->binlog_query(THD::STMT_QUERY_TYPE, query.ptr(), query.length(), /* is_trans */ TRUE, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8ec50a8b772..31ca121ea66 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1849,6 +1849,23 @@ typedef struct st_lex : public Query_tables_list */ bool protect_against_global_read_lock; + /* + The following three variables are used in 'CREATE TABLE IF NOT EXISTS ... + SELECT' statement. They are used to binlog the statement. + + create_select_start_with_brace will be set if there is a '(' before + the first SELECT clause + + create_select_pos records the relative position of the SELECT clause + in the whole statement. + + create_select_in_comment will be set if SELECT keyword is in conditional + comment. + */ + bool create_select_start_with_brace; + uint create_select_pos; + bool create_select_in_comment; + st_lex(); virtual ~st_lex() diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1b7f690259a..366c01b1754 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -141,6 +141,14 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, bool transactional_table; DBUG_ENTER("mysql_load"); + /* + Bug #34283 + mysqlbinlog leaves tmpfile after termination if binlog contains + load data infile, so in mixed mode we go to row-based for + avoiding the problem. + */ + thd->set_current_stmt_binlog_row_based_if_mixed(); + #ifdef EMBEDDED_LIBRARY read_file_from_client = 0; //server is always in the same process #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c1ddf49e9c2..94164a30311 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2708,6 +2708,25 @@ mysql_execute_command(THD *thd) { TABLE_LIST *duplicate; create_table= lex->unlink_first_table(&link_to_local); + + if (create_table->view) + { + if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, + ER(ER_TABLE_EXISTS_ERROR), + create_info.alias); + my_ok(thd); + } + else + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias); + res= 1; + } + goto end_with_restore_list; + } + if ((duplicate= unique_table(thd, create_table, select_tables, 0))) { update_non_unique_table_error(create_table, "CREATE", duplicate); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d43353a3b53..debd1b07fe5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2381,14 +2381,9 @@ JOIN::destroy() having_equal= 0; cleanup(1); - /* Cleanup items referencing temporary table columns */ - if (!tmp_all_fields3.is_empty()) - { - List_iterator_fast<Item> it(tmp_all_fields3); - Item *item; - while ((item= it++)) - item->cleanup(); - } + /* Cleanup items referencing temporary table columns */ + cleanup_item_list(tmp_all_fields1); + cleanup_item_list(tmp_all_fields3); if (exec_tmp_table1) free_tmp_table(thd, exec_tmp_table1); if (exec_tmp_table2) @@ -2400,6 +2395,19 @@ JOIN::destroy() DBUG_RETURN(error); } + +void JOIN::cleanup_item_list(List<Item> &items) const +{ + if (!items.is_empty()) + { + List_iterator_fast<Item> it(items); + Item *item; + while ((item= it++)) + item->cleanup(); + } +} + + /** An entry point to single-unit select (a select without UNION). @@ -4599,12 +4607,10 @@ best_access_path(JOIN *join, tmp= records; set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); if (table->covering_keys.is_set(key)) - { - /* we can use only index tree */ - tmp= record_count * table->file->keyread_read_time(key, 1, tmp); - } + tmp= table->file->keyread_time(key, 1, tmp); else - tmp= record_count*min(tmp,s->worst_seeks); + tmp= table->file->read_time(key, 1, min(tmp,s->worst_seeks)-1); + tmp*= record_count; } } else @@ -4764,12 +4770,10 @@ best_access_path(JOIN *join, /* Limit the number of matched rows */ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key); if (table->covering_keys.is_set(key)) - { - /* we can use only index tree */ - tmp= record_count * table->file->keyread_read_time(key, 1, tmp); - } + tmp= table->file->keyread_time(key, 1, tmp); else - tmp= record_count * min(tmp,s->worst_seeks); + tmp= table->file->read_time(key, 1, min(tmp,s->worst_seeks)-1); + tmp*= record_count; } else tmp= best_time; // Do nothing @@ -4777,7 +4781,7 @@ best_access_path(JOIN *join, loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp); } /* not ft_key */ - if (tmp < best_time - records/(double) TIME_FOR_COMPARE) + if (tmp + 0.0001 < best_time - records/(double) TIME_FOR_COMPARE) { best_time= tmp + records/(double) TIME_FOR_COMPARE; best= tmp; @@ -7797,6 +7801,8 @@ bool error_if_full_join(JOIN *join) { if (tab->type == JT_ALL && (!tab->select || !tab->select->quick)) { + /* This error should not be ignored. */ + join->select_lex->no_error= FALSE; my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); return(1); @@ -9975,10 +9981,10 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, no ON expression and not a semi-join => can be flattened. */ TABLE_LIST *right_neighbor= NULL; - bool fix_name_res= FALSE; li.rewind(); while ((table= li++)) { + bool fix_name_res= FALSE; nested_join= table->nested_join; if (table->sj_on_expr && !in_sj) { @@ -14298,7 +14304,9 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!end_of_records) { copy_fields(&join->tmp_table_param); - copy_funcs(join->tmp_table_param.items_to_copy); + if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd)) + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ + #ifdef TO_BE_DELETED if (!table->uniques) // If not unique handling { @@ -14406,7 +14414,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), memcpy(table->record[0]+key_part->offset, group->buff, 1); } init_tmptable_sum_functions(join->sum_funcs); - copy_funcs(join->tmp_table_param.items_to_copy); + if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd)) + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if ((error= table->file->ha_write_row(table->record[0]))) { if (create_internal_tmp_table_from_heap(join->thd, table, @@ -14447,7 +14456,8 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), init_tmptable_sum_functions(join->sum_funcs); copy_fields(&join->tmp_table_param); // Groups are copied twice. - copy_funcs(join->tmp_table_param.items_to_copy); + if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd)) + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if (!(error= table->file->ha_write_row(table->record[0]))) join->send_records++; // New group @@ -14536,7 +14546,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (idx < (int) join->send_group_parts) { copy_fields(&join->tmp_table_param); - copy_funcs(join->tmp_table_param.items_to_copy); + if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd)) + DBUG_RETURN(NESTED_LOOP_ERROR); if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) @@ -15015,9 +15026,20 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, } +/** + Find shortest key suitable for full table scan. + + @param table Table to scan + @param usable_keys Allowed keys + + @return + MAX_KEY no suitable key found + key index otherwise +*/ + uint find_shortest_key(TABLE *table, const key_map *usable_keys) { - uint min_length= (uint) ~0; + double min_cost= DBL_MAX; uint best= MAX_KEY; if (!usable_keys->is_clear_all()) { @@ -15025,9 +15047,10 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys) { if (usable_keys->is_set(nr)) { - if (table->key_info[nr].key_length < min_length) + double cost= table->file->keyread_time(nr, 1, table->file->records()); + if (cost < min_cost) { - min_length=table->key_info[nr].key_length; + min_cost= cost; best=nr; } } @@ -17627,14 +17650,39 @@ update_sum_func(Item_sum **func_ptr) return 0; } -/** Copy result of functions to record in tmp_table. */ +/** + Copy result of functions to record in tmp_table. -void -copy_funcs(Item **func_ptr) + Uses the thread pointer to check for errors in + some of the val_xxx() methods called by the + save_in_result_field() function. + TODO: make the Item::val_xxx() return error code + + @param func_ptr array of the function Items to copy to the tmp table + @param thd pointer to the current thread for error checking + @retval + FALSE if OK + @retval + TRUE on error +*/ + +bool +copy_funcs(Item **func_ptr, const THD *thd) { Item *func; for (; (func = *func_ptr) ; func_ptr++) + { func->save_in_result_field(1); + /* + Need to check the THD error state because Item::val_xxx() don't + return error code, but can generate errors + TODO: change it for a real status check when Item::val_xxx() + are extended to return status code. + */ + if (thd->is_error()) + return TRUE; + } + return FALSE; } diff --git a/sql/sql_select.h b/sql/sql_select.h index e095974d008..885cff0163c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1752,6 +1752,7 @@ private: */ bool implicit_grouping; bool make_simple_join(JOIN *join, TABLE *tmp_table); + void cleanup_item_list(List<Item> &items) const; }; @@ -1771,7 +1772,9 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &new_list1, List<Item> &new_list2, uint elements, List<Item> &fields); void copy_fields(TMP_TABLE_PARAM *param); -void copy_funcs(Item **func_ptr); +bool copy_funcs(Item **func_ptr, const THD *thd); +bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, + int error, bool ignore_last_dupp_error); uint find_shortest_key(TABLE *table, const key_map *usable_keys); Field* create_tmp_field_from_field(THD *thd, Field* org_field, const char *name, TABLE *table, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 29fdf4dc58d..e05ea4a5dcd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4104,6 +4104,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, else { char option_buff[350],*ptr; + String str(option_buff,sizeof(option_buff), system_charset_info); TABLE *show_table= tables->table; TABLE_SHARE *share= show_table->s; handler *file= show_table->file; @@ -4136,53 +4137,58 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, table->field[4]->store(tmp_buff, strlen(tmp_buff), cs); table->field[5]->store((longlong) share->frm_version, TRUE); - ptr=option_buff; + str.length(0); if (share->min_rows) { - ptr=strmov(ptr," min_rows="); - ptr=longlong10_to_str(share->min_rows,ptr,10); + str.qs_append(STRING_WITH_LEN(" min_rows=")); + str.qs_append(share->min_rows); } if (share->max_rows) { - ptr=strmov(ptr," max_rows="); - ptr=longlong10_to_str(share->max_rows,ptr,10); + str.qs_append(STRING_WITH_LEN(" max_rows=")); + str.qs_append(share->max_rows); } if (share->avg_row_length) { - ptr=strmov(ptr," avg_row_length="); - ptr=longlong10_to_str(share->avg_row_length,ptr,10); + str.qs_append(STRING_WITH_LEN(" avg_row_length=")); + str.qs_append(share->avg_row_length); } if (share->db_create_options & HA_OPTION_PACK_KEYS) - ptr=strmov(ptr," pack_keys=1"); + str.qs_append(STRING_WITH_LEN(" pack_keys=1")); if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) - ptr=strmov(ptr," pack_keys=0"); + str.qs_append(STRING_WITH_LEN(" pack_keys=0")); /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */ if (share->db_create_options & HA_OPTION_CHECKSUM) - ptr=strmov(ptr," checksum=1"); + str.qs_append(STRING_WITH_LEN(" checksum=1")); if (share->page_checksum != HA_CHOICE_UNDEF) - ptr= strxmov(ptr, " page_checksum=", - ha_choice_values[(uint) share->page_checksum], NullS); + { + str.qs_append(STRING_WITH_LEN(" page_checksum=")); + str.qs_append(ha_choice_values[(uint) share->page_checksum]); + } if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) - ptr=strmov(ptr," delay_key_write=1"); + str.qs_append(STRING_WITH_LEN(" delay_key_write=1")); if (share->row_type != ROW_TYPE_DEFAULT) - ptr=strxmov(ptr, " row_format=", - ha_row_type[(uint) share->row_type], - NullS); + { + str.qs_append(STRING_WITH_LEN(" row_format=")); + str.qs_append(ha_row_type[(uint) share->row_type]); + } if (share->key_block_size) { - ptr= strmov(ptr, " key_block_size="); - ptr= longlong10_to_str(share->key_block_size, ptr, 10); + str.qs_append(STRING_WITH_LEN(" key_block_size=")); + str.qs_append(share->key_block_size); } #ifdef WITH_PARTITION_STORAGE_ENGINE if (is_partitioned) - ptr= strmov(ptr, " partitioned"); + str.qs_append(STRING_WITH_LEN(" partitioned")); #endif if (share->transactional != HA_CHOICE_UNDEF) - ptr= strxmov(ptr, " transactional=", - ha_choice_values[(uint) share->transactional], NullS); - table->field[19]->store(option_buff+1, - (ptr == option_buff ? 0 : - (uint) (ptr-option_buff)-1), cs); + { + str.qs_append(STRING_WITH_LEN(" transactional=")); + str.qs_append(ha_choice_values[(uint) share->transactional]); + } + append_create_options(thd, &str, share->option_list); + if (str.length()) + table->field[19]->store(str.ptr()+1, str.length()-1, cs); tmp_buff= (share->table_charset ? share->table_charset->name : "default"); @@ -7577,13 +7583,16 @@ int finalize_schema_table(st_plugin_int *plugin) ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data; DBUG_ENTER("finalize_schema_table"); - if (schema_table && plugin->plugin->deinit) + if (schema_table) { - DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str)); - if (plugin->plugin->deinit(NULL)) + if (plugin->plugin->deinit) { - DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", - plugin->name.str)); + DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str)); + if (plugin->plugin->deinit(NULL)) + { + DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", + plugin->name.str)); + } } my_free(schema_table, MYF(0)); } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index db3d07a28a4..eafd8502706 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -687,10 +687,10 @@ void String::qs_append(int i) str_length+= (int) (end-buff); } -void String::qs_append(uint i) +void String::qs_append(ulonglong i) { char *buff= Ptr + str_length; - char *end= int10_to_str(i, buff, 10); + char *end= longlong10_to_str(i, buff,10); str_length+= (int) (end-buff); } diff --git a/sql/sql_string.h b/sql/sql_string.h index a9df0dc2620..e595de47f99 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -108,7 +108,7 @@ public: inline uint32 alloced_length() const { return Alloced_length;} inline char& operator [] (uint32 i) const { return Ptr[i]; } inline void length(uint32 len) { str_length=len ; } - inline bool is_empty() { return (str_length == 0); } + inline bool is_empty() const { return (str_length == 0); } inline void mark_as_const() { Alloced_length= 0;} inline const char *ptr() const { return Ptr; } inline char *c_ptr() @@ -336,6 +336,10 @@ public: int4store(Ptr + position,value); } + void qs_append(const char *str) + { + qs_append(str, strlen(str)); + } void qs_append(const char *str, uint32 len); void qs_append(double d); void qs_append(double *d); @@ -345,7 +349,15 @@ public: str_length++; } void qs_append(int i); - void qs_append(uint i); + void qs_append(uint i) + { + qs_append((ulonglong)i); + } + void qs_append(ulong i) + { + qs_append((ulonglong)i); + } + void qs_append(ulonglong i); /* Inline (general) functions used by the protocol functions */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 531227eb76f..acdf262f977 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1202,56 +1202,6 @@ reopen_tables: } -/** - Implementation of the safe update options during UPDATE IGNORE. This syntax - causes an UPDATE statement to ignore all errors. In safe update mode, - however, we must never ignore the ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE. There - is a special hook in my_message_sql that will otherwise delete all errors - when the IGNORE option is specified. - - In the future, all IGNORE handling should be used with this class and all - traces of the hack outlined below should be removed. - - - The parser detects IGNORE option and sets thd->lex->ignore= 1 - - - In JOIN::optimize, if this is set, then - thd->lex->current_select->no_error gets set. - - - In my_message_sql(), if the flag above is set then any error is - unconditionally converted to a warning. - - We are moving in the direction of using Internal_error_handler subclasses - to do all such error tweaking, please continue this effort if new bugs - appear. - */ -class Safe_dml_handler : public Internal_error_handler { - -private: - bool m_handled_error; - -public: - explicit Safe_dml_handler() : m_handled_error(FALSE) {} - - bool handle_error(uint sql_errno, - const char *message, - MYSQL_ERROR::enum_warning_level level, - THD *thd) - { - if (level == MYSQL_ERROR::WARN_LEVEL_ERROR && - sql_errno == ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE) - - { - thd->main_da.set_error_status(thd, sql_errno, message); - m_handled_error= TRUE; - return TRUE; - } - return FALSE; - } - - bool handled_error() { return m_handled_error; } - -}; - /* Setup multi-update handling and call SELECT to do the join */ @@ -1281,11 +1231,6 @@ bool mysql_multi_update(THD *thd, List<Item> total_list; - Safe_dml_handler handler; - bool using_handler= thd->options & OPTION_SAFE_UPDATES; - if (using_handler) - thd->push_internal_handler(&handler); - res= mysql_select(thd, &select_lex->ref_pointer_array, table_list, select_lex->with_wild, total_list, @@ -1295,21 +1240,9 @@ bool mysql_multi_update(THD *thd, OPTION_SETUP_TABLES_DONE, result, unit, select_lex); - if (using_handler) - { - Internal_error_handler *top_handler; - top_handler= thd->pop_internal_handler(); - DBUG_ASSERT(&handler == top_handler); - } - DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); res|= thd->is_error(); - /* - Todo: remove below code and make Safe_dml_handler do error processing - instead. That way we can return the actual error instead of - ER_UNKNOWN_ERROR. - */ - if (unlikely(res) && (!using_handler || !handler.handled_error())) + if (unlikely(res)) { /* If we had a another error reported earlier then this will be ignored */ result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 75a16e19d83..87a8dd278c2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1314,6 +1314,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <table> table_ident table_ident_nodb references xid + table_ident_opt_wild %type <simple_string> remember_name remember_end opt_ident opt_db text_or_password @@ -3908,17 +3909,26 @@ create2a: create3 {} | opt_partitioning create_select ')' - { Select->set_braces(1);} + { + Select->set_braces(1); + Lex->create_select_start_with_brace= TRUE; + } union_opt {} ; create3: /* empty */ {} | opt_duplicate opt_as create_select - { Select->set_braces(0);} + { + Select->set_braces(0); + Lex->create_select_start_with_brace= FALSE; + } union_clause {} | opt_duplicate opt_as '(' create_select ')' - { Select->set_braces(1);} + { + Select->set_braces(1); + Lex->create_select_start_with_brace= TRUE; + } union_opt {} ; @@ -4543,6 +4553,19 @@ create_select: lex->current_select->table_list.save_and_clear(&lex->save_list); mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; + + if (lex->sql_command == SQLCOM_CREATE_TABLE && + (lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)) + { + Lex_input_stream *lip= YYLIP; + + if (lex->spcont) + lex->create_select_pos= lip->get_tok_start() - + lex->sphead->m_tmp_query; + else + lex->create_select_pos= lip->get_tok_start() - lip->get_buf(); + lex->create_select_in_comment= (lip->in_comment == DISCARD_COMMENT); + } } select_options select_item_list { @@ -9816,7 +9839,7 @@ table_alias_ref_list: ; table_alias_ref: - table_ident + table_ident_opt_wild { if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING | TL_OPTION_ALIAS, @@ -11629,6 +11652,21 @@ table_ident: } ; +table_ident_opt_wild: + ident opt_wild + { + $$= new Table_ident($1); + if ($$ == NULL) + MYSQL_YYABORT; + } + | ident '.' ident opt_wild + { + $$= new Table_ident(YYTHD, $1,$3,0); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + table_ident_nodb: ident { diff --git a/sql/tztime.cc b/sql/tztime.cc index 3f3060fbc10..25b3b0c8994 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2269,7 +2269,7 @@ my_tz_find(THD *thd, const String *name) DBUG_PRINT("enter", ("time zone name='%s'", name ? ((String *)name)->c_ptr_safe() : "NULL")); - if (!name) + if (!name || name->is_empty()) DBUG_RETURN(0); VOID(pthread_mutex_lock(&tz_LOCK)); |