summaryrefslogtreecommitdiff
path: root/sql/sql_lex.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r--sql/sql_lex.cc1385
1 files changed, 1235 insertions, 150 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 93002677fbd..5f9742a9e20 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -53,6 +53,540 @@ const LEX_CSTRING empty_clex_str= {"", 0};
const LEX_CSTRING star_clex_str= {"*", 1};
const LEX_CSTRING param_clex_str= {"?", 1};
+
+/**
+ Helper action for a case expression statement (the expr in 'CASE expr').
+ This helper is used for 'searched' cases only.
+ @param lex the parser lex context
+ @param expr the parsed expression
+ @return 0 on success
+*/
+
+int sp_expr_lex::case_stmt_action_expr()
+{
+ int case_expr_id= spcont->register_case_expr();
+ sp_instr_set_case_expr *i;
+
+ if (spcont->push_case_expr_id(case_expr_id))
+ return 1;
+
+ i= new (thd->mem_root)
+ sp_instr_set_case_expr(sphead->instructions(), spcont, case_expr_id,
+ get_item(), this);
+
+ sphead->add_cont_backpatch(i);
+ return sphead->add_instr(i);
+}
+
+/**
+ Helper action for a case when condition.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+ @param when the parsed expression for the WHEN clause
+ @param simple true for simple cases, false for searched cases
+*/
+
+int sp_expr_lex::case_stmt_action_when(bool simple)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump_if_not *i;
+ Item_case_expr *var;
+ Item *expr;
+
+ if (simple)
+ {
+ var= new (thd->mem_root)
+ Item_case_expr(thd, spcont->get_current_case_expr_id());
+
+#ifdef DBUG_ASSERT_EXISTS
+ if (var)
+ {
+ var->m_sp= sphead;
+ }
+#endif
+
+ expr= new (thd->mem_root) Item_func_eq(thd, var, get_item());
+ i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, expr, this);
+ }
+ else
+ i= new (thd->mem_root) sp_instr_jump_if_not(ip, spcont, get_item(), this);
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ return
+ !MY_TEST(i) ||
+ sphead->push_backpatch(thd, i, spcont->push_label(thd, &empty_clex_str, 0)) ||
+ sphead->add_cont_backpatch(i) ||
+ sphead->add_instr(i);
+}
+
+/**
+ Helper action for a case then statements.
+ This helper is used for both 'simple' and 'searched' cases.
+ @param lex the parser lex context
+*/
+
+int LEX::case_stmt_action_then()
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, spcont);
+ if (!MY_TEST(i) || sphead->add_instr(i))
+ return 1;
+
+ /*
+ BACKPATCH: Resolving forward jump from
+ "case_stmt_action_when" to "case_stmt_action_then"
+ (jump_if_not from instruction 2 to 5, 5 to 8 ... in the example)
+ */
+
+ sphead->backpatch(spcont->pop_label());
+
+ /*
+ BACKPATCH: Registering forward jump from
+ "case_stmt_action_then" to after END CASE
+ (jump from instruction 4 to 12, 7 to 12 ... in the example)
+ */
+
+ return sphead->push_backpatch(thd, i, spcont->last_label());
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to push a system variable into the assignment list.
+
+ @param tmp the system variable with base name
+ @param var_type the scope of the variable
+ @param val the value being assigned to the variable
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+bool
+LEX::set_system_variable(enum enum_var_type var_type,
+ sys_var *sysvar, const Lex_ident_sys_st *base_name,
+ Item *val)
+{
+ set_var *setvar;
+
+ /* No AUTOCOMMIT from a stored function or trigger. */
+ if (spcont && sysvar == Sys_autocommit_ptr)
+ sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+
+ if (val && val->type() == Item::FIELD_ITEM &&
+ ((Item_field*)val)->table_name.str)
+ {
+ my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), sysvar->name.str);
+ return TRUE;
+ }
+
+ if (!(setvar= new (thd->mem_root) set_var(thd, var_type, sysvar,
+ base_name, val)))
+ return TRUE;
+
+ return var_list.push_back(setvar, thd->mem_root);
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to SET a field of NEW row.
+
+ @param name the field name
+ @param val the value being assigned to the row
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val)
+{
+ Item_trigger_field *trg_fld;
+ sp_instr_set_trigger_field *sp_fld;
+
+ /* QQ: Shouldn't this be field's default value ? */
+ if (! val)
+ val= new (thd->mem_root) Item_null(thd);
+
+ DBUG_ASSERT(trg_chistics.action_time == TRG_ACTION_BEFORE &&
+ (trg_chistics.event == TRG_EVENT_INSERT ||
+ trg_chistics.event == TRG_EVENT_UPDATE));
+
+ trg_fld= new (thd->mem_root)
+ Item_trigger_field(thd, current_context(),
+ Item_trigger_field::NEW_ROW,
+ *name, UPDATE_ACL, FALSE);
+
+ if (unlikely(trg_fld == NULL))
+ return TRUE;
+
+ sp_fld= new (thd->mem_root)
+ sp_instr_set_trigger_field(sphead->instructions(),
+ spcont, trg_fld, val, this);
+
+ if (unlikely(sp_fld == NULL))
+ return TRUE;
+
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ trg_table_fields.link_in_list(trg_fld, &trg_fld->next_trg_field);
+
+ return sphead->add_instr(sp_fld);
+}
+
+
+/**
+ Create an object to represent a SP variable in the Item-hierarchy.
+
+ @param name The SP variable name.
+ @param spvar The SP variable (optional).
+ @param start_in_q Start position of the SP variable name in the query.
+ @param end_in_q End position of the SP variable name in the query.
+
+ @remark If spvar is not specified, the name is used to search for the
+ variable in the parse-time context. If the variable does not
+ exist, a error is set and NULL is returned to the caller.
+
+ @return An Item_splocal object representing the SP variable, or NULL on error.
+*/
+Item_splocal*
+LEX::create_item_for_sp_var(const Lex_ident_cli_st *cname, sp_variable *spvar)
+{
+ const Sp_rcontext_handler *rh;
+ Item_splocal *item;
+ const char *start_in_q= cname->pos();
+ const char *end_in_q= cname->end();
+ uint pos_in_q, len_in_q;
+ Lex_ident_sys name(thd, cname);
+
+ if (name.is_null())
+ return NULL; // EOM
+
+ /* If necessary, look for the variable. */
+ if (spcont && !spvar)
+ spvar= find_variable(&name, &rh);
+
+ if (!spvar)
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
+ return NULL;
+ }
+
+ DBUG_ASSERT(spcont && spvar);
+
+ /* Position and length of the SP variable name in the query. */
+ pos_in_q= (uint)(start_in_q - sphead->m_tmp_query);
+ len_in_q= (uint)(end_in_q - start_in_q);
+
+ item= new (thd->mem_root)
+ Item_splocal(thd, rh, &name, spvar->offset, spvar->type_handler(),
+ pos_in_q, len_in_q);
+
+#ifdef DBUG_ASSERT_EXISTS
+ if (item)
+ item->m_sp= sphead;
+#endif
+
+ return item;
+}
+
+
+/**
+ Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
+ See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
+ This function returns the proper item for the SQL expression
+ <code>left [NOT] IN ( expr )</code>
+ @param thd the current thread
+ @param left the in predicand
+ @param equal true for IN predicates, false for NOT IN predicates
+ @param expr first and only expression of the in value list
+ @return an expression representing the IN predicate.
+*/
+Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
+ Item *expr)
+{
+ /*
+ Relevant references for this issue:
+ - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
+ - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
+ - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
+ - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
+ - SQL:2003 Feature F561, "Full value expressions".
+
+ The exception in SQL:2003 Note 184 means:
+ Item_singlerow_subselect, which corresponds to a <scalar subquery>,
+ should be re-interpreted as an Item_in_subselect, which corresponds
+ to a <table subquery> when used inside an <in predicate>.
+
+ Our reading of Note 184 is reccursive, so that all:
+ - IN (( <subquery> ))
+ - IN ((( <subquery> )))
+ - IN '('^N <subquery> ')'^N
+ - etc
+ should be interpreted as a <table subquery>, no matter how deep in the
+ expression the <subquery> is.
+ */
+
+ Item *result;
+
+ DBUG_ENTER("handle_sql2003_note184_exception");
+
+ if (expr->type() == Item::SUBSELECT_ITEM)
+ {
+ Item_subselect *expr2 = (Item_subselect*) expr;
+
+ if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
+ {
+ Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
+ st_select_lex *subselect;
+
+ /*
+ Implement the mandated change, by altering the semantic tree:
+ left IN Item_singlerow_subselect(subselect)
+ is modified to
+ left IN (subselect)
+ which is represented as
+ Item_in_subselect(left, subselect)
+ */
+ subselect= expr3->invalidate_and_restore_select_lex();
+ result= new (thd->mem_root) Item_in_subselect(thd, left, subselect);
+
+ if (! equal)
+ result = negate_expression(thd, result);
+
+ DBUG_RETURN(result);
+ }
+ }
+
+ if (equal)
+ result= new (thd->mem_root) Item_func_eq(thd, left, expr);
+ else
+ result= new (thd->mem_root) Item_func_ne(thd, left, expr);
+
+ DBUG_RETURN(result);
+}
+
+/**
+ Create a separate LEX for each assignment if in SP.
+
+ If we are in SP we want have own LEX for each assignment.
+ This is mostly because it is hard for several sp_instr_set
+ and sp_instr_set_trigger instructions share one LEX.
+ (Well, it is theoretically possible but adds some extra
+ overhead on preparation for execution stage and IMO less
+ robust).
+
+ QQ: May be we should simply prohibit group assignments in SP?
+
+ @see sp_create_assignment_instr
+
+ @param thd Thread context
+ @param pos The position in the raw SQL buffer
+*/
+
+
+bool sp_create_assignment_lex(THD *thd, const char *pos)
+{
+ if (thd->lex->sphead)
+ {
+ sp_lex_local *new_lex;
+ if (!(new_lex= new (thd->mem_root) sp_lex_set_var(thd, thd->lex)) ||
+ new_lex->main_select_push())
+ return true;
+ new_lex->sphead->m_tmp_query= pos;
+ return thd->lex->sphead->reset_lex(thd, new_lex);
+ }
+ else
+ if (thd->lex->main_select_push(false))
+ return true;
+ return false;
+}
+
+
+/**
+ Create a SP instruction for a SET assignment.
+
+ @see sp_create_assignment_lex
+
+ @param thd - Thread context
+ @param no_lookahead - True if the parser has no lookahead
+ @param need_set_keyword - if a SET statement "SET a=10",
+ or a direct assignment overwise "a:=10"
+ @return false if success, true otherwise.
+*/
+
+bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
+ bool need_set_keyword)
+{
+ LEX *lex= thd->lex;
+
+ if (lex->sphead)
+ {
+ if (!lex->var_list.is_empty())
+ {
+ /*
+ - Every variable assignment from the same SET command, e.g.:
+ SET @var1=expr1, @var2=expr2;
+ produce each own sp_create_assignment_instr() call
+ lex->var_list.elements is 1 in this case.
+ - This query:
+ SET TRANSACTION READ ONLY, ISOLATION LEVEL SERIALIZABLE;
+ in translated to:
+ SET tx_read_only=1, tx_isolation=ISO_SERIALIZABLE;
+ but produces a single sp_create_assignment_instr() call
+ which includes the query fragment covering both options.
+ */
+ DBUG_ASSERT(lex->var_list.elements >= 1 && lex->var_list.elements <= 2);
+ /*
+ sql_mode=ORACLE's direct assignment of a global variable
+ is not possible by the grammar.
+ */
+ DBUG_ASSERT(lex->option_type != OPT_GLOBAL || need_set_keyword);
+ /*
+ We have assignment to user or system variable or
+ option setting, so we should construct sp_instr_stmt
+ for it.
+ */
+ Lex_input_stream *lip= &thd->m_parser_state->m_lip;
+
+ /*
+ Extract the query statement from the tokenizer. The
+ end is either lip->ptr, if there was no lookahead,
+ lip->tok_end otherwise.
+ */
+ static const LEX_CSTRING setlc= { STRING_WITH_LEN("SET ") };
+ static const LEX_CSTRING setgl= { STRING_WITH_LEN("SET GLOBAL ") };
+ const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end();
+ Lex_cstring qbuf(lex->sphead->m_tmp_query, qend);
+ if (lex->new_sp_instr_stmt(thd,
+ lex->option_type == OPT_GLOBAL ? setgl :
+ need_set_keyword ? setlc :
+ null_clex_str,
+ qbuf))
+ return true;
+ }
+ lex->pop_select();
+ if (lex->check_main_unit_semantics())
+ {
+ /*
+ "lex" can be referrenced by:
+ - sp_instr_set SET a= expr;
+ - sp_instr_set_row_field SET r.a= expr;
+ - sp_instr_stmt (just generated above) SET @a= expr;
+ In this case, "lex" is fully owned by sp_instr_xxx and it will
+ be deleted by the destructor ~sp_instr_xxx().
+ So we should remove "lex" from the stack sp_head::m_lex,
+ to avoid double free.
+ Note, in case "lex" is not owned by any sp_instr_xxx,
+ it's also safe to remove it from the stack right now.
+ So we can remove it unconditionally, without testing lex->sp_lex_in_use.
+ */
+ lex->sphead->restore_lex(thd);
+ return true;
+ }
+ enum_var_type inner_option_type= lex->option_type;
+ if (lex->sphead->restore_lex(thd))
+ return true;
+ /* Copy option_type to outer lex in case it has changed. */
+ thd->lex->option_type= inner_option_type;
+ }
+ else
+ lex->pop_select();
+ return false;
+}
+
+
+void LEX::add_key_to_list(LEX_CSTRING *field_name,
+ enum Key::Keytype type, bool check_exists)
+{
+ Key *key;
+ MEM_ROOT *mem_root= thd->mem_root;
+ key= new (mem_root)
+ Key(type, &null_clex_str, HA_KEY_ALG_UNDEF, false,
+ DDL_options(check_exists ?
+ DDL_options::OPT_IF_NOT_EXISTS :
+ DDL_options::OPT_NONE));
+ key->columns.push_back(new (mem_root) Key_part_spec(field_name, 0),
+ mem_root);
+ alter_info.key_list.push_back(key, mem_root);
+}
+
+
+bool LEX::add_alter_list(LEX_CSTRING name, Virtual_column_info *expr,
+ bool exists)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ Alter_column *ac= new (mem_root) Alter_column(name, expr, exists);
+ if (unlikely(ac == NULL))
+ return true;
+ alter_info.alter_list.push_back(ac, mem_root);
+ alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
+ return false;
+}
+
+
+bool LEX::add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name, bool exists)
+{
+ Alter_column *ac= new (thd->mem_root) Alter_column(name, new_name, exists);
+ if (unlikely(ac == NULL))
+ return true;
+ alter_info.alter_list.push_back(ac, thd->mem_root);
+ alter_info.flags|= ALTER_RENAME_COLUMN;
+ return false;
+}
+
+
+void LEX::init_last_field(Column_definition *field,
+ const LEX_CSTRING *field_name,
+ const CHARSET_INFO *cs)
+{
+ last_field= field;
+
+ field->field_name= *field_name;
+
+ /* reset LEX fields that are used in Create_field::set_and_check() */
+ charset= cs;
+}
+
+
+bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
+{
+ /*
+ if charset is NULL - we're parsing a field declaration.
+ we cannot call find_bin_collation for a field here, because actual
+ field charset is determined in get_sql_field_charset() much later.
+ so we only set a flag.
+ */
+ if (!charset)
+ {
+ charset= cs;
+ last_field->flags|= bin ? BINCMP_FLAG : 0;
+ return false;
+ }
+
+ charset= bin ? find_bin_collation(cs ? cs : charset)
+ : cs ? cs : charset;
+ return charset == NULL;
+}
+
+
+Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
+{
+ Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
+ if (unlikely(!v))
+ return 0;
+ v->expr= expr;
+ v->utf8= 0; /* connection charset */
+ return v;
+}
+
+
+
/**
@note The order of the elements of this array must correspond to
the order of elements in enum_binlog_stmt_unsafe.
@@ -352,7 +886,7 @@ size_t Lex_input_stream::get_body_utf8_maximum_length(THD *thd)
"2" should be a reasonable multiplier that safely covers escaping needs.
*/
return (m_buf_length / thd->variables.character_set_client->mbminlen) *
- my_charset_utf8_bin.mbmaxlen * 2/*for escaping*/;
+ my_charset_utf8mb3_bin.mbmaxlen * 2/*for escaping*/;
}
@@ -457,14 +991,14 @@ extern "C" {
@param end - the end of the destination string
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
+ uchar *str, uchar *end)
{
DBUG_ASSERT(escape > 0);
if (str + 1 >= end)
return MY_CS_TOOSMALL2; // Not enough space, need at least two bytes.
*str= (uchar)escape;
- int cnvres= my_charset_utf8_handler.wc_mb(cs, wc, str + 1, end);
+ int cnvres= my_charset_utf8mb3_handler.wc_mb(cs, wc, str + 1, end);
if (cnvres > 0)
return cnvres + 1; // The character was normally put
if (cnvres == MY_CS_ILUNI)
@@ -486,12 +1020,12 @@ int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
@param end - the end of the destination string
@returns - a code according to the wc_mb() conversion.
*/
-int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
- my_wc_t wc, my_wc_t escape, my_wc_t ewc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_opt_escape(CHARSET_INFO *cs,
+ my_wc_t wc, my_wc_t escape, my_wc_t ewc,
+ uchar *str, uchar *end)
{
- return escape ? my_wc_mb_utf8_with_escape(cs, escape, ewc, str, end) :
- my_charset_utf8_handler.wc_mb(cs, wc, str, end);
+ return escape ? my_wc_mb_utf8mb3_with_escape(cs, escape, ewc, str, end) :
+ my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end);
}
/**
@@ -510,54 +1044,55 @@ int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
@param escape - the escape character (backslash, or 0)
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_escape(CHARSET_INFO *cs, my_wc_t wc, uchar *str, uchar *end,
- my_wc_t sep, my_wc_t escape)
+int my_wc_mb_utf8mb3_escape(CHARSET_INFO *cs, my_wc_t wc,
+ uchar *str, uchar *end,
+ my_wc_t sep, my_wc_t escape)
{
DBUG_ASSERT(escape == 0 || escape == '\\');
DBUG_ASSERT(sep == '"' || sep == '\'');
switch (wc) {
- case 0: return my_wc_mb_utf8_opt_escape(cs, wc, escape, '0', str, end);
- case '\t': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 't', str, end);
- case '\r': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'r', str, end);
- case '\n': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'n', str, end);
- case '\032': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'Z', str, end);
+ case 0: return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, '0', str, end);
+ case '\t': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 't', str, end);
+ case '\r': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'r', str, end);
+ case '\n': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'n', str, end);
+ case '\032': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'Z', str, end);
case '\'':
case '\"':
if (wc == sep)
- return my_wc_mb_utf8_with_escape(cs, wc, wc, str, end);
+ return my_wc_mb_utf8mb3_with_escape(cs, wc, wc, str, end);
}
- return my_charset_utf8_handler.wc_mb(cs, wc, str, end); // No escaping needed
+ return my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end); // No escaping needed
}
/** wc_mb() compatible routines for all sql_mode and delimiter combinations */
-int my_wc_mb_utf8_escape_single_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_single_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', '\\');
}
-int my_wc_mb_utf8_escape_double_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_double_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', '\\');
}
-int my_wc_mb_utf8_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', 0);
}
-int my_wc_mb_utf8_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', 0);
}
}; // End of extern "C"
@@ -571,10 +1106,10 @@ my_charset_conv_wc_mb
Lex_input_stream::get_escape_func(THD *thd, my_wc_t sep) const
{
return thd->backslash_escapes() ?
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote_and_backslash:
- my_wc_mb_utf8_escape_single_quote_and_backslash) :
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote:
- my_wc_mb_utf8_escape_single_quote);
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote_and_backslash:
+ my_wc_mb_utf8mb3_escape_single_quote_and_backslash) :
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote:
+ my_wc_mb_utf8mb3_escape_single_quote);
}
@@ -614,7 +1149,7 @@ void Lex_input_stream::body_utf8_append_escape(THD *thd,
DBUG_ASSERT(m_body_utf8 + get_body_utf8_maximum_length(thd) >=
m_body_utf8_ptr + txt->length * 2);
uint32 cnv_length= my_convert_using_func(m_body_utf8_ptr, txt->length * 2,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
get_escape_func(thd, sep),
txt->str, txt->length,
cs, cs->cset->mb_wc,
@@ -707,7 +1242,6 @@ void LEX::start(THD *thd_arg)
set_var_list.empty();
param_list.empty();
view_list.empty();
- with_column_list.empty();
with_persistent_for_clause= FALSE;
column_list= NULL;
index_list= NULL;
@@ -939,6 +1473,9 @@ bool is_native_function(THD *thd, const LEX_CSTRING *name)
if (is_lex_native_function(name))
return true;
+ if (Type_handler::handler_by_name(thd, *name))
+ return true;
+
return false;
}
@@ -1008,7 +1545,7 @@ my_unescape(CHARSET_INFO *cs, char *to, const char *str, const char *end,
{
#ifdef USE_MB
int l;
- if (use_mb(cs) && (l= my_ismbchar(cs, str, end)))
+ if (cs->use_mb() && (l= my_ismbchar(cs, str, end)))
{
while (l--)
*to++ = *str++;
@@ -1086,7 +1623,7 @@ bool Lex_input_stream::get_text(Lex_string_with_metadata_st *dst, uint sep,
#ifdef USE_MB
{
int l;
- if (use_mb(cs) &&
+ if (cs->use_mb() &&
(l = my_ismbchar(cs,
get_ptr() -1,
get_end_of_query()))) {
@@ -2032,7 +2569,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
next_state= MY_LEX_HOSTNAME;
break;
}
- yylval->lex_str.str= (char*) get_ptr();
+ yylval->lex_str.str= (char*) get_ptr() - 1;
yylval->lex_str.length= 1;
return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname
@@ -2130,12 +2667,12 @@ int Lex_input_stream::scan_ident_start(THD *thd, Lex_ident_cli_st *str)
const uchar *const ident_map= cs->ident_map;
DBUG_ASSERT(m_tok_start <= m_ptr);
- if (use_mb(cs))
+ if (cs->use_mb())
{
is_8bit= true;
while (ident_map[c= yyGet()])
{
- int char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
break;
skip_binary(char_length - 1);
@@ -2173,10 +2710,10 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str,
bool resolve_introducer= true;
DBUG_ASSERT(m_ptr == m_tok_start + 1); // m_ptr points to the second byte
- if (use_mb(cs))
+ if (cs->use_mb())
{
is_8bit= true;
- int char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
{
*st= MY_LEX_CHAR;
@@ -2186,7 +2723,7 @@ int Lex_input_stream::scan_ident_middle(THD *thd, Lex_ident_cli_st *str,
while (ident_map[c= yyGet()])
{
- char_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ char_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (char_length <= 0)
break;
if (char_length > 1 || (c & 0x80))
@@ -2280,7 +2817,7 @@ int Lex_input_stream::scan_ident_delimited(THD *thd,
m_cpp_ptr= (char *) m_cpp_tok_start + 1;
return quote_char;
}
- int var_length= my_charlen(cs, get_ptr() - 1, get_end_of_query());
+ int var_length= cs->charlen(get_ptr() - 1, get_end_of_query());
if (var_length == 1)
{
if (c == quote_char)
@@ -2359,10 +2896,10 @@ void st_select_lex_unit::init_query()
{
init_query_common();
set_linkage(GLOBAL_OPTIONS_TYPE);
- select_limit_cnt= HA_POS_ERROR;
- offset_limit_cnt= 0;
+ lim.set_unlimited();
union_distinct= 0;
prepared= optimized= optimized_2= executed= 0;
+ bag_set_op_optimized= 0;
optimize_started= 0;
item= 0;
union_result= 0;
@@ -2379,8 +2916,8 @@ void st_select_lex_unit::init_query()
with_element= 0;
cloned_from= 0;
columns_are_renamed= false;
- intersect_mark= NULL;
with_wrapped_tvc= false;
+ have_except_all_or_intersect_all= false;
}
void st_select_lex::init_query()
@@ -2483,6 +3020,7 @@ void st_select_lex::init_select()
curr_tvc_name= 0;
in_tvc= false;
versioned_tables= 0;
+ nest_flags= 0;
}
/*
@@ -2644,7 +3182,7 @@ st_select_lex_node *st_select_lex_node:: insert_chain_before(
{
end_chain_node->link_next= *ptr_pos_to_insert;
(*ptr_pos_to_insert)->link_prev= &end_chain_node->link_next;
- this->link_prev= ptr_pos_to_insert;
+ link_prev= ptr_pos_to_insert;
return this;
}
@@ -2834,7 +3372,7 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last,
return TRUE;
} while ((c= c->outer_context) != NULL && (c->select_lex != last));
is_correlated= TRUE;
- this->master_unit()->item->is_correlated= TRUE;
+ master_unit()->item->is_correlated= TRUE;
return FALSE;
}
@@ -3028,11 +3566,114 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
}
+/*
+ @brief
+ Print the whole statement
+
+ @param str Print into this string
+ @param query_type Flags describing how to print
+
+ @detail
+ The intent is to allow to eventually print back any query.
+
+ This is useful e.g. for storage engines that take over diferrent kinds of
+ queries
+*/
+
+void LEX::print(String *str, enum_query_type query_type)
+{
+ if (sql_command == SQLCOM_UPDATE)
+ {
+ SELECT_LEX *sel= first_select_lex();
+ str->append(STRING_WITH_LEN("UPDATE "));
+ if (ignore)
+ str->append(STRING_WITH_LEN("IGNORE "));
+ // table name. If the query was using a view, we need
+ // the underlying table name, not the view name
+ TABLE_LIST *base_tbl= query_tables->table->pos_in_table_list;
+ base_tbl->print(thd, table_map(0), str, query_type);
+ str->append(STRING_WITH_LEN(" SET "));
+ // print item assignments
+ List_iterator<Item> it(sel->item_list);
+ List_iterator<Item> it2(value_list);
+ Item *col_ref, *value;
+ bool first= true;
+ while ((col_ref= it++) && (value= it2++))
+ {
+ if (first)
+ first= false;
+ else
+ str->append(STRING_WITH_LEN(", "));
+ col_ref->print(str, query_type);
+ str->append(STRING_WITH_LEN("="));
+ value->print(str, query_type);
+ }
+
+ if (sel->where)
+ {
+ str->append(STRING_WITH_LEN(" WHERE "));
+ sel->where->print(str, query_type);
+ }
+
+ if (sel->order_list.elements)
+ {
+ str->append(STRING_WITH_LEN(" ORDER BY "));
+ for (ORDER *ord= sel->order_list.first; ord; ord= ord->next)
+ {
+ if (ord != sel->order_list.first)
+ str->append(STRING_WITH_LEN(", "));
+ (*ord->item)->print(str, query_type);
+ }
+ }
+ if (sel->select_limit)
+ {
+ str->append(STRING_WITH_LEN(" LIMIT "));
+ sel->select_limit->print(str, query_type);
+ }
+ }
+ else if (sql_command == SQLCOM_DELETE)
+ {
+ SELECT_LEX *sel= first_select_lex();
+ str->append(STRING_WITH_LEN("DELETE "));
+ if (ignore)
+ str->append(STRING_WITH_LEN("IGNORE "));
+
+ str->append(STRING_WITH_LEN("FROM "));
+ // table name. If the query was using a view, we need
+ // the underlying table name, not the view name
+ TABLE_LIST *base_tbl= query_tables->table->pos_in_table_list;
+ base_tbl->print(thd, table_map(0), str, query_type);
+
+ if (sel->where)
+ {
+ str->append(STRING_WITH_LEN(" WHERE "));
+ sel->where->print(str, query_type);
+ }
+
+ if (sel->order_list.elements)
+ {
+ str->append(STRING_WITH_LEN(" ORDER BY "));
+ for (ORDER *ord= sel->order_list.first; ord; ord= ord->next)
+ {
+ if (ord != sel->order_list.first)
+ str->append(STRING_WITH_LEN(", "));
+ (*ord->item)->print(str, query_type);
+ }
+ }
+ if (sel->select_limit)
+ {
+ str->append(STRING_WITH_LEN(" LIMIT "));
+ sel->select_limit->print(str, query_type);
+ }
+ }
+ else
+ DBUG_ASSERT(0); // Not implemented yet
+}
+
void st_select_lex_unit::print(String *str, enum_query_type query_type)
{
- bool union_all= !union_distinct;
if (with_clause)
- with_clause->print(str, query_type);
+ with_clause->print(thd, str, query_type);
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
if (sl != first_select())
@@ -3044,8 +3685,6 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
/* fall through */
case UNION_TYPE:
str->append(STRING_WITH_LEN(" union "));
- if (union_all)
- str->append(STRING_WITH_LEN("all "));
break;
case INTERSECT_TYPE:
str->append(STRING_WITH_LEN(" intersect "));
@@ -3054,8 +3693,8 @@ void st_select_lex_unit::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN(" except "));
break;
}
- if (sl == union_distinct)
- union_all= TRUE;
+ if (!sl->distinct)
+ str->append(STRING_WITH_LEN("all "));
}
if (sl->braces)
str->append('(');
@@ -3279,12 +3918,12 @@ LEX::LEX()
default_used(0), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX)
{
- init_dynamic_array2(&plugins, sizeof(plugin_ref), plugins_static_buffer,
- INITIAL_LEX_PLUGIN_LIST_SIZE,
+ init_dynamic_array2(PSI_INSTRUMENT_ME, &plugins, sizeof(plugin_ref),
+ plugins_static_buffer, INITIAL_LEX_PLUGIN_LIST_SIZE,
INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE);
mi.init();
- init_dynamic_array2(&delete_gtid_domain, sizeof(uint32),
+ init_dynamic_array2(PSI_INSTRUMENT_ME, &delete_gtid_domain, sizeof(uint32),
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
@@ -3541,12 +4180,7 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
{
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
- offset_limit_cnt= sl->get_offset();
- select_limit_cnt= sl->get_limit();
- if (select_limit_cnt + offset_limit_cnt >= select_limit_cnt)
- select_limit_cnt+= offset_limit_cnt;
- else
- select_limit_cnt= HA_POS_ERROR;
+ lim.set_limit(sl->get_limit(), sl->get_offset());
}
@@ -3570,6 +4204,8 @@ bool st_select_lex_unit::union_needs_tmp_table()
with_wrapped_tvc= true;
break;
}
+ if (sl != first_select() && sl->linkage != UNION_TYPE)
+ return true;
}
}
if (with_wrapped_tvc)
@@ -3939,7 +4575,7 @@ void LEX::reset_n_backup_query_tables_list(Query_tables_list *backup)
We have to perform full initialization here since otherwise we
will damage backed up state.
*/
- this->reset_query_tables_list(TRUE);
+ reset_query_tables_list(TRUE);
}
@@ -3953,8 +4589,8 @@ void LEX::reset_n_backup_query_tables_list(Query_tables_list *backup)
void LEX::restore_backup_query_tables_list(Query_tables_list *backup)
{
- this->destroy_query_tables_list();
- this->set_query_tables_list(backup);
+ destroy_query_tables_list();
+ set_query_tables_list(backup);
}
@@ -4185,7 +4821,7 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only)
}
if (subquery_predicate->substype() == Item_subselect::IN_SUBS)
{
- Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate;
+ Item_in_subselect *in_subs= subquery_predicate->get_IN_subquery();
if (in_subs->is_jtbm_merged)
continue;
}
@@ -4613,7 +5249,7 @@ void SELECT_LEX::update_used_tables()
*/
if (tl->jtbm_subselect)
{
- Item *left_expr= tl->jtbm_subselect->left_expr;
+ Item *left_expr= tl->jtbm_subselect->left_exp();
left_expr->walk(&Item::update_table_bitmaps_processor, FALSE, NULL);
}
@@ -4770,7 +5406,7 @@ void st_select_lex::set_explain_type(bool on_the_fly)
if ((parent_item= master_unit()->item) &&
parent_item->substype() == Item_subselect::IN_SUBS)
{
- Item_in_subselect *in_subs= (Item_in_subselect*)parent_item;
+ Item_in_subselect *in_subs= parent_item->get_IN_subquery();
/*
Surprisingly, in_subs->is_set_strategy() can return FALSE here,
even for the last invocation of this function for the select.
@@ -5085,9 +5721,10 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
sl=sl->outer_select())
{
Item *subs= sl->master_unit()->item;
- if (subs && subs->type() == Item::SUBSELECT_ITEM &&
+ Item_in_subselect *in_subs= (subs ? subs->get_IN_subquery() : NULL);
+ if (in_subs &&
((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS &&
- ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN))
+ in_subs->test_strategy(SUBS_SEMI_JOIN))
{
continue;
}
@@ -5144,8 +5781,8 @@ bool LEX::set_arena_for_set_stmt(Query_arena *backup)
mem_root_for_set_stmt= new MEM_ROOT();
if (unlikely(!(mem_root_for_set_stmt)))
DBUG_RETURN(1);
- init_sql_alloc(mem_root_for_set_stmt, "set_stmt",
- ALLOC_ROOT_SET, ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC));
+ init_sql_alloc(PSI_INSTRUMENT_ME, mem_root_for_set_stmt, ALLOC_ROOT_SET,
+ ALLOC_ROOT_SET, MYF(MY_THREAD_SPECIFIC));
}
if (unlikely(!(arena_for_set_stmt= new(mem_root_for_set_stmt)
Query_arena_memroot(mem_root_for_set_stmt,
@@ -5272,7 +5909,7 @@ int st_select_lex_unit::save_union_explain(Explain_query *output)
eu->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
/*
Note: Non-merged semi-joins cannot be made out of UNIONs currently, so we
- dont ever set EXPLAIN_NODE_NON_MERGED_SJ.
+ don't ever set EXPLAIN_NODE_NON_MERGED_SJ.
*/
for (SELECT_LEX *sl= first; sl; sl= sl->next_select())
eu->add_select(sl->select_number);
@@ -5303,10 +5940,8 @@ int st_select_lex_unit::save_union_explain_part2(Explain_query *output)
for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit();
unit; unit= unit->next_unit())
{
- if (!(unit->item && unit->item->eliminated))
- {
+ if (unit->explainable())
eu->add_child(unit->first_select()->select_number);
- }
}
fake_select_lex->join->explain= &eu->fake_select_lex_explain;
}
@@ -5467,7 +6102,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
Name_resolution_context *context= &wrapping_sel->context;
context->init();
wrapping_sel->automatic_brackets= FALSE;
-
+ wrapping_sel->mark_as_unit_nest();
wrapping_sel->register_unit(unit, context);
/* stuff dummy SELECT * FROM (...) */
@@ -5477,8 +6112,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5540,8 +6174,7 @@ SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5662,9 +6295,22 @@ sp_variable *LEX::sp_param_init(LEX_CSTRING *name)
}
-bool LEX::sp_param_fill_definition(sp_variable *spvar)
+bool LEX::sp_param_fill_definition(sp_variable *spvar,
+ const Lex_field_type_st &def)
+{
+ return
+ last_field->set_attributes(thd, def, charset,
+ COLUMN_DEFINITION_ROUTINE_PARAM) ||
+ sphead->fill_spvar_definition(thd, last_field, &spvar->name);
+}
+
+
+bool LEX::sf_return_fill_definition(const Lex_field_type_st &def)
{
- return sphead->fill_spvar_definition(thd, last_field, &spvar->name);
+ return
+ last_field->set_attributes(thd, def, charset,
+ COLUMN_DEFINITION_FUNCTION_RETURN) ||
+ sphead->fill_field_definition(thd, last_field);
}
@@ -5674,6 +6320,7 @@ void LEX::set_stmt_init()
mysql_init_select(this);
option_type= OPT_SESSION;
autocommit= 0;
+ var_list.empty();
};
@@ -5731,7 +6378,7 @@ static bool is_old(const char *str)
bool LEX::is_trigger_new_or_old_reference(const LEX_CSTRING *name) const
{
// "name" is not necessarily NULL-terminated!
- return sphead && sphead->m_handler->type() == TYPE_ENUM_TRIGGER &&
+ return sphead && sphead->m_handler->type() == SP_TYPE_TRIGGER &&
name->length == 3 && (is_new(name->str) || is_old(name->str));
}
@@ -5780,7 +6427,7 @@ bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars,
bool last= i + 1 == (uint) nvars;
spvar->default_value= dflt_value_item;
/* The last instruction is responsible for freeing LEX. */
- sp_instr_set *is= new (this->thd->mem_root)
+ sp_instr_set *is= new (thd->mem_root)
sp_instr_set(sphead->instructions(),
spcont, &sp_rcontext_handler_local,
spvar->offset, dflt_value_item,
@@ -6073,14 +6720,14 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name,
sp_variable *spvar= spcont->add_variable(thd, name);
spcont->declare_var_boundary(1);
spvar->field_def.field_name= spvar->name;
- spvar->field_def.set_handler(&type_handler_longlong);
- type_handler_longlong.Column_definition_prepare_stage2(&spvar->field_def,
- NULL, HA_CAN_GEOMETRY);
+ spvar->field_def.set_handler(&type_handler_slonglong);
+ type_handler_slonglong.Column_definition_prepare_stage2(&spvar->field_def,
+ NULL, HA_CAN_GEOMETRY);
if (!value && unlikely(!(value= new (thd->mem_root) Item_null(thd))))
return NULL;
spvar->default_value= value;
- sp_instr_set *is= new (this->thd->mem_root)
+ sp_instr_set *is= new (thd->mem_root)
sp_instr_set(sphead->instructions(),
spcont, &sp_rcontext_handler_local,
spvar->offset, value,
@@ -6118,7 +6765,7 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
SELECT rec.a, rec.b;
END FOR;
*/
- if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name)))
+ if (!(item= new (thd->mem_root) Item_field(thd, NULL, name)))
return true;
bounds->m_index->set_item_and_free_list(item, NULL);
if (thd->lex->sphead->restore_lex(thd))
@@ -6272,7 +6919,7 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd,
name= item_splocal->m_name;
else if ((item_field= item->type() == Item::FIELD_ITEM ?
static_cast<Item_field *>(item) : NULL) &&
- item_field->table_name == NULL)
+ item_field->table_name.str == NULL)
name= item_field->field_name;
else if (item->type() == Item::FUNC_ITEM &&
static_cast<Item_func*>(item)->functype() == Item_func::FUNC_SP &&
@@ -6904,7 +7551,7 @@ bool LEX::sp_exit_block(THD *thd, sp_label *lab, Item *when)
sp_instr_jump_if_not *i= new (thd->mem_root)
sp_instr_jump_if_not(sphead->instructions(),
spcont,
- when, thd->lex);
+ when, this);
if (unlikely(i == NULL) ||
unlikely(sphead->add_instr(i)) ||
unlikely(sp_exit_block(thd, lab)))
@@ -6967,17 +7614,40 @@ bool LEX::sp_continue_loop(THD *thd, sp_label *lab)
}
-bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
+bool LEX::sp_continue_statement(THD *thd)
{
- if (!when)
- return sp_continue_loop(thd, lab);
+ sp_label *lab= spcont->find_label_current_loop_start();
+ if (unlikely(!lab))
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", "");
+ return true;
+ }
+ DBUG_ASSERT(lab->type == sp_label::ITERATION);
+ return sp_continue_loop(thd, lab);
+}
+
+
+bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name)
+{
+ sp_label *lab= spcont->find_label(label_name);
+ if (!lab || lab->type != sp_label::ITERATION)
+ {
+ my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", label_name->str);
+ return true;
+ }
+ return sp_continue_loop(thd, lab);
+}
+
+bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
+{
+ DBUG_ASSERT(when);
DBUG_ASSERT(sphead == thd->lex->sphead);
DBUG_ASSERT(spcont == thd->lex->spcont);
sp_instr_jump_if_not *i= new (thd->mem_root)
sp_instr_jump_if_not(sphead->instructions(),
spcont,
- when, thd->lex);
+ when, this);
if (unlikely(i == NULL) ||
unlikely(sphead->add_instr(i)) ||
unlikely(sp_continue_loop(thd, lab)))
@@ -6987,7 +7657,7 @@ bool LEX::sp_continue_loop(THD *thd, sp_label *lab, Item *when)
}
-bool LEX::sp_continue_statement(THD *thd, Item *when)
+bool sp_expr_lex::sp_continue_when_statement(THD *thd)
{
sp_label *lab= spcont->find_label_current_loop_start();
if (unlikely(!lab))
@@ -6996,12 +7666,12 @@ bool LEX::sp_continue_statement(THD *thd, Item *when)
return true;
}
DBUG_ASSERT(lab->type == sp_label::ITERATION);
- return sp_continue_loop(thd, lab, when);
+ return sp_continue_loop(thd, lab, get_item());
}
-bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name,
- Item *when)
+bool sp_expr_lex::sp_continue_when_statement(THD *thd,
+ const LEX_CSTRING *label_name)
{
sp_label *lab= spcont->find_label(label_name);
if (!lab || lab->type != sp_label::ITERATION)
@@ -7009,7 +7679,7 @@ bool LEX::sp_continue_statement(THD *thd, const LEX_CSTRING *label_name,
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "CONTINUE", label_name->str);
return true;
}
- return sp_continue_loop(thd, lab, when);
+ return sp_continue_loop(thd, lab, get_item());
}
@@ -7074,10 +7744,10 @@ void LEX::sp_pop_loop_empty_label(THD *thd)
}
-bool LEX::sp_while_loop_expression(THD *thd, Item *expr)
+bool LEX::sp_while_loop_expression(THD *thd, Item *item)
{
sp_instr_jump_if_not *i= new (thd->mem_root)
- sp_instr_jump_if_not(sphead->instructions(), spcont, expr, this);
+ sp_instr_jump_if_not(sphead->instructions(), spcont, item, this);
return (unlikely(i == NULL) ||
/* Jumping forward */
unlikely(sphead->push_backpatch(thd, i, spcont->last_label())) ||
@@ -7128,7 +7798,7 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd,
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
- name, SELECT_ACL, tmp_read_only);
+ *name, SELECT_ACL, tmp_read_only);
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
@@ -7277,7 +7947,7 @@ Item *LEX::create_item_for_loop_bound(THD *thd,
Pass NULL as the name resolution context.
This is OK, fix_fields() won't be called for this Item_field.
*/
- return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c);
+ return new (thd->mem_root) Item_field(thd, NULL, *a, *b, *c);
}
@@ -7315,7 +7985,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, a, b);
- return create_item_ident_field(thd, NullS, a->str, b);
+ return create_item_ident_field(thd, Lex_ident_sys(), *a, *b);
}
@@ -7488,11 +8158,11 @@ Item *LEX::create_item_ident(THD *thd,
if ((thd->variables.sql_mode & MODE_ORACLE) && b.length == 7)
{
- if (!my_strnncoll(system_charset_info,
+ if (!system_charset_info->strnncoll(
(const uchar *) b.str, 7,
(const uchar *) "NEXTVAL", 7))
return create_item_func_nextval(thd, &null_clex_str, &a);
- else if (!my_strnncoll(system_charset_info,
+ else if (!system_charset_info->strnncoll(
(const uchar *) b.str, 7,
(const uchar *) "CURRVAL", 7))
return create_item_func_lastval(thd, &null_clex_str, &a);
@@ -7507,16 +8177,15 @@ Item *LEX::create_item_ident(THD *thd,
const Lex_ident_sys_st *b,
const Lex_ident_sys_st *c)
{
- const char *schema= (thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str);
-
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if ((thd->variables.sql_mode & MODE_ORACLE) && c->length == 7)
{
- if (!my_strnncoll(system_charset_info,
+ if (!system_charset_info->strnncoll(
(const uchar *) c->str, 7,
(const uchar *) "NEXTVAL", 7))
return create_item_func_nextval(thd, a, b);
- else if (!my_strnncoll(system_charset_info,
+ else if (!system_charset_info->strnncoll(
(const uchar *) c->str, 7,
(const uchar *) "CURRVAL", 7))
return create_item_func_lastval(thd, a, b);
@@ -7531,7 +8200,7 @@ Item *LEX::create_item_ident(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, b, c);
- return create_item_ident_field(thd, schema, b->str, c);
+ return create_item_ident_field(thd, schema, *b, *c);
}
@@ -7618,11 +8287,12 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
}
-Item *LEX::create_item_ident_field(THD *thd, const char *db,
- const char *table,
- const Lex_ident_sys_st *name)
+Item *LEX::create_item_ident_field(THD *thd,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &table,
+ const Lex_ident_sys_st &name)
{
- if (check_expr_allows_fields_or_error(thd, name->str))
+ if (check_expr_allows_fields_or_error(thd, name.str))
return NULL;
if (current_select->parsing_place != IN_HAVING ||
@@ -7702,7 +8372,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
-bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
+bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item)
{
sp_pcontext *ctx;
const Sp_rcontext_handler *rh;
@@ -7716,8 +8386,8 @@ bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
Generate instructions for:
SET x.y= expr;
*/
-bool LEX::set_variable(const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+bool LEX::set_variable(const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *item)
{
const Sp_rcontext_handler *rh;
@@ -7747,10 +8417,10 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
bool LEX::set_default_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
- static LEX_CSTRING default_base_name= {STRING_WITH_LEN("default")};
+ static Lex_ident_sys default_base_name= {STRING_WITH_LEN("default")};
sys_var *var= find_sys_var(thd, name->str, name->length);
if (!var)
return true;
@@ -7764,18 +8434,19 @@ bool LEX::set_default_system_variable(enum_var_type var_type,
bool LEX::set_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
sys_var *var= find_sys_var(thd, name->str, name->length);
DBUG_ASSERT(thd->is_error() || var != NULL);
- return likely(var) ? set_system_variable(var_type, var, &null_clex_str, val) : true;
+ static Lex_ident_sys null_str;
+ return likely(var) ? set_system_variable(var_type, var, &null_str, val) : true;
}
bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
- const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+ const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *val)
{
sys_var *tmp;
@@ -8459,15 +9130,15 @@ bool LEX::call_statement_start(THD *thd, sp_name *name)
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name)
{
sp_name *spname= make_sp_name(thd, name);
return unlikely(!spname) || call_statement_start(thd, spname);
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1,
- const LEX_CSTRING *name2)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2)
{
sp_name *spname= make_sp_name(thd, name1, name2);
return unlikely(!spname) || call_statement_start(thd, spname);
@@ -8495,7 +9166,7 @@ sp_package *LEX::create_package_start(THD *thd,
}
if (unlikely(set_command_with_check(command, options)))
return NULL;
- if (sph->type() == TYPE_ENUM_PACKAGE_BODY)
+ if (sph->type() == SP_TYPE_PACKAGE_BODY)
{
/*
If we start parsing a "CREATE PACKAGE BODY", we need to load
@@ -8570,16 +9241,13 @@ bool LEX::create_package_finalize(THD *thd,
}
-bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
- stored_procedure_type type_arg)
+bool LEX::add_grant_command(THD *thd, const List<LEX_COLUMN> &columns)
{
if (columns.elements)
{
thd->parse_error();
return true;
}
- sql_command= sql_command_arg,
- type= type_arg;
return false;
}
@@ -8616,9 +9284,9 @@ bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table,
{
DBUG_ASSERT(field_name.str);
Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
- table->db.str,
- table->alias.str,
- &field_name);
+ table->db,
+ table->alias,
+ field_name);
if (unlikely(!fld) || unlikely(item_list.push_back(fld)))
return true;
@@ -8731,13 +9399,27 @@ Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
}
+Item *LEX::make_item_func_call_native_or_parse_error(THD *thd,
+ Lex_ident_cli_st &name,
+ List<Item> *args)
+{
+ Create_func *builder= find_native_function_builder(thd, &name);
+ DBUG_EXECUTE_IF("make_item_func_call_native_simulate_not_found",
+ builder= NULL;);
+ if (builder)
+ return builder->create_func(thd, &name, args);
+ thd->parse_error(ER_SYNTAX_ERROR, name.end());
+ return NULL;
+}
+
+
Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *name)
{
Item *item;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- NullS, name->str,
- &star_clex_str)))
+ null_clex_str, *name,
+ star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -8749,11 +9431,10 @@ Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *b)
{
Item *item;
- const char* schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str;
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- schema, b->str,
- &star_clex_str)))
+ schema, *b, star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -9028,6 +9709,7 @@ void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit)
bool LEX::main_select_push(bool service)
{
DBUG_ENTER("LEX::main_select_push");
+ DBUG_PRINT("info", ("service: %u", service));
current_select_number= ++thd->lex->stmt_lex->current_select_number;
builtin_select.select_number= current_select_number;
builtin_select.is_service_select= service;
@@ -9303,6 +9985,17 @@ LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
}
+SELECT_LEX_UNIT *
+LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *sel,
+ enum sub_select_type unit_type,
+ bool distinct)
+{
+ return
+ add_primary_to_query_expression_body(unit, sel, unit_type, distinct,
+ thd->variables.sql_mode & MODE_ORACLE);
+}
+
/**
Add query primary to a parenthesized query primary
pruducing a new query expression body
@@ -9703,7 +10396,7 @@ bool LEX::sp_proc_stmt_statement_finalize(THD *thd, bool no_lookahead)
It is done by transformer.
The extracted condition is saved in cond_pushed_into_where of this select.
- cond can remain un empty after the extraction of the condition that can be
+ COND can remain not empty after the extraction of the conditions that can be
pushed into WHERE. It is saved in remaining_cond.
@note
@@ -10507,6 +11200,89 @@ bool LEX::stmt_create_stored_function_start(const DDL_options_st &options,
}
+bool LEX::stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &name)
+{
+ if (unlikely(db.str && check_db_name((LEX_STRING*) &db)))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
+ return true;
+ }
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ set_command(SQLCOM_DROP_FUNCTION, options);
+ spname= new (thd->mem_root) sp_name(&db, &name, true);
+ return spname == NULL;
+}
+
+
+bool LEX::stmt_drop_function(const DDL_options_st &options,
+ const Lex_ident_sys_st &name)
+{
+ LEX_CSTRING db= {0, 0};
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ if (thd->db.str && unlikely(copy_db_to(&db)))
+ return true;
+ set_command(SQLCOM_DROP_FUNCTION, options);
+ spname= new (thd->mem_root) sp_name(&db, &name, false);
+ return spname == NULL;
+}
+
+
+bool LEX::stmt_drop_procedure(const DDL_options_st &options,
+ sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ return true;
+ }
+ set_command(SQLCOM_DROP_PROCEDURE, options);
+ spname= name;
+ return false;
+}
+
+
+bool LEX::stmt_alter_function_start(sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
+ return true;
+ }
+ if (main_select_push())
+ return true;
+ sp_chistics.init();
+ sql_command= SQLCOM_ALTER_FUNCTION;
+ spname= name;
+ return false;
+}
+
+
+bool LEX::stmt_alter_procedure_start(sp_name *name)
+{
+ if (unlikely(sphead))
+ {
+ my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
+ return true;
+ }
+ if (main_select_push())
+ return true;
+ sp_chistics.init();
+ sql_command= SQLCOM_ALTER_PROCEDURE;
+ spname= name;
+ return false;
+}
+
+
Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
{
Spvar_definition *res;
@@ -10523,6 +11299,301 @@ Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
}
+Item *
+Lex_cast_type_st::create_typecast_item_or_error(THD *thd, Item *item,
+ CHARSET_INFO *cs) const
+{
+ Item *tmp= create_typecast_item(thd, item, cs);
+ if (!tmp)
+ {
+ Name name= m_type_handler->name();
+ char buf[128];
+ size_t length= my_snprintf(buf, sizeof(buf), "CAST(expr AS %.*s)",
+ (int) name.length(), name.ptr());
+ my_error(ER_UNKNOWN_OPERATOR, MYF(0),
+ ErrConvString(buf, length, system_charset_info).ptr());
+ }
+ return tmp;
+}
+
+
+void Lex_field_type_st::set_handler_length_flags(const Type_handler *handler,
+ const char *length,
+ uint32 flags)
+{
+ DBUG_ASSERT(!handler->is_unsigned());
+ if (flags & UNSIGNED_FLAG)
+ handler= handler->type_handler_unsigned();
+ set(handler, length, NULL);
+}
+
+
+bool LEX::set_field_type_udt(Lex_field_type_st *type,
+ const LEX_CSTRING &name,
+ const Lex_length_and_dec_st &attr)
+{
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error(thd, name)))
+ return true;
+ type->set(h, attr);
+ charset= &my_charset_bin;
+ return false;
+}
+
+
+bool LEX::set_cast_type_udt(Lex_cast_type_st *type,
+ const LEX_CSTRING &name)
+{
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error(thd, name)))
+ return true;
+ type->set(h);
+ charset= NULL;
+ return false;
+}
+
+
+bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_label *lab= spcont->last_label(); /* Jumping back */
+ sp_instr_jump_if_not *i= new (thd->mem_root)
+ sp_instr_jump_if_not(ip, spcont, get_item(), lab->ip, this);
+ if (unlikely(i == NULL) ||
+ unlikely(sphead->add_instr(i)))
+ return true;
+ /* We can shortcut the cont_backpatch here */
+ i->m_cont_dest= ip+1;
+ return false;
+}
+
+
+bool sp_expr_lex::sp_if_expr(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump_if_not *i= new (thd->mem_root)
+ sp_instr_jump_if_not(ip, spcont, get_item(), this);
+ return
+ (unlikely(i == NULL) ||
+ unlikely(sphead->push_backpatch(thd, i,
+ spcont->push_label(thd, &empty_clex_str,
+ 0))) ||
+ unlikely(sphead->add_cont_backpatch(i)) ||
+ unlikely(sphead->add_instr(i)));
+}
+
+
+bool LEX::sp_if_after_statements(THD *thd)
+{
+ uint ip= sphead->instructions();
+ sp_instr_jump *i= new (thd->mem_root) sp_instr_jump(ip, spcont);
+ if (unlikely(i == NULL) ||
+ unlikely(sphead->add_instr(i)))
+ return true;
+ sphead->backpatch(spcont->pop_label());
+ sphead->push_backpatch(thd, i, spcont->push_label(thd, &empty_clex_str, 0));
+ return false;
+}
+
+
+sp_condition_value *LEX::stmt_signal_value(const Lex_ident_sys_st &ident)
+{
+ sp_condition_value *cond;
+ /* SIGNAL foo cannot be used outside of stored programs */
+ if (unlikely(spcont == NULL))
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), ident.str);
+ return NULL;
+ }
+ cond= spcont->find_declared_or_predefined_condition(thd, &ident);
+ if (unlikely(cond == NULL))
+ {
+ my_error(ER_SP_COND_MISMATCH, MYF(0), ident.str);
+ return NULL;
+ }
+ bool bad= thd->variables.sql_mode & MODE_ORACLE ?
+ !cond->has_sql_state() :
+ cond->type != sp_condition_value::SQLSTATE;
+ if (unlikely(bad))
+ {
+ my_error(ER_SIGNAL_BAD_CONDITION_TYPE, MYF(0));
+ return NULL;
+ }
+ return cond;
+}
+
+
+bool LEX::add_table_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *ref_table_name,
+ DDL_options ddl_options)
+{
+ Key *key= new (thd->mem_root) Foreign_key(name,
+ &last_key->columns,
+ constraint_name,
+ &ref_table_name->db,
+ &ref_table_name->table,
+ &ref_list,
+ fk_delete_opt,
+ fk_update_opt,
+ fk_match_option,
+ ddl_options);
+ if (unlikely(key == NULL))
+ return true;
+
+ /*
+ handle_if_exists_options() expects the two keys in this order:
+ the Foreign_key, followed by its auto-generated Key.
+ */
+ alter_info.key_list.push_back(key, thd->mem_root);
+ alter_info.key_list.push_back(last_key, thd->mem_root);
+
+ option_list= NULL;
+
+ /* Only used for ALTER TABLE. Ignored otherwise. */
+ alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
+
+ return false;
+}
+
+
+bool LEX::add_column_foreign_key(const LEX_CSTRING *name,
+ const LEX_CSTRING *constraint_name,
+ Table_ident *ref_table_name,
+ DDL_options ddl_options)
+{
+ if (last_field->vcol_info || last_field->vers_sys_field())
+ {
+ thd->parse_error();
+ return true;
+ }
+ if (unlikely(!(last_key= (new (thd->mem_root)
+ Key(Key::MULTIPLE, constraint_name,
+ HA_KEY_ALG_UNDEF, true, ddl_options)))))
+ return true;
+ Key_part_spec *key= new (thd->mem_root) Key_part_spec(name, 0);
+ if (unlikely(key == NULL))
+ return true;
+ last_key->columns.push_back(key, thd->mem_root);
+ if (ref_list.is_empty())
+ {
+ ref_list.push_back(key, thd->mem_root);
+ }
+ if (unlikely(add_table_foreign_key(constraint_name, constraint_name,
+ ref_table_name, ddl_options)))
+ return true;
+ option_list= NULL;
+
+ /* Only used for ALTER TABLE. Ignored otherwise. */
+ alter_info.flags|= ALTER_ADD_FOREIGN_KEY;
+
+ return false;
+}
+
+
+bool LEX::stmt_grant_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ privilege_t grant_option)
+{
+ sql_command= SQLCOM_GRANT;
+ return
+ grant->set_object_name(thd, ident, current_select, grant_option) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_table(sql_command, *grant));
+}
+
+
+bool LEX::stmt_revoke_table(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident)
+{
+ sql_command= SQLCOM_REVOKE;
+ return
+ grant->set_object_name(thd, ident, current_select, NO_ACL) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_table(sql_command, *grant));
+}
+
+
+bool LEX::stmt_grant_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph,
+ privilege_t grant_option)
+{
+ sql_command= SQLCOM_GRANT;
+ return
+ grant->set_object_name(thd, ident, current_select, grant_option) ||
+ add_grant_command(thd, grant->columns()) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_sp(sql_command,
+ *grant, sph));
+}
+
+
+bool LEX::stmt_revoke_sp(THD *thd,
+ Grant_privilege *grant,
+ const Lex_grant_object_name &ident,
+ const Sp_handler &sph)
+{
+ sql_command= SQLCOM_REVOKE;
+ return
+ grant->set_object_name(thd, ident, current_select, NO_ACL) ||
+ add_grant_command(thd, grant->columns()) ||
+ !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_sp(sql_command,
+ *grant, sph));
+}
+
+
+bool LEX::stmt_grant_proxy(THD *thd, LEX_USER *user, privilege_t grant_option)
+{
+ users_list.push_front(user);
+ sql_command= SQLCOM_GRANT;
+ return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command,
+ grant_option));
+}
+
+
+bool LEX::stmt_revoke_proxy(THD *thd, LEX_USER *user)
+{
+ users_list.push_front(user);
+ sql_command= SQLCOM_REVOKE;
+ return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command,
+ NO_ACL));
+}
+
+
+LEX_USER *LEX::current_user_for_set_password(THD *thd)
+{
+ LEX_CSTRING pw= { STRING_WITH_LEN("password") };
+ if (unlikely(spcont && spcont->find_variable(&pw, false)))
+ {
+ my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
+ return NULL;
+ }
+ LEX_USER *res;
+ if (unlikely(!(res= (LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
+ return NULL;
+ res->user= current_user;
+ return res;
+}
+
+
+bool LEX::sp_create_set_password_instr(THD *thd,
+ LEX_USER *user,
+ USER_AUTH *auth,
+ bool no_lookahead)
+{
+ user->auth= auth;
+ set_var_password *var= new (thd->mem_root) set_var_password(user);
+ if (unlikely(var == NULL) ||
+ unlikely(var_list.push_back(var, thd->mem_root)))
+ return true;
+ autocommit= true;
+ if (sphead)
+ sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ return sp_create_assignment_instr(thd, no_lookahead);
+}
+
+
bool LEX::map_data_type(const Lex_ident_sys_st &schema_name,
Lex_field_type_st *type) const
{
@@ -10536,16 +11607,30 @@ bool LEX::map_data_type(const Lex_ident_sys_st &schema_name,
my_snprintf(buf, sizeof(buf), "%.*s.%.*s",
(int) schema_name.length, schema_name.str,
(int) type_name.length(), type_name.ptr());
-#if MYSQL_VERSION_ID > 100500
-#error Please remove the old code
my_error(ER_UNKNOWN_DATA_TYPE, MYF(0), buf);
-#else
- my_printf_error(ER_UNKNOWN_ERROR, "Unknown data type: '%-.64s'",
- MYF(0), buf);
-#endif
return true;
}
const Type_handler *mapped= schema->map_data_type(thd, type->type_handler());
type->set_handler(mapped);
return false;
}
+
+
+bool SELECT_LEX_UNIT::explainable() const
+{
+ /*
+ EXPLAIN/ANALYZE unit, when:
+ (1) if it's a subquery - it's not part of eliminated WHERE/ON clause.
+ (2) if it's a CTE - it's not hanging (needed for execution)
+ (3) if it's a derived - it's not merged
+ if it's not 1/2/3 - it's some weird internal thing, ignore it
+ */
+ return item ?
+ !item->eliminated : // (1)
+ with_element ?
+ derived && derived->derived_result &&
+ !with_element->is_hanging_recursive(): // (2)
+ derived ?
+ derived->is_materialized_derived() : // (3)
+ false;
+}