forked from StoneAtom/StoneDB
2684 lines
67 KiB
C++
2684 lines
67 KiB
C++
/* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License, version 2.0, for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#ifndef PARSE_TREE_NODES_INCLUDED
|
|
#define PARSE_TREE_NODES_INCLUDED
|
|
|
|
#include "my_global.h"
|
|
#include "parse_tree_helpers.h" // PT_item_list
|
|
#include "parse_tree_hints.h"
|
|
#include "sp_head.h" // sp_head
|
|
#include "sql_class.h" // THD
|
|
#include "sql_lex.h" // LEX
|
|
#include "sql_parse.h" // add_join_natural
|
|
#include "sql_update.h" // Sql_cmd_update
|
|
#include "sql_admin.h" // Sql_cmd_shutdown etc.
|
|
|
|
|
|
template<enum_parsing_context Context> class PTI_context;
|
|
|
|
|
|
class PT_statement : public Parse_tree_node
|
|
{
|
|
public:
|
|
virtual Sql_cmd *make_cmd(THD *thd)= 0;
|
|
};
|
|
|
|
|
|
class PT_select_lex : public Parse_tree_node
|
|
{
|
|
public:
|
|
SELECT_LEX *value;
|
|
};
|
|
|
|
|
|
class PT_subselect : public PT_select_lex
|
|
{
|
|
typedef PT_select_lex super;
|
|
|
|
POS pos;
|
|
PT_select_lex *query_expression_body;
|
|
|
|
public:
|
|
explicit PT_subselect(const POS &pos,
|
|
PT_select_lex *query_expression_body_arg)
|
|
: pos(pos), query_expression_body(query_expression_body_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
LEX *lex= pc->thd->lex;
|
|
if (!lex->expr_allows_subselect ||
|
|
lex->sql_command == (int)SQLCOM_PURGE)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
/*
|
|
we are making a "derived table" for the parenthesis
|
|
as we need to have a lex level to fit the union
|
|
after the parenthesis, e.g.
|
|
(SELECT .. ) UNION ... becomes
|
|
SELECT * FROM ((SELECT ...) UNION ...)
|
|
*/
|
|
SELECT_LEX *child= lex->new_query(pc->select);
|
|
if (child == NULL)
|
|
return true;
|
|
|
|
Parse_context inner_pc(pc->thd, child);
|
|
if (query_expression_body->contextualize(&inner_pc))
|
|
return true;
|
|
|
|
lex->pop_context();
|
|
pc->select->n_child_sum_items += child->n_sum_items;
|
|
/*
|
|
A subquery (and all the subsequent query blocks in a UNION) can add
|
|
columns to an outer query block. Reserve space for them.
|
|
*/
|
|
for (SELECT_LEX *temp = child; temp != NULL;
|
|
temp = temp->next_select())
|
|
{
|
|
pc->select->select_n_where_fields+= temp->select_n_where_fields;
|
|
pc->select->select_n_having_items+= temp->select_n_having_items;
|
|
}
|
|
value= query_expression_body->value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_order_expr : public Parse_tree_node, public ORDER
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
public:
|
|
PT_order_expr(Item *item_arg, bool is_asc)
|
|
{
|
|
item_ptr= item_arg;
|
|
direction= is_asc ? ORDER::ORDER_ASC : ORDER::ORDER_DESC;
|
|
}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
return super::contextualize(pc) || item_ptr->itemize(pc, &item_ptr);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_order_list : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
public:
|
|
SQL_I_List<ORDER> value;
|
|
|
|
public:
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
for (ORDER *o= value.first; o != NULL; o= o->next)
|
|
{
|
|
if (static_cast<PT_order_expr *>(o)->contextualize(pc))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void push_back(PT_order_expr *order)
|
|
{
|
|
order->item= &order->item_ptr;
|
|
order->used_alias= false;
|
|
order->used= 0;
|
|
order->is_position= false;
|
|
value.link_in_list(order, &order->next);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_gorder_list : public PT_order_list
|
|
{
|
|
typedef PT_order_list super;
|
|
|
|
public:
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
SELECT_LEX *sel= pc->select;
|
|
if (sel->linkage != GLOBAL_OPTIONS_TYPE &&
|
|
sel->olap != UNSPECIFIED_OLAP_TYPE &&
|
|
(sel->linkage != UNION_TYPE || sel->braces))
|
|
{
|
|
my_error(ER_WRONG_USAGE, MYF(0),
|
|
"CUBE/ROLLUP", "ORDER BY");
|
|
return true;
|
|
}
|
|
|
|
return super::contextualize(pc);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_item_list : public PT_item_list
|
|
{
|
|
typedef PT_item_list super;
|
|
|
|
public:
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
pc->select->item_list= value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_limit_clause : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
Limit_options limit_options;
|
|
|
|
public:
|
|
PT_limit_clause(const Limit_options &limit_options_arg)
|
|
: limit_options(limit_options_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
if (pc->select->master_unit()->is_union() && !pc->select->braces)
|
|
{
|
|
pc->select= pc->select->master_unit()->fake_select_lex;
|
|
assert(pc->select != NULL);
|
|
}
|
|
|
|
if (limit_options.is_offset_first && limit_options.opt_offset != NULL &&
|
|
limit_options.opt_offset->itemize(pc, &limit_options.opt_offset))
|
|
return true;
|
|
|
|
if (limit_options.limit->itemize(pc, &limit_options.limit))
|
|
return true;
|
|
|
|
if (!limit_options.is_offset_first && limit_options.opt_offset != NULL &&
|
|
limit_options.opt_offset->itemize(pc, &limit_options.opt_offset))
|
|
return true;
|
|
|
|
pc->select->select_limit= limit_options.limit;
|
|
pc->select->offset_limit= limit_options.opt_offset;
|
|
pc->select->explicit_limit= true;
|
|
|
|
pc->thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_list : public Parse_tree_node
|
|
{
|
|
public:
|
|
TABLE_LIST *value;
|
|
};
|
|
|
|
|
|
class PT_table_factor_table_ident : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
Table_ident *table_ident;
|
|
List<String> *opt_use_partition;
|
|
LEX_STRING *opt_table_alias;
|
|
List<Index_hint> *opt_key_definition;
|
|
|
|
public:
|
|
PT_table_factor_table_ident(Table_ident *table_ident_arg,
|
|
List<String> *opt_use_partition_arg,
|
|
LEX_STRING *opt_table_alias_arg,
|
|
List<Index_hint> *opt_key_definition_arg)
|
|
: table_ident(table_ident_arg),
|
|
opt_use_partition(opt_use_partition_arg),
|
|
opt_table_alias(opt_table_alias_arg),
|
|
opt_key_definition(opt_key_definition_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
Yacc_state *yyps= &thd->m_parser_state->m_yacc;
|
|
|
|
value= pc->select->add_table_to_list(thd, table_ident, opt_table_alias, 0,
|
|
yyps->m_lock_type,
|
|
yyps->m_mdl_type,
|
|
opt_key_definition,
|
|
opt_use_partition);
|
|
if (value == NULL)
|
|
return true;
|
|
pc->select->add_joined_table(value);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
enum PT_join_table_type
|
|
{
|
|
JTT_NORMAL = 0x01,
|
|
JTT_STRAIGHT = 0x02,
|
|
JTT_NATURAL = 0x04,
|
|
JTT_LEFT = 0x08,
|
|
JTT_RIGHT = 0x10,
|
|
|
|
JTT_NATURAL_LEFT = JTT_NATURAL | JTT_LEFT,
|
|
JTT_NATURAL_RIGHT = JTT_NATURAL | JTT_RIGHT
|
|
};
|
|
|
|
|
|
template<PT_join_table_type Type>
|
|
class PT_join_table : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
protected:
|
|
PT_table_list *tab1_node;
|
|
POS join_pos;
|
|
PT_table_list *tab2_node;
|
|
|
|
TABLE_LIST *tr1;
|
|
TABLE_LIST *tr2;
|
|
|
|
|
|
public:
|
|
PT_join_table(PT_table_list *tab1_node_arg, const POS &join_pos_arg,
|
|
PT_table_list *tab2_node_arg)
|
|
: tab1_node(tab1_node_arg), join_pos(join_pos_arg), tab2_node(tab2_node_arg),
|
|
tr1(NULL), tr2(NULL)
|
|
{
|
|
assert(dbug_exclusive_flags(JTT_NORMAL | JTT_STRAIGHT | JTT_NATURAL));
|
|
assert(dbug_exclusive_flags(JTT_LEFT | JTT_RIGHT));
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
bool dbug_exclusive_flags(unsigned int mask)
|
|
{
|
|
#ifdef __GNUC__
|
|
return __builtin_popcount(Type & mask) <= 1;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || contextualize_tabs(pc))
|
|
return true;
|
|
|
|
if (Type & (JTT_LEFT | JTT_RIGHT))
|
|
{
|
|
if (Type & JTT_LEFT)
|
|
tr2->outer_join|= JOIN_TYPE_LEFT;
|
|
else
|
|
{
|
|
TABLE_LIST *inner_table= pc->select->convert_right_join();
|
|
/* swap tr1 and tr2 */
|
|
assert(inner_table == tr1);
|
|
tr1= tr2;
|
|
tr2= inner_table;
|
|
}
|
|
}
|
|
|
|
if (Type & JTT_NATURAL)
|
|
add_join_natural(tr1, tr2, NULL, pc->select);
|
|
|
|
if (Type & JTT_STRAIGHT)
|
|
tr2->straight= true;
|
|
|
|
return false;
|
|
}
|
|
|
|
protected:
|
|
bool contextualize_tabs(Parse_context *pc)
|
|
{
|
|
if (tr1 != NULL)
|
|
return false; // already done
|
|
|
|
if (tab1_node->contextualize(pc) || tab2_node->contextualize(pc))
|
|
return true;
|
|
|
|
tr1= tab1_node->value;
|
|
tr2= tab2_node->value;
|
|
|
|
if (tr1 == NULL || tr2 == NULL)
|
|
{
|
|
error(pc, join_pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
template<PT_join_table_type Type>
|
|
class PT_join_table_on : public PT_join_table<Type>
|
|
{
|
|
typedef PT_join_table<Type> super;
|
|
|
|
Item *on;
|
|
|
|
public:
|
|
PT_join_table_on(PT_table_list *tab1_node_arg, const POS &join_pos_arg,
|
|
PT_table_list *tab2_node_arg, Item *on_arg)
|
|
: super(tab1_node_arg, join_pos_arg, tab2_node_arg), on(on_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (this->contextualize_tabs(pc))
|
|
return true;
|
|
|
|
if (push_new_name_resolution_context(pc, this->tr1, this->tr2))
|
|
{
|
|
this->error(pc, this->join_pos);
|
|
return true;
|
|
}
|
|
|
|
SELECT_LEX *sel= pc->select;
|
|
sel->parsing_place= CTX_ON;
|
|
|
|
if (super::contextualize(pc) || on->itemize(pc, &on))
|
|
return true;
|
|
assert(sel == pc->select);
|
|
|
|
add_join_on(this->tr2, on);
|
|
pc->thd->lex->pop_context();
|
|
assert(sel->parsing_place == CTX_ON);
|
|
sel->parsing_place= CTX_NONE;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
template<PT_join_table_type Type>
|
|
class PT_join_table_using : public PT_join_table<Type>
|
|
{
|
|
typedef PT_join_table<Type> super;
|
|
|
|
List<String> *using_fields;
|
|
|
|
public:
|
|
PT_join_table_using(PT_table_list *tab1_node_arg, const POS &join_pos_arg,
|
|
PT_table_list *tab2_node_arg,
|
|
List<String> *using_fields_arg)
|
|
: super(tab1_node_arg, join_pos_arg, tab2_node_arg),
|
|
using_fields(using_fields_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
add_join_natural(this->tr1, this->tr2, using_fields, pc->select);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_ref_join_table : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
Parse_tree_node *join_table;
|
|
|
|
public:
|
|
explicit PT_table_ref_join_table(Parse_tree_node *join_table_arg)
|
|
: join_table(join_table_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || join_table->contextualize(pc))
|
|
return true;
|
|
|
|
value= pc->select->nest_last_join(pc->thd);
|
|
return value == NULL;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_part2_derived : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
ulonglong opt_query_spec_options;
|
|
PT_item_list *select_item_list;
|
|
|
|
public:
|
|
PT_select_part2_derived(ulonglong opt_query_spec_options_arg,
|
|
PT_item_list *select_item_list_arg)
|
|
: opt_query_spec_options(opt_query_spec_options_arg),
|
|
select_item_list(select_item_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
SELECT_LEX *select= pc->select;
|
|
|
|
select->parsing_place= CTX_SELECT_LIST;
|
|
|
|
if (select->validate_base_options(thd->lex, opt_query_spec_options))
|
|
return true;
|
|
select->set_base_options(opt_query_spec_options);
|
|
if (opt_query_spec_options & SELECT_HIGH_PRIORITY)
|
|
{
|
|
Yacc_state *yyps= &thd->m_parser_state->m_yacc;
|
|
yyps->m_lock_type= TL_READ_HIGH_PRIORITY;
|
|
yyps->m_mdl_type= MDL_SHARED_READ;
|
|
}
|
|
|
|
if (select_item_list->contextualize(pc))
|
|
return true;
|
|
assert(select == pc->select);
|
|
|
|
// Ensure we're resetting parsing place of the right select
|
|
assert(select->parsing_place == CTX_SELECT_LIST);
|
|
select->parsing_place= CTX_NONE;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_group : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_order_list *group_list;
|
|
olap_type olap;
|
|
|
|
public:
|
|
PT_group(PT_order_list *group_list_arg, olap_type olap_arg)
|
|
: group_list(group_list_arg), olap(olap_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_order : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_order_list *order_list;
|
|
|
|
public:
|
|
|
|
explicit PT_order(PT_order_list *order_list_arg)
|
|
: order_list(order_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_procedure_analyse : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
Proc_analyse_params params;
|
|
|
|
public:
|
|
PT_procedure_analyse(const Proc_analyse_params ¶ms_arg)
|
|
: params(params_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
|
|
if (!lex->parsing_options.allows_select_procedure)
|
|
{
|
|
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE");
|
|
return true;
|
|
}
|
|
|
|
if (lex->select_lex != pc->select)
|
|
{
|
|
my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
|
|
return true;
|
|
}
|
|
|
|
lex->proc_analyse= ¶ms;
|
|
lex->set_uncacheable(pc->select, UNCACHEABLE_SIDEEFFECT);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_order_or_limit_order : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_order *order;
|
|
PT_limit_clause *opt_limit;
|
|
|
|
public:
|
|
PT_order_or_limit_order(PT_order *order_arg, PT_limit_clause *opt_limit_arg)
|
|
: order(order_arg), opt_limit(opt_limit_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
return super::contextualize(pc) || order->contextualize(pc) ||
|
|
(opt_limit != NULL && opt_limit->contextualize(pc));
|
|
}
|
|
};
|
|
|
|
|
|
class PT_union_order_or_limit : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
Parse_tree_node *order_or_limit;
|
|
|
|
public:
|
|
PT_union_order_or_limit(Parse_tree_node *order_or_limit_arg)
|
|
: order_or_limit(order_or_limit_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
assert(pc->select->linkage != GLOBAL_OPTIONS_TYPE);
|
|
SELECT_LEX *fake= pc->select->master_unit()->fake_select_lex;
|
|
if (fake)
|
|
{
|
|
fake->no_table_names_allowed= true;
|
|
pc->select= fake;
|
|
}
|
|
pc->thd->where= "global ORDER clause";
|
|
|
|
if (order_or_limit->contextualize(pc))
|
|
return true;
|
|
|
|
pc->select->no_table_names_allowed= 0;
|
|
pc->thd->where= "";
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_expression : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
Parse_tree_node *opt_from_clause;
|
|
Item *opt_where;
|
|
PT_group *opt_group;
|
|
Item *opt_having;
|
|
PT_order *opt_order;
|
|
PT_limit_clause *opt_limit;
|
|
PT_procedure_analyse *opt_procedure_analyse;
|
|
Select_lock_type opt_select_lock_type;
|
|
|
|
public:
|
|
PT_table_expression(Parse_tree_node *opt_from_clause_arg,
|
|
Item *opt_where_arg,
|
|
PT_group *opt_group_arg,
|
|
Item *opt_having_arg,
|
|
PT_order *opt_order_arg,
|
|
PT_limit_clause *opt_limit_arg,
|
|
PT_procedure_analyse *opt_procedure_analyse_arg,
|
|
const Select_lock_type &opt_select_lock_type_arg)
|
|
: opt_from_clause(opt_from_clause_arg),
|
|
opt_where(opt_where_arg),
|
|
opt_group(opt_group_arg),
|
|
opt_having(opt_having_arg),
|
|
opt_order(opt_order_arg),
|
|
opt_limit(opt_limit_arg),
|
|
opt_procedure_analyse(opt_procedure_analyse_arg),
|
|
opt_select_lock_type(opt_select_lock_type_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
(opt_from_clause != NULL && opt_from_clause->contextualize(pc)) ||
|
|
(opt_where != NULL && opt_where->itemize(pc, &opt_where)) ||
|
|
(opt_group != NULL && opt_group->contextualize(pc)) ||
|
|
(opt_having != NULL && opt_having->itemize(pc, &opt_having)))
|
|
return true;
|
|
|
|
pc->select->set_where_cond(opt_where);
|
|
pc->select->set_having_cond(opt_having);
|
|
|
|
if ((opt_order != NULL && opt_order->contextualize(pc)) ||
|
|
(opt_limit != NULL && opt_limit->contextualize(pc)) ||
|
|
(opt_procedure_analyse != NULL &&
|
|
opt_procedure_analyse->contextualize(pc)))
|
|
return true;
|
|
|
|
/*
|
|
@todo: explain should not affect how we construct the query data
|
|
structure. Instead, consider to let lock_tables() adjust lock
|
|
requests according to the explain flag.
|
|
*/
|
|
if (opt_select_lock_type.is_set && !pc->thd->lex->is_explain())
|
|
{
|
|
pc->select->set_lock_for_tables(opt_select_lock_type.lock_type);
|
|
pc->thd->lex->safe_to_cache_query=
|
|
opt_select_lock_type.is_safe_to_cache_query;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_factor_select_sym : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
POS pos;
|
|
PT_hint_list *opt_hint_list;
|
|
Query_options select_options;
|
|
PT_item_list *select_item_list;
|
|
PT_table_expression *table_expression;
|
|
|
|
public:
|
|
PT_table_factor_select_sym(const POS &pos,
|
|
PT_hint_list *opt_hint_list_arg,
|
|
Query_options select_options_arg,
|
|
PT_item_list *select_item_list_arg,
|
|
PT_table_expression *table_expression_arg)
|
|
: pos(pos),
|
|
opt_hint_list(opt_hint_list_arg),
|
|
select_options(select_options_arg),
|
|
select_item_list(select_item_list_arg),
|
|
table_expression(table_expression_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_select_derived_union_select : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
PT_table_list *select_derived;
|
|
Parse_tree_node *opt_union_order_or_limit;
|
|
POS union_or_limit_pos;
|
|
|
|
public:
|
|
PT_select_derived_union_select(PT_table_list *select_derived_arg,
|
|
Parse_tree_node *opt_union_order_or_limit_arg,
|
|
const POS &union_or_limit_pos_arg)
|
|
: select_derived(select_derived_arg),
|
|
opt_union_order_or_limit(opt_union_order_or_limit_arg),
|
|
union_or_limit_pos(union_or_limit_pos_arg)
|
|
{}
|
|
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
select_derived->contextualize(pc) ||
|
|
(opt_union_order_or_limit != NULL &&
|
|
opt_union_order_or_limit->contextualize(pc)))
|
|
return true;
|
|
|
|
if (select_derived->value != NULL && opt_union_order_or_limit != NULL)
|
|
{
|
|
error(pc, union_or_limit_pos);
|
|
return true;
|
|
}
|
|
|
|
value= select_derived->value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_derived_union_union : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
PT_table_list *select_derived_union;
|
|
POS union_pos;
|
|
bool is_distinct;
|
|
PT_select_lex *query_specification;
|
|
|
|
public:
|
|
|
|
PT_select_derived_union_union(PT_table_list *select_derived_union_arg,
|
|
const POS &union_pos_arg,
|
|
bool is_distinct_arg,
|
|
PT_select_lex *query_specification_arg)
|
|
: select_derived_union(select_derived_union_arg),
|
|
union_pos(union_pos_arg),
|
|
is_distinct(is_distinct_arg),
|
|
query_specification(query_specification_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || select_derived_union->contextualize(pc))
|
|
return true;
|
|
|
|
pc->select= pc->thd->lex->new_union_query(pc->select, is_distinct);
|
|
if (pc->select == NULL)
|
|
return true;
|
|
|
|
if (query_specification->contextualize(pc))
|
|
return true;
|
|
|
|
/*
|
|
Remove from the name resolution context stack the context of the
|
|
last query block in the union.
|
|
*/
|
|
pc->thd->lex->pop_context();
|
|
|
|
if (select_derived_union->value != NULL)
|
|
{
|
|
error(pc, union_pos);
|
|
return true;
|
|
}
|
|
value= NULL;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_factor_parenthesis : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
PT_table_list *select_derived_union;
|
|
LEX_STRING *opt_table_alias;
|
|
POS alias_pos;
|
|
|
|
public:
|
|
|
|
PT_table_factor_parenthesis(PT_table_list *select_derived_union_arg,
|
|
LEX_STRING *opt_table_alias_arg,
|
|
const POS &alias_pos_arg)
|
|
: select_derived_union(select_derived_union_arg),
|
|
opt_table_alias(opt_table_alias_arg),
|
|
alias_pos(alias_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_derived_table_list : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
POS pos;
|
|
PT_table_list *head;
|
|
PT_table_list *tail;
|
|
|
|
public:
|
|
PT_derived_table_list(const POS &pos,
|
|
PT_table_list *head_arg, PT_table_list *tail_arg)
|
|
: pos(pos), head(head_arg), tail(tail_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
head->contextualize(pc) || tail->contextualize(pc))
|
|
return true;
|
|
|
|
if (head->value == NULL || tail->value == NULL)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
value= tail->value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_derived : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
POS pos;
|
|
PT_table_list *derived_table_list;
|
|
|
|
public:
|
|
|
|
PT_select_derived(const POS &pos, PT_table_list *derived_table_list_arg)
|
|
: pos(pos), derived_table_list(derived_table_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
SELECT_LEX * const outer_select= pc->select;
|
|
|
|
if (outer_select->init_nested_join(pc->thd))
|
|
return true;
|
|
|
|
if (derived_table_list->contextualize(pc))
|
|
return true;
|
|
|
|
/*
|
|
for normal joins, derived_table_list->value != NULL and
|
|
end_nested_join() != NULL, for derived tables, both must equal NULL
|
|
*/
|
|
|
|
value= outer_select->end_nested_join(pc->thd);
|
|
|
|
if (value == NULL && derived_table_list->value != NULL)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
|
|
if (derived_table_list->value == NULL && value != NULL)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_join_table_list : public PT_table_list
|
|
{
|
|
typedef PT_table_list super;
|
|
|
|
POS pos;
|
|
PT_table_list *derived_table_list;
|
|
|
|
public:
|
|
PT_join_table_list(const POS &pos, PT_table_list *derived_table_list_arg)
|
|
: pos(pos), derived_table_list(derived_table_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || derived_table_list->contextualize(pc))
|
|
return true;
|
|
|
|
if (derived_table_list->value == NULL)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
value= derived_table_list->value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_table_reference_list : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_join_table_list *join_table_list;
|
|
|
|
public:
|
|
PT_table_reference_list(PT_join_table_list *join_table_list_arg)
|
|
: join_table_list(join_table_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || join_table_list->contextualize(pc))
|
|
return true;
|
|
|
|
SELECT_LEX *sel= pc->select;
|
|
sel->context.table_list=
|
|
sel->context.first_name_resolution_table=
|
|
sel->table_list.first;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_query_specification_select : public PT_select_lex
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_hint_list *opt_hint_list;
|
|
PT_select_part2_derived *select_part2_derived;
|
|
PT_table_expression *table_expression;
|
|
|
|
public:
|
|
PT_query_specification_select(
|
|
PT_hint_list *opt_hint_list_arg,
|
|
PT_select_part2_derived *select_part2_derived_arg,
|
|
PT_table_expression *table_expression_arg)
|
|
: opt_hint_list(opt_hint_list_arg),
|
|
select_part2_derived(select_part2_derived_arg),
|
|
table_expression(table_expression_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || select_part2_derived->contextualize(pc))
|
|
return true;
|
|
|
|
// Parentheses carry no meaning here.
|
|
pc->select->set_braces(false);
|
|
|
|
if (table_expression->contextualize(pc))
|
|
return true;
|
|
|
|
value= pc->select->master_unit()->first_select();
|
|
|
|
if (opt_hint_list != NULL && opt_hint_list->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_paren_derived : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_hint_list *opt_hint_list;
|
|
PT_select_part2_derived *select_part2_derived;
|
|
PT_table_expression *table_expression;
|
|
|
|
public:
|
|
PT_select_paren_derived(PT_hint_list *opt_hint_list_arg,
|
|
PT_select_part2_derived *select_part2_derived_arg,
|
|
PT_table_expression *table_expression_arg)
|
|
: opt_hint_list(opt_hint_list_arg),
|
|
select_part2_derived(select_part2_derived_arg),
|
|
table_expression(table_expression_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
pc->select->set_braces(true);
|
|
|
|
if (select_part2_derived->contextualize(pc) ||
|
|
table_expression->contextualize(pc))
|
|
return true;
|
|
|
|
if (setup_select_in_parentheses(pc->select))
|
|
return true;
|
|
|
|
if (opt_hint_list != NULL && opt_hint_list->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_query_specification_parenthesis : public PT_select_lex
|
|
{
|
|
typedef PT_select_lex super;
|
|
|
|
PT_select_paren_derived *select_paren_derived;
|
|
Parse_tree_node *opt_union_order_or_limit;
|
|
|
|
public:
|
|
PT_query_specification_parenthesis(
|
|
PT_select_paren_derived *select_paren_derived_arg,
|
|
Parse_tree_node *opt_union_order_or_limit_arg)
|
|
: select_paren_derived(select_paren_derived_arg),
|
|
opt_union_order_or_limit(opt_union_order_or_limit_arg)
|
|
{}
|
|
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
select_paren_derived->contextualize(pc) ||
|
|
(opt_union_order_or_limit != NULL &&
|
|
opt_union_order_or_limit->contextualize(pc)))
|
|
return true;
|
|
|
|
value= pc->select->master_unit()->first_select();
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_query_expression_body_union : public PT_select_lex
|
|
{
|
|
typedef PT_select_lex super;
|
|
|
|
POS pos;
|
|
PT_select_lex *query_expression_body;
|
|
bool is_distinct;
|
|
PT_select_lex *query_specification;
|
|
|
|
public:
|
|
PT_query_expression_body_union(const POS &pos,
|
|
PT_select_lex *query_expression_body_arg,
|
|
bool is_distinct_arg,
|
|
PT_select_lex *query_specification_arg)
|
|
: pos(pos),
|
|
query_expression_body(query_expression_body_arg),
|
|
is_distinct(is_distinct_arg),
|
|
query_specification(query_specification_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || query_expression_body->contextualize(pc))
|
|
return true;
|
|
|
|
LEX *lex= pc->thd->lex;
|
|
|
|
if (pc->select->linkage == GLOBAL_OPTIONS_TYPE)
|
|
{
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
pc->select= lex->new_union_query(pc->select, is_distinct);
|
|
if (pc->select == NULL)
|
|
return true;
|
|
|
|
if (query_specification->contextualize(pc))
|
|
return true;
|
|
|
|
lex->pop_context();
|
|
value= query_expression_body->value;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_internal_variable_name : public Parse_tree_node
|
|
{
|
|
public:
|
|
sys_var_with_base value;
|
|
};
|
|
|
|
|
|
class PT_internal_variable_name_1d : public PT_internal_variable_name
|
|
{
|
|
typedef PT_internal_variable_name super;
|
|
|
|
LEX_STRING ident;
|
|
|
|
public:
|
|
PT_internal_variable_name_1d(const LEX_STRING &ident_arg)
|
|
: ident(ident_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
sp_pcontext *pctx= lex->get_sp_current_parsing_ctx();
|
|
sp_variable *spv;
|
|
|
|
value.var= NULL;
|
|
value.base_name= ident;
|
|
|
|
/* Best effort lookup for system variable. */
|
|
if (!pctx || !(spv= pctx->find_variable(ident, false)))
|
|
{
|
|
/* Not an SP local variable */
|
|
if (find_sys_var_null_base(thd, &value))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Possibly an SP local variable (or a shadowed sysvar).
|
|
Will depend on the context of the SET statement.
|
|
*/
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
Parse tree node class for 2-dimentional variable names (example: @global.x)
|
|
*/
|
|
class PT_internal_variable_name_2d : public PT_internal_variable_name
|
|
{
|
|
typedef PT_internal_variable_name super;
|
|
|
|
public:
|
|
const POS pos;
|
|
private:
|
|
LEX_STRING ident1;
|
|
LEX_STRING ident2;
|
|
|
|
public:
|
|
PT_internal_variable_name_2d(const POS &pos,
|
|
const LEX_STRING &ident1_arg,
|
|
const LEX_STRING &ident2_arg)
|
|
: pos(pos), ident1(ident1_arg), ident2(ident2_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_internal_variable_name_default : public PT_internal_variable_name
|
|
{
|
|
typedef PT_internal_variable_name super;
|
|
|
|
LEX_STRING ident;
|
|
|
|
public:
|
|
PT_internal_variable_name_default(const LEX_STRING &ident_arg)
|
|
: ident(ident_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
sys_var *tmp=find_sys_var(pc->thd, ident.str, ident.length);
|
|
if (!tmp)
|
|
return true;
|
|
if (!tmp->is_struct())
|
|
{
|
|
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), ident.str);
|
|
return true;
|
|
}
|
|
value.var= tmp;
|
|
value.base_name.str= (char*) "default";
|
|
value.base_name.length= 7;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_following_option_type : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
POS pos;
|
|
PT_internal_variable_name *name;
|
|
Item *opt_expr;
|
|
|
|
public:
|
|
PT_option_value_following_option_type(const POS &pos,
|
|
PT_internal_variable_name *name_arg,
|
|
Item *opt_expr_arg)
|
|
: pos(pos), name(name_arg), opt_expr(opt_expr_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || name->contextualize(pc) ||
|
|
(opt_expr != NULL && opt_expr->itemize(pc, &opt_expr)))
|
|
return true;
|
|
|
|
if (name->value.var && name->value.var != trg_new_row_fake_var)
|
|
{
|
|
/* It is a system variable. */
|
|
if (set_system_variable(pc->thd, &name->value, pc->thd->lex->option_type,
|
|
opt_expr))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Not in trigger assigning value to new row,
|
|
and option_type preceding local variable is illegal.
|
|
*/
|
|
error(pc, pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type : public Parse_tree_node {};
|
|
|
|
|
|
class PT_option_value_no_option_type_internal :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
PT_internal_variable_name *name;
|
|
Item *opt_expr;
|
|
POS expr_pos;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_internal(PT_internal_variable_name *name_arg,
|
|
Item *opt_expr_arg,
|
|
const POS &expr_pos_arg)
|
|
: name(name_arg), opt_expr(opt_expr_arg), expr_pos(expr_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_user_var :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
LEX_STRING name;
|
|
Item *expr;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_user_var(const LEX_STRING &name_arg,
|
|
Item *expr_arg)
|
|
: name(name_arg), expr(expr_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || expr->itemize(pc, &expr))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
Item_func_set_user_var *item;
|
|
item= new (pc->mem_root) Item_func_set_user_var(name, expr, false);
|
|
if (item == NULL)
|
|
return true;
|
|
set_var_user *var= new set_var_user(item);
|
|
if (var == NULL)
|
|
return true;
|
|
thd->lex->var_list.push_back(var);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_sys_var :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
enum_var_type type;
|
|
PT_internal_variable_name *name;
|
|
Item *opt_expr;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_sys_var(enum_var_type type_arg,
|
|
PT_internal_variable_name *name_arg,
|
|
Item *opt_expr_arg)
|
|
: type(type_arg), name(name_arg), opt_expr(opt_expr_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || name->contextualize(pc) ||
|
|
(opt_expr != NULL && opt_expr->itemize(pc, &opt_expr)))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
struct sys_var_with_base tmp= name->value;
|
|
if (tmp.var == trg_new_row_fake_var)
|
|
{
|
|
error(pc, down_cast<PT_internal_variable_name_2d *>(name)->pos);
|
|
return true;
|
|
}
|
|
/* Lookup if necessary: must be a system variable. */
|
|
if (tmp.var == NULL)
|
|
{
|
|
if (find_sys_var_null_base(thd, &tmp))
|
|
return true;
|
|
}
|
|
if (set_system_variable(thd, &tmp, type, opt_expr))
|
|
return true;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_charset :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
const CHARSET_INFO *opt_charset;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_charset(const CHARSET_INFO *opt_charset_arg)
|
|
: opt_charset(opt_charset_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
int flags= opt_charset ? 0 : set_var_collation_client::SET_CS_DEFAULT;
|
|
const CHARSET_INFO *cs2;
|
|
cs2= opt_charset ? opt_charset
|
|
: global_system_variables.character_set_client;
|
|
set_var_collation_client *var;
|
|
var= new set_var_collation_client(flags,
|
|
cs2,
|
|
thd->variables.collation_database,
|
|
cs2);
|
|
if (var == NULL)
|
|
return true;
|
|
lex->var_list.push_back(var);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_names :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
POS pos;
|
|
|
|
public:
|
|
explicit PT_option_value_no_option_type_names(const POS &pos) : pos(pos) {}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
sp_pcontext *pctx= lex->get_sp_current_parsing_ctx();
|
|
LEX_STRING names= { C_STRING_WITH_LEN("names") };
|
|
|
|
if (pctx && pctx->find_variable(names, false))
|
|
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
|
|
else
|
|
error(pc, pos);
|
|
|
|
return true; // alwais fails with an error
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_names_charset :
|
|
public PT_option_value_no_option_type
|
|
{
|
|
typedef PT_option_value_no_option_type super;
|
|
|
|
const CHARSET_INFO *opt_charset;
|
|
const CHARSET_INFO *opt_collation;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_names_charset(
|
|
const CHARSET_INFO *opt_charset_arg,
|
|
const CHARSET_INFO *opt_collation_arg)
|
|
: opt_charset(opt_charset_arg), opt_collation(opt_collation_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
const CHARSET_INFO *cs2;
|
|
const CHARSET_INFO *cs3;
|
|
int flags= set_var_collation_client::SET_CS_NAMES
|
|
| (opt_charset ? 0 : set_var_collation_client::SET_CS_DEFAULT)
|
|
| (opt_collation ? set_var_collation_client::SET_CS_COLLATE : 0);
|
|
cs2= opt_charset ? opt_charset
|
|
: global_system_variables.character_set_client;
|
|
cs3= opt_collation ? opt_collation : cs2;
|
|
if (!my_charset_same(cs2, cs3))
|
|
{
|
|
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
|
|
cs3->name, cs2->csname);
|
|
return true;
|
|
}
|
|
set_var_collation_client *var;
|
|
var= new set_var_collation_client(flags, cs3, cs3, cs3);
|
|
if (var == NULL)
|
|
return true;
|
|
lex->var_list.push_back(var);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list : public Parse_tree_node {};
|
|
|
|
|
|
class PT_option_value_no_option_type_password :
|
|
public PT_start_option_value_list
|
|
{
|
|
typedef PT_start_option_value_list super;
|
|
|
|
const char *password;
|
|
POS expr_pos;
|
|
|
|
public:
|
|
explicit PT_option_value_no_option_type_password(const char *password_arg,
|
|
const POS &expr_pos_arg)
|
|
: password(password_arg), expr_pos(expr_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_option_value_no_option_type_password_for :
|
|
public PT_start_option_value_list
|
|
{
|
|
typedef PT_start_option_value_list super;
|
|
|
|
LEX_USER *user;
|
|
const char *password;
|
|
POS expr_pos;
|
|
|
|
public:
|
|
PT_option_value_no_option_type_password_for(LEX_USER *user_arg,
|
|
const char *password_arg,
|
|
const POS &expr_pos_arg)
|
|
: user(user_arg), password(password_arg), expr_pos(expr_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
set_var_password *var;
|
|
|
|
/*
|
|
In case of anonymous user, user->user is set to empty string with
|
|
length 0. But there might be case when user->user.str could be NULL.
|
|
For Ex: "set password for current_user() = password('xyz');".
|
|
In this case, set user information as of the current user.
|
|
*/
|
|
if (!user->user.str)
|
|
{
|
|
LEX_CSTRING sctx_priv_user= thd->security_context()->priv_user();
|
|
assert(sctx_priv_user.str);
|
|
user->user.str= sctx_priv_user.str;
|
|
user->user.length= sctx_priv_user.length;
|
|
}
|
|
if (!user->host.str)
|
|
{
|
|
LEX_CSTRING sctx_priv_host= thd->security_context()->priv_host();
|
|
assert(sctx_priv_host.str);
|
|
user->host.str= (char *) sctx_priv_host.str;
|
|
user->host.length= sctx_priv_host.length;
|
|
}
|
|
|
|
var= new set_var_password(user, const_cast<char *>(password));
|
|
if (var == NULL)
|
|
return true;
|
|
lex->var_list.push_back(var);
|
|
lex->autocommit= TRUE;
|
|
lex->is_set_password_sql= true;
|
|
if (lex->sphead)
|
|
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
|
|
if (sp_create_assignment_instr(pc->thd, expr_pos.raw.end))
|
|
return true;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_type : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
enum_var_type type;
|
|
PT_option_value_following_option_type *value;
|
|
|
|
public:
|
|
PT_option_value_type(enum_var_type type_arg,
|
|
PT_option_value_following_option_type *value_arg)
|
|
: type(type_arg), value(value_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
pc->thd->lex->option_type= type;
|
|
return super::contextualize(pc) || value->contextualize(pc);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_list_head : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
POS delimiter_pos;
|
|
Parse_tree_node *value;
|
|
POS value_pos;
|
|
|
|
public:
|
|
PT_option_value_list_head(const POS &delimiter_pos_arg,
|
|
Parse_tree_node *value_arg,
|
|
const POS &value_pos_arg)
|
|
: delimiter_pos(delimiter_pos_arg), value(value_arg), value_pos(value_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
#ifndef NDEBUG
|
|
LEX *old_lex= thd->lex;
|
|
#endif//NDEBUG
|
|
|
|
sp_create_assignment_lex(thd, delimiter_pos.raw.end);
|
|
assert(thd->lex->select_lex == thd->lex->current_select());
|
|
Parse_context inner_pc(pc->thd, thd->lex->select_lex);
|
|
|
|
if (value->contextualize(&inner_pc))
|
|
return true;
|
|
|
|
if (sp_create_assignment_instr(pc->thd, value_pos.raw.end))
|
|
return true;
|
|
assert(thd->lex == old_lex &&
|
|
thd->lex->current_select() == pc->select);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_option_value_list : public PT_option_value_list_head
|
|
{
|
|
typedef PT_option_value_list_head super;
|
|
|
|
PT_option_value_list_head *head;
|
|
|
|
public:
|
|
PT_option_value_list(PT_option_value_list_head *head_arg,
|
|
const POS &delimiter_pos_arg,
|
|
Parse_tree_node *tail, const POS &tail_pos)
|
|
: super(delimiter_pos_arg, tail, tail_pos), head(head_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
return head->contextualize(pc) || super::contextualize(pc);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list_no_type : public PT_start_option_value_list
|
|
{
|
|
typedef PT_start_option_value_list super;
|
|
|
|
PT_option_value_no_option_type *head;
|
|
POS head_pos;
|
|
PT_option_value_list_head *tail;
|
|
|
|
public:
|
|
PT_start_option_value_list_no_type(PT_option_value_no_option_type *head_arg,
|
|
const POS &head_pos_arg,
|
|
PT_option_value_list_head *tail_arg)
|
|
: head(head_arg), head_pos(head_pos_arg), tail(tail_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || head->contextualize(pc))
|
|
return true;
|
|
|
|
if (sp_create_assignment_instr(pc->thd, head_pos.raw.end))
|
|
return true;
|
|
assert(pc->thd->lex->select_lex == pc->thd->lex->current_select());
|
|
pc->select= pc->thd->lex->select_lex;
|
|
|
|
if (tail != NULL && tail->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_transaction_characteristic : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
const char *name;
|
|
int32 value;
|
|
|
|
public:
|
|
PT_transaction_characteristic(const char *name_arg, int32 value_arg)
|
|
: name(name_arg), value(value_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
Item *item= new (pc->mem_root) Item_int(value);
|
|
if (item == NULL)
|
|
return true;
|
|
set_var *var= new set_var(lex->option_type,
|
|
find_sys_var(thd, name),
|
|
&null_lex_str,
|
|
item);
|
|
if (var == NULL)
|
|
return true;
|
|
lex->var_list.push_back(var);
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class PT_transaction_access_mode : public PT_transaction_characteristic
|
|
{
|
|
typedef PT_transaction_characteristic super;
|
|
|
|
public:
|
|
explicit PT_transaction_access_mode(bool is_read_only)
|
|
: super("transaction_read_only", (int32) is_read_only)
|
|
{}
|
|
};
|
|
|
|
|
|
class PT_isolation_level : public PT_transaction_characteristic
|
|
{
|
|
typedef PT_transaction_characteristic super;
|
|
|
|
public:
|
|
explicit PT_isolation_level(enum_tx_isolation level)
|
|
: super("transaction_isolation", (int32) level)
|
|
{}
|
|
};
|
|
|
|
|
|
class PT_transaction_characteristics : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_transaction_characteristic *head;
|
|
PT_transaction_characteristic *opt_tail;
|
|
|
|
public:
|
|
PT_transaction_characteristics(PT_transaction_characteristic *head_arg,
|
|
PT_transaction_characteristic *opt_tail_arg)
|
|
: head(head_arg), opt_tail(opt_tail_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
return (super::contextualize(pc) || head->contextualize(pc) ||
|
|
(opt_tail != NULL && opt_tail->contextualize(pc)));
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list_transaction :
|
|
public PT_start_option_value_list
|
|
{
|
|
typedef PT_start_option_value_list super;
|
|
|
|
PT_transaction_characteristics * characteristics;
|
|
POS end_pos;
|
|
|
|
public:
|
|
PT_start_option_value_list_transaction(
|
|
PT_transaction_characteristics * characteristics_arg,
|
|
const POS &end_pos_arg)
|
|
: characteristics(characteristics_arg), end_pos(end_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
thd->lex->option_type= OPT_DEFAULT;
|
|
if (characteristics->contextualize(pc))
|
|
return true;
|
|
|
|
if (sp_create_assignment_instr(thd, end_pos.raw.end))
|
|
return true;
|
|
assert(pc->thd->lex->select_lex == pc->thd->lex->current_select());
|
|
pc->select= pc->thd->lex->select_lex;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list_following_option_type :
|
|
public Parse_tree_node
|
|
{};
|
|
|
|
|
|
class PT_start_option_value_list_following_option_type_eq :
|
|
public PT_start_option_value_list_following_option_type
|
|
{
|
|
typedef PT_start_option_value_list_following_option_type super;
|
|
|
|
PT_option_value_following_option_type *head;
|
|
POS head_pos;
|
|
PT_option_value_list_head *opt_tail;
|
|
|
|
public:
|
|
PT_start_option_value_list_following_option_type_eq(
|
|
PT_option_value_following_option_type *head_arg,
|
|
const POS &head_pos_arg,
|
|
PT_option_value_list_head *opt_tail_arg)
|
|
: head(head_arg), head_pos(head_pos_arg), opt_tail(opt_tail_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || head->contextualize(pc))
|
|
return true;
|
|
|
|
if (sp_create_assignment_instr(pc->thd, head_pos.raw.end))
|
|
return true;
|
|
assert(pc->thd->lex->select_lex == pc->thd->lex->current_select());
|
|
pc->select= pc->thd->lex->select_lex;
|
|
|
|
if (opt_tail != NULL && opt_tail->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list_following_option_type_transaction :
|
|
public PT_start_option_value_list_following_option_type
|
|
{
|
|
typedef PT_start_option_value_list_following_option_type super;
|
|
|
|
PT_transaction_characteristics *characteristics;
|
|
POS characteristics_pos;
|
|
|
|
public:
|
|
PT_start_option_value_list_following_option_type_transaction(
|
|
PT_transaction_characteristics *characteristics_arg,
|
|
const POS &characteristics_pos_arg)
|
|
: characteristics(characteristics_arg),
|
|
characteristics_pos(characteristics_pos_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) || characteristics->contextualize(pc))
|
|
return true;
|
|
|
|
if (sp_create_assignment_instr(pc->thd, characteristics_pos.raw.end))
|
|
return true;
|
|
assert(pc->thd->lex->select_lex == pc->thd->lex->current_select());
|
|
pc->select= pc->thd->lex->select_lex;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_start_option_value_list_type : public PT_start_option_value_list
|
|
{
|
|
typedef PT_start_option_value_list super;
|
|
|
|
enum_var_type type;
|
|
PT_start_option_value_list_following_option_type *list;
|
|
|
|
public:
|
|
PT_start_option_value_list_type(
|
|
enum_var_type type_arg,
|
|
PT_start_option_value_list_following_option_type *list_arg)
|
|
: type(type_arg), list(list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
pc->thd->lex->option_type= type;
|
|
return super::contextualize(pc) || list->contextualize(pc);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_set : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
POS set_pos;
|
|
PT_start_option_value_list *list;
|
|
|
|
public:
|
|
PT_set(const POS &set_pos_arg, PT_start_option_value_list *list_arg)
|
|
: set_pos(set_pos_arg), list(list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
THD *thd= pc->thd;
|
|
LEX *lex= thd->lex;
|
|
lex->sql_command= SQLCOM_SET_OPTION;
|
|
lex->option_type= OPT_SESSION;
|
|
lex->var_list.empty();
|
|
lex->autocommit= false;
|
|
|
|
sp_create_assignment_lex(thd, set_pos.raw.end);
|
|
assert(pc->thd->lex->select_lex == pc->thd->lex->current_select());
|
|
pc->select= pc->thd->lex->select_lex;
|
|
|
|
return list->contextualize(pc);
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_init : public Parse_tree_node {};
|
|
|
|
|
|
class PT_union_list : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
bool is_distinct;
|
|
PT_select_init *select_init;
|
|
|
|
public:
|
|
PT_union_list(bool is_distinct_arg, PT_select_init *select_init_arg)
|
|
: is_distinct(is_distinct_arg), select_init(select_init_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
pc->select= pc->thd->lex->new_union_query(pc->select, is_distinct);
|
|
if (pc->select == NULL)
|
|
return true;
|
|
|
|
if (select_init->contextualize(pc))
|
|
return true;
|
|
/*
|
|
Remove from the name resolution context stack the context of the
|
|
last query block in the union.
|
|
*/
|
|
pc->thd->lex->pop_context();
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_into_destination : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
public:
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
if (!pc->thd->lex->parsing_options.allows_select_into)
|
|
{
|
|
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_into_destination_outfile : public PT_into_destination
|
|
{
|
|
typedef PT_into_destination super;
|
|
|
|
const char *file_name;
|
|
const CHARSET_INFO *charset;
|
|
const Field_separators field_term;
|
|
const Line_separators line_term;
|
|
|
|
public:
|
|
PT_into_destination_outfile(const LEX_STRING &file_name_arg,
|
|
const CHARSET_INFO *charset_arg,
|
|
const Field_separators &field_term_arg,
|
|
const Line_separators &line_term_arg)
|
|
: file_name(file_name_arg.str),
|
|
charset(charset_arg),
|
|
field_term(field_term_arg),
|
|
line_term(line_term_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
LEX *lex= pc->thd->lex;
|
|
lex->set_uncacheable(pc->select, UNCACHEABLE_SIDEEFFECT);
|
|
if (!(lex->exchange= new sql_exchange(file_name, 0)) ||
|
|
!(lex->result= new Query_result_export(lex->exchange)))
|
|
return true;
|
|
|
|
lex->exchange->cs= charset;
|
|
lex->exchange->field.merge_field_separators(field_term);
|
|
lex->exchange->line.merge_line_separators(line_term);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_into_destination_dumpfile : public PT_into_destination
|
|
{
|
|
typedef PT_into_destination super;
|
|
|
|
const char *file_name;
|
|
|
|
public:
|
|
explicit PT_into_destination_dumpfile(const LEX_STRING &file_name_arg)
|
|
: file_name(file_name_arg.str)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
LEX *lex= pc->thd->lex;
|
|
if (!lex->describe)
|
|
{
|
|
lex->set_uncacheable(pc->select, UNCACHEABLE_SIDEEFFECT);
|
|
if (!(lex->exchange= new sql_exchange(file_name, 1)))
|
|
return true;
|
|
if (!(lex->result= new Query_result_dump(lex->exchange)))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_var : public Parse_tree_node
|
|
{
|
|
public:
|
|
const LEX_STRING name;
|
|
|
|
explicit PT_select_var(const LEX_STRING &name_arg) : name(name_arg) {}
|
|
|
|
virtual bool is_local() const { return false; }
|
|
virtual uint get_offset() const { assert(0); return 0; }
|
|
};
|
|
|
|
|
|
class PT_select_sp_var : public PT_select_var
|
|
{
|
|
typedef PT_select_var super;
|
|
|
|
uint offset;
|
|
|
|
#ifndef NDEBUG
|
|
/*
|
|
Routine to which this Item_splocal belongs. Used for checking if correct
|
|
runtime context is used for variable handling.
|
|
*/
|
|
sp_head *sp;
|
|
#endif
|
|
|
|
public:
|
|
PT_select_sp_var(const LEX_STRING &name_arg) : super(name_arg) {}
|
|
|
|
virtual bool is_local() const { return true; }
|
|
virtual uint get_offset() const { return offset; }
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
LEX *lex= pc->thd->lex;
|
|
#ifndef NDEBUG
|
|
sp= lex->sphead;
|
|
#endif
|
|
sp_pcontext *pctx= lex->get_sp_current_parsing_ctx();
|
|
sp_variable *spv;
|
|
|
|
if (!pctx || !(spv= pctx->find_variable(name, false)))
|
|
{
|
|
my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
|
|
return true;
|
|
}
|
|
|
|
offset= spv->offset;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_var_list : public PT_into_destination
|
|
{
|
|
typedef PT_into_destination super;
|
|
|
|
public:
|
|
List<PT_select_var> value;
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
List_iterator<PT_select_var> it(value);
|
|
PT_select_var *var;
|
|
while ((var= it++))
|
|
{
|
|
if (var->contextualize(pc))
|
|
return true;
|
|
}
|
|
|
|
LEX * const lex= pc->thd->lex;
|
|
if (lex->describe)
|
|
return false;
|
|
|
|
Query_dumpvar *dumpvar= new (pc->mem_root) Query_dumpvar;
|
|
if (dumpvar == NULL)
|
|
return true;
|
|
|
|
dumpvar->var_list= value;
|
|
lex->result= dumpvar;
|
|
lex->set_uncacheable(pc->select, UNCACHEABLE_SIDEEFFECT);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool push_back(PT_select_var *var) { return value.push_back(var); }
|
|
};
|
|
|
|
|
|
class PT_select_options_and_item_list : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
Query_options options;
|
|
PT_item_list *item_list;
|
|
|
|
public:
|
|
PT_select_options_and_item_list(const Query_options &options_arg,
|
|
PT_item_list *item_list_arg)
|
|
: options(options_arg), item_list(item_list_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
pc->select->parsing_place= CTX_SELECT_LIST;
|
|
|
|
if (options.query_spec_options & SELECT_HIGH_PRIORITY)
|
|
{
|
|
Yacc_state *yyps= &pc->thd->m_parser_state->m_yacc;
|
|
yyps->m_lock_type= TL_READ_HIGH_PRIORITY;
|
|
yyps->m_mdl_type= MDL_SHARED_READ;
|
|
}
|
|
if (options.save_to(pc))
|
|
return true;
|
|
|
|
if (item_list->contextualize(pc))
|
|
return true;
|
|
|
|
// Ensure we're resetting parsing place of the right select
|
|
assert(pc->select->parsing_place == CTX_SELECT_LIST);
|
|
pc->select->parsing_place= CTX_NONE;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_part2 : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_select_options_and_item_list *select_options_and_item_list;
|
|
PT_into_destination *opt_into1;
|
|
PT_table_reference_list *from_clause; // actually is optional (NULL) for DUAL
|
|
Item *opt_where_clause;
|
|
PT_group *opt_group_clause;
|
|
Item *opt_having_clause;
|
|
PT_order *opt_order_clause;
|
|
PT_limit_clause *opt_limit_clause;
|
|
PT_procedure_analyse *opt_procedure_analyse_clause;
|
|
PT_into_destination *opt_into2;
|
|
Select_lock_type opt_select_lock_type;
|
|
|
|
public:
|
|
PT_select_part2(
|
|
PT_select_options_and_item_list *select_options_and_item_list_arg,
|
|
PT_into_destination *opt_into1_arg,
|
|
PT_table_reference_list *from_clause_arg,
|
|
Item *opt_where_clause_arg,
|
|
PT_group *opt_group_clause_arg,
|
|
Item *opt_having_clause_arg,
|
|
PT_order *opt_order_clause_arg,
|
|
PT_limit_clause *opt_limit_clause_arg,
|
|
PT_procedure_analyse *opt_procedure_analyse_clause_arg,
|
|
PT_into_destination *opt_into2_arg,
|
|
const Select_lock_type &opt_select_lock_type_arg)
|
|
: select_options_and_item_list(select_options_and_item_list_arg),
|
|
opt_into1(opt_into1_arg),
|
|
from_clause(from_clause_arg),
|
|
opt_where_clause(opt_where_clause_arg),
|
|
opt_group_clause(opt_group_clause_arg),
|
|
opt_having_clause(opt_having_clause_arg),
|
|
opt_order_clause(opt_order_clause_arg),
|
|
opt_limit_clause(opt_limit_clause_arg),
|
|
opt_procedure_analyse_clause(opt_procedure_analyse_clause_arg),
|
|
opt_into2(opt_into2_arg),
|
|
opt_select_lock_type(opt_select_lock_type_arg)
|
|
{}
|
|
explicit PT_select_part2(
|
|
PT_select_options_and_item_list *select_options_and_item_list_arg)
|
|
: select_options_and_item_list(select_options_and_item_list_arg),
|
|
opt_into1(NULL),
|
|
from_clause(NULL),
|
|
opt_where_clause(NULL),
|
|
opt_group_clause(NULL),
|
|
opt_having_clause(NULL),
|
|
opt_order_clause(NULL),
|
|
opt_limit_clause(NULL),
|
|
opt_procedure_analyse_clause(NULL),
|
|
opt_into2(NULL),
|
|
opt_select_lock_type()
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
select_options_and_item_list->contextualize(pc) ||
|
|
(opt_into1 != NULL &&
|
|
opt_into1->contextualize(pc)) ||
|
|
(from_clause != NULL &&
|
|
from_clause->contextualize(pc)) ||
|
|
(opt_where_clause != NULL &&
|
|
opt_where_clause->itemize(pc, &opt_where_clause)) ||
|
|
(opt_group_clause != NULL &&
|
|
opt_group_clause->contextualize(pc)) ||
|
|
(opt_having_clause != NULL &&
|
|
opt_having_clause->itemize(pc, &opt_having_clause)))
|
|
return true;
|
|
|
|
pc->select->set_where_cond(opt_where_clause);
|
|
pc->select->set_having_cond(opt_having_clause);
|
|
|
|
if ((opt_order_clause != NULL &&
|
|
opt_order_clause->contextualize(pc)) ||
|
|
(opt_limit_clause != NULL &&
|
|
opt_limit_clause->contextualize(pc)) ||
|
|
(opt_procedure_analyse_clause != NULL &&
|
|
opt_procedure_analyse_clause->contextualize(pc)) ||
|
|
(opt_into2 != NULL &&
|
|
opt_into2->contextualize(pc)))
|
|
return true;
|
|
|
|
assert(opt_into1 == NULL || opt_into2 == NULL);
|
|
assert(opt_procedure_analyse_clause == NULL ||
|
|
(opt_into1 == NULL && opt_into2 == NULL));
|
|
|
|
/*
|
|
@todo: explain should not affect how we construct the query data
|
|
structure. Instead, consider to let lock_tables() adjust lock
|
|
requests according to the explain flag.
|
|
*/
|
|
if (opt_select_lock_type.is_set && !pc->thd->lex->is_explain())
|
|
{
|
|
pc->select->set_lock_for_tables(opt_select_lock_type.lock_type);
|
|
pc->thd->lex->safe_to_cache_query=
|
|
opt_select_lock_type.is_safe_to_cache_query;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_paren : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_hint_list *opt_hint_list;
|
|
PT_select_part2 *select_part2;
|
|
|
|
public:
|
|
PT_select_paren(PT_hint_list *opt_hint_list_arg,
|
|
PT_select_part2 *select_part2_arg)
|
|
: opt_hint_list(opt_hint_list_arg), select_part2(select_part2_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
/*
|
|
In order to correctly process UNION's global ORDER BY we need to
|
|
set braces before parsing the clause.
|
|
*/
|
|
pc->select->set_braces(true);
|
|
|
|
if (select_part2->contextualize(pc))
|
|
return true;
|
|
|
|
if (setup_select_in_parentheses(pc->select))
|
|
return true;
|
|
|
|
if (opt_hint_list != NULL && opt_hint_list->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_init_parenthesis : public PT_select_init
|
|
{
|
|
typedef PT_select_init super;
|
|
|
|
PT_select_paren *select_paren;
|
|
Parse_tree_node *union_opt;
|
|
|
|
public:
|
|
PT_select_init_parenthesis(PT_select_paren *select_paren_arg,
|
|
Parse_tree_node *union_opt_arg)
|
|
: select_paren(select_paren_arg), union_opt(union_opt_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
return (super::contextualize(pc) || select_paren->contextualize(pc) ||
|
|
(union_opt != NULL && union_opt->contextualize(pc)));
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select_init2 : public PT_select_init
|
|
{
|
|
typedef PT_select_init super;
|
|
|
|
PT_hint_list *opt_hint_list;
|
|
PT_select_part2 *select_part2;
|
|
PT_union_list *opt_union_clause;
|
|
|
|
public:
|
|
PT_select_init2(PT_hint_list *opt_hint_list_arg,
|
|
PT_select_part2 *select_part2_arg,
|
|
PT_union_list *opt_union_clause_arg)
|
|
: opt_hint_list(opt_hint_list_arg),
|
|
select_part2(select_part2_arg),
|
|
opt_union_clause(opt_union_clause_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc) ||
|
|
select_part2->contextualize(pc))
|
|
return true;
|
|
|
|
// Parentheses carry no meaning here.
|
|
pc->select->set_braces(false);
|
|
|
|
if (opt_hint_list != NULL && opt_hint_list->contextualize(pc))
|
|
return true;
|
|
|
|
if (opt_union_clause != NULL && opt_union_clause->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_select : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_select_init *select_init;
|
|
enum_sql_command sql_command;
|
|
|
|
public:
|
|
explicit PT_select(PT_select_init *select_init_arg,
|
|
enum_sql_command sql_command_arg)
|
|
: select_init(select_init_arg), sql_command(sql_command_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc)
|
|
{
|
|
if (super::contextualize(pc))
|
|
return true;
|
|
|
|
pc->thd->lex->sql_command= sql_command;
|
|
|
|
if (select_init->contextualize(pc))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_delete : public PT_statement
|
|
{
|
|
typedef PT_statement super;
|
|
|
|
PT_hint_list *opt_hints;
|
|
const int opt_delete_options;
|
|
Table_ident *table_ident;
|
|
Mem_root_array_YY<Table_ident *> table_list;
|
|
List<String> *opt_use_partition;
|
|
PT_join_table_list *join_table_list;
|
|
Item *opt_where_clause;
|
|
PT_order *opt_order_clause;
|
|
Item *opt_delete_limit_clause;
|
|
|
|
public:
|
|
// single-table DELETE node constructor:
|
|
PT_delete(MEM_ROOT *mem_root,
|
|
PT_hint_list *opt_hints_arg,
|
|
int opt_delete_options_arg,
|
|
Table_ident *table_ident_arg,
|
|
List<String> *opt_use_partition_arg,
|
|
Item *opt_where_clause_arg,
|
|
PT_order *opt_order_clause_arg,
|
|
Item *opt_delete_limit_clause_arg)
|
|
: opt_hints(opt_hints_arg),
|
|
opt_delete_options(opt_delete_options_arg),
|
|
table_ident(table_ident_arg),
|
|
opt_use_partition(opt_use_partition_arg),
|
|
join_table_list(NULL),
|
|
opt_where_clause(opt_where_clause_arg),
|
|
opt_order_clause(opt_order_clause_arg),
|
|
opt_delete_limit_clause(opt_delete_limit_clause_arg)
|
|
{
|
|
table_list.init(mem_root);
|
|
}
|
|
|
|
// multi-table DELETE node constructor:
|
|
PT_delete(PT_hint_list *opt_hints_arg,
|
|
int opt_delete_options_arg,
|
|
const Mem_root_array_YY<Table_ident *> &table_list_arg,
|
|
PT_join_table_list *join_table_list_arg,
|
|
Item *opt_where_clause_arg)
|
|
: opt_hints(opt_hints_arg),
|
|
opt_delete_options(opt_delete_options_arg),
|
|
table_ident(NULL),
|
|
table_list(table_list_arg),
|
|
opt_use_partition(NULL),
|
|
join_table_list(join_table_list_arg),
|
|
opt_where_clause(opt_where_clause_arg),
|
|
opt_order_clause(NULL),
|
|
opt_delete_limit_clause(NULL)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
|
|
virtual Sql_cmd *make_cmd(THD *thd);
|
|
|
|
bool is_multitable() const
|
|
{
|
|
assert((table_ident != NULL) ^ (table_list.size() > 0));
|
|
return table_ident == NULL;
|
|
}
|
|
|
|
private:
|
|
bool add_table(Parse_context *pc, Table_ident *table);
|
|
};
|
|
|
|
|
|
class PT_update : public PT_statement
|
|
{
|
|
typedef PT_statement super;
|
|
|
|
PT_hint_list *opt_hints;
|
|
thr_lock_type opt_low_priority;
|
|
bool opt_ignore;
|
|
PT_join_table_list *join_table_list;
|
|
PT_item_list *column_list;
|
|
PT_item_list *value_list;
|
|
Item *opt_where_clause;
|
|
PT_order *opt_order_clause;
|
|
Item *opt_limit_clause;
|
|
|
|
Sql_cmd_update sql_cmd;
|
|
|
|
public:
|
|
PT_update(PT_hint_list *opt_hints_arg,
|
|
thr_lock_type opt_low_priority_arg,
|
|
bool opt_ignore_arg,
|
|
PT_join_table_list *join_table_list_arg,
|
|
PT_item_list *column_list_arg,
|
|
PT_item_list *value_list_arg,
|
|
Item *opt_where_clause_arg,
|
|
PT_order *opt_order_clause_arg,
|
|
Item *opt_limit_clause_arg)
|
|
: opt_hints(opt_hints_arg),
|
|
opt_low_priority(opt_low_priority_arg),
|
|
opt_ignore(opt_ignore_arg),
|
|
join_table_list(join_table_list_arg),
|
|
column_list(column_list_arg),
|
|
value_list(value_list_arg),
|
|
opt_where_clause(opt_where_clause_arg),
|
|
opt_order_clause(opt_order_clause_arg),
|
|
opt_limit_clause(opt_limit_clause_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
|
|
virtual Sql_cmd *make_cmd(THD *thd);
|
|
};
|
|
|
|
|
|
class PT_create_select : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
PT_hint_list *opt_hints;
|
|
Query_options options;
|
|
PT_item_list *item_list;
|
|
PT_table_expression *table_expression;
|
|
|
|
public:
|
|
PT_create_select(PT_hint_list *opt_hints_arg,
|
|
const Query_options &options_arg,
|
|
PT_item_list *item_list_arg,
|
|
PT_table_expression *table_expression_arg)
|
|
: opt_hints(opt_hints_arg),
|
|
options(options_arg),
|
|
item_list(item_list_arg),
|
|
table_expression(table_expression_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_insert_values_list : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
List<List_item> many_values;
|
|
|
|
public:
|
|
virtual bool contextualize(Parse_context *pc);
|
|
|
|
bool push_back(List<Item> *x) { return many_values.push_back(x); }
|
|
|
|
virtual List<List_item> &get_many_values()
|
|
{
|
|
assert(is_contextualized());
|
|
return many_values;
|
|
}
|
|
};
|
|
|
|
|
|
class PT_insert_query_expression : public Parse_tree_node
|
|
{
|
|
typedef Parse_tree_node super;
|
|
|
|
bool braces;
|
|
PT_create_select *create_select;
|
|
Parse_tree_node * opt_union;
|
|
|
|
public:
|
|
PT_insert_query_expression(bool braces_arg,
|
|
PT_create_select *create_select_arg,
|
|
Parse_tree_node * opt_union_arg)
|
|
: braces(braces_arg),
|
|
create_select(create_select_arg),
|
|
opt_union(opt_union_arg)
|
|
{}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
|
|
class PT_insert : public PT_statement
|
|
{
|
|
typedef PT_statement super;
|
|
|
|
const bool is_replace;
|
|
PT_hint_list *opt_hints;
|
|
const thr_lock_type lock_option;
|
|
const bool ignore;
|
|
Table_ident * const table_ident;
|
|
List<String> * const opt_use_partition;
|
|
PT_item_list * const column_list;
|
|
PT_insert_values_list * const row_value_list;
|
|
PT_insert_query_expression * const insert_query_expression;
|
|
PT_item_list * const opt_on_duplicate_column_list;
|
|
PT_item_list * const opt_on_duplicate_value_list;
|
|
|
|
public:
|
|
PT_insert(bool is_replace_arg,
|
|
PT_hint_list *opt_hints_arg,
|
|
thr_lock_type lock_option_arg,
|
|
bool ignore_arg,
|
|
Table_ident *table_ident_arg,
|
|
List<String> *opt_use_partition_arg,
|
|
PT_item_list *column_list_arg,
|
|
PT_insert_values_list *row_value_list_arg,
|
|
PT_insert_query_expression *insert_query_expression_arg,
|
|
PT_item_list *opt_on_duplicate_column_list_arg,
|
|
PT_item_list *opt_on_duplicate_value_list_arg)
|
|
: is_replace(is_replace_arg),
|
|
opt_hints(opt_hints_arg),
|
|
lock_option(lock_option_arg),
|
|
ignore(ignore_arg),
|
|
table_ident(table_ident_arg),
|
|
opt_use_partition(opt_use_partition_arg),
|
|
column_list(column_list_arg),
|
|
row_value_list(row_value_list_arg),
|
|
insert_query_expression(insert_query_expression_arg),
|
|
opt_on_duplicate_column_list(opt_on_duplicate_column_list_arg),
|
|
opt_on_duplicate_value_list(opt_on_duplicate_value_list_arg)
|
|
{
|
|
// REPLACE statement can't have IGNORE flag:
|
|
assert(!is_replace || !ignore);
|
|
// REPLACE statement can't have ON DUPLICATE KEY UPDATE clause:
|
|
assert(!is_replace || opt_on_duplicate_column_list == NULL);
|
|
// INSERT/REPLACE ... SELECT can't have VALUES clause:
|
|
assert((row_value_list != NULL) ^ (insert_query_expression != NULL));
|
|
// ON DUPLICATE KEY UPDATE: column and value arrays must have same sizes:
|
|
assert((opt_on_duplicate_column_list == NULL &&
|
|
opt_on_duplicate_value_list == NULL) ||
|
|
(opt_on_duplicate_column_list->elements() ==
|
|
opt_on_duplicate_value_list->elements()));
|
|
}
|
|
|
|
virtual bool contextualize(Parse_context *pc);
|
|
|
|
virtual Sql_cmd *make_cmd(THD *thd);
|
|
|
|
private:
|
|
bool has_select() const { return insert_query_expression != NULL; }
|
|
};
|
|
|
|
|
|
class PT_shutdown : public PT_statement
|
|
{
|
|
Sql_cmd_shutdown sql_cmd;
|
|
|
|
public:
|
|
virtual Sql_cmd *make_cmd(THD *) { return &sql_cmd; }
|
|
};
|
|
|
|
|
|
class PT_alter_instance : public PT_statement
|
|
{
|
|
typedef PT_statement super;
|
|
|
|
Sql_cmd_alter_instance sql_cmd;
|
|
|
|
public:
|
|
explicit PT_alter_instance(enum alter_instance_action_enum alter_instance_action)
|
|
: sql_cmd(alter_instance_action)
|
|
{}
|
|
|
|
virtual Sql_cmd *make_cmd(THD *thd);
|
|
virtual bool contextualize(Parse_context *pc);
|
|
};
|
|
|
|
#endif /* PARSE_TREE_NODES_INCLUDED */
|