summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2017-10-27 20:48:16 +0400
committerAlexander Barkov <bar@mariadb.org>2017-10-27 20:48:16 +0400
commit5dd5253f7e50c21fa758e2eb58f3aa9c9754e733 (patch)
treeb537a2c1400b996bdb5008be0eec6b198965f6c7 /sql
parente7637ec061a0046d116c135a15f3afbb77e1c4d5 (diff)
downloadmariadb-git-5dd5253f7e50c21fa758e2eb58f3aa9c9754e733.tar.gz
MDEV-14139 Anchored data types for variables
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h28
-rw-r--r--sql/sql_lex.cc254
-rw-r--r--sql/sql_lex.h30
3 files changed, 233 insertions, 79 deletions
diff --git a/sql/field.h b/sql/field.h
index 951d6940a88..5999f3e0a34 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -4061,6 +4061,23 @@ public:
|| unireg_check == Field::TIMESTAMP_DNUN_FIELD;
}
+ void set_type(const Column_definition &other)
+ {
+ set_handler(other.type_handler());
+ length= other.length;
+ char_length= other.char_length;
+ decimals= other.decimals;
+ flags= other.flags;
+ pack_length= other.pack_length;
+ key_length= other.key_length;
+ unireg_check= other.unireg_check;
+ interval= other.interval;
+ charset= other.charset;
+ srid= other.srid;
+ geom_type= other.geom_type;
+ pack_flag= other.pack_flag;
+ }
+
// Replace the entire value by another definition
void set_column_definition(const Column_definition *def)
{
@@ -4127,12 +4144,14 @@ class Spvar_definition: public Column_definition
class Qualified_column_ident *m_column_type_ref; // for %TYPE
class Table_ident *m_table_rowtype_ref; // for table%ROWTYPE
bool m_cursor_rowtype_ref; // for cursor%ROWTYPE
+ uint m_cursor_rowtype_offset; // for cursor%ROWTYPE
Row_definition_list *m_row_field_definitions; // for ROW
public:
Spvar_definition()
:m_column_type_ref(NULL),
m_table_rowtype_ref(NULL),
m_cursor_rowtype_ref(false),
+ m_cursor_rowtype_offset(0),
m_row_field_definitions(NULL)
{ }
Spvar_definition(THD *thd, Field *field)
@@ -4140,6 +4159,7 @@ public:
m_column_type_ref(NULL),
m_table_rowtype_ref(NULL),
m_cursor_rowtype_ref(false),
+ m_cursor_rowtype_offset(0),
m_row_field_definitions(NULL)
{ }
const Type_handler *type_handler() const
@@ -4168,9 +4188,15 @@ public:
{
m_table_rowtype_ref= ref;
}
- void set_cursor_rowtype_ref(bool ref)
+
+ uint cursor_rowtype_offset() const
+ {
+ return m_cursor_rowtype_offset;
+ }
+ void set_cursor_rowtype_ref(bool ref, uint offset)
{
m_cursor_rowtype_ref= ref;
+ m_cursor_rowtype_offset= offset;
}
/*
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 5f198e40254..938b386a816 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -5259,15 +5259,69 @@ 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);
+ 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.
@@ -5280,37 +5334,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))
- 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);
}
@@ -5334,57 +5370,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(true, 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);
@@ -5392,11 +5447,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);
@@ -5404,7 +5476,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);
}
@@ -5472,7 +5592,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(true, coffset);
if (sphead->add_for_loop_open_cursor(thd, spcont, spvar, pcursor, coffset,
param_lex, parameters))
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3f02158b9b1..8ace65aedf7 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3195,26 +3195,34 @@ public:
void sp_variable_declarations_init(THD *thd, int nvars);
bool sp_variable_declarations_finalize(THD *thd, int nvars,
const Column_definition *cdef,
- Row_definition_list *row,
Item *def);
- bool sp_variable_declarations_finalize(THD *thd, int nvars,
- const Column_definition *cdef,
- Item *def)
- {
- return sp_variable_declarations_finalize(thd, nvars, cdef, NULL, def);
- }
+ bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def);
bool sp_variable_declarations_row_finalize(THD *thd, int nvars,
Row_definition_list *row,
- Item *def)
- {
- return sp_variable_declarations_finalize(thd, nvars, NULL, row, def);
- }
+ Item *def);
bool sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
Qualified_column_ident *col,
Item *def);
bool sp_variable_declarations_rowtype_finalize(THD *thd, int nvars,
Qualified_column_ident *,
Item *def);
+ bool sp_variable_declarations_cursor_rowtype_finalize(THD *thd, int nvars,
+ uint offset,
+ Item *def);
+ bool sp_variable_declarations_table_rowtype_finalize(THD *thd, int nvars,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &table,
+ Item *def);
+ bool sp_variable_declarations_column_type_finalize(THD *thd, int nvars,
+ Qualified_column_ident *ref,
+ Item *def);
+ bool sp_variable_declarations_vartype_finalize(THD *thd, int nvars,
+ const LEX_CSTRING &name,
+ Item *def);
+ bool sp_variable_declarations_copy_type_finalize(THD *thd, int nvars,
+ const Column_definition &ref,
+ Row_definition_list *fields,
+ Item *def);
bool sp_handler_declaration_init(THD *thd, int type);
bool sp_handler_declaration_finalize(THD *thd, int type);