summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2010-10-28 19:04:23 +0200
committerSergei Golubchik <sergii@pisem.net>2010-10-28 19:04:23 +0200
commit8e7ebfbce89a472b3c5a6c30e6de101e567a8218 (patch)
tree9f9950feb45222c7df4f37c841f4af593ec75ee5 /sql
parent3bdede3c67032345ca5f71dd53ca308377dc2398 (diff)
parent7c24e8d54d1d41374b7836e3273e7e5eaf22e2c4 (diff)
downloadmariadb-git-8e7ebfbce89a472b3c5a6c30e6de101e567a8218.tar.gz
5.2 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc4
-rw-r--r--sql/ha_partition.cc7
-rw-r--r--sql/handler.cc42
-rw-r--r--sql/handler.h11
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/item_func.cc24
-rw-r--r--sql/item_func.h1
-rw-r--r--sql/item_geofunc.h15
-rw-r--r--sql/item_sum.cc26
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/item_timefunc.h2
-rw-r--r--sql/log.cc118
-rw-r--r--sql/multi_range_read.cc6
-rw-r--r--sql/mysqld.cc21
-rw-r--r--sql/opt_range.cc15
-rw-r--r--sql/opt_subselect.h2
-rw-r--r--sql/spatial.cc6
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_insert.cc125
-rw-r--r--sql/sql_lex.h17
-rw-r--r--sql/sql_load.cc8
-rw-r--r--sql/sql_parse.cc19
-rw-r--r--sql/sql_select.cc108
-rw-r--r--sql/sql_select.h5
-rw-r--r--sql/sql_show.cc67
-rw-r--r--sql/sql_string.cc4
-rw-r--r--sql/sql_string.h16
-rw-r--r--sql/sql_update.cc69
-rw-r--r--sql/sql_yacc.yy46
-rw-r--r--sql/tztime.cc2
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(&param->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));