← Back to team overview

maria-developers team mailing list archive

Re: MDEV-10596

 

Hi Alexander,
I just need a  confirmation on remove test on use_dyn_char_param().

This test avoid unnecessary  loop on parameters at runtime in sql_mode=default or when all varchar parameter size are specified in sql_mode=oracle (I agree, it's not really Oracle compliant, but it's a useful feature).
Do you really want I remove it  ? 

Thank you very much.


> -----Message d'origine-----
> De : Alexander Barkov [mailto:bar@xxxxxxxxxxx]
> Envoyé : mercredi 27 septembre 2017 09:38
> À : jerome brauge
> Cc : MariaDB Developers (maria-developers@xxxxxxxxxxxxxxxxxxx)
> Objet : 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