maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #10898
Re: MDEV-10596
Hi Jerome,
Thank you very much for your contribution!
On 09/12/2017 04:42 PM, jerome brauge wrote:
> Hi Alexander,
> In sql_mode=oracle, when a stored procedure varchar parameter is defined without size, you have chosen to translate it by VARCHAR(4000) (or CHAR(2000) for CHAR parameter).
> Oracle does not work like this. Size is inherited from the size of argument at runtime.
<cut>
Your patch looks very good.
I have minor improvement suggestions, to make the code more future-proof.
Please find my comments below:
<cut>
> diff --git a/mysql-test/suite/compat/oracle/t/sp-param.test b/mysql-test/suite/compat/oracle/t/sp-param.test
> index 2320331..be929cb 100644
> --- a/mysql-test/suite/compat/oracle/t/sp-param.test
> +++ b/mysql-test/suite/compat/oracle/t/sp-param.test
<cut>
> +--error ER_DATA_TOO_LONG
> +declare str varchar(6000);
> + pout varchar(4000);
> +begin
> + str:=lpad('x',6000,'y');
> + call p1(pout,str);
> + select length(pout);
> +end;
> +/
> +drop procedure p1
> +/
> \ No newline at end of file
Please add a new line.
<cut>
> diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
> index d98f800..6531046 100644
> --- a/sql/sp_pcontext.cc
> +++ b/sql/sp_pcontext.cc
> @@ -95,7 +95,8 @@ sp_pcontext::sp_pcontext()
> : Sql_alloc(),
> m_max_var_index(0), m_max_cursor_index(0),
> m_parent(NULL), m_pboundary(0),
> - m_scope(REGULAR_SCOPE)
> + m_scope(REGULAR_SCOPE),
> + m_dyn_varchar_param(false)
> {
> init(0, 0, 0);
> }
> diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
> index 215ebbe..776bd10 100644
> --- a/sql/sp_pcontext.h
> +++ b/sql/sp_pcontext.h
> @@ -692,6 +692,12 @@ class sp_pcontext : public Sql_alloc
> return m_for_loop;
> }
>
> + void set_dyn_char_param()
> + { m_dyn_varchar_param= true; }
> +
> + bool use_dyn_char_param() const
> + { return m_dyn_varchar_param; }
> +
> private:
> /// Constructor for a tree node.
> /// @param prev the parent parsing context
> @@ -786,6 +792,8 @@ class sp_pcontext : public Sql_alloc
>
> /// FOR LOOP characteristics
> Lex_for_loop m_for_loop;
> +
> + bool m_dyn_varchar_param;
> }; // class sp_pcontext : public Sql_alloc
>
>
> diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
> index 8c598e8..3e449cd 100644
> --- a/sql/sp_rcontext.cc
> +++ b/sql/sp_rcontext.cc
> @@ -63,7 +63,8 @@ sp_rcontext::~sp_rcontext()
> sp_rcontext *sp_rcontext::create(THD *thd,
> const sp_pcontext *root_parsing_ctx,
> Field *return_value_fld,
> - bool resolve_type_refs)
> + bool resolve_type_refs,
> + List<Item> *args)
> {
> sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
> return_value_fld,
> @@ -75,6 +76,34 @@ sp_rcontext *sp_rcontext::create(THD *thd,
> List<Spvar_definition> field_def_lst;
> ctx->m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
>
> + if (ctx->m_root_parsing_ctx->use_dyn_char_param() && args)
> + {
> + List_iterator<Spvar_definition> it(field_def_lst);
> + List_iterator<Item> it_args(*args);
> + DBUG_ASSERT(field_def_lst.elements >= args->elements );
> + Spvar_definition *def;
> + Item *arg;
> + uint arg_max_length;
> + /*
> + If length is not specified for varchar arguments, set length to the
> + maximum length of the real argument. Goals are:
> + -- avoid to allocate too much inused memory for m_var_table
> + -- allow length check inside the callee rather than during copy of
> + returned values in output variables.
> + -- allow varchar parameter size greater than 4000
> + Default length has been stored in "decimal" member during parse.
> + */
> + while ((def= it++) && (arg= it_args++))
> + {
> + if (def->type_handler() == &type_handler_varchar && def->decimals)
> + {
> + arg_max_length= arg->max_char_length();
> + def->length= arg_max_length > 0 ? arg_max_length : def->decimals;
> + def->create_length_to_internal_length_string();
> + }
> + }
> + }
I'd like to make the code more symmetric across data types.
It's very likely that we'll want some more
formal-param-to-actual-param-adjustment in the future.
Can you please move this code into a new virtual method in Type_handler?
Something like this:
virtual bool adjust_spparam_type(Spvar_definition *def, Item *from) const
{
return false;
}
and override it for VARCHAR:
/*
If length is not specified for a varchar parameter, set length to the
maximum length of the actual argument. Goals are:
- avoid to allocate too much unused memory for m_var_table
- allow length check inside the callee rather than during copy of
returned values in output variables.
- allow varchar parameter size greater than 4000
Default length has been stored in "decimal" member during parse.
*/
bool Type_handler_varchar::adjust_spparam_type(Spvar_definition *def,
Item *param) const
{
if (def->decimals)
{
arg_max_length= param->max_char_length();
def->length= arg_max_length > 0 ? arg_max_length : def->decimals;
def->create_length_to_internal_length_string();
}
return false;
}
Also, move the loop code into a new methods in sp_rcontext,
e.g. like this:
bool sp_rcontext::adjust_formal_params_to_actual_params(THD *thd,
List<Spvar_definition> &field_def_lst,
List<Item> *args)
{
List_iterator<Spvar_definition> it(field_def_lst);
List_iterator<Item> it_args(*args);
DBUG_ASSERT(field_def_lst.elements >= args->elements );
Spvar_definition *def;
Item *arg;
uint arg_max_length;
while ((def= it++) && (arg= it_args++))
{
if (def->type_handler()->adjust_spparam_type(def, arg))
true;
}
return false;
}
and call it from sp_rcontext::create() as follows:
if (adjust_formal_params_to_actual_params(thd, args))
return NULL.
No needs to test for ctx->m_root_parsing_ctx->use_dyn_char_param().
Just do it always unconditionally.
Please also remove:
sp_rcontext::set_dyn_char_param()
sp_rcontext::use_dyn_char_param()
sp_rcontext::m_dyn_varchar_param;
Btw, why did you add it?
Is it to safe on populating List<Item> ?
If so, then we can just pass arguments as follows;
sp_rcontext::create(THD *thd,
const sp_pcontext *root_parsing_ctx,
Field *return_value_fld,
bool resolve_type_refs)
bool resolve_type_refs,
Item **args, uint arg_count);
and:
bool sp_rcontext::adjust_formal_params_to_actual_params(THD *thd,
List<Spvar_definition>
&field_def_lst,
Item **args,
uint arg_count);
<cut>
> diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
> index 97a55df..8e8a016 100644
> --- a/sql/sql_yacc_ora.yy
> +++ b/sql/sql_yacc_ora.yy
<cut>
> @@ -6565,17 +6567,20 @@ opt_field_length_default_1:
> the maximum possible length in characters in case of mbmaxlen=4
> (e.g. utf32, utf16, utf8mb4). However, we'll have character sets with
> mbmaxlen=5 soon (e.g. gb18030).
> -
> - Let's translate VARCHAR to VARCHAR(4000), which covert all possible Oracle
> - values.
> */
> opt_field_length_default_sp_param_varchar:
> - /* empty */ { $$= (char*) "4000"; }
> - | field_length { $$= $1; }
> + /* empty */ {
> + $$.set("4000", "4000");
> + Lex->spcont->set_dyn_char_param();
> + }
> + | field_length { $$.set($1, NULL); }
Please follow our coding style for *.yy.
A multi-line code block corresponding to the "empty" rule should
go under the comment "/* empty */", like this:
opt_field_length_default_sp_param_varchar:
/* empty */
{
$$.set("4000", "4000");
Lex->spcont->set_dyn_char_param();
}
| field_length { $$.set($1, NULL); }
But if we don't need set_dyn_char_param(),
the above will be simplified to:
opt_field_length_default_sp_param_varchar:
/* empty */ { $$.set("4000", "4000"); }
| field_length { $$.set($1, NULL); }
It's ok to put single-line code blocks to the right.
>
> opt_field_length_default_sp_param_char:
> - /* empty */ { $$= (char*) "2000"; }
> - | field_length { $$= $1; }
> + /* empty */ {
> + $$.set("2000", "2000");
> + Lex->spcont->set_dyn_char_param();
> + }
> + | field_length { $$.set($1, NULL); }
Same here.
>
> opt_precision:
> /* empty */ { $$.set(0, 0); }
Thanks!
Follow ups
References