Skip to content

Commit f44d5de

Browse files
author
halfspawn
committed
MDEV-13919 sql_mode=ORACLE: Derive length of VARCHAR SP parameters with no length from actual parameters
1 parent d387bc8 commit f44d5de

File tree

9 files changed

+251
-21
lines changed

9 files changed

+251
-21
lines changed

mysql-test/suite/compat/oracle/r/sp-param.result

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,89 @@ t1 CREATE TABLE "t1" (
130130
)
131131
DROP TABLE t1;
132132
DROP FUNCTION f1;
133+
134+
MDEV-13919 sql_mode=ORACLE: Derive length of VARCHAR SP parameters with no length from actual parameters
135+
136+
set sql_mode= 'oracle,strict_trans_tables';
137+
CREATE OR REPLACE PROCEDURE p1(pinout INOUT varchar, pin IN varchar)
138+
AS
139+
BEGIN
140+
pinout:=pin;
141+
END;
142+
/
143+
call p1(@w,'0123456789')
144+
/
145+
declare w varchar(10);
146+
begin
147+
call p1(w,'0123456789');
148+
end;
149+
/
150+
declare w varchar(5);
151+
begin
152+
call p1(w,'0123456789');
153+
end;
154+
/
155+
ERROR 22001: Data too long for column 'pinout' at row 1
156+
declare w varchar(20);
157+
begin
158+
w:='aaa';
159+
call p1(w,'0123456789');
160+
end;
161+
/
162+
declare w varchar(8);
163+
begin
164+
w:='aaa';
165+
call p1(w,'0123456789');
166+
end;
167+
/
168+
ERROR 22001: Data too long for column 'pinout' at row 1
169+
declare str varchar(6000);
170+
pout varchar(6000);
171+
begin
172+
str:=lpad('x',6000,'y');
173+
call p1(pout,str);
174+
select length(pout);
175+
end;
176+
/
177+
length(pout)
178+
6000
179+
declare str varchar(6000);
180+
pout varchar(4000);
181+
begin
182+
str:=lpad('x',6000,'y');
183+
call p1(pout,str);
184+
select length(pout);
185+
end;
186+
/
187+
ERROR 22001: Data too long for column 'pinout' at row 1
188+
declare str varchar(40000);
189+
pout varchar(60000);
190+
begin
191+
str:=lpad('x',40000,'y');
192+
call p1(pout,str);
193+
select length(pout);
194+
end;
195+
/
196+
length(pout)
197+
40000
198+
declare str text(80000);
199+
pout text(80000);
200+
begin
201+
str:=lpad('x',80000,'y');
202+
call p1(pout,str);
203+
select length(pout);
204+
end;
205+
/
206+
ERROR 22001: Data too long for column 'pin' at row 1
207+
declare str text(80000);
208+
pout text(80000);
209+
begin
210+
str:=lpad('x',60000,'y');
211+
call p1(pout,str);
212+
select length(pout);
213+
end;
214+
/
215+
length(pout)
216+
60000
217+
drop procedure p1
218+
/

mysql-test/suite/compat/oracle/t/sp-param.test

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,85 @@ SET sql_mode=ORACLE;
3535
--let type = RAW
3636
--let length = 4000
3737
--source sp-param.inc
38+
39+
--echo
40+
--echo MDEV-13919 sql_mode=ORACLE: Derive length of VARCHAR SP parameters with no length from actual parameters
41+
--echo
42+
set sql_mode= 'oracle,strict_trans_tables';
43+
delimiter /;
44+
CREATE OR REPLACE PROCEDURE p1(pinout INOUT varchar, pin IN varchar)
45+
AS
46+
BEGIN
47+
pinout:=pin;
48+
END;
49+
/
50+
call p1(@w,'0123456789')
51+
/
52+
declare w varchar(10);
53+
begin
54+
call p1(w,'0123456789');
55+
end;
56+
/
57+
--error ER_DATA_TOO_LONG
58+
declare w varchar(5);
59+
begin
60+
call p1(w,'0123456789');
61+
end;
62+
/
63+
declare w varchar(20);
64+
begin
65+
w:='aaa';
66+
call p1(w,'0123456789');
67+
end;
68+
/
69+
--error ER_DATA_TOO_LONG
70+
declare w varchar(8);
71+
begin
72+
w:='aaa';
73+
call p1(w,'0123456789');
74+
end;
75+
/
76+
declare str varchar(6000);
77+
pout varchar(6000);
78+
begin
79+
str:=lpad('x',6000,'y');
80+
call p1(pout,str);
81+
select length(pout);
82+
end;
83+
/
84+
--error ER_DATA_TOO_LONG
85+
declare str varchar(6000);
86+
pout varchar(4000);
87+
begin
88+
str:=lpad('x',6000,'y');
89+
call p1(pout,str);
90+
select length(pout);
91+
end;
92+
/
93+
declare str varchar(40000);
94+
pout varchar(60000);
95+
begin
96+
str:=lpad('x',40000,'y');
97+
call p1(pout,str);
98+
select length(pout);
99+
end;
100+
/
101+
--error ER_DATA_TOO_LONG
102+
declare str text(80000);
103+
pout text(80000);
104+
begin
105+
str:=lpad('x',80000,'y');
106+
call p1(pout,str);
107+
select length(pout);
108+
end;
109+
/
110+
declare str text(80000);
111+
pout text(80000);
112+
begin
113+
str:=lpad('x',60000,'y');
114+
call p1(pout,str);
115+
select length(pout);
116+
end;
117+
/
118+
drop procedure p1
119+
/

