summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc4
-rw-r--r--sql/ha_partition.cc7
-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/mysqld.cc19
-rw-r--r--sql/opt_range.cc4
-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.cc83
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_show.cc13
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_update.cc69
-rw-r--r--sql/sql_yacc.yy46
-rw-r--r--sql/tztime.cc2
25 files changed, 430 insertions, 194 deletions
diff --git a/sql/field.cc b/sql/field.cc
index c88ba52f31f..cc3a9863587 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;
@@ -4562,7 +4562,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 bde8ff053e7..305f83a25e5 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -2403,9 +2403,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/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 4eef380d5a9..6fb3f99662d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4614,7 +4614,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 41cdcfa4312..bc0dc60accf 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2262,7 +2262,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
*/
@@ -2276,6 +2276,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)
@@ -2304,6 +2312,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;
}
@@ -4266,6 +4280,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 2b466960af2..bdaa217d555 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1368,6 +1368,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 45c3ee3cd20..0a51a0de5d7 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -417,26 +417,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() */
@@ -2565,7 +2545,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))
@@ -3153,7 +3134,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 ac6a56400a4..0725a754174 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 a7a64090f6c..11eed70f399 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -881,6 +881,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 3b3da7adfe7..6adf9846a3a 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5102,71 +5102,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/mysqld.cc b/sql/mysqld.cc
index 5da8d1cdb7f..f159b58a2e1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -196,6 +196,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)
@@ -3963,14 +3966,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);
- }
}
}
@@ -4620,11 +4624,16 @@ we force server id to 2, but this MySQL server will not act as a slave.");
#ifdef __WIN__
if (!opt_console)
{
+<<<<<<< TREE
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);
+>>>>>>> MERGE-SOURCE
setbuf(stderr, NULL);
FreeConsole(); // Remove window
}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index acff21c55d5..4ef839ffdcf 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -5534,7 +5534,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/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 5317b5af9ac..56b6a246423 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2642,7 +2642,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;
@@ -2678,6 +2680,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,
@@ -2693,7 +2697,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 e23f2f86b82..37cc20a07e7 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2993,6 +2993,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));
@@ -3296,7 +3299,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.
*/
@@ -3308,9 +3311,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);
@@ -3384,9 +3386,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;
@@ -3401,6 +3401,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) ...
@@ -3650,7 +3747,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;
@@ -3691,7 +3789,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
@@ -3759,10 +3860,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;
@@ -3778,7 +3879,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];
@@ -3796,7 +3896,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 87d6403710a..3d5e1cf60bf 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1816,6 +1816,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 55c3b766d80..a031a921c60 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2758,6 +2758,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 619d847ed90..48b2a1b116f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2384,14 +2384,9 @@ JOIN::destroy()
cond_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)
@@ -2402,6 +2397,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).
@@ -6896,6 +6904,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);
@@ -8964,10 +8974,10 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
/* Flatten nested joins that 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 (nested_join && !table->on_expr)
{
@@ -12809,7 +12819,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
{
@@ -12915,7 +12927,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,
@@ -12955,7 +12968,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
@@ -13042,7 +13056,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)
@@ -13339,6 +13354,17 @@ 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;
@@ -16109,14 +16135,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 b3938fbbbb6..2a9af48f1cd 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -600,6 +600,7 @@ private:
*/
bool implicit_grouping;
bool make_simple_join(JOIN *join, TABLE *tmp_table);
+ void cleanup_item_list(List<Item> &items) const;
};
@@ -624,7 +625,7 @@ 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);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 683b0e67929..8266594081c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -6957,13 +6957,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.h b/sql/sql_string.h
index 9e22f7b6a27..6eb0d74fde9 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -102,7 +102,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()
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f6165b8d4b2..33834df3ca6 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1196,56 +1196,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
*/
@@ -1275,11 +1225,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,
@@ -1289,21 +1234,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 b06178b5889..f7f1e30c907 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1300,6 +1300,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
@@ -3886,17 +3887,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 {}
;
@@ -4521,6 +4531,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
{
@@ -9621,7 +9644,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,
@@ -11396,6 +11419,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 cd6e63be039..1277383895a 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2259,7 +2259,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));