summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysql.h.pp3
-rw-r--r--include/mysql_com.h3
-rw-r--r--sql/item.cc77
-rw-r--r--sql/item.h23
-rw-r--r--sql/share/errmsg-utf8.txt3
-rw-r--r--sql/sql_error.h5
-rw-r--r--sql/sql_insert.cc54
-rw-r--r--sql/sql_parse.cc14
-rw-r--r--sql/sql_prepare.cc19
9 files changed, 158 insertions, 43 deletions
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index f80865e5b49..7e3df97b8b0 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -10,8 +10,7 @@ enum enum_server_command
COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE,
COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON,
COM_MDB_GAP_BEG,
- COM_MDB_GAP_END=252,
- COM_STMT_BULK_EXECUTE,
+ COM_MDB_GAP_END=253,
COM_MULTI,
COM_END
};
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 1dcdb3a0127..fc2365ecd25 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -105,8 +105,7 @@ enum enum_server_command
COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON,
/* don't forget to update const char *command_name[] in sql_parse.cc */
COM_MDB_GAP_BEG,
- COM_MDB_GAP_END=252,
- COM_STMT_BULK_EXECUTE,
+ COM_MDB_GAP_END=253,
COM_MULTI,
/* Must be last */
COM_END
diff --git a/sql/item.cc b/sql/item.cc
index 15f022652de..cae2ab5bdfa 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3132,7 +3132,8 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
Item_basic_value(thd),
Rewritable_query_parameter(pos_in_query_arg, 1),
Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
- state(NO_VALUE), indicators(0),
+ state(NO_VALUE), default_value_ref(NULL), default_value_source(NULL),
+ indicators(0),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
set_param_func(default_set_param_func),
@@ -3441,6 +3442,8 @@ void Item_param::reset()
DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_*
methods).
*/
+
+ default_value_source= NULL;
DBUG_VOID_RETURN;
}
@@ -3723,7 +3726,9 @@ bool Item_param::basic_const_item() const
Item *
Item_param::clone_item(THD *thd)
{
+
MEM_ROOT *mem_root= thd->mem_root;
+
switch (state) {
case NULL_VALUE:
return new (mem_root) Item_null(thd, name);
@@ -3824,6 +3829,9 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
null_value= src->null_value;
state= src->state;
value= src->value;
+ default_value_ref= src->default_value_ref;
+ default_value_source= src->default_value_source;
+
decimal_value.swap(src->decimal_value);
str_value.swap(src->str_value);
@@ -3831,6 +3839,28 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
}
+bool Item_param::set_default()
+{
+ if (!default_value_ref)
+ {
+ my_message(ER_INVALID_DEFAULT_PARAM,
+ ER_THD(current_thd, ER_INVALID_DEFAULT_PARAM), MYF(0));
+ return TRUE;
+ }
+ THD *thd= default_value_ref->table->in_use;
+ if (!default_value_source)
+ {
+ default_value_source= new (thd->mem_root)
+ Item_default_value(thd, &thd->lex->select_lex.context, default_value_ref);
+ if (!default_value_source ||
+ default_value_source->fix_fields(thd, (Item **)&default_value_source))
+ return TRUE;
+ bitmap_set_bit(default_value_ref->table->read_set,
+ default_value_ref->field_index);
+ }
+ return set_value(thd, NULL, (Item**)&default_value_source);
+}
+
/**
This operation is intended to store some item value in Item_param to be
used later.
@@ -3989,6 +4019,17 @@ bool Item_param::append_for_log(THD *thd, String *str)
return str->append(*val);
}
+
+bool Item_param::walk(Item_processor processor, bool walk_subquery, void *arg)
+{
+ if (default_value_source &&
+ default_value_source->walk(processor, walk_subquery, arg))
+ {
+ return TRUE;
+ }
+ return (this->*processor)(arg);
+}
+
/****************************************************************************
Item_copy
****************************************************************************/
@@ -8196,36 +8237,38 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const
bool Item_default_value::fix_fields(THD *thd, Item **items)
{
Item *real_arg;
- Item_field *field_arg;
Field *def_field;
DBUG_ASSERT(fixed == 0);
- if (!arg)
+ if (!arg && !arg_fld)
{
fixed= 1;
return FALSE;
}
- if (!arg->fixed && arg->fix_fields(thd, &arg))
- goto error;
+ if (arg)
+ {
+ if (!arg->fixed && arg->fix_fields(thd, &arg))
+ goto error;
- real_arg= arg->real_item();
- if (real_arg->type() != FIELD_ITEM)
- {
- my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
- goto error;
- }
+ real_arg= arg->real_item();
+ if (real_arg->type() != FIELD_ITEM)
+ {
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
+ goto error;
+ }
- field_arg= (Item_field *)real_arg;
- if ((field_arg->field->flags & NO_DEFAULT_VALUE_FLAG))
+ arg_fld= ((Item_field *)real_arg)->field;
+ }
+ if ((arg_fld->flags & NO_DEFAULT_VALUE_FLAG))
{
- my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg_fld->field_name);
goto error;
}
- if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
+ if (!(def_field= (Field*) thd->alloc(arg_fld->size_of())))
goto error;
- memcpy((void *)def_field, (void *)field_arg->field,
- field_arg->field->size_of());
+ memcpy((void *)def_field, (void *)arg_fld,
+ arg_fld->size_of());
def_field->move_field_offset((my_ptrdiff_t)
(def_field->table->s->default_values -
def_field->table->record[0]));
diff --git a/sql/item.h b/sql/item.h
index 5e70c06d6a4..79144f4f1d7 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1836,6 +1836,8 @@ public:
*/
virtual void under_not(Item_func_not * upper
__attribute__((unused))) {};
+
+ virtual void set_default_value_source(Field *fld) {};
};
@@ -2641,6 +2643,9 @@ public:
}
};
+
+class Item_default_value;
+
/*
Item represents one placeholder ('?') of prepared statement
@@ -2666,6 +2671,8 @@ public:
DECIMAL_VALUE
} state;
+ Field *default_value_ref;
+ Item_default_value *default_value_source;
/*
Used for bulk protocol. Indicates if we should expect
indicators byte before value of the parameter
@@ -2729,6 +2736,10 @@ public:
bool get_date(MYSQL_TIME *tm, ulonglong fuzzydate);
int save_in_field(Field *field, bool no_conversions);
+ virtual void set_default_value_source(Field *fld)
+ { default_value_ref= fld; }
+
+ bool set_default();
void set_null();
void set_int(longlong i, uint32 max_length_arg);
void set_double(double i);
@@ -2772,8 +2783,8 @@ public:
constant, assert otherwise. This method is called only if
basic_const_item returned TRUE.
*/
- Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
Item *clone_item(THD *thd);
+ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
/*
Implement by-value equality evaluation if parameter value
is set and is a basic constant (integer, real or string).
@@ -2799,6 +2810,7 @@ public:
virtual void make_field(THD *thd, Send_field *field);
+ virtual bool walk(Item_processor processor, bool walk_subquery, void *arg);
private:
Send_field *m_out_param_info;
};
@@ -4880,14 +4892,19 @@ class Item_default_value : public Item_field
void calculate();
public:
Item *arg;
+ Field *arg_fld;
Item_default_value(THD *thd, Name_resolution_context *context_arg)
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
- arg(NULL) {}
+ arg(NULL), arg_fld(NULL) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
:Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
(const char *)NULL),
- arg(a) {}
+ arg(a), arg_fld(NULL) {}
+ Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
+ :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
+ (const char *)NULL),
+ arg(NULL), arg_fld(a) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8dfa519ba2d..454ad123498 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7214,3 +7214,6 @@ ER_CALCULATING_DEFAULT_VALUE
eng "Got an error when calculating default value for %`s"
ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000
eng "Expression for field %`-.64s is refering to uninitialized field %`s"
+ER_INVALID_DEFAULT_PARAM
+ eng "Default value is not supported for such parameter usage"
+ ukr "Значення за замовчуванням не підтримано для цього випадку використання параьетра"
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 70d40e3e6a0..aa8e6c6b0f3 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -712,7 +712,10 @@ public:
m_status == DA_OK_BULK); return m_message; }
bool skip_flush() const
- { DBUG_ASSERT(m_status == DA_OK); return m_skip_flush; }
+ {
+ DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK);
+ return m_skip_flush;
+ }
void set_skip_flush()
{ m_skip_flush= TRUE; }
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3fae78aa9e8..08143bbaeef 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -637,6 +637,50 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
}
}
+static
+void setup_deault_parameters(TABLE_LIST *table, List<Item> *fields,
+ List<Item> *values)
+{
+
+ List_iterator_fast<Item> itv(*values);
+ Item *val;
+ if (fields->elements)
+ {
+ List_iterator_fast<Item> itf(*fields);
+ Item *fld;
+ while((fld= itf++) && (val= itv++))
+ {
+ fld= fld->real_item();
+ if (fld->type() == Item::FIELD_ITEM)
+ val->set_default_value_source(((Item_field *)fld)->field);
+ }
+ }
+ else if (table != NULL)
+ {
+ if (table->view)
+ {
+ Field_iterator_view field_it;
+ field_it.set(table);
+ for (; !field_it.end_of_fields() && (val= itv++); field_it.next())
+ {
+ Item *fld= field_it.item()->real_item();
+ if (fld->type() == Item::FIELD_ITEM)
+ val->set_default_value_source(((Item_field *)fld)->field);
+ }
+ }
+ else
+ {
+ Field_iterator_table_ref field_it;
+ field_it.set(table);
+ for (; !field_it.end_of_fields() && (val= itv++); field_it.next())
+ {
+ Field *fld= field_it.field();
+ val->set_default_value_source(fld);
+ }
+ }
+ }
+}
+
/**
INSERT statement implementation
@@ -727,11 +771,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
THD_STAGE_INFO(thd, stage_init);
thd->lex->used_tables=0;
values= its++;
- DBUG_ASSERT(bulk_iterations > 0);
- if (bulk_parameters_set(thd))
- DBUG_RETURN(TRUE);
value_count= values->elements;
+ DBUG_ASSERT(bulk_iterations > 0);
if (mysql_prepare_insert(thd, table_list, table, fields, values,
update_fields, update_values, duplic, &unused_conds,
FALSE,
@@ -775,6 +817,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_READ, 0, 0))
goto abort;
switch_to_nullable_trigger_fields(*values, table);
+ setup_deault_parameters(table_list, &fields, values);
}
its.rewind ();
@@ -1458,6 +1501,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
/* Prepare the fields in the statement. */
if (values)
{
+
/* if we have INSERT ... VALUES () we cannot have a GROUP BY clause */
DBUG_ASSERT (!select_lex->group_list.elements);
@@ -1476,6 +1520,10 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
check_insert_fields(thd, context->table_list, fields, *values,
!insert_into_view, 0, &map));
+ setup_deault_parameters(table_list, &fields, values);
+ if (bulk_parameters_set(thd))
+ DBUG_RETURN(TRUE);
+
if (!res && check_fields)
{
bool saved_abort_on_warning= thd->abort_on_warning;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 27dcdd713d6..7780755a5fe 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -394,7 +394,7 @@ const LEX_STRING command_name[257]={
{ 0, 0 }, //250
{ 0, 0 }, //251
{ 0, 0 }, //252
- { C_STRING_WITH_LEN("Execute_bulk") }, //253
+ { 0, 0 }, //253
{ C_STRING_WITH_LEN("Com_multi") }, //254
{ C_STRING_WITH_LEN("Error") } // Last command number 255
};
@@ -1731,12 +1731,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_STMT_EXECUTE:
{
- mysqld_stmt_execute(thd, packet, packet_length);
- break;
- }
- case COM_STMT_BULK_EXECUTE:
- {
- mysqld_stmt_bulk_execute(thd, packet, packet_length);
+ ulong iterations= uint4korr(packet + 5);
+ if (iterations < 2 ||
+ (thd->client_capabilities & MARIADB_CLIENT_STMT_BULK_OPERATIONS))
+ mysqld_stmt_execute(thd, packet, packet_length);
+ else
+ mysqld_stmt_bulk_execute(thd, packet, packet_length);
break;
}
case COM_STMT_FETCH:
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9f618d1ef9b..60e3bf19e58 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -991,7 +991,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
indicators= *((*read_pos)++);
else
indicators= STMT_INDICATOR_NONE;
- if ((*read_pos) >= data_end)
+ if ((*read_pos) > data_end)
DBUG_RETURN(1);
switch (indicators) {
case STMT_INDICATOR_NONE:
@@ -1005,8 +1005,8 @@ static bool insert_bulk_params(Prepared_statement *stmt,
param->set_null();
break;
case STMT_INDICATOR_DEFAULT:
- // TODO: support default
- DBUG_ASSERT(0);
+ if (param->set_default())
+ DBUG_RETURN(1);
break;
}
}
@@ -4079,11 +4079,12 @@ reexecute:
my_bool bulk_parameters_set(THD *thd)
{
+ DBUG_ENTER("bulk_parameters_set");
Prepared_statement *stmt= (Prepared_statement *) thd->bulk_param;
if (stmt && stmt->set_bulk_parameters())
- return FALSE;
- return FALSE;
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
}
ulong bulk_parameters_iterations(THD *thd)
@@ -4097,6 +4098,8 @@ ulong bulk_parameters_iterations(THD *thd)
my_bool Prepared_statement::set_bulk_parameters()
{
+ DBUG_ENTER("Prepared_statement::set_bulk_parameters");
+ DBUG_PRINT("info", ("iteration: %lu", iterations));
if (iterations)
{
#ifndef EMBEDDED_LIBRARY
@@ -4108,12 +4111,12 @@ my_bool Prepared_statement::set_bulk_parameters()
my_error(ER_WRONG_ARGUMENTS, MYF(0),
"mysqld_stmt_bulk_execute");
reset_stmt_params(this);
- return true;
+ DBUG_RETURN(true);
}
iterations--;
}
start_param= 0;
- return false;
+ DBUG_RETURN(false);
}
ulong Prepared_statement::bulk_iterations()
@@ -4170,7 +4173,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
}
#ifdef NOT_YET_FROM_MYSQL_5_6
- if (unlikely(thd->security_ctx->password_expired &&
+ if (unlikely(thd->security_ctx->password_expired &&
!lex->is_change_password))
{
my_error(ER_MUST_CHANGE_PASSWORD, MYF(0));