MDEV-36705 Preparations for associative arrays (MDEV-34319)
- Moving the definition of "class Type_handler_row" into a new file sql_type_row.h. Also moving *some* of its methods into sql_type_row.cc. The rest of the methods will be moved in the patch for MDEV-34319. Moving the definition of my_var_sp_row_field into sql_type_row.cc. - Fixing the grammar for function_call_generic to get the first production as "ident_cli_func" rather than "ident_func". The upcoming patch needs to know the position of the function name within the client query. - Adding new data types to store data types defined by "TYPE" declarations: * sp_type_def * sp_type_def_list sp_pcontext now derives from sp_type_def_list - A new virtual method in Field: virtual Item_field *make_item_field_spvar(THD *thd, const Spvar_definition &def); Using it in sp_rcontext::init_var_items(). - Fixing my_var_sp to get sp_rcontext_addr in the parameter instead of two separate parameters (rcontext_handler + offset). - Adding new virtual methods in my_var: virtual bool set_row(THD *thd, List<Item> &select_list); It's used when a select_list record is assigned to a single composite variable, such as ROW, specified in the INTO clause. Using it in select_dumpvar::send_data(). virtual bool check_assignability(THD *thd, const List<Item> &select_list, bool *assign_as_row) const; It's used to check if the select_list is compatible with a single INTO variable, in select_dumpvar::prepare(). - Fixing LEX methods create_outvar() to get identifiers a Lex_ident_sys_st values instead of generic LEX_CSTRING values. - Adding virtual methods in Type_handler: // Used in Item_func_null_predicate::check_arguments() virtual bool has_null_predicate() const; // Used in LEX::sp_variable_declarations_finalize() virtual bool sp_variable_declarations_finalize(THD *thd, LEX *lex, int nvars, const Column_definition &def) const; // Handle SELECT 1 INTO spvar; virtual my_var *make_outvar(THD *thd, const Lex_ident_sys_st &name, const sp_rcontext_addr &addr, sp_head *sphead, bool validate_only) const; // Handle SELECT 1 INTO spvar.field; virtual my_var *make_outvar_field(THD *thd, const Lex_ident_sys_st &name, const sp_rcontext_addr &addr, const Lex_ident_sys_st &field, sp_head *sphead, bool validate_only) const; // create the value in: DECLARE var rec_t DEFAULT rec_t(1,'c'); virtual Item *make_typedef_constructor_item(THD *thd, const sp_type_def &def, List<Item> *arg_list) const; - A new helper method: Row_definition_list *Row_definition_list::deep_copy(THD *thd) const;
This commit is contained in:
parent
c8f527a5dd
commit
9e13cf0862
@ -136,6 +136,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
||||
../sql/sql_schema.cc
|
||||
../sql/lex_charset.cc ../sql/charset_collations.cc
|
||||
../sql/sql_type.cc ../sql/sql_type.h
|
||||
../sql/sql_type_row.cc
|
||||
../sql/sql_mode.cc
|
||||
../sql/sql_type_string.cc
|
||||
../sql/sql_type_json.cc
|
||||
|
@ -195,6 +195,7 @@ SET (SQL_SOURCE
|
||||
opt_vcol_substitution.cc
|
||||
opt_hints_parser.cc opt_hints_parser.h scan_char.h
|
||||
opt_hints.cc opt_hints.h
|
||||
sql_type_row.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
|
||||
${GEN_SOURCES}
|
||||
|
@ -1077,6 +1077,12 @@ void Field::make_sort_key_part(uchar *buff,uint length)
|
||||
}
|
||||
|
||||
|
||||
Item_field *Field::make_item_field_spvar(THD *thd, const Spvar_definition &def)
|
||||
{
|
||||
return new (thd->mem_root) Item_field(thd, this);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@brief
|
||||
Create a packed sort key part
|
||||
|
@ -2035,6 +2035,8 @@ public:
|
||||
{
|
||||
return const_item;
|
||||
}
|
||||
virtual Item_field *make_item_field_spvar(THD *thd,
|
||||
const Spvar_definition &def);
|
||||
virtual Data_type_compatibility can_optimize_keypart_ref(
|
||||
const Item_bool_func *cond,
|
||||
const Item *item) const;
|
||||
@ -5301,6 +5303,8 @@ public:
|
||||
return m_table;
|
||||
}
|
||||
Virtual_tmp_table **virtual_tmp_table_addr() override { return &m_table; }
|
||||
Item_field *make_item_field_spvar(THD *thd,
|
||||
const Spvar_definition &def) override;
|
||||
bool row_create_fields(THD *thd, List<Spvar_definition> *list);
|
||||
bool row_create_fields(THD *thd, const Spvar_definition &def);
|
||||
bool sp_prepare_and_store_item(THD *thd, Item **value) override;
|
||||
@ -5708,6 +5712,7 @@ public:
|
||||
bool adjust_formal_params_to_actual_params(THD *thd,
|
||||
Item **args, uint arg_count);
|
||||
bool resolve_type_refs(THD *);
|
||||
Row_definition_list *deep_copy(THD *thd) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -5826,7 +5831,6 @@ public:
|
||||
m_row_field_definitions= list;
|
||||
}
|
||||
|
||||
class Item_field_row *make_item_field_row(THD *thd, Field_row *field);
|
||||
};
|
||||
|
||||
|
||||
|
@ -5834,6 +5834,17 @@ bool Item_func_null_predicate::count_sargable_conds(void *arg)
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_null_predicate::check_arguments() const
|
||||
{
|
||||
DBUG_ASSERT(arg_count == 1);
|
||||
if (args[0]->type_handler()->has_null_predicate())
|
||||
return false;
|
||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||
args[0]->type_handler()->name().ptr(), func_name());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_isnull::val_bool()
|
||||
{
|
||||
DBUG_ASSERT(fixed());
|
||||
|
@ -2824,6 +2824,7 @@ protected:
|
||||
Item_func::Functype type, Item *value) override;
|
||||
public:
|
||||
Item_func_null_predicate(THD *thd, Item *a): Item_bool_func(thd, a) { }
|
||||
bool check_arguments() const override;
|
||||
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
|
||||
table_map usable_tables, SARGABLE_PARAM **sargables)
|
||||
override;
|
||||
|
@ -75,6 +75,11 @@ bool sp_condition_value::equals(const sp_condition_value *cv) const
|
||||
}
|
||||
|
||||
|
||||
sp_type_def_list::sp_type_def_list()
|
||||
:m_type_defs(PSI_INSTRUMENT_MEM)
|
||||
{ }
|
||||
|
||||
|
||||
void sp_pcontext::init(uint var_offset,
|
||||
uint cursor_offset,
|
||||
int num_case_expressions)
|
||||
@ -94,7 +99,7 @@ sp_pcontext::sp_pcontext()
|
||||
m_parent(NULL), m_pboundary(0),
|
||||
m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM),
|
||||
m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM),
|
||||
m_handlers(PSI_INSTRUMENT_MEM), m_records(PSI_INSTRUMENT_MEM),
|
||||
m_handlers(PSI_INSTRUMENT_MEM),
|
||||
m_children(PSI_INSTRUMENT_MEM), m_scope(REGULAR_SCOPE)
|
||||
{
|
||||
init(0, 0, 0);
|
||||
@ -107,7 +112,7 @@ sp_pcontext::sp_pcontext(sp_pcontext *prev, sp_pcontext::enum_scope scope)
|
||||
m_parent(prev), m_pboundary(0),
|
||||
m_vars(PSI_INSTRUMENT_MEM), m_case_expr_ids(PSI_INSTRUMENT_MEM),
|
||||
m_conditions(PSI_INSTRUMENT_MEM), m_cursors(PSI_INSTRUMENT_MEM),
|
||||
m_handlers(PSI_INSTRUMENT_MEM), m_records(PSI_INSTRUMENT_MEM),
|
||||
m_handlers(PSI_INSTRUMENT_MEM),
|
||||
m_children(PSI_INSTRUMENT_MEM), m_scope(scope)
|
||||
{
|
||||
init(prev->m_var_offset + prev->m_max_var_index,
|
||||
@ -427,35 +432,28 @@ sp_condition_value *sp_pcontext::find_condition(const LEX_CSTRING *name,
|
||||
}
|
||||
|
||||
|
||||
bool sp_pcontext::add_record(THD *thd, const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
bool sp_type_def_list::type_defs_add_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
{
|
||||
sp_record *p= new (thd->mem_root) sp_record(name, field);
|
||||
auto p= new (thd->mem_root) sp_type_def_record(name, field);
|
||||
|
||||
if (p == NULL)
|
||||
if (p == nullptr)
|
||||
return true;
|
||||
|
||||
return m_records.append(p);
|
||||
return m_type_defs.append(p);
|
||||
}
|
||||
|
||||
|
||||
sp_record *sp_pcontext::find_record(const LEX_CSTRING *name,
|
||||
bool current_scope_only) const
|
||||
sp_type_def *sp_pcontext::find_type_def(const LEX_CSTRING &name,
|
||||
bool current_scope_only) const
|
||||
{
|
||||
size_t i= m_records.elements();
|
||||
|
||||
while (i--)
|
||||
{
|
||||
sp_record *p= m_records.at(i);
|
||||
|
||||
if (p->eq_name(name))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
auto p= sp_type_def_list::find_type_def(name);
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
return (!current_scope_only && m_parent) ?
|
||||
m_parent->find_record(name, false) :
|
||||
m_parent->find_type_def(name, false) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "sql_string.h" // LEX_STRING
|
||||
#include "field.h" // Create_field
|
||||
#include "sql_array.h" // Dynamic_array
|
||||
#include "sp_type_def.h"
|
||||
|
||||
|
||||
/// This class represents a stored program variable or a parameter
|
||||
@ -391,7 +392,8 @@ public:
|
||||
/// - for error checking (e.g. to check correct number of parameters);
|
||||
/// - to resolve SQL-handlers.
|
||||
|
||||
class sp_pcontext : public Sql_alloc
|
||||
class sp_pcontext : public Sql_alloc,
|
||||
public sp_type_def_list
|
||||
{
|
||||
public:
|
||||
enum enum_scope
|
||||
@ -752,27 +754,23 @@ public:
|
||||
return m_scope;
|
||||
}
|
||||
|
||||
sp_type_def *find_type_def(const LEX_CSTRING &name,
|
||||
bool current_scope_only) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Record.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool add_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field);
|
||||
|
||||
sp_record *find_record(const LEX_CSTRING *name,
|
||||
bool current_scope_only) const;
|
||||
|
||||
bool declare_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
bool type_defs_declare_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
{
|
||||
if (find_record(&name, true))
|
||||
if (unlikely(find_type_def(name, true)))
|
||||
{
|
||||
my_error(ER_SP_DUP_DECL, MYF(0), name.str);
|
||||
return true;
|
||||
}
|
||||
return add_record(thd, name, field);
|
||||
return type_defs_add_record(thd, name, field);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -839,9 +837,6 @@ private:
|
||||
/// Stack of SQL-handlers.
|
||||
Dynamic_array<sp_handler *> m_handlers;
|
||||
|
||||
/// Stack of records.
|
||||
Dynamic_array<sp_record *> m_records;
|
||||
|
||||
/*
|
||||
In the below example the label <<lab>> has two meanings:
|
||||
- GOTO lab : must go before the beginning of the loop
|
||||
|
@ -170,6 +170,29 @@ sp_rcontext *sp_rcontext::create(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create a deep copy.
|
||||
Used e.g. for "TYPE IS RECORD" variables.
|
||||
*/
|
||||
Row_definition_list *Row_definition_list::deep_copy(THD *thd) const
|
||||
{
|
||||
Row_definition_list *row= new (thd->mem_root) Row_definition_list();
|
||||
if (unlikely(row == NULL))
|
||||
return nullptr;
|
||||
|
||||
// Create a deep copy of the elements
|
||||
List_iterator<Spvar_definition> it(*const_cast<Row_definition_list*>(this));
|
||||
for (Spvar_definition *def= it++; def; def= it++)
|
||||
{
|
||||
Spvar_definition *new_def= new (thd->mem_root) Spvar_definition(*def);
|
||||
if (unlikely(new_def == NULL) ||
|
||||
row->push_back(new_def, thd->mem_root))
|
||||
return nullptr;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
bool Row_definition_list::append_uniq(MEM_ROOT *mem_root, Spvar_definition *var)
|
||||
{
|
||||
DBUG_ASSERT(elements);
|
||||
@ -402,25 +425,6 @@ bool Row_definition_list::resolve_type_refs(THD *thd)
|
||||
};
|
||||
|
||||
|
||||
Item_field_row *Spvar_definition::make_item_field_row(THD *thd,
|
||||
Field_row *field)
|
||||
{
|
||||
Item_field_row *item= new (thd->mem_root) Item_field_row(thd, field);
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
if (field->row_create_fields(thd, *this))
|
||||
return nullptr;
|
||||
|
||||
// field->virtual_tmp_table() returns nullptr in case of ROW TYPE OF cursor
|
||||
if (field->virtual_tmp_table() &&
|
||||
item->add_array_of_item_field(thd, *field->virtual_tmp_table()))
|
||||
return nullptr;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
bool sp_rcontext::init_var_items(THD *thd,
|
||||
List<Spvar_definition> &field_def_lst)
|
||||
{
|
||||
@ -438,10 +442,7 @@ bool sp_rcontext::init_var_items(THD *thd,
|
||||
for (uint idx= 0; idx < num_vars; ++idx, def= it++)
|
||||
{
|
||||
Field *field= m_var_table->field[idx];
|
||||
Field_row *field_row= dynamic_cast<Field_row*>(field);
|
||||
if (!(m_var_items[idx]= field_row ?
|
||||
def->make_item_field_row(thd, field_row) :
|
||||
new (thd->mem_root) Item_field(thd, field)))
|
||||
if (!(m_var_items[idx]= field->make_item_field_spvar(thd, *def)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
98
sql/sp_type_def.h
Normal file
98
sql/sp_type_def.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2025, Rakuten Securities
|
||||
Copyright (c) 2025, MariaDB plc
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; version 2 of
|
||||
the License.
|
||||
|
||||
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 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-1335 USA
|
||||
*/
|
||||
#ifndef SQL_TYPE_DEF_H
|
||||
#define SQL_TYPE_DEF_H
|
||||
|
||||
#include "sql_type.h"
|
||||
/*
|
||||
This class represents a type definition in a stored program.
|
||||
*/
|
||||
|
||||
class sp_type_def : public Sql_alloc,
|
||||
public Type_handler_hybrid_field_type
|
||||
{
|
||||
protected:
|
||||
/// Name of the type.
|
||||
Lex_ident_column m_name;
|
||||
|
||||
public:
|
||||
sp_type_def(const Lex_ident_column &name_arg, const Type_handler *th)
|
||||
:Sql_alloc(),
|
||||
Type_handler_hybrid_field_type(th),
|
||||
m_name(name_arg)
|
||||
{ }
|
||||
|
||||
bool eq_name(const LEX_CSTRING &name) const
|
||||
{
|
||||
return m_name.streq(name);
|
||||
}
|
||||
|
||||
const Lex_ident_column &get_name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
Item *make_constructor_item(THD *thd, List<Item> *args) const
|
||||
{
|
||||
return type_handler()->make_typedef_constructor_item(thd, *this, args);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
This class represents 'DECLARE RECORD' statement.
|
||||
*/
|
||||
class sp_type_def_record : public sp_type_def
|
||||
{
|
||||
public:
|
||||
Row_definition_list *field;
|
||||
|
||||
public:
|
||||
sp_type_def_record(const Lex_ident_column &name_arg,
|
||||
Row_definition_list *prmfield)
|
||||
:sp_type_def(name_arg, &type_handler_row),
|
||||
field(prmfield)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class sp_type_def_list
|
||||
{
|
||||
protected:
|
||||
/// Stack of type definitions.
|
||||
Dynamic_array<sp_type_def *> m_type_defs;
|
||||
public:
|
||||
sp_type_def_list();
|
||||
sp_type_def *find_type_def(const LEX_CSTRING &name) const
|
||||
{
|
||||
for (uint i= 0; i < m_type_defs.elements(); i++)
|
||||
{
|
||||
sp_type_def *p= m_type_defs.at(i);
|
||||
if (p->eq_name(name))
|
||||
return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool type_defs_add_record(THD *thd, const Lex_ident_column &name,
|
||||
Row_definition_list *field);
|
||||
};
|
||||
|
||||
|
||||
#endif // SQL_TYPE_DEF_H
|
@ -4110,14 +4110,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
||||
m_var_sp_row= NULL;
|
||||
|
||||
if (var_list.elements == 1 &&
|
||||
(mvsp= var_list.head()->get_my_var_sp()) &&
|
||||
mvsp->type_handler() == &type_handler_row)
|
||||
(mvsp= var_list.head()->get_my_var_sp()))
|
||||
{
|
||||
// SELECT INTO row_type_sp_variable
|
||||
if (mvsp->get_rcontext(thd->spcont)->get_variable(mvsp->offset)->cols() !=
|
||||
list.elements)
|
||||
bool assign_as_row= false;
|
||||
if (mvsp->check_assignability(thd, list, &assign_as_row))
|
||||
goto error;
|
||||
m_var_sp_row= mvsp;
|
||||
if (assign_as_row)
|
||||
m_var_sp_row= mvsp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4596,13 +4595,7 @@ sp_rcontext *my_var_sp::get_rcontext(sp_rcontext *local_ctx) const
|
||||
|
||||
bool my_var_sp::set(THD *thd, Item *item)
|
||||
{
|
||||
return get_rcontext(thd->spcont)->set_variable(thd, offset, &item);
|
||||
}
|
||||
|
||||
bool my_var_sp_row_field::set(THD *thd, Item *item)
|
||||
{
|
||||
return get_rcontext(thd->spcont)->
|
||||
set_variable_row_field(thd, offset, m_field_offset, &item);
|
||||
return get_rcontext(thd->spcont)->set_variable(thd, offset(), &item);
|
||||
}
|
||||
|
||||
|
||||
@ -4643,10 +4636,12 @@ int select_dumpvar::send_data(List<Item> &items)
|
||||
my_message(ER_TOO_MANY_ROWS, ER_THD(thd, ER_TOO_MANY_ROWS), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (m_var_sp_row ?
|
||||
m_var_sp_row->get_rcontext(thd->spcont)->
|
||||
set_variable_row(thd, m_var_sp_row->offset, items) :
|
||||
send_data_to_var_list(items))
|
||||
if (m_var_sp_row)
|
||||
{
|
||||
if (m_var_sp_row->set_row(thd, items))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (send_data_to_var_list(items))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
DBUG_RETURN(thd->is_error());
|
||||
|
@ -7538,47 +7538,53 @@ public:
|
||||
virtual my_var_sp *get_my_var_sp() { return NULL; }
|
||||
};
|
||||
|
||||
class my_var_sp: public my_var {
|
||||
const Sp_rcontext_handler *m_rcontext_handler;
|
||||
class my_var_sp: public my_var,
|
||||
public sp_rcontext_addr
|
||||
{
|
||||
const Type_handler *m_type_handler;
|
||||
public:
|
||||
uint offset;
|
||||
/*
|
||||
Routine to which this Item_splocal belongs. Used for checking if correct
|
||||
runtime context is used for variable handling.
|
||||
*/
|
||||
sp_head *sp;
|
||||
my_var_sp(const Sp_rcontext_handler *rcontext_handler,
|
||||
const LEX_CSTRING *j, uint o, const Type_handler *type_handler,
|
||||
sp_head *s)
|
||||
: my_var(j, LOCAL_VAR),
|
||||
m_rcontext_handler(rcontext_handler),
|
||||
m_type_handler(type_handler), offset(o), sp(s) { }
|
||||
my_var_sp(const Lex_ident_sys_st &name, const sp_rcontext_addr &addr,
|
||||
const Type_handler *type_handler, sp_head *s)
|
||||
: my_var(&name, LOCAL_VAR),
|
||||
sp_rcontext_addr(addr), m_type_handler(type_handler), sp(s) { }
|
||||
~my_var_sp() = default;
|
||||
bool set(THD *thd, Item *val) override;
|
||||
virtual bool set_row(THD *thd, List<Item> &select_list)
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return set(thd, select_list.head());
|
||||
}
|
||||
my_var_sp *get_my_var_sp() override { return this; }
|
||||
const Type_handler *type_handler() const
|
||||
{ return m_type_handler; }
|
||||
sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const;
|
||||
/*
|
||||
Check if the value list is compatible with the INTO variable.
|
||||
This method is called if there is only one variable in the INTO list, e.g.:
|
||||
SELECT <select list> INTO spvar_varchar; -- scalar variable
|
||||
*/
|
||||
virtual bool check_assignability(THD *thd,
|
||||
const List<Item> &select_list,
|
||||
bool *assign_as_row) const
|
||||
{
|
||||
// The ROW data type has its own my_var_sp. See sql_type_row.cc.
|
||||
DBUG_ASSERT(type_handler() != &type_handler_row);
|
||||
/*
|
||||
If the variable is not scalar (and it's also known not to be ROW),
|
||||
then it's not compatible with the select list, because Items
|
||||
in the select list can only be scalar.
|
||||
*/
|
||||
*assign_as_row= false;
|
||||
return select_list.elements != 1 ||
|
||||
!type_handler()->is_scalar_type() /*e.g. assoc array */;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
This class handles fields of a ROW SP variable when it's used as a OUT
|
||||
parameter in a stored procedure.
|
||||
*/
|
||||
class my_var_sp_row_field: public my_var_sp
|
||||
{
|
||||
uint m_field_offset;
|
||||
public:
|
||||
my_var_sp_row_field(const Sp_rcontext_handler *rcontext_handler,
|
||||
const LEX_CSTRING *varname, const LEX_CSTRING *fieldname,
|
||||
uint var_idx, uint field_idx, sp_head *s)
|
||||
:my_var_sp(rcontext_handler, varname, var_idx,
|
||||
&type_handler_double/*Not really used*/, s),
|
||||
m_field_offset(field_idx)
|
||||
{ }
|
||||
bool set(THD *thd, Item *val) override;
|
||||
};
|
||||
|
||||
class my_var_user: public my_var {
|
||||
public:
|
||||
|
142
sql/sql_lex.cc
142
sql/sql_lex.cc
@ -6903,11 +6903,9 @@ bool LEX::sp_variable_declarations_set_default(THD *thd, int nvars,
|
||||
|
||||
|
||||
bool
|
||||
LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars,
|
||||
LEX::sp_variable_declarations_copy_type_finalize_internal(THD *thd, int nvars,
|
||||
const Column_definition &ref,
|
||||
Row_definition_list *fields,
|
||||
Item *default_value,
|
||||
const LEX_CSTRING &expr_str)
|
||||
Row_definition_list *fields)
|
||||
{
|
||||
for (uint i= 0 ; i < (uint) nvars; i++)
|
||||
{
|
||||
@ -6920,7 +6918,21 @@ LEX::sp_variable_declarations_copy_type_finalize(THD *thd, int nvars,
|
||||
}
|
||||
spvar->field_def.field_name= spvar->name;
|
||||
}
|
||||
if (unlikely(sp_variable_declarations_set_default(thd, nvars,
|
||||
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,
|
||||
const LEX_CSTRING &expr_str)
|
||||
{
|
||||
if (unlikely(sp_variable_declarations_copy_type_finalize_internal(thd, nvars,
|
||||
ref,
|
||||
fields)) ||
|
||||
unlikely(sp_variable_declarations_set_default(thd, nvars,
|
||||
default_value, expr_str)))
|
||||
return true;
|
||||
spcont->declare_var_boundary(0);
|
||||
@ -6934,83 +6946,28 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
const LEX_CSTRING &expr_str)
|
||||
{
|
||||
DBUG_ASSERT(cdef);
|
||||
|
||||
if (cdef->type_handler() == &type_handler_row)
|
||||
{
|
||||
if (sp_record *sprec=
|
||||
(sp_record *)cdef->get_attr_const_void_ptr(0)) {
|
||||
return sp_variable_declarations_rec_finalize(thd, nvars,
|
||||
sprec->field,
|
||||
dflt_value_item, expr_str);
|
||||
}
|
||||
}
|
||||
|
||||
Column_definition tmp(*cdef);
|
||||
if (sphead->fill_spvar_definition(thd, &tmp))
|
||||
if (unlikely(cdef->type_handler()->sp_variable_declarations_finalize(thd,
|
||||
this,
|
||||
nvars,
|
||||
*cdef)))
|
||||
return true;
|
||||
return sp_variable_declarations_copy_type_finalize(thd, nvars, tmp, NULL,
|
||||
dflt_value_item, expr_str);
|
||||
if (unlikely(sp_variable_declarations_set_default(thd, nvars,
|
||||
dflt_value_item, expr_str)))
|
||||
return true;
|
||||
spcont->declare_var_boundary(0);
|
||||
return sphead->restore_lex(thd);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::sp_variable_declarations_rec_finalize(THD *thd, int nvars,
|
||||
Row_definition_list *src_row,
|
||||
Item *dflt_value_item,
|
||||
const LEX_CSTRING &expr_str)
|
||||
{
|
||||
DBUG_ASSERT(src_row);
|
||||
|
||||
// Create a copy of the row definition list to fill
|
||||
// definitions
|
||||
Row_definition_list *row= new (thd->mem_root) Row_definition_list();
|
||||
if (unlikely(row == NULL))
|
||||
return true;
|
||||
|
||||
// Create a deep copy of the elements
|
||||
List_iterator<Spvar_definition> it(*src_row);
|
||||
for (Spvar_definition *def= it++; def; def= it++)
|
||||
{
|
||||
Spvar_definition *new_def= new (thd->mem_root) Spvar_definition(*def);
|
||||
if (unlikely(new_def == NULL))
|
||||
return true;
|
||||
|
||||
row->push_back(new_def, thd->mem_root);
|
||||
}
|
||||
|
||||
return sp_variable_declarations_row_finalize(thd, nvars, row,
|
||||
dflt_value_item, expr_str);
|
||||
}
|
||||
|
||||
bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars,
|
||||
Row_definition_list *row,
|
||||
Item *dflt_value_item,
|
||||
const LEX_CSTRING &expr_str)
|
||||
{
|
||||
DBUG_ASSERT(row);
|
||||
/*
|
||||
Prepare all row fields.
|
||||
Note, we do it only one time outside of the below loop.
|
||||
The converted list in "row" is further reused by all variable
|
||||
declarations processed by the current call.
|
||||
Example:
|
||||
DECLARE
|
||||
a, b, c ROW(x VARCHAR(10) CHARACTER SET utf8);
|
||||
BEGIN
|
||||
...
|
||||
END;
|
||||
*/
|
||||
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);
|
||||
spvar->field_def.set_row_field_definitions(row);
|
||||
if (sphead->fill_spvar_definition(thd, &spvar->field_def, &spvar->name))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sp_variable_declarations_set_default(thd, nvars, dflt_value_item,
|
||||
if (Type_handler_row::sp_variable_declarations_row_finalize(thd, this,
|
||||
nvars,
|
||||
row) ||
|
||||
sp_variable_declarations_set_default(thd, nvars, dflt_value_item,
|
||||
expr_str))
|
||||
return true;
|
||||
spcont->declare_var_boundary(0);
|
||||
@ -8760,38 +8717,39 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
my_var *LEX::create_outvar(THD *thd, const LEX_CSTRING *name)
|
||||
my_var *LEX::create_outvar(THD *thd,const Lex_ident_sys_st &name)
|
||||
{
|
||||
const Sp_rcontext_handler *rh;
|
||||
sp_variable *spv;
|
||||
if (likely((spv= find_variable(name, &rh))))
|
||||
return result ? new (thd->mem_root)
|
||||
my_var_sp(rh, name, spv->offset,
|
||||
spv->type_handler(), sphead) :
|
||||
NULL /* EXPLAIN */;
|
||||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), name->str);
|
||||
return NULL;
|
||||
if (unlikely(!(spv= find_variable(&name, &rh))))
|
||||
{
|
||||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
|
||||
return NULL;
|
||||
}
|
||||
const sp_rcontext_addr addr(rh, spv->offset);
|
||||
my_var *var= spv->type_handler()->make_outvar(thd, name, addr,
|
||||
sphead, !result);
|
||||
DBUG_ASSERT(var || thd->is_error() || !result);
|
||||
return var;
|
||||
}
|
||||
|
||||
|
||||
my_var *LEX::create_outvar(THD *thd,
|
||||
const LEX_CSTRING *a,
|
||||
const LEX_CSTRING *b)
|
||||
const Lex_ident_sys_st &a,
|
||||
const Lex_ident_sys_st &b)
|
||||
{
|
||||
const Sp_rcontext_handler *rh;
|
||||
sp_variable *t;
|
||||
if (unlikely(!(t= find_variable(a, &rh))))
|
||||
if (unlikely(!(t= find_variable(&a, &rh))))
|
||||
{
|
||||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), a->str);
|
||||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), a.str);
|
||||
return NULL;
|
||||
}
|
||||
uint row_field_offset;
|
||||
if (!t->find_row_field(a, b, &row_field_offset))
|
||||
return NULL;
|
||||
return result ?
|
||||
new (thd->mem_root) my_var_sp_row_field(rh, a, b, t->offset,
|
||||
row_field_offset, sphead) :
|
||||
NULL /* EXPLAIN */;
|
||||
const sp_rcontext_addr addr(rh, t->offset);
|
||||
my_var *var= t->type_handler()->make_outvar_field(thd, a, addr, b,
|
||||
sphead, !result);
|
||||
DBUG_ASSERT(var || thd->is_error() || !result);
|
||||
return var;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3977,6 +3977,11 @@ public:
|
||||
const LEX_CSTRING &name,
|
||||
Item *def,
|
||||
const LEX_CSTRING &expr_str);
|
||||
protected:
|
||||
bool sp_variable_declarations_copy_type_finalize_internal(THD *thd, int nvars,
|
||||
const Column_definition &ref,
|
||||
Row_definition_list *fields);
|
||||
public:
|
||||
bool sp_variable_declarations_copy_type_finalize(THD *thd, int nvars,
|
||||
const Column_definition &ref,
|
||||
Row_definition_list *fields,
|
||||
@ -4269,7 +4274,7 @@ public:
|
||||
Item *make_item_func_call_native_or_parse_error(THD *thd,
|
||||
Lex_ident_cli_st &name,
|
||||
List<Item> *args);
|
||||
my_var *create_outvar(THD *thd, const LEX_CSTRING *name);
|
||||
my_var *create_outvar(THD *thd, const Lex_ident_sys_st &name);
|
||||
|
||||
/*
|
||||
Create a my_var instance for a ROW field variable that was used
|
||||
@ -4279,8 +4284,8 @@ public:
|
||||
@param field_name - the variable field name
|
||||
*/
|
||||
my_var *create_outvar(THD *thd,
|
||||
const LEX_CSTRING *var_name,
|
||||
const LEX_CSTRING *field_name);
|
||||
const Lex_ident_sys_st &var_name,
|
||||
const Lex_ident_sys_st &field_name);
|
||||
|
||||
bool is_trigger_new_or_old_reference(const LEX_CSTRING *name) const;
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "log.h"
|
||||
#include "tztime.h"
|
||||
#include <mysql/plugin_data_type.h>
|
||||
#include "sp_type_def.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
|
||||
const DTCollation &DTCollation_numeric::singleton()
|
||||
@ -2773,6 +2775,27 @@ Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool
|
||||
Type_handler::sp_variable_declarations_finalize(THD *thd,
|
||||
LEX *lex, int nvars,
|
||||
const Column_definition &cdef)
|
||||
const
|
||||
{
|
||||
Column_definition tmp(cdef);
|
||||
if (lex->sphead->fill_spvar_definition(thd, &tmp))
|
||||
return true;
|
||||
|
||||
for (uint i= 0 ; i < (uint) nvars; i++)
|
||||
{
|
||||
uint offset= (uint) nvars - 1 - i;
|
||||
sp_variable *spvar= lex->spcont->get_last_context_variable(offset);
|
||||
spvar->field_def.set_type(tmp);
|
||||
spvar->field_def.field_name= spvar->name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler::
|
||||
Column_definition_validate_check_constraint(THD *thd,
|
||||
Column_definition * c) const
|
||||
@ -3647,6 +3670,35 @@ uint Type_handler_blob_common::calc_key_length(const Column_definition &def) con
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
// SELECT 1 INTO spvar;
|
||||
my_var *Type_handler::make_outvar(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const
|
||||
{
|
||||
if (validate_only) // e.g. EXPLAIN SELECT
|
||||
return nullptr;
|
||||
return new (thd->mem_root) my_var_sp(name, addr, this, sphead);
|
||||
}
|
||||
|
||||
|
||||
// SELECT 1 INTO spvar.field;
|
||||
my_var *Type_handler::make_outvar_field(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
const Lex_ident_sys_st &field,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const
|
||||
{
|
||||
my_printf_error(ER_UNKNOWN_ERROR,
|
||||
"'%s' is not a row variable", MYF(0), name.str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
|
||||
const LEX_CSTRING *name,
|
||||
@ -4907,19 +4959,6 @@ bool Type_handler_timestamp_common::
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_row::
|
||||
Item_hybrid_func_fix_attributes(THD *thd,
|
||||
const LEX_CSTRING &opname,
|
||||
Type_handler_hybrid_field_type *,
|
||||
Type_all_attributes *atrr,
|
||||
Item **items, uint nitems)
|
||||
const
|
||||
{
|
||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||
name().ptr(), opname.str);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
bool Type_handler::
|
||||
@ -9874,3 +9913,12 @@ int initialize_data_type_plugin(void *plugin_)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Item *Type_handler::make_typedef_constructor_item(THD *thd,
|
||||
const sp_type_def &def,
|
||||
List<Item> *arg_list) const
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), def.get_name().str);
|
||||
return nullptr;
|
||||
}
|
||||
|
423
sql/sql_type.h
423
sql/sql_type.h
@ -19,6 +19,7 @@
|
||||
|
||||
#include "mysqld.h"
|
||||
#include "lex_string.h"
|
||||
#include "lex_ident_sys.h"
|
||||
#include "sql_type_timeofday.h"
|
||||
#include "sql_array.h"
|
||||
#include "sql_const.h"
|
||||
@ -97,6 +98,9 @@ class Conv_source;
|
||||
class ST_FIELD_INFO;
|
||||
class Type_collection;
|
||||
class Create_func;
|
||||
class sp_type_def;
|
||||
class sp_head;
|
||||
class my_var;
|
||||
|
||||
#define my_charset_numeric my_charset_latin1
|
||||
|
||||
@ -4181,6 +4185,7 @@ public:
|
||||
virtual bool can_return_extract_source(interval_type type) const;
|
||||
virtual bool is_bool_type() const { return false; }
|
||||
virtual bool is_general_purpose_string_type() const { return false; }
|
||||
virtual bool has_null_predicate() const { return true; }
|
||||
virtual decimal_digits_t Item_time_precision(THD *thd, Item *item) const;
|
||||
virtual decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const;
|
||||
virtual decimal_digits_t Item_decimal_scale(const Item *item) const;
|
||||
@ -4322,6 +4327,10 @@ public:
|
||||
virtual bool Column_definition_prepare_stage2(Column_definition *c,
|
||||
handler *file,
|
||||
ulonglong table_flags) const= 0;
|
||||
virtual bool sp_variable_declarations_finalize(THD *thd,
|
||||
LEX *lex, int nvars,
|
||||
const Column_definition &def)
|
||||
const;
|
||||
virtual bool Key_part_spec_init_primary(Key_part_spec *part,
|
||||
const Column_definition &def,
|
||||
const handler *file) const;
|
||||
@ -4373,6 +4382,33 @@ public:
|
||||
const Bit_addr &bit,
|
||||
const Column_definition_attributes *attr,
|
||||
uint32 flags) const= 0;
|
||||
/*
|
||||
Make a my_var to handle:
|
||||
SELECT 1 INTO spvar;
|
||||
@param thd - Current thd
|
||||
@param name - The variable name
|
||||
@param addr - The variable run-time address
|
||||
@param sphead - The sphead containing the variable
|
||||
@param validate_only - Do not make my_var, only raise an SQL error
|
||||
if the variable is not used correctly.
|
||||
This is needed for EXPLAIN SELECT statements.
|
||||
@returns - A pointer to a new my_var instance.
|
||||
nullptr if "validate_only" was passed.
|
||||
nullptr if the variable is not used correcly
|
||||
(an SQL error is raised in this case).
|
||||
*/
|
||||
virtual my_var *make_outvar(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const;
|
||||
// SELECT 1 INTO spvar.field;
|
||||
virtual my_var *make_outvar_field(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
const Lex_ident_sys_st &field,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const;
|
||||
virtual void
|
||||
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
|
||||
uchar *buff) const;
|
||||
@ -4543,6 +4579,9 @@ public:
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
virtual Item *make_typedef_constructor_item(THD *thd,
|
||||
const sp_type_def &def,
|
||||
List<Item> *arg_list) const;
|
||||
|
||||
/**
|
||||
normalize_cond() replaces
|
||||
@ -4742,389 +4781,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Special handler for ROW
|
||||
*/
|
||||
class Type_handler_row: public Type_handler
|
||||
{
|
||||
public:
|
||||
virtual ~Type_handler_row() = default;
|
||||
const Name &default_value() const override;
|
||||
bool validate_implicit_default_value(THD *, const Column_definition &)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
const Type_collection *type_collection() const override;
|
||||
bool is_scalar_type() const override { return false; }
|
||||
bool can_return_int() const override { return false; }
|
||||
bool can_return_decimal() const override { return false; }
|
||||
bool can_return_real() const override { return false; }
|
||||
bool can_return_str() const override { return false; }
|
||||
bool can_return_text() const override { return false; }
|
||||
bool can_return_date() const override { return false; }
|
||||
bool can_return_time() const override { return false; }
|
||||
enum_field_types field_type() const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return MYSQL_TYPE_NULL;
|
||||
};
|
||||
protocol_send_type_t protocol_send_type() const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return PROTOCOL_SEND_STRING;
|
||||
}
|
||||
Item_result result_type() const override
|
||||
{
|
||||
return ROW_RESULT;
|
||||
}
|
||||
Item_result cmp_type() const override
|
||||
{
|
||||
return ROW_RESULT;
|
||||
}
|
||||
enum_dynamic_column_type dyncol_type(const Type_all_attributes *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return DYN_COL_NULL;
|
||||
}
|
||||
const Type_handler *type_handler_for_comparison() const override;
|
||||
int stored_field_cmp_to_item(THD *, Field *, Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool Column_definition_fix_attributes(Column_definition *) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void Column_definition_reuse_fix_attributes(THD *, Column_definition *,
|
||||
const Field *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
bool Column_definition_prepare_stage1(THD *thd,
|
||||
MEM_ROOT *mem_root,
|
||||
Column_definition *c,
|
||||
column_definition_type_t type,
|
||||
const Column_derived_attributes
|
||||
*derived_attr)
|
||||
const override;
|
||||
bool Column_definition_redefine_stage1(Column_definition *,
|
||||
const Column_definition *,
|
||||
const handler *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Column_definition_prepare_stage2(Column_definition *, handler *,
|
||||
ulonglong) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Spvar_definition_with_complex_data_types(Spvar_definition *def)
|
||||
const override;
|
||||
|
||||
Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &,
|
||||
const Type_all_attributes &, TABLE_SHARE *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
Field *make_table_field_from_def(TABLE_SHARE *share,
|
||||
MEM_ROOT *mem_root,
|
||||
const LEX_CSTRING *name,
|
||||
const Record_addr &addr,
|
||||
const Bit_addr &bit,
|
||||
const Column_definition_attributes *attr,
|
||||
uint32 flags) const override;
|
||||
void make_sort_key_part(uchar *to, Item *item,
|
||||
const SORT_FIELD_ATTR *sort_field,
|
||||
String *tmp) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
uint make_packed_sort_key_part(uchar *, Item *, const SORT_FIELD_ATTR *,
|
||||
String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
void sort_length(THD *, const Type_std_attributes *, SORT_FIELD_ATTR *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
uint32 max_display_length(const Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
uint32 max_display_length_for_field(const Conv_source &) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
uint32 calc_pack_length(uint32) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
|
||||
Item *a, Item *b) const override;
|
||||
decimal_digits_t Item_decimal_precision(const Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return DECIMAL_MAX_PRECISION;
|
||||
}
|
||||
bool Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
||||
override;
|
||||
bool Item_param_set_from_value(THD *thd,
|
||||
Item_param *param,
|
||||
const Type_all_attributes *attr,
|
||||
const st_value *value) const override;
|
||||
bool Item_send(Item *, Protocol *, st_value *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
void Item_update_null_value(Item *item) const override;
|
||||
int Item_save_in_field(Item *, Field *, bool) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
||||
bool can_change_cond_ref_to_const(Item_bool_func2 *, Item *, Item *,
|
||||
Item_bool_func2 *, Item *, Item *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
||||
override;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
||||
Item_copy *create_item_copy(THD *, Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override;
|
||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||
const LEX_CSTRING &name,
|
||||
Type_handler_hybrid_field_type *,
|
||||
Type_all_attributes *atrr,
|
||||
Item **items, uint nitems)
|
||||
const override;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_val_bool(Item *item) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
void Item_get_date(THD *, Item *, Temporal::Warn *, MYSQL_TIME *ltime,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||
}
|
||||
longlong Item_val_int_signed_typecast(Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
longlong Item_val_int_unsigned_typecast(Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
String *Item_func_hex_val_str_ascii(Item_func_hex *, String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
|
||||
String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0.0;
|
||||
}
|
||||
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
my_decimal *Item_func_hybrid_field_type_val_decimal(
|
||||
Item_func_hybrid_field_type *,
|
||||
my_decimal *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
void Item_func_hybrid_field_type_get_date(THD *,
|
||||
Item_func_hybrid_field_type *,
|
||||
Temporal::Warn *,
|
||||
MYSQL_TIME *ltime,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||
}
|
||||
|
||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
double Item_func_min_max_val_real(Item_func_min_max *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
longlong Item_func_min_max_val_int(Item_func_min_max *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||
my_decimal *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool Item_func_min_max_get_date(THD *, Item_func_min_max*, MYSQL_TIME *,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_func_between_fix_length_and_dec(Item_func_between *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
longlong Item_func_between_val_int(Item_func_between *func) const override;
|
||||
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
|
||||
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const
|
||||
override;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const
|
||||
override;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
|
||||
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const
|
||||
override;
|
||||
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
|
||||
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
|
||||
|
||||
bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
|
||||
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
|
||||
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
|
||||
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
|
||||
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
|
||||
};
|
||||
#include "sql_type_row.h"
|
||||
|
||||
|
||||
/*
|
||||
|
223
sql/sql_type_row.cc
Normal file
223
sql/sql_type_row.cc
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
Copyright (c) 2025, Rakuten Securities
|
||||
Copyright (c) 2015, 2025, MariaDB plc
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; version 2 of
|
||||
the License.
|
||||
|
||||
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 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-1335 USA
|
||||
*/
|
||||
#include "sql_type.h"
|
||||
#include "sql_type_row.h"
|
||||
#include "item.h"
|
||||
#include "sql_select.h"
|
||||
#include "field.h"
|
||||
#include "sp_rcontext.h"
|
||||
#include "sp_type_def.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
|
||||
bool Type_handler_row::
|
||||
sp_variable_declarations_row_finalize(THD *thd, LEX *lex, int nvars,
|
||||
Row_definition_list *row)
|
||||
{
|
||||
DBUG_ASSERT(row);
|
||||
/*
|
||||
Prepare all row fields.
|
||||
Note, we do it only one time outside of the below loop.
|
||||
The converted list in "row" is further reused by all variable
|
||||
declarations processed by the current call.
|
||||
Example:
|
||||
DECLARE
|
||||
a, b, c ROW(x VARCHAR(10) CHARACTER SET utf8);
|
||||
BEGIN
|
||||
...
|
||||
END;
|
||||
*/
|
||||
if (lex->sphead->row_fill_field_definitions(thd, row))
|
||||
return true;
|
||||
|
||||
for (uint i= 0 ; i < (uint) nvars ; i++)
|
||||
{
|
||||
uint offset= (uint) nvars - 1 - i;
|
||||
sp_variable *spvar= lex->spcont->get_last_context_variable(offset);
|
||||
spvar->field_def.set_row_field_definitions(row);
|
||||
if (lex->sphead->fill_spvar_definition(thd, &spvar->field_def,
|
||||
&spvar->name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class my_var_sp_row: public my_var_sp
|
||||
{
|
||||
public:
|
||||
my_var_sp_row(const Lex_ident_sys_st &name, const sp_rcontext_addr &addr,
|
||||
sp_head *s)
|
||||
:my_var_sp(name, addr, &type_handler_row, s)
|
||||
{ }
|
||||
bool check_assignability(THD *thd, const List<Item> &select_list,
|
||||
bool *assign_as_row) const override
|
||||
{
|
||||
Item_field *item= get_rcontext(thd->spcont)->get_variable(offset());
|
||||
const Field_row *field= dynamic_cast<const Field_row*>(item->field);
|
||||
DBUG_ASSERT(field);
|
||||
*assign_as_row= true;
|
||||
return !field ||
|
||||
select_list.elements != field->virtual_tmp_table()->s->fields;
|
||||
}
|
||||
bool set_row(THD *thd, List<Item> &select_list) override
|
||||
{
|
||||
return get_rcontext(thd->spcont)->set_variable_row(thd, offset(),
|
||||
select_list);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
This class handles fields of a ROW SP variable when it's used as a OUT
|
||||
parameter in a stored procedure.
|
||||
*/
|
||||
class my_var_sp_row_field: public my_var_sp
|
||||
{
|
||||
uint m_field_offset;
|
||||
public:
|
||||
my_var_sp_row_field(const Lex_ident_sys_st &varname,
|
||||
const sp_rcontext_addr &varaddr,
|
||||
uint field_idx, sp_head *s)
|
||||
:my_var_sp(varname, varaddr,
|
||||
&type_handler_double/*Not really used*/, s),
|
||||
m_field_offset(field_idx)
|
||||
{ }
|
||||
bool check_assignability(THD *thd, const List<Item> &select_list,
|
||||
bool *assign_as_row) const override
|
||||
{
|
||||
*assign_as_row= false;
|
||||
return select_list.elements == 1;
|
||||
}
|
||||
bool set(THD *thd, Item *item) override
|
||||
{
|
||||
return get_rcontext(thd->spcont)->
|
||||
set_variable_row_field(thd, offset(), m_field_offset, &item);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
my_var *Type_handler_row::make_outvar(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const
|
||||
{
|
||||
if (validate_only) // e.g. EXPLAIN SELECT .. INTO spvar_row;
|
||||
return nullptr;
|
||||
return new (thd->mem_root) my_var_sp_row(name, addr, sphead);
|
||||
}
|
||||
|
||||
|
||||
my_var *Type_handler_row::make_outvar_field(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
const Lex_ident_sys_st &field,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const
|
||||
{
|
||||
const Sp_rcontext_handler *rh;
|
||||
sp_variable *t= thd->lex->find_variable(&name, &rh);
|
||||
DBUG_ASSERT(t);
|
||||
DBUG_ASSERT(t->type_handler() == this);
|
||||
|
||||
uint row_field_offset;
|
||||
if (!t->find_row_field(&name, &field, &row_field_offset))
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0), name.str, field.str);
|
||||
return NULL;
|
||||
}
|
||||
if (validate_only) // e.g. EXPLAIN SELECT .. INTO spvar_row.field;
|
||||
return nullptr;
|
||||
return new (thd->mem_root) my_var_sp_row_field(name, addr, row_field_offset,
|
||||
sphead);
|
||||
}
|
||||
|
||||
|
||||
Item_field *Field_row::make_item_field_spvar(THD *thd,
|
||||
const Spvar_definition &def)
|
||||
{
|
||||
Item_field_row *item= new (thd->mem_root) Item_field_row(thd, this);
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
if (row_create_fields(thd, def))
|
||||
return nullptr;
|
||||
|
||||
// virtual_tmp_table() returns nullptr in case of ROW TYPE OF cursor
|
||||
if (virtual_tmp_table() &&
|
||||
item->add_array_of_item_field(thd, *virtual_tmp_table()))
|
||||
return nullptr;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Type_handler_row::
|
||||
sp_variable_declarations_finalize(THD *thd, LEX *lex, int nvars,
|
||||
const Column_definition &cdef) const
|
||||
{
|
||||
const sp_type_def_record *rec= static_cast<const sp_type_def_record*>
|
||||
(cdef.get_attr_const_void_ptr(0));
|
||||
DBUG_ASSERT(!rec || rec->field);
|
||||
if (!rec || !rec->field)
|
||||
{
|
||||
// A variable with an explicit ROW data type
|
||||
return Type_handler::sp_variable_declarations_finalize(thd, lex,
|
||||
nvars, cdef);
|
||||
}
|
||||
|
||||
// TYPE row_t IS RECORD
|
||||
Row_definition_list *row= rec->field->deep_copy(thd);
|
||||
return row == nullptr ||
|
||||
Type_handler_row::sp_variable_declarations_row_finalize(thd,
|
||||
lex,
|
||||
nvars,
|
||||
row);
|
||||
}
|
||||
|
||||
|
||||
Item *Type_handler_row::make_typedef_constructor_item(THD *thd,
|
||||
const sp_type_def &def,
|
||||
List<Item> *args) const
|
||||
{
|
||||
if (unlikely(args == nullptr))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), def.get_name().str);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new (thd->mem_root) Item_row(thd, *args);
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_row::
|
||||
Item_hybrid_func_fix_attributes(THD *thd,
|
||||
const LEX_CSTRING &opname,
|
||||
Type_handler_hybrid_field_type *,
|
||||
Type_all_attributes *atrr,
|
||||
Item **items, uint nitems)
|
||||
const
|
||||
{
|
||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||
name().ptr(), opname.str);
|
||||
return true;
|
||||
}
|
434
sql/sql_type_row.h
Normal file
434
sql/sql_type_row.h
Normal file
@ -0,0 +1,434 @@
|
||||
/*
|
||||
Copyright (c) 2025, Rakuten Securities
|
||||
Copyright (c) 2025, MariaDB plc
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; version 2 of
|
||||
the License.
|
||||
|
||||
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 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-1335 USA
|
||||
*/
|
||||
#ifndef SQL_TYPE_ROW_INCLUDED
|
||||
#define SQL_TYPE_ROW_INCLUDED
|
||||
|
||||
|
||||
class Row_definition_list;
|
||||
|
||||
/*
|
||||
Special handler for ROW
|
||||
*/
|
||||
class Type_handler_row: public Type_handler
|
||||
{
|
||||
public:
|
||||
static bool sp_variable_declarations_row_finalize(THD *thd, LEX *lex,
|
||||
int nvars,
|
||||
Row_definition_list *row);
|
||||
public:
|
||||
virtual ~Type_handler_row() = default;
|
||||
const Name &default_value() const override;
|
||||
bool validate_implicit_default_value(THD *, const Column_definition &)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
const Type_collection *type_collection() const override;
|
||||
bool is_scalar_type() const override { return false; }
|
||||
bool can_return_int() const override { return false; }
|
||||
bool can_return_decimal() const override { return false; }
|
||||
bool can_return_real() const override { return false; }
|
||||
bool can_return_str() const override { return false; }
|
||||
bool can_return_text() const override { return false; }
|
||||
bool can_return_date() const override { return false; }
|
||||
bool can_return_time() const override { return false; }
|
||||
enum_field_types field_type() const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return MYSQL_TYPE_NULL;
|
||||
};
|
||||
protocol_send_type_t protocol_send_type() const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return PROTOCOL_SEND_STRING;
|
||||
}
|
||||
Item_result result_type() const override
|
||||
{
|
||||
return ROW_RESULT;
|
||||
}
|
||||
Item_result cmp_type() const override
|
||||
{
|
||||
return ROW_RESULT;
|
||||
}
|
||||
enum_dynamic_column_type dyncol_type(const Type_all_attributes *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return DYN_COL_NULL;
|
||||
}
|
||||
const Type_handler *type_handler_for_comparison() const override;
|
||||
bool has_null_predicate() const override { return false; }
|
||||
int stored_field_cmp_to_item(THD *, Field *, Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool Column_definition_fix_attributes(Column_definition *) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void Column_definition_reuse_fix_attributes(THD *, Column_definition *,
|
||||
const Field *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
bool Column_definition_prepare_stage1(THD *thd,
|
||||
MEM_ROOT *mem_root,
|
||||
Column_definition *c,
|
||||
column_definition_type_t type,
|
||||
const Column_derived_attributes
|
||||
*derived_attr)
|
||||
const override;
|
||||
bool Column_definition_redefine_stage1(Column_definition *,
|
||||
const Column_definition *,
|
||||
const handler *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Column_definition_prepare_stage2(Column_definition *, handler *,
|
||||
ulonglong) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Spvar_definition_with_complex_data_types(Spvar_definition *def)
|
||||
const override;
|
||||
bool sp_variable_declarations_finalize(THD *thd,
|
||||
LEX *lex, int nvars,
|
||||
const Column_definition &def)
|
||||
const override;
|
||||
|
||||
Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &,
|
||||
const Type_all_attributes &, TABLE_SHARE *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
Field *make_table_field_from_def(TABLE_SHARE *share,
|
||||
MEM_ROOT *mem_root,
|
||||
const LEX_CSTRING *name,
|
||||
const Record_addr &addr,
|
||||
const Bit_addr &bit,
|
||||
const Column_definition_attributes *attr,
|
||||
uint32 flags) const override;
|
||||
void make_sort_key_part(uchar *to, Item *item,
|
||||
const SORT_FIELD_ATTR *sort_field,
|
||||
String *tmp) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
uint make_packed_sort_key_part(uchar *, Item *, const SORT_FIELD_ATTR *,
|
||||
String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
void sort_length(THD *, const Type_std_attributes *, SORT_FIELD_ATTR *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
}
|
||||
uint32 max_display_length(const Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
uint32 max_display_length_for_field(const Conv_source &) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
uint32 calc_pack_length(uint32) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
|
||||
Item *a, Item *b) const override;
|
||||
decimal_digits_t Item_decimal_precision(const Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return DECIMAL_MAX_PRECISION;
|
||||
}
|
||||
bool Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
||||
override;
|
||||
bool Item_param_set_from_value(THD *thd,
|
||||
Item_param *param,
|
||||
const Type_all_attributes *attr,
|
||||
const st_value *value) const override;
|
||||
bool Item_send(Item *, Protocol *, st_value *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
void Item_update_null_value(Item *item) const override;
|
||||
int Item_save_in_field(Item *, Field *, bool) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
// SELECT 1,2,3 INTO spvar_row;
|
||||
my_var *make_outvar(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const override;
|
||||
// SELECT 1 INTO spvar_row.field;
|
||||
virtual my_var *make_outvar_field(THD *thd,
|
||||
const Lex_ident_sys_st &name,
|
||||
const sp_rcontext_addr &addr,
|
||||
const Lex_ident_sys_st &field,
|
||||
sp_head *sphead,
|
||||
bool validate_only) const override;
|
||||
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
||||
bool can_change_cond_ref_to_const(Item_bool_func2 *, Item *, Item *,
|
||||
Item_bool_func2 *, Item *, Item *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
||||
override;
|
||||
Item *make_typedef_constructor_item(THD *thd, const sp_type_def &def,
|
||||
List<Item> *arg_list) const override;
|
||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
||||
Item_copy *create_item_copy(THD *, Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override;
|
||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||
const LEX_CSTRING &name,
|
||||
Type_handler_hybrid_field_type *,
|
||||
Type_all_attributes *atrr,
|
||||
Item **items, uint nitems)
|
||||
const override;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_val_bool(Item *item) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
void Item_get_date(THD *, Item *, Temporal::Warn *, MYSQL_TIME *ltime,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||
}
|
||||
longlong Item_val_int_signed_typecast(Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
longlong Item_val_int_unsigned_typecast(Item *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
String *Item_func_hex_val_str_ascii(Item_func_hex *, String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
|
||||
String *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0.0;
|
||||
}
|
||||
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
my_decimal *Item_func_hybrid_field_type_val_decimal(
|
||||
Item_func_hybrid_field_type *,
|
||||
my_decimal *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
void Item_func_hybrid_field_type_get_date(THD *,
|
||||
Item_func_hybrid_field_type *,
|
||||
Temporal::Warn *,
|
||||
MYSQL_TIME *ltime,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||
}
|
||||
|
||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
double Item_func_min_max_val_real(Item_func_min_max *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
longlong Item_func_min_max_val_int(Item_func_min_max *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||
my_decimal *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
bool Item_func_min_max_get_date(THD *, Item_func_min_max*, MYSQL_TIME *,
|
||||
date_mode_t) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_func_between_fix_length_and_dec(Item_func_between *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
longlong Item_func_between_val_int(Item_func_between *func) const override;
|
||||
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
|
||||
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const
|
||||
override;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const
|
||||
override;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
|
||||
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const
|
||||
override;
|
||||
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
|
||||
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
|
||||
|
||||
bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
|
||||
override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
|
||||
const override
|
||||
{
|
||||
MY_ASSERT_UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
|
||||
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
|
||||
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
|
||||
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
|
||||
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
|
||||
};
|
||||
|
||||
|
||||
#endif /* SQL_TYPE_ROW_INCLUDED */
|
@ -290,7 +290,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
|
||||
class sp_head *sphead;
|
||||
class sp_name *spname;
|
||||
class sp_variable *spvar;
|
||||
class sp_record *sprec;
|
||||
class sp_type_def_record *sprec;
|
||||
class With_element_head *with_element_head;
|
||||
class With_clause *with_clause;
|
||||
class Virtual_column_info *virtual_column;
|
||||
@ -1340,7 +1340,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
|
||||
%type <ident_sys>
|
||||
IDENT_sys
|
||||
ident_func
|
||||
ident
|
||||
label_ident
|
||||
sp_decl_ident
|
||||
@ -6483,9 +6482,9 @@ field_type_all_with_record:
|
||||
}
|
||||
| udt_name float_options srid_option
|
||||
{
|
||||
sp_record *sprec = NULL;
|
||||
sp_type_def *sprec = NULL;
|
||||
if (Lex->spcont)
|
||||
sprec = Lex->spcont->find_record(&$1, false);
|
||||
sprec = Lex->spcont->find_type_def($1, false);
|
||||
|
||||
if (sprec == NULL)
|
||||
{
|
||||
@ -10933,13 +10932,15 @@ function_call_conflict:
|
||||
in sql/item_create.cc
|
||||
*/
|
||||
function_call_generic:
|
||||
ident_func '('
|
||||
ident_cli_func '('
|
||||
{
|
||||
#ifdef HAVE_DLOPEN
|
||||
udf_func *udf= 0;
|
||||
LEX *lex= Lex;
|
||||
Lex_ident_sys ident(thd, &$1);
|
||||
|
||||
if (using_udf_functions &&
|
||||
(udf= find_udf($1.str, $1.length)) &&
|
||||
(udf= find_udf(ident.str, ident.length)) &&
|
||||
udf->type == UDFTYPE_AGGREGATE)
|
||||
{
|
||||
if (unlikely(lex->current_select->inc_in_sum_expr()))
|
||||
@ -10957,9 +10958,11 @@ function_call_generic:
|
||||
const Type_handler *h;
|
||||
Create_func *builder;
|
||||
Item *item= NULL;
|
||||
sp_record* rec= NULL;
|
||||
const sp_type_def *tdef= NULL;
|
||||
const Lex_ident_sys ident(thd, &$1);
|
||||
|
||||
if (unlikely(Lex_ident_routine::check_name_with_error($1)))
|
||||
if (unlikely(ident.is_null() ||
|
||||
Lex_ident_routine::check_name_with_error(ident)))
|
||||
MYSQL_YYABORT;
|
||||
|
||||
/*
|
||||
@ -10973,20 +10976,20 @@ function_call_generic:
|
||||
This will be revised with WL#2128 (SQL PATH)
|
||||
*/
|
||||
builder= Schema::find_implied(thd)->
|
||||
find_native_function_builder(thd, $1);
|
||||
find_native_function_builder(thd, ident);
|
||||
if (builder)
|
||||
{
|
||||
item= builder->create_func(thd, &$1, $4);
|
||||
item= builder->create_func(thd, &ident, $4);
|
||||
}
|
||||
else if ((h= Type_handler::handler_by_name(thd, $1)) &&
|
||||
else if ((h= Type_handler::handler_by_name(thd, ident)) &&
|
||||
(item= h->make_constructor_item(thd, $4)))
|
||||
{
|
||||
// Found a constructor with a proper argument count
|
||||
}
|
||||
else if (Lex->spcont &&
|
||||
(rec = Lex->spcont->find_record(&$1, false)))
|
||||
(tdef= Lex->spcont->find_type_def(ident, false)))
|
||||
{
|
||||
item= new (thd->mem_root) Item_row(thd, *$4);
|
||||
item= tdef->make_constructor_item(thd, $4);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -11008,7 +11011,7 @@ function_call_generic:
|
||||
{
|
||||
builder= find_qualified_function_builder(thd);
|
||||
DBUG_ASSERT(builder);
|
||||
item= builder->create_func(thd, &$1, $4);
|
||||
item= builder->create_func(thd, &ident, $4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13346,12 +13349,13 @@ select_outvar:
|
||||
}
|
||||
| ident_or_text
|
||||
{
|
||||
if (unlikely(!($$= Lex->create_outvar(thd, &$1)) && Lex->result))
|
||||
const Lex_ident_sys name(thd, &$1);
|
||||
if (unlikely(!($$= Lex->create_outvar(thd, name)) && Lex->result))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| ident '.' ident
|
||||
{
|
||||
if (unlikely(!($$= Lex->create_outvar(thd, &$1, &$3)) && Lex->result))
|
||||
if (unlikely(!($$= Lex->create_outvar(thd, $1, $3)) && Lex->result))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
@ -16027,15 +16031,6 @@ ident_cli_func:
|
||||
| keyword_func_sp_var_not_label { $$= $1; }
|
||||
;
|
||||
|
||||
ident_func:
|
||||
ident_cli_func
|
||||
{
|
||||
if (unlikely(thd->to_ident_sys_alloc(&$$, &$1)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
TEXT_STRING_sys:
|
||||
TEXT_STRING
|
||||
{
|
||||
@ -20200,7 +20195,7 @@ sp_decl_non_handler:
|
||||
| TYPE_SYM ident_directly_assignable IS RECORD_SYM rec_type_body
|
||||
{
|
||||
if (unlikely(Lex->spcont->
|
||||
declare_record(thd, Lex_ident_column($2), $5)))
|
||||
type_defs_declare_record(thd, Lex_ident_column($2), $5)))
|
||||
MYSQL_YYABORT;
|
||||
|
||||
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user