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.cc318
1 files changed, 240 insertions, 78 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b8d51a5783f..ce43a45b872 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2386,6 +2386,30 @@ st_select_lex_node *st_select_lex_node:: insert_chain_before(
return this;
}
+
+/*
+ Detach the node from its master and attach it to a new master
+*/
+
+void st_select_lex_node::move_as_slave(st_select_lex_node *new_master)
+{
+ exclude_from_tree();
+ if (new_master->slave)
+ {
+ st_select_lex_node *curr= new_master->slave;
+ for ( ; curr->next ; curr= curr->next) ;
+ prev= &curr->next;
+ }
+ else
+ {
+ prev= &new_master->slave;
+ new_master->slave= this;
+ }
+ next= 0;
+ master= new_master;
+}
+
+
/*
Exclude a node from the tree lex structure, but leave it in the global
list of nodes.
@@ -4495,7 +4519,8 @@ void st_select_lex::set_explain_type(bool on_the_fly)
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
*/
if (tab->table && tab->table->pos_in_table_list &&
- tab->table->pos_in_table_list->with)
+ tab->table->pos_in_table_list->with &&
+ tab->table->pos_in_table_list->with->is_recursive)
{
uses_cte= true;
break;
@@ -5208,15 +5233,73 @@ void LEX::sp_variable_declarations_init(THD *thd, int nvars)
thd->variables.collation_database);
}
+
+bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars,
+ Item *dflt_value_item)
+{
+ if (!dflt_value_item &&
+ !(dflt_value_item= new (thd->mem_root) Item_null(thd)))
+ return true;
+
+ for (uint i= 0 ; i < (uint) nvars ; i++)
+ {
+ sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
+ 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(sphead->instructions(),
+ spcont, spvar->offset, dflt_value_item,
+ this, last);
+ if (is == NULL || sphead->add_instr(is))
+ return true;
+ }
+ return false;
+}
+
+
+bool
+LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars,
+ const Column_definition &ref,
+ Row_definition_list *fields,
+ Item *default_value)
+{
+ for (uint i= 0 ; i < (uint) nvars; i++)
+ {
+ sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
+ spvar->field_def.set_type(ref);
+ if (fields)
+ {
+ DBUG_ASSERT(ref.type_handler() == &type_handler_row);
+ spvar->field_def.set_row_field_definitions(fields);
+ }
+ spvar->field_def.field_name= spvar->name;
+ }
+ if (sp_variable_declarations_set_default(thd, nvars, default_value))
+ return true;
+ spcont->declare_var_boundary(0);
+ return sphead->restore_lex(thd);
+}
+
+
bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
const Column_definition *cdef,
- Row_definition_list *row,
Item *dflt_value_item)
{
- if (!dflt_value_item &&
- !(dflt_value_item= new (thd->mem_root) Item_null(thd)))
+ DBUG_ASSERT(cdef);
+ Column_definition tmp(*cdef);
+ if (sphead->fill_spvar_definition(thd, &tmp))
return true;
+ return sp_variable_declarations_copy_type_finalize(thd, nvars, tmp, NULL,
+ dflt_value_item);
+}
+
+bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars,
+ Row_definition_list *row,
+ Item *dflt_value_item)
+{
+ DBUG_ASSERT(row);
/*
Prepare all row fields.
Note, we do it only one time outside of the below loop.
@@ -5229,37 +5312,19 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
...
END;
*/
- if (row && sphead->row_fill_field_definitions(thd, row))
+ if (sphead->row_fill_field_definitions(thd, row))
return true;
for (uint i= 0 ; i < (uint) nvars ; i++)
{
sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
- bool last= i + 1 == (uint) nvars;
-
- if (!spvar)
- return true;
-
- spvar->default_value= dflt_value_item;
-
- if (cdef)
- {
- if (!last)
- spvar->field_def.set_column_definition(cdef);
- }
- if (sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name))
- return true;
spvar->field_def.set_row_field_definitions(row);
-
- /* The last instruction is responsible for freeing LEX. */
- sp_instr_set *is= new (this->thd->mem_root)
- sp_instr_set(sphead->instructions(),
- spcont, spvar->offset, dflt_value_item,
- this, last);
- if (is == NULL || sphead->add_instr(is))
+ if (sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name))
return true;
}
+ if (sp_variable_declarations_set_default(thd, nvars, dflt_value_item))
+ return true;
spcont->declare_var_boundary(0);
return sphead->restore_lex(thd);
}
@@ -5283,57 +5348,76 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
const sp_pcursor *pcursor= ref->table.str && ref->db.str ? NULL :
spcont->find_cursor(&ref->m_column, &coffp,
false);
+ if (pcursor)
+ return sp_variable_declarations_cursor_rowtype_finalize(thd, nvars,
+ coffp, def);
+ /*
+ When parsing a qualified identifier chain, the parser does not know yet
+ if it's going to be a qualified column name (for %TYPE),
+ or a qualified table name (for %ROWTYPE). So it collects the chain
+ into Qualified_column_ident.
+ Now we know that it was actually a qualified table name (%ROWTYPE).
+ Create a new Table_ident from Qualified_column_ident,
+ shifting fields as follows:
+ - ref->m_column becomes table_ref->table
+ - ref->table becomes table_ref->db
+ */
+ return sp_variable_declarations_table_rowtype_finalize(thd, nvars,
+ ref->table,
+ ref->m_column,
+ def);
+}
+
- if (!def && !(def= new (thd->mem_root) Item_null(thd)))
+bool
+LEX::sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &table,
+ Item *def)
+{
+ Table_ident *table_ref;
+ if (!(table_ref= new (thd->mem_root) Table_ident(thd, &db, &table, false)))
+ return true;
+ // Loop through all variables in the same declaration
+ for (uint i= 0 ; i < (uint) nvars; i++)
+ {
+ sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
+ spvar->field_def.set_table_rowtype_ref(table_ref);
+ sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name);
+ }
+ if (sp_variable_declarations_set_default(thd, nvars, def))
return true;
+ // Make sure sp_rcontext is created using the invoker security context:
+ sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
+ spcont->declare_var_boundary(0);
+ return sphead->restore_lex(thd);
+}
+
+
+bool
+LEX::sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars,
+ uint offset,
+ Item *def)
+{
+ const sp_pcursor *pcursor= spcont->find_cursor(offset);
// Loop through all variables in the same declaration
for (uint i= 0 ; i < (uint) nvars; i++)
{
- bool last= i + 1 == (uint) nvars;
sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
- if (pcursor)
- {
- spvar->field_def.set_cursor_rowtype_ref(true);
- sp_instr_cursor_copy_struct *instr=
- new (thd->mem_root) sp_instr_cursor_copy_struct(sphead->instructions(),
- spcont, pcursor->lex(),
- spvar->offset);
- if (instr == NULL || sphead->add_instr(instr))
- return true;
- }
- else
- {
- /*
- When parsing a qualified identifier chain, the parser does not know yet
- if it's going to be a qualified column name (for %TYPE),
- or a qualified table name (for %ROWTYPE). So it collects the chain
- into Qualified_column_ident.
- Now we know that it was actually a qualified table name (%ROWTYPE).
- Create a new Table_ident from Qualified_column_ident,
- shifting fields as follows:
- - ref->m_column becomes table_ref->table
- - ref->table becomes table_ref->db
- */
- Table_ident *table_ref;
- if (!(table_ref= new (thd->mem_root) Table_ident(thd,
- &ref->table,
- &ref->m_column,
- false)))
- return true;
- spvar->field_def.set_table_rowtype_ref(table_ref);
- }
+ spvar->field_def.set_cursor_rowtype_ref(offset);
+ sp_instr_cursor_copy_struct *instr=
+ new (thd->mem_root) sp_instr_cursor_copy_struct(sphead->instructions(),
+ spcont, pcursor->lex(),
+ spvar->offset);
+ if (instr == NULL || sphead->add_instr(instr))
+ return true;
+
sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name);
- spvar->default_value= def;
- /* The last instruction is responsible for freeing LEX. */
- sp_instr_set *is= new (this->thd->mem_root)
- sp_instr_set(sphead->instructions(),
- spcont, spvar->offset, def,
- this, last);
- if (is == NULL || sphead->add_instr(is))
- return true;
}
+ if (sp_variable_declarations_set_default(thd, nvars, def))
+ return true;
// Make sure sp_rcontext is created using the invoker security context:
sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
spcont->declare_var_boundary(0);
@@ -5341,11 +5425,28 @@ LEX::sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
}
+/*
+ Add declarations for table column and SP variable anchor types:
+ - DECLARE spvar1 TYPE OF db1.table1.column1;
+ - DECLARE spvar1 TYPE OF table1.column1;
+ - DECLARE spvar1 TYPE OF spvar0;
+*/
bool
LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
Qualified_column_ident *ref,
Item *def)
{
+ return ref->db.length == 0 && ref->table.length == 0 ?
+ sp_variable_declarations_vartype_finalize(thd, nvars, ref->m_column, def) :
+ sp_variable_declarations_column_type_finalize(thd, nvars, ref, def);
+}
+
+
+bool
+LEX::sp_variable_declarations_column_type_finalize(THD *thd, int nvars,
+ Qualified_column_ident *ref,
+ Item *def)
+{
for (uint i= 0 ; i < (uint) nvars; i++)
{
sp_variable *spvar= spcont->get_last_context_variable((uint) nvars - 1 - i);
@@ -5353,7 +5454,55 @@ LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
spvar->field_def.field_name= spvar->name;
}
sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
- return sp_variable_declarations_finalize(thd, nvars, NULL, NULL, def);
+ if (sp_variable_declarations_set_default(thd, nvars, def))
+ return true;
+ spcont->declare_var_boundary(0);
+ return sphead->restore_lex(thd);
+}
+
+
+bool
+LEX::sp_variable_declarations_vartype_finalize(THD *thd, int nvars,
+ const LEX_CSTRING &ref,
+ Item *default_value)
+{
+ sp_variable *t;
+ if (!spcont || !(t= spcont->find_variable(&ref, false)))
+ {
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), ref.str);
+ return true;
+ }
+
+ if (t->field_def.is_cursor_rowtype_ref())
+ {
+ uint offset= t->field_def.cursor_rowtype_offset();
+ return sp_variable_declarations_cursor_rowtype_finalize(thd, nvars,
+ offset,
+ default_value);
+ }
+
+ if (t->field_def.is_column_type_ref())
+ {
+ Qualified_column_ident *tmp= t->field_def.column_type_ref();
+ return sp_variable_declarations_column_type_finalize(thd, nvars, tmp,
+ default_value);
+ }
+
+ if (t->field_def.is_table_rowtype_ref())
+ {
+ const Table_ident *tmp= t->field_def.table_rowtype_ref();
+ return sp_variable_declarations_table_rowtype_finalize(thd, nvars,
+ tmp->db,
+ tmp->table,
+ default_value);
+ }
+
+ // A reference to a scalar or a row variable with an explicit data type
+ return sp_variable_declarations_copy_type_finalize(thd, nvars,
+ t->field_def,
+ t->field_def.
+ row_field_definitions(),
+ default_value);
}
@@ -5421,7 +5570,7 @@ LEX::sp_add_for_loop_cursor_variable(THD *thd,
if (!(spvar->default_value= new (thd->mem_root) Item_null(thd)))
return NULL;
- spvar->field_def.set_cursor_rowtype_ref(true);
+ spvar->field_def.set_cursor_rowtype_ref(coffset);
if (sphead->add_for_loop_open_cursor(thd, spcont, spvar, pcursor, coffset,
param_lex, parameters))
@@ -5445,7 +5594,7 @@ bool LEX::sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop)
{
sp_variable *src= i == 0 ? loop.m_index : loop.m_upper_bound;
args[i]= new (thd->mem_root)
- Item_splocal(thd, &src->name, src->offset, src->sql_type());
+ Item_splocal(thd, &src->name, src->offset, src->type_handler());
if (args[i] == NULL)
return true;
#ifdef DBUG_ASSERT_EXISTS
@@ -5579,7 +5728,7 @@ bool LEX::sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop)
{
Item_splocal *splocal= new (thd->mem_root)
Item_splocal(thd, &loop.m_index->name, loop.m_index->offset,
- loop.m_index->sql_type());
+ loop.m_index->type_handler());
if (splocal == NULL)
return true;
#ifdef DBUG_ASSERT_EXISTS
@@ -6350,7 +6499,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
{
if (!(item= new (thd->mem_root)
Item_splocal_row_field_by_name(thd, a, b, spv->offset,
- MYSQL_TYPE_NULL,
+ &type_handler_null,
pos.pos(), pos.length())))
return NULL;
}
@@ -6364,7 +6513,7 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
if (!(item= new (thd->mem_root)
Item_splocal_row_field(thd, a, b,
spv->offset, row_field_offset,
- def->real_field_type(),
+ def->type_handler(),
pos.pos(), pos.length())))
return NULL;
}
@@ -6533,7 +6682,7 @@ Item *LEX::create_item_limit(THD *thd,
Query_fragment pos(thd, sphead, start, end);
Item_splocal *item;
if (!(item= new (thd->mem_root) Item_splocal(thd, a,
- spv->offset, spv->sql_type(),
+ spv->offset, spv->type_handler(),
pos.pos(), pos.length())))
return NULL;
#ifdef DBUG_ASSERT_EXISTS
@@ -6652,11 +6801,8 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_CSTRING *name,
spv->offset,
pos.pos(),
pos.length()) :
- spv->field_def.is_row() || spv->field_def.is_table_rowtype_ref() ?
- new (thd->mem_root) Item_splocal_row(thd, name, spv->offset,
- pos.pos(), pos.length()) :
new (thd->mem_root) Item_splocal(thd, name,
- spv->offset, spv->sql_type(),
+ spv->offset, spv->type_handler(),
pos.pos(), pos.length());
if (splocal == NULL)
return NULL;
@@ -7186,6 +7332,22 @@ bool LEX::add_grant_command(THD *thd, enum_sql_command sql_command_arg,
}
+Item *LEX::make_item_func_substr(THD *thd, Item *a, Item *b, Item *c)
+{
+ return (thd->variables.sql_mode & MODE_ORACLE) ?
+ new (thd->mem_root) Item_func_substr_oracle(thd, a, b, c) :
+ new (thd->mem_root) Item_func_substr(thd, a, b, c);
+}
+
+
+Item *LEX::make_item_func_substr(THD *thd, Item *a, Item *b)
+{
+ return (thd->variables.sql_mode & MODE_ORACLE) ?
+ new (thd->mem_root) Item_func_substr_oracle(thd, a, b) :
+ new (thd->mem_root) Item_func_substr(thd, a, b);
+}
+
+
Item *LEX::make_item_func_replace(THD *thd,
Item *org,
Item *find,