sql/sp_head.cc

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,8 @@ bool sp_head::check_execute_access(THD *thd) const
14391439
@retval NULL - error (access denided or EOM)
14401440
@retval !NULL - success (the invoker has rights to all %TYPE tables)
14411441
*/
1442-
sp_rcontext *sp_head::rcontext_create(THD *thd, Field *ret_value)
1442+
sp_rcontext *sp_head::rcontext_create(THD *thd, Field *ret_value,
1443+
List<Item> *args)
14431444
{
14441445
bool has_column_type_refs= m_flags & HAS_COLUMN_TYPE_REFS;
14451446
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1449,7 +1450,7 @@ sp_rcontext *sp_head::rcontext_create(THD *thd, Field *ret_value)
14491450
return NULL;
14501451
#endif
14511452
sp_rcontext *res= sp_rcontext::create(thd, m_pcont, ret_value,
1452-
has_column_type_refs);
1453+
has_column_type_refs, args);
14531454
#ifndef NO_EMBEDDED_ACCESS_CHECKS
14541455
if (has_column_type_refs)
14551456
m_security_ctx.restore_security_context(thd, save_security_ctx);
@@ -1556,7 +1557,7 @@ sp_head::execute_trigger(THD *thd,
15561557
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
15571558

15581559
if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL,
1559-
m_flags & HAS_COLUMN_TYPE_REFS)))
1560+
m_flags & HAS_COLUMN_TYPE_REFS, NULL)))
15601561
{
15611562
err_status= TRUE;
15621563
goto err_with_cleanup;
@@ -1637,6 +1638,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
16371638
MEM_ROOT call_mem_root;
16381639
Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
16391640
Query_arena backup_arena;
1641+
List<Item> largs;
16401642
DBUG_ENTER("sp_head::execute_function");
16411643
DBUG_PRINT("info", ("function %s", m_name.str));
16421644

@@ -1671,7 +1673,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
16711673
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
16721674
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
16731675

1674-
if (!(nctx= rcontext_create(thd, return_value_fld)))
1676+
for (uint i= 0 ; i < argcount ; i++)
1677+
{
1678+
largs.push_back(argp[i]);
1679+
}
1680+
1681+
if (!(nctx= rcontext_create(thd, return_value_fld, &largs)))
16751682
{
16761683
thd->restore_active_arena(&call_arena, &backup_arena);
16771684
err_status= TRUE;
@@ -1886,7 +1893,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
18861893
if (! octx)
18871894
{
18881895
/* Create a temporary old context. */
1889-
if (!(octx= rcontext_create(thd, NULL)))
1896+
if (!(octx= rcontext_create(thd, NULL, args)))
18901897
{
18911898
DBUG_PRINT("error", ("Could not create octx"));
18921899
DBUG_RETURN(TRUE);
@@ -1901,7 +1908,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
19011908
thd->spcont->callers_arena= thd;
19021909
}
19031910

1904-
if (!(nctx= rcontext_create(thd, NULL)))
1911+
if (!(nctx= rcontext_create(thd, NULL, args)))
19051912
{
19061913
delete nctx; /* Delete nctx if it was init() that failed. */
19071914
thd->spcont= save_spcont;

sql/sp_head.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class sp_head :private Query_arena,
215215
m_sp_cache_version= version_arg;
216216
}
217217

218-
sp_rcontext *rcontext_create(THD *thd, Field *retval);
218+
sp_rcontext *rcontext_create(THD *thd, Field *retval, List<Item> *args);
219219

220220
private:
221221
/**

sql/sp_rcontext.cc

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ sp_rcontext::~sp_rcontext()
6363
sp_rcontext *sp_rcontext::create(THD *thd,
6464
const sp_pcontext *root_parsing_ctx,
6565
Field *return_value_fld,
66-
bool resolve_type_refs)
66+
bool resolve_type_refs,
67+
List<Item> *args)
6768
{
6869
sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
6970
return_value_fld,
@@ -75,6 +76,10 @@ sp_rcontext *sp_rcontext::create(THD *thd,
7576
List<Spvar_definition> field_def_lst;
7677
ctx->m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
7778

79+
if (args &&
80+
ctx->adjust_formal_params_to_actual_params(thd, field_def_lst, args))
81+
return NULL;
82+
7883
if (ctx->alloc_arrays(thd) ||
7984
(resolve_type_refs && ctx->resolve_type_refs(thd, field_def_lst)) ||
8085
ctx->init_var_table(thd, field_def_lst) ||
@@ -88,6 +93,24 @@ sp_rcontext *sp_rcontext::create(THD *thd,
8893
}
8994

9095

96+
bool sp_rcontext::adjust_formal_params_to_actual_params(THD *thd,
97+
List<Spvar_definition> &field_def_lst,
98+
List<Item> *args)
99+
{
100+
List_iterator<Spvar_definition> it(field_def_lst);
101+
List_iterator<Item> it_args(*args);
102+
DBUG_ASSERT(field_def_lst.elements >= args->elements );
103+
Spvar_definition *def;
104+
Item *arg;
105+
while ((def= it++) && (arg= it_args++))
106+
{
107+
if (def->type_handler()->adjust_spparam_type(def, arg))
108+
true;
109+
}
110+
return false;
111+
}
112+
113+
91114
bool sp_rcontext::alloc_arrays(THD *thd)
92115
{
93116
{

sql/sp_rcontext.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ class sp_rcontext : public Sql_alloc
7171
static sp_rcontext *create(THD *thd,
7272
const sp_pcontext *root_parsing_ctx,
7373
Field *return_value_fld,
74-
bool resolve_type_refs);
74+
bool resolve_type_refs,
75+
List<Item> *args);
7576

7677
~sp_rcontext();
7778

@@ -344,6 +345,9 @@ class sp_rcontext : public Sql_alloc
344345
Qualified_column_ident *ref);
345346
bool resolve_table_rowtype_ref(THD *thd, Row_definition_list &defs,
346347
Table_ident *ref);
348+
bool adjust_formal_params_to_actual_params(THD *thd,
349+
List<Spvar_definition> &field_def_lst,
350+
List<Item> *args);
347351

348352
/// Create and initialize an Item-adapter (Item_field) for each SP-var field.
349353
///

sql/sql_type.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,6 +2384,29 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
23842384
attr.collation);
23852385
}
23862386

2387+
/*
2388+
If length is not specified for a varchar parameter, set length to the
2389+
maximum length of the actual argument. Goals are:
2390+
- avoid to allocate too much unused memory for m_var_table
2391+
- allow length check inside the callee rather than during copy of
2392+
returned values in output variables.
2393+
- allow varchar parameter size greater than 4000
2394+
Default length has been stored in "decimal" member during parse.
2395+
*/
2396+
bool Type_handler_varchar::adjust_spparam_type(Spvar_definition *def,
2397+
Item *from) const
2398+
{
2399+
if (def->decimals)
2400+
{
2401+
uint def_max_char_length= MAX_FIELD_VARCHARLENGTH / def->charset->mbmaxlen;
2402+
uint arg_max_length= from->max_char_length();
2403+
set_if_smaller(arg_max_length, def_max_char_length);
2404+
def->length= arg_max_length > 0 ? arg_max_length : def->decimals;
2405+
def->create_length_to_internal_length_string();
2406+
}
2407+
return false;
2408+
}
2409+
23872410
/*************************************************************************/
23882411

23892412
uint32 Type_handler_decimal_result::max_display_length(const Item *item) const

sql/sql_type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class in_vector;
6565
class Type_handler_hybrid_field_type;
6666
class Sort_param;
6767
class Arg_comparator;
68+
class Spvar_definition;
6869
struct st_value;
6970
class Protocol;
7071
class handler;
@@ -688,6 +689,10 @@ class Type_handler
688689
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
689690
CHARSET_INFO *cs) const
690691
{ return this; }
692+
virtual bool adjust_spparam_type(Spvar_definition *def, Item *from) const
693+
{
694+
return false;
695+
}
691696
virtual ~Type_handler() {}
692697
/**
693698
Determines MariaDB traditional data types that always present
@@ -2523,6 +2528,7 @@ class Type_handler_varchar: public Type_handler_longstr
25232528
const Record_addr &addr,
25242529
const Type_all_attributes &attr,
25252530
TABLE *table) const;
2531+
bool adjust_spparam_type(Spvar_definition *def, Item *from) const;
25262532
};
25272533

25282534

0 commit comments

Comments
 (0)