diff options
-rw-r--r-- | include/mysql.h.pp | 3 | ||||
-rw-r--r-- | include/mysql_com.h | 3 | ||||
-rw-r--r-- | sql/item.cc | 77 | ||||
-rw-r--r-- | sql/item.h | 23 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 3 | ||||
-rw-r--r-- | sql/sql_error.h | 5 | ||||
-rw-r--r-- | sql/sql_insert.cc | 54 | ||||
-rw-r--r-- | sql/sql_parse.cc | 14 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 19 |
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)); |