diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2014-10-22 19:47:05 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2014-10-22 19:58:50 +0200 |
commit | af93dc48cffdc9a071e3ec6e1fe51f1d7d06686b (patch) | |
tree | 938d7fa8cbefa67161d50172ff962a842904d71c /sql | |
parent | c3db4459561bc491582bef6bea7b83e9fe464a10 (diff) | |
download | mariadb-git-bb-set-statement.tar.gz |
MDEV-5231: Per query variables from Percona Server (rewritten)bb-set-statement
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.h | 11 | ||||
-rw-r--r-- | sql/item_func.cc | 2 | ||||
-rw-r--r-- | sql/lex.h | 1 | ||||
-rw-r--r-- | sql/set_var.cc | 13 | ||||
-rw-r--r-- | sql/set_var.h | 7 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_lex.cc | 13 | ||||
-rw-r--r-- | sql/sql_lex.h | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 103 | ||||
-rw-r--r-- | sql/sql_plugin.h | 8 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 8 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 74 |
14 files changed, 218 insertions, 32 deletions
diff --git a/sql/item.h b/sql/item.h index ff0c786ab94..e006622dca2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2819,6 +2819,16 @@ protected: fixed= 1; } public: + Item_string(CHARSET_INFO *csi, const char *str_arg, uint length_arg) + : m_cs_specified(FALSE) + { + collation.set(csi, DERIVATION_COERCIBLE); + set_name(NULL, 0, system_charset_info); + decimals= NOT_FIXED_DEC; + fixed= 1; + str_value.copy(str_arg, length_arg, csi); + max_length= str_value.numchars() * csi->mbmaxlen; + } // Constructors with the item name set from its value Item_string(const char *str, uint length, CHARSET_INFO *cs, Derivation dv, uint repertoire) @@ -2954,6 +2964,7 @@ public: } return MYSQL_TYPE_STRING; // Not a temporal literal } + }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4ec0466bda8..25c0197cb9b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5547,7 +5547,7 @@ get_var_with_binlog(THD *thd, enum_sql_command sql_command, tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name, new Item_null()))); /* Create the variable */ - if (sql_set_variables(thd, &tmp_var_list)) + if (sql_set_variables(thd, &tmp_var_list, false)) { thd->lex= sav_lex; goto err; diff --git a/sql/lex.h b/sql/lex.h index 5ca188f99a0..51b69f00990 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -567,6 +567,7 @@ static SYMBOL symbols[] = { { "START", SYM(START_SYM)}, { "STARTING", SYM(STARTING)}, { "STARTS", SYM(STARTS_SYM)}, + { "STATEMENT", SYM(STATEMENT_SYM)}, { "STATS_AUTO_RECALC",SYM(STATS_AUTO_RECALC_SYM)}, { "STATS_PERSISTENT", SYM(STATS_PERSISTENT_SYM)}, { "STATS_SAMPLE_PAGES",SYM(STATS_SAMPLE_PAGES_SYM)}, diff --git a/sql/set_var.cc b/sql/set_var.cc index bae65118112..1dad3603799 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -147,7 +147,7 @@ sys_var::sys_var(sys_var_chain *chain, const char *name_arg, flags(flags_arg), show_val_type(show_val_type_arg), guard(lock), offset(off), on_check(on_check_func), on_update(on_update_func), deprecation_substitute(substitute), - is_os_charset(FALSE) + is_os_charset(FALSE), default_val(FALSE) { /* There is a limitation in handle_options() related to short options: @@ -675,9 +675,10 @@ sys_var *intern_find_sys_var(const char *str, uint length) -1 ERROR, message not sent */ -int sql_set_variables(THD *thd, List<set_var_base> *var_list) +int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free) { - int error; + int error= 0; + bool was_error= thd->is_error(); List_iterator_fast<set_var_base> it(*var_list); DBUG_ENTER("sql_set_variables"); @@ -687,7 +688,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list) if ((error= var->check(thd))) goto err; } - if (!(error= MY_TEST(thd->is_error()))) + if (was_error || !(error= MY_TEST(thd->is_error()))) { it.rewind(); while ((var= it++)) @@ -695,7 +696,8 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list) } err: - free_underlaid_joins(thd, &thd->lex->select_lex); + if (free) + free_underlaid_joins(thd, &thd->lex->select_lex); DBUG_RETURN(error); } @@ -788,6 +790,7 @@ int set_var::light_check(THD *thd) */ int set_var::update(THD *thd) { + var->set_is_default(value == 0); return value ? var->update(thd, this) : var->set_default(thd, this); } diff --git a/sql/set_var.h b/sql/set_var.h index fe2a0d8e953..e4a4385f056 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -87,6 +87,7 @@ protected: on_update_function on_update; const char *const deprecation_substitute; bool is_os_charset; ///< true if the value is in character_set_filesystem + bool default_val; public: sys_var(sys_var_chain *chain, const char *name_arg, const char *comment, @@ -191,6 +192,8 @@ public: return insert_dynamic(array, (uchar*)&option); } void do_deprecated_warning(THD *thd); + bool is_default() { return default_val; } + void set_is_default(bool def) { default_val= def; } virtual uchar *default_value_ptr(THD *thd) { return (uchar*)&option.def_value; } @@ -249,6 +252,7 @@ public: virtual int check(THD *thd)=0; /* To check privileges etc. */ virtual int update(THD *thd)=0; /* To set the value */ virtual int light_check(THD *thd) { return check(thd); } /* for PS */ + virtual bool is_system() { return FALSE; } }; @@ -290,6 +294,7 @@ public: else value=value_arg; } + virtual bool is_system() { return 1; } int check(THD *thd); int update(THD *thd); int light_check(THD *thd); @@ -388,7 +393,7 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type); int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond); sys_var *find_sys_var(THD *thd, const char *str, uint length=0); -int sql_set_variables(THD *thd, List<set_var_base> *var_list); +int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free); #define SYSVAR_AUTOSIZE(VAR,VAL) \ do { \ diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 199a822d022..bb428079433 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7111,3 +7111,5 @@ ER_TABLE_DEFINITION_TOO_BIG eng "The definition for table %`s is too big" ER_STATEMENT_TIMEOUT 70100 eng "Query execution was interrupted (max_statement_time exceeded)" +ER_SUBQUERIES_NOT_SUPPORTED 42000 + eng "%s does not support subqueries or stored functions." diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 34fa0308f7d..90c550d6a30 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3441,6 +3441,7 @@ void Query_arena::free_items() { next= free_list->next; DBUG_ASSERT(free_list != next); + DBUG_PRINT("info", ("free item: 0x%lx", (ulong) free_list)); free_list->delete_self(); } /* Postcondition: free_list is 0 */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 4198402ae9b..7a34960e390 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3826,6 +3826,10 @@ public: thr_timer_end(&query_timer); #endif } + void restore_set_statement_var() + { + main_lex.restore_set_statement_var(); + } }; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 7eb38b1dd7a..6432e1937be 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -542,6 +542,8 @@ void lex_start(THD *thd) lex->reset_slave_info.all= false; lex->limit_rows_examined= 0; lex->limit_rows_examined_cnt= ULONGLONG_MAX; + lex->var_list.empty(); + lex->stmt_var_list.empty(); DBUG_VOID_RETURN; } @@ -4233,6 +4235,17 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, return res; } +void LEX::restore_set_statement_var() +{ + DBUG_ENTER("LEX::restore_set_statement_var"); + if (!old_var_list.is_empty()) + { + DBUG_PRINT("info", ("vars: %d", old_var_list.elements)); + sql_set_variables(thd, &old_var_list, false); + old_var_list.empty(); + } + DBUG_VOID_RETURN; +} /* Save explain structures of a UNION. The only variable member is whether the diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b18cff131ca..6c631e20c87 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2401,6 +2401,8 @@ struct LEX: public Query_tables_list List<Item> *insert_list,field_list,value_list,update_list; List<List_item> many_values; List<set_var_base> var_list; + List<set_var_base> stmt_var_list; //SET_STATEMENT values + List<set_var_base> old_var_list; // SET STATEMENT old values List<Item_func_set_user_var> set_var_list; // in-query assignment list List<Item_param> param_list; List<LEX_STRING> view_list; // view list (list of field names in view) @@ -2775,6 +2777,7 @@ struct LEX: public Query_tables_list int print_explain(select_result_sink *output, uint8 explain_flags, bool is_analyze, bool *printed_anything); + void restore_set_statement_var(); }; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b905d8b0bd6..20bc0431d4d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2635,6 +2635,98 @@ mysql_execute_command(THD *thd) thd->get_binlog_format(&orig_binlog_format, &orig_current_stmt_binlog_format); + if (!lex->stmt_var_list.is_empty()) + { + DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); + + lex->old_var_list.empty(); + List_iterator_fast<set_var_base> it(lex->stmt_var_list); + set_var_base *var; + while ((var=it++)) + { + DBUG_ASSERT(var->is_system()); + set_var *o= NULL, *v= (set_var*)var; + if (v->var->is_default()) + o= new set_var(v->type, v->var, &v->base, NULL); + else + { + switch (v->var->option.var_type) + { + case GET_BOOL: + case GET_INT: + case GET_LONG: + case GET_LL: + { + bool null_value; + longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(v->type, v->var, &v->base, + (null_value ? + (Item *)new Item_null() : + (Item *)new Item_int(val))); + } + break; + case GET_UINT: + case GET_ULONG: + case GET_ULL: + { + bool null_value; + ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(v->type, v->var, &v->base, + (null_value ? + (Item *)new Item_null() : + (Item *)new Item_uint(val))); + } + break; + case GET_DOUBLE: + { + bool null_value; + double val= v->var->val_real(&null_value, thd, v->type, &v->base); + o= new set_var(v->type, v->var, &v->base, + (null_value ? + (Item *)new Item_null() : + (Item *)new Item_float(val, 1))); + } + break; + default: + case GET_NO_ARG: + case GET_DISABLED: + DBUG_ASSERT(0); + case 0: + case GET_FLAGSET: + case GET_ASK_ADDR: + case GET_TYPE_MASK: + case GET_ENUM: + case GET_SET: + case GET_STR: + case GET_STR_ALLOC: + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; + val= v->var->val_str(&tmp, thd, v->type, &v->base); + if (val) + { + Item_string *str= new Item_string(v->var->charset(thd), + val->ptr(), val->length()); + o= new set_var(v->type, v->var, &v->base, str); + } + else + o= new set_var(v->type, v->var, &v->base, new Item_null()); + } + break; + } + } + DBUG_ASSERT(o); + lex->old_var_list.push_back(o); + } + if (thd->is_error() || + (res= sql_set_variables(thd, &lex->stmt_var_list, false))) + { + if (!thd->is_error()) + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); + goto error; + } + } + /* Force statement logging for DDL commands to allow us to update privilege, system or statistic tables directly without the updates @@ -4100,7 +4192,7 @@ end_with_restore_list: if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables, TRUE, 0))) goto error; - if (!(res= sql_set_variables(thd, lex_var_list))) + if (!(res= sql_set_variables(thd, lex_var_list, true))) { my_ok(thd); } @@ -4344,8 +4436,7 @@ end_with_restore_list: DBUG_ASSERT(lex->event_parse_data); if (lex->table_or_sp_used()) { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " - "function calls as part of this statement"); + my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "CREATE/ALTER EVENT"); break; } @@ -4665,8 +4756,7 @@ end_with_restore_list: { if (lex->table_or_sp_used()) { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " - "function calls as part of this statement"); + my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "KILL"); break; } @@ -5059,6 +5149,7 @@ create_sp_error: case SQLCOM_COMPOUND: DBUG_ASSERT(all_tables == 0); DBUG_ASSERT(thd->in_sub_stmt == 0); + lex->sphead->m_sql_mode= thd->variables.sql_mode; if (do_execute_sp(thd, lex->sphead)) goto error; break; @@ -5482,6 +5573,8 @@ finish: DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() || thd->in_multi_stmt_transaction_mode()); + + lex->restore_set_statement_var(); lex->unit.cleanup(); if (! thd->in_sub_stmt) diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 6b310865bba..59970b61574 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -189,4 +189,12 @@ extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, int type, uint state_mask, void *arg); extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl, plugin_foreach_func *func, void *arg); + +/** + Create deep copy of system_variables instance. +*/ +extern +struct system_variables * +copy_system_variables(const struct system_variables *src); +extern void free_system_variables(struct system_variables *v); #endif diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index b1765cdda04..5c67a4c45a7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -3299,7 +3299,7 @@ void Prepared_statement::cleanup_stmt() { DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: 0x%lx", (long) this)); - + thd->restore_set_statement_var(); cleanup_items(free_list); thd->cleanup_after_query(); thd->rollback_item_tree_changes(); @@ -3619,7 +3619,9 @@ Prepared_statement::execute_loop(String *expanded_query, Reprepare_observer reprepare_observer; bool error; int reprepare_attempt= 0; - +#ifndef DBUG_OFF + Item *free_list_state= thd->free_list; +#endif thd->select_number= select_number_after_prepare; /* Check if we got an error when sending long data */ if (state == Query_arena::STMT_ERROR) @@ -3646,7 +3648,7 @@ reexecute: allocated items when cleaning up after validation of the prepared statement. */ - DBUG_ASSERT(thd->free_list == NULL); + DBUG_ASSERT(thd->free_list == free_list_state); /* Install the metadata observer. If some metadata version is diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 09f7678fd83..5ebf4d29a80 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -256,7 +256,6 @@ static bool maybe_start_compound_statement(THD *thd) Lex->sp_chistics.suid= SP_IS_NOT_SUID; Lex->sphead->set_body_start(thd, YYLIP->get_cpp_ptr()); - Lex->sphead->m_sql_mode= thd->variables.sql_mode; } return 0; } @@ -788,8 +787,10 @@ static void sp_create_assignment_lex(THD *thd, bool no_lookahead) lex->var_list.empty(); lex->autocommit= 0; /* get_ptr() is only correct with no lookahead. */ - DBUG_ASSERT(no_lookahead); - lex->sphead->m_tmp_query= lip->get_ptr(); + if (no_lookahead) + lex->sphead->m_tmp_query= lip->get_ptr(); + else + lex->sphead->m_tmp_query= lip->get_tok_end(); /* Inherit from outer lex. */ lex->option_type= old_lex->option_type; } @@ -932,10 +933,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 163 shift/reduce conflicts. + Currently there are 164 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 163 +%expect 164 /* Comments for TOKENS. @@ -1481,6 +1482,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token STARTING %token STARTS_SYM %token START_SYM /* SQL-2003-R */ +%token STATEMENT_SYM %token STATS_AUTO_RECALC_SYM %token STATS_PERSISTENT_SYM %token STATS_SAMPLE_PAGES_SYM @@ -14317,6 +14319,7 @@ keyword_sp: | SQL_NO_CACHE_SYM {} | SQL_THREAD {} | STARTS_SYM {} + | STATEMENT_SYM {} | STATUS_SYM {} | STORAGE_SYM {} | STRING_SYM {} @@ -14391,8 +14394,36 @@ set: } start_option_value_list {} + | SET STATEMENT_SYM + { + LEX *lex= Lex; + mysql_init_select(lex); + lex->sql_command= SQLCOM_SET_OPTION; + lex->autocommit= 0; + } + set_stmt_option_value_following_option_type_list + { + LEX *lex= Lex; + if (lex->table_or_sp_used()) + { + my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"); + MYSQL_YYABORT; + } + lex->stmt_var_list= lex->var_list; + lex->var_list.empty(); + } + FOR_SYM verb_clause + {} ; +set_stmt_option_value_following_option_type_list: + /* + Only system variables can be used here. If this condition is changed + please check careful code under lex->option_type == OPT_STATEMENT + condition on wrong type casts. + */ + option_value_following_option_type + | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type // Start of option value list start_option_value_list: @@ -14497,20 +14528,29 @@ option_value_following_option_type: { LEX *lex= Lex; - if ($1.var && $1.var != trg_new_row_fake_var) + /* + Ignore SET STATEMENT variables list on slaves because system + variables are not replicated except certain variables set the + values of whose are written to binlog event header and nothing + additional is required to set them. + */ + if (!thd->slave_thread) { - /* It is a system variable. */ - if (set_system_variable(thd, &$1, lex->option_type, $3)) + if ($1.var && $1.var != trg_new_row_fake_var) + { + /* It is a system variable. */ + if (set_system_variable(thd, &$1, lex->option_type, $3)) + MYSQL_YYABORT; + } + else + { + /* + Not in trigger assigning value to new row, + and option_type preceding local variable is illegal. + */ + my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; - } - else - { - /* - Not in trigger assigning value to new row, - and option_type preceding local variable is illegal. - */ - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; + } } } ; |