diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-10-27 20:48:16 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-10-27 20:48:16 +0400 |
commit | 5dd5253f7e50c21fa758e2eb58f3aa9c9754e733 (patch) | |
tree | b537a2c1400b996bdb5008be0eec6b198965f6c7 /sql | |
parent | e7637ec061a0046d116c135a15f3afbb77e1c4d5 (diff) | |
download | mariadb-git-5dd5253f7e50c21fa758e2eb58f3aa9c9754e733.tar.gz |
MDEV-14139 Anchored data types for variables
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.h | 28 | ||||
-rw-r--r-- | sql/sql_lex.cc | 254 | ||||
-rw-r--r-- | sql/sql_lex.h | 30 |
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); |