Commit 4025cfae authored by Alexander Barkov's avatar Alexander Barkov

MDEV-15416 Crash when reading I_S.PARAMETERS

parent 5f7c764f
......@@ -524,3 +524,105 @@ SPECIFIC_CATALOG SPECIFIC_SCHEMA SPECIFIC_NAME ORDINAL_POSITION PARAMETER_MODE P
def i_s_parameters_test test_func5 0 NULL NULL varchar 30 90 NULL NULL NULL utf8 utf8_general_ci varchar(30) FUNCTION
def i_s_parameters_test test_func5 1 IN s char 20 60 NULL NULL NULL utf8 utf8_general_ci char(20) FUNCTION
DROP DATABASE i_s_parameters_test;
USE test;
#
# Start of 10.3 tests
#
#
# MDEV-15416 Crash when reading I_S.PARAMETERS
#
CREATE PROCEDURE p1(a0 TYPE OF t1.a,
a1 TYPE OF test.t1.a,
b0 ROW TYPE OF t1,
b1 ROW TYPE OF test.t1,
c ROW(a INT,b DOUBLE))
BEGIN
END;
$$
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME = 'p1';
SPECIFIC_CATALOG def
SPECIFIC_SCHEMA test
SPECIFIC_NAME p1
ORDINAL_POSITION 1
PARAMETER_MODE IN
PARAMETER_NAME a0
DATA_TYPE TYPE OF
CHARACTER_MAXIMUM_LENGTH NULL
CHARACTER_OCTET_LENGTH NULL
NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL
DATETIME_PRECISION NULL
CHARACTER_SET_NAME NULL
COLLATION_NAME NULL
DTD_IDENTIFIER TYPE OF `t1`.`a`
ROUTINE_TYPE PROCEDURE
-------- --------
SPECIFIC_CATALOG def
SPECIFIC_SCHEMA test
SPECIFIC_NAME p1
ORDINAL_POSITION 2
PARAMETER_MODE IN
PARAMETER_NAME a1
DATA_TYPE TYPE OF
CHARACTER_MAXIMUM_LENGTH NULL
CHARACTER_OCTET_LENGTH NULL
NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL
DATETIME_PRECISION NULL
CHARACTER_SET_NAME NULL
COLLATION_NAME NULL
DTD_IDENTIFIER TYPE OF `test`.`t1`.`a`
ROUTINE_TYPE PROCEDURE
-------- --------
SPECIFIC_CATALOG def
SPECIFIC_SCHEMA test
SPECIFIC_NAME p1
ORDINAL_POSITION 3
PARAMETER_MODE IN
PARAMETER_NAME b0
DATA_TYPE ROW TYPE OF
CHARACTER_MAXIMUM_LENGTH NULL
CHARACTER_OCTET_LENGTH NULL
NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL
DATETIME_PRECISION NULL
CHARACTER_SET_NAME NULL
COLLATION_NAME NULL
DTD_IDENTIFIER ROW TYPE OF `t1`
ROUTINE_TYPE PROCEDURE
-------- --------
SPECIFIC_CATALOG def
SPECIFIC_SCHEMA test
SPECIFIC_NAME p1
ORDINAL_POSITION 4
PARAMETER_MODE IN
PARAMETER_NAME b1
DATA_TYPE ROW TYPE OF
CHARACTER_MAXIMUM_LENGTH NULL
CHARACTER_OCTET_LENGTH NULL
NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL
DATETIME_PRECISION NULL
CHARACTER_SET_NAME NULL
COLLATION_NAME NULL
DTD_IDENTIFIER ROW TYPE OF `test`.`t1`
ROUTINE_TYPE PROCEDURE
-------- --------
SPECIFIC_CATALOG def
SPECIFIC_SCHEMA test
SPECIFIC_NAME p1
ORDINAL_POSITION 5
PARAMETER_MODE IN
PARAMETER_NAME c
DATA_TYPE ROW
CHARACTER_MAXIMUM_LENGTH NULL
CHARACTER_OCTET_LENGTH NULL
NUMERIC_PRECISION NULL
NUMERIC_SCALE NULL
DATETIME_PRECISION NULL
CHARACTER_SET_NAME NULL
COLLATION_NAME NULL
DTD_IDENTIFIER ROW
ROUTINE_TYPE PROCEDURE
-------- --------
DROP PROCEDURE p1;
--echo #
--echo # MDEV-15416 Crash when reading I_S.PARAMETERS
--echo #
--echo # Create in sql_mode=ORACLE, display in sql_mode=ORACLE and sql_mode=DEFAULT
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE PROCEDURE p1(a0 t1.a%TYPE,
a1 test.t1.a%TYPE,
b0 t1%ROWTYPE,
b1 test.t1%ROWTYPE,
d ROW(a INT,b DOUBLE))
AS
BEGIN
NULL;
END;
$$
DELIMITER ;$$
--vertical_results
SET sql_mode=ORACLE;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1';
SET sql_mode=DEFAULT;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1';
--horizontal_results
DROP PROCEDURE p1;
SET sql_mode=ORACLE;
DELIMITER $$;
CREATE FUNCTION f1(a0 t1.a%TYPE,
a1 test.t1.a%TYPE,
b0 t1%ROWTYPE,
b1 test.t1%ROWTYPE,
d ROW(a INT,b DOUBLE))
RETURN INT
AS
BEGIN
RETURN 0;
END;
$$
DELIMITER ;$$
--vertical_results
SET sql_mode=ORACLE;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1';
SET sql_mode=DEFAULT;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1';
--horizontal_results
DROP FUNCTION f1;
--echo # Create in sql_mode=DEFAULT, display in sql_mode=DEFAULT and sql_mode=ORACLE
SET sql_mode=DEFAULT;
DELIMITER $$;
CREATE PROCEDURE p1(a0 TYPE OF t1.a,
a1 TYPE OF test.t1.a,
b0 ROW TYPE OF t1,
b1 ROW TYPE OF test.t1,
d ROW(a INT,b DOUBLE))
BEGIN
END;
$$
DELIMITER ;$$
--vertical_results
SET sql_mode=DEFAULT;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1';
SET sql_mode=ORACLE;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='p1';
--horizontal_results
DROP PROCEDURE p1;
SET sql_mode=DEFAULT;
DELIMITER $$;
CREATE FUNCTION f1(a0 TYPE OF t1.a,
a1 TYPE OF test.t1.a,
b0 ROW TYPE OF t1,
b1 ROW TYPE OF test.t1,
d ROW(a INT,b DOUBLE))
RETURNS INT
BEGIN
RETURN 0;
END;
$$
DELIMITER ;$$
--vertical_results
SET sql_mode=DEFAULT;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1';
SET sql_mode=ORACLE;
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME='f1';
--horizontal_results
DROP FUNCTION f1;
......@@ -249,3 +249,28 @@ WHERE SPECIFIC_SCHEMA = 'i_s_parameters_test' AND SPECIFIC_NAME = 'test_func5';
# Cleanup
DROP DATABASE i_s_parameters_test;
USE test;
--echo #
--echo # Start of 10.3 tests
--echo #
--echo #
--echo # MDEV-15416 Crash when reading I_S.PARAMETERS
--echo #
DELIMITER $$;
CREATE PROCEDURE p1(a0 TYPE OF t1.a,
a1 TYPE OF test.t1.a,
b0 ROW TYPE OF t1,
b1 ROW TYPE OF test.t1,
c ROW(a INT,b DOUBLE))
BEGIN
END;
$$
DELIMITER ;$$
--vertical_results
SELECT *, '--------' FROM INFORMATION_SCHEMA.PARAMETERS WHERE SPECIFIC_NAME = 'p1';
--horizontal_results
DROP PROCEDURE p1;
......@@ -4169,6 +4169,12 @@ class Spvar_definition: public Column_definition
bool is_column_type_ref() const { return m_column_type_ref != 0; }
bool is_table_rowtype_ref() const { return m_table_rowtype_ref != 0; }
bool is_cursor_rowtype_ref() const { return m_cursor_rowtype_ref; }
bool is_explicit_data_type() const
{
return !is_column_type_ref() &&
!is_table_rowtype_ref() &&
!is_cursor_rowtype_ref();
}
class Qualified_column_ident *column_type_ref() const
{
return m_column_type_ref;
......
......@@ -2962,7 +2962,7 @@ Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
defstr.set_charset(creation_ctx->get_client_cs());
if (show_create_sp(thd, &defstr,
sp_name_obj.m_db, sp_name_obj.m_name,
params, returns, empty_body_lex_cstring(),
params, returns, empty_body_lex_cstring(sql_mode),
Sp_chistics(), definer, DDL_options(), sql_mode))
return 0;
......@@ -2976,3 +2976,18 @@ Sp_handler::sp_load_for_information_schema(THD *thd, TABLE *proc_table,
return sp;
}
LEX_CSTRING Sp_handler_procedure::empty_body_lex_cstring(sql_mode_t mode) const
{
static LEX_CSTRING m_empty_body_std= {C_STRING_WITH_LEN("BEGIN END")};
static LEX_CSTRING m_empty_body_ora= {C_STRING_WITH_LEN("AS BEGIN NULL; END")};
return mode & MODE_ORACLE ? m_empty_body_ora : m_empty_body_std;
}
LEX_CSTRING Sp_handler_function::empty_body_lex_cstring(sql_mode_t mode) const
{
static LEX_CSTRING m_empty_body_std= {C_STRING_WITH_LEN("RETURN NULL")};
static LEX_CSTRING m_empty_body_ora= {C_STRING_WITH_LEN("AS BEGIN RETURN NULL; END")};
return mode & MODE_ORACLE ? m_empty_body_ora : m_empty_body_std;
}
......@@ -146,7 +146,7 @@ class Sp_handler
}
virtual stored_procedure_type type() const= 0;
virtual LEX_CSTRING type_lex_cstring() const= 0;
virtual LEX_CSTRING empty_body_lex_cstring() const
virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("???")};
DBUG_ASSERT(0);
......@@ -244,11 +244,7 @@ class Sp_handler_procedure: public Sp_handler
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PROCEDURE")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
}
LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
const char *show_create_routine_col1_caption() const
{
return "Procedure";
......@@ -298,11 +294,7 @@ class Sp_handler_function: public Sp_handler
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("FUNCTION")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("RETURN NULL")};
return m_empty_body;
}
LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
const char *show_create_routine_col1_caption() const
{
return "Function";
......@@ -371,7 +363,7 @@ class Sp_handler_package_spec: public Sp_handler_package
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PACKAGE")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
......@@ -404,7 +396,7 @@ class Sp_handler_package_body: public Sp_handler_package
static LEX_CSTRING m_type_str= {C_STRING_WITH_LEN("PACKAGE BODY")};
return m_type_str;
}
LEX_CSTRING empty_body_lex_cstring() const
LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
{
static LEX_CSTRING m_empty_body= {C_STRING_WITH_LEN("BEGIN END")};
return m_empty_body;
......
......@@ -58,6 +58,7 @@
#include "sp_head.h"
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_show.h" // append_identifier
#include "transaction.h"
#include "sql_select.h" /* declares create_tmp_table() */
#include "debug_sync.h"
......@@ -7626,4 +7627,20 @@ void Database_qualified_name::copy(MEM_ROOT *mem_root,
}
bool Table_ident::append_to(THD *thd, String *str) const
{
return (db.length &&
(append_identifier(thd, str, db.str, db.length) ||
str->append('.'))) ||
append_identifier(thd, str, table.str, table.length);
}
bool Qualified_column_ident::append_to(THD *thd, String *str) const
{
return Table_ident::append_to(thd, str) || str->append('.') ||
append_identifier(thd, str, m_column.str, m_column.length);
}
#endif /* !defined(MYSQL_CLIENT) */
......@@ -5607,6 +5607,7 @@ class Table_ident :public Sql_alloc
db= *db_name;
}
bool resolve_table_rowtype_ref(THD *thd, Row_definition_list &defs);
bool append_to(THD *thd, String *to) const;
};
......@@ -5631,6 +5632,7 @@ class Qualified_column_ident: public Table_ident
m_column(*column)
{ }
bool resolve_type_ref(THD *thd, Column_definition *def);
bool append_to(THD *thd, String *to) const;
};
......
......@@ -5677,6 +5677,118 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
}
/*
Print DATA_TYPE independently from sql_mode.
It's only a brief human-readable description, without attributes,
so it should not be used by client programs to generate SQL scripts.
*/
static bool print_anchor_data_type(const Spvar_definition *def,
String *data_type)
{
if (def->column_type_ref())
return data_type->append(STRING_WITH_LEN("TYPE OF"));
if (def->is_table_rowtype_ref())
return data_type->append(STRING_WITH_LEN("ROW TYPE OF"));
/*
"ROW TYPE OF cursor" is not possible yet.
May become possible when we add package-wide cursors.
*/
DBUG_ASSERT(0);
return false;
}
/*
DTD_IDENTIFIER is the full data type description with attributes.
It can be used by client programs to generate SQL scripts.
Let's print it according to the current sql_mode.
It will make output in line with the value in mysql.proc.param_list,
so both I_S.XXX.DTD_IDENTIFIER and mysql.proc.param_list use the same notation:
default or Oracle, according to the sql_mode at the SP creation time.
The caller must make sure to set thd->variables.sql_mode to the routine sql_mode.
*/
static bool print_anchor_dtd_identifier(THD *thd, const Spvar_definition *def,
String *dtd_identifier)
{
if (def->column_type_ref())
return (thd->variables.sql_mode & MODE_ORACLE) ?
def->column_type_ref()->append_to(thd, dtd_identifier) ||
dtd_identifier->append(STRING_WITH_LEN("%TYPE")) :
dtd_identifier->append(STRING_WITH_LEN("TYPE OF ")) ||
def->column_type_ref()->append_to(thd, dtd_identifier);
if (def->is_table_rowtype_ref())
return (thd->variables.sql_mode & MODE_ORACLE) ?
def->table_rowtype_ref()->append_to(thd, dtd_identifier) ||
dtd_identifier->append(STRING_WITH_LEN("%ROWTYPE")) :
dtd_identifier->append(STRING_WITH_LEN("ROW TYPE OF ")) ||
def->table_rowtype_ref()->append_to(thd, dtd_identifier);
DBUG_ASSERT(0); // See comments in print_anchor_data_type()
return false;
}
/*
Set columns DATA_TYPE and DTD_IDENTIFIER from an SP variable definition
*/
static void store_variable_type(THD *thd, const sp_variable *spvar,
TABLE *tmptbl,
TABLE_SHARE *tmpshare,
CHARSET_INFO *cs,
TABLE *table, uint offset)
{
if (spvar->field_def.is_explicit_data_type())
{
if (spvar->field_def.is_row())
{
// Explicit ROW
table->field[offset]->store(STRING_WITH_LEN("ROW"), cs);
table->field[offset]->set_notnull();
// Perhaps eventually we need to print all ROW elements in DTD_IDENTIFIER
table->field[offset + 8]->store(STRING_WITH_LEN("ROW"), cs);
table->field[offset + 8]->set_notnull();
}
else
{
// Explicit scalar data type
Field *field= spvar->field_def.make_field(tmpshare, thd->mem_root,
&spvar->name);
field->table= tmptbl;
tmptbl->in_use= thd;
store_column_type(table, field, cs, offset);
}
}
else
{
StringBuffer<128> data_type(cs), dtd_identifier(cs);
if (print_anchor_data_type(&spvar->field_def, &data_type))
{
table->field[offset]->store(STRING_WITH_LEN("ERROR"), cs); // EOM?
table->field[offset]->set_notnull();
}
else
{
DBUG_ASSERT(data_type.length());
table->field[offset]->store(data_type.ptr(), data_type.length(), cs);
table->field[offset]->set_notnull();
}
if (print_anchor_dtd_identifier(thd, &spvar->field_def, &dtd_identifier))
{
table->field[offset + 8]->store(STRING_WITH_LEN("ERROR"), cs); // EOM?
table->field[offset + 8]->set_notnull();
}
else
{
DBUG_ASSERT(dtd_identifier.length());
table->field[offset + 8]->store(dtd_identifier.ptr(),
dtd_identifier.length(), cs);
table->field[offset + 8]->set_notnull();
}
}
}
static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
TABLE *table, bool res,
const LEX_CSTRING *db_name,
......@@ -6032,6 +6144,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
const Sp_handler *sph;
bool free_sp_head;
bool error= 0;
sql_mode_t sql_mode;
DBUG_ENTER("store_schema_params");
bzero((char*) &tbl, sizeof(TABLE));
......@@ -6041,6 +6154,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_DB]->val_str_nopad(thd->mem_root, &db);
proc_table->field[MYSQL_PROC_FIELD_NAME]->val_str_nopad(thd->mem_root, &name);
proc_table->field[MYSQL_PROC_FIELD_DEFINER]->val_str_nopad(thd->mem_root, &definer);
sql_mode= (sql_mode_t) proc_table->field[MYSQL_PROC_FIELD_SQL_MODE]->val_int();
sph= Sp_handler::handler((stored_procedure_type) proc_table->field[MYSQL_PROC_MYSQL_TYPE]->val_int());
if (!sph)
sph= &sp_handler_procedure;
......@@ -6057,15 +6171,15 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
proc_table->field[MYSQL_PROC_FIELD_RETURNS]->val_str_nopad(thd->mem_root,
&returns);
sp= sph->sp_load_for_information_schema(thd, proc_table, db, name,
params, returns,
(ulong) proc_table->
field[MYSQL_PROC_FIELD_SQL_MODE]->
val_int(),
params, returns, sql_mode,
&free_sp_head);
if (sp)
{
Field *field;
LEX_CSTRING tmp_string;
Sql_mode_save sql_mode_backup(thd);
thd->variables.sql_mode= sql_mode;
if (sph->type() == TYPE_ENUM_FUNCTION)
{
restore_record(table, s->default_values);
......@@ -6124,11 +6238,7 @@ bool store_schema_params(THD *thd, TABLE *table, TABLE *proc_table,
&tmp_string);
table->field[15]->store(tmp_string, cs);
field= spvar->field_def.make_field(&share, thd->mem_root,
&spvar->name);
field->table= &tbl;
tbl.in_use= thd;
store_column_type(table, field, cs, 6);
store_variable_type(thd, spvar, &tbl, &share, cs, table, 6);
if (schema_table_store_record(thd, table))
{
error= 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment