Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
c4a908cb
Commit
c4a908cb
authored
Jan 30, 2018
by
Alexander Barkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-13790 UNHEX() of a somewhat complicated CONCAT() returns NULL
parent
dae4fb0a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
76 additions
and
117 deletions
+76
-117
mysql-test/r/func_concat.result
mysql-test/r/func_concat.result
+6
-0
mysql-test/t/func_concat.test
mysql-test/t/func_concat.test
+6
-0
sql/item_strfunc.cc
sql/item_strfunc.cc
+63
-117
sql/item_strfunc.h
sql/item_strfunc.h
+1
-0
No files found.
mysql-test/r/func_concat.result
View file @
c4a908cb
...
...
@@ -262,3 +262,9 @@ c2
abcdefghi-abcdefghi
DROP TABLE t1;
SET optimizer_switch=@save_optimizer_switch;
#
# MDEV-13790 UNHEX() of a somewhat complicated CONCAT() returns NULL
#
SELECT UNHEX(CONCAT('414C2', HEX(8 + ROUND(RAND()*7)), SUBSTR(SHA(UUID()),6,33),HEX(2+ROUND(RAND()*8)))) IS NULL AS c1;
c1
0
mysql-test/t/func_concat.test
View file @
c4a908cb
...
...
@@ -236,3 +236,9 @@ SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TRIM(t) t2 FROM t1) sub;
DROP
TABLE
t1
;
SET
optimizer_switch
=@
save_optimizer_switch
;
--
echo
#
--
echo
# MDEV-13790 UNHEX() of a somewhat complicated CONCAT() returns NULL
--
echo
#
SELECT
UNHEX
(
CONCAT
(
'414C2'
,
HEX
(
8
+
ROUND
(
RAND
()
*
7
)),
SUBSTR
(
SHA
(
UUID
()),
6
,
33
),
HEX
(
2
+
ROUND
(
RAND
()
*
8
))))
IS
NULL
AS
c1
;
sql/item_strfunc.cc
View file @
c4a908cb
...
...
@@ -630,138 +630,84 @@ String *Item_func_decode_histogram::val_str(String *str)
///////////////////////////////////////////////////////////////////////////////
/*
Realloc the result buffer.
NOTE: We should be prudent in the initial allocation unit -- the
size of the arguments is a function of data distribution, which
can be any. Instead of overcommitting at the first row, we grow
the allocated amount by the factor of 2. This ensures that no
more than 25% of memory will be overcommitted on average.
@param IN/OUT str - the result string
@param IN length - new total space required in "str"
@retval false - on success
@retval true - on error
*/
bool
Item_func_concat
::
realloc_result
(
String
*
str
,
uint
length
)
const
{
if
(
str
->
alloced_length
()
>=
length
)
return
false
;
// Alloced space is big enough, nothing to do.
if
(
str
->
alloced_length
()
==
0
)
return
str
->
alloc
(
length
);
/*
Item_func_concat::val_str() makes sure the result length does not grow
higher than max_allowed_packet. So "length" is limited to 1G here.
We can't say anything about the current value of str->alloced_length(),
as str was initially set by args[0]->val_str(str).
So multiplication by 2 can overflow, if args[0] for some reasons
did not limit the result to max_alloced_packet. But it's not harmful,
"str" will be realloced exactly to "length" bytes in case of overflow.
*/
uint
new_length
=
MY_MAX
(
str
->
alloced_length
()
*
2
,
length
);
return
str
->
realloc
(
new_length
);
}
/**
Concatenate args with the following premises:
If only one arg (which is ok), return value of arg;
Don't reallocate val_str() if not absolute necessary.
*/
String
*
Item_func_concat
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
String
*
res
,
*
res2
,
*
use_as_buff
;
uint
i
;
bool
is_const
=
0
;
THD
*
thd
=
current_thd
;
String
*
res
;
null_value
=
0
;
if
(
!
(
res
=
args
[
0
]
->
val_str
(
str
)))
if
(
!
(
res
=
args
[
0
]
->
val_str
(
str
)))
goto
null
;
use_as_buff
=
&
tmp_value
;
/* Item_subselect in --ps-protocol mode will state it as a non-const */
is_const
=
args
[
0
]
->
const_item
()
||
!
args
[
0
]
->
used_tables
();
for
(
i
=
1
;
i
<
arg_count
;
i
++
)
{
if
(
res
->
length
()
==
0
)
{
if
(
!
(
res
=
args
[
i
]
->
val_str
(
str
)))
goto
null
;
/*
CONCAT accumulates its result in the result of its the first
non-empty argument. Because of this we need is_const to be
evaluated only for it.
*/
is_const
=
args
[
i
]
->
const_item
()
||
!
args
[
i
]
->
used_tables
();
}
else
{
if
(
!
(
res2
=
args
[
i
]
->
val_str
(
use_as_buff
)))
goto
null
;
if
(
res2
->
length
()
==
0
)
continue
;
if
(
res
->
length
()
+
res2
->
length
()
>
current_thd
->
variables
.
max_allowed_packet
)
{
push_warning_printf
(
current_thd
,
Sql_condition
::
WARN_LEVEL_WARN
,
ER_WARN_ALLOWED_PACKET_OVERFLOWED
,
ER
(
ER_WARN_ALLOWED_PACKET_OVERFLOWED
),
func_name
(),
current_thd
->
variables
.
max_allowed_packet
);
goto
null
;
}
if
(
!
is_const
&&
res
->
alloced_length
()
>=
res
->
length
()
+
res2
->
length
())
{
// Use old buffer
res
->
append
(
*
res2
);
}
else
if
(
str
->
alloced_length
()
>=
res
->
length
()
+
res2
->
length
())
{
if
(
str
->
ptr
()
==
res2
->
ptr
())
str
->
replace
(
0
,
0
,
*
res
);
else
{
str
->
copy
(
*
res
);
str
->
append
(
*
res2
);
}
res
=
str
;
use_as_buff
=
&
tmp_value
;
}
else
if
(
res
==
&
tmp_value
)
{
if
(
res
->
append
(
*
res2
))
// Must be a blob
goto
null
;
}
else
if
(
res2
==
&
tmp_value
)
{
// This can happend only 1 time
if
(
tmp_value
.
replace
(
0
,
0
,
*
res
))
goto
null
;
res
=
&
tmp_value
;
use_as_buff
=
str
;
// Put next arg here
}
else
if
(
tmp_value
.
is_alloced
()
&&
res2
->
ptr
()
>=
tmp_value
.
ptr
()
&&
res2
->
ptr
()
<=
tmp_value
.
ptr
()
+
tmp_value
.
alloced_length
())
{
/*
This happens really seldom:
In this case res2 is sub string of tmp_value. We will
now work in place in tmp_value to set it to res | res2
*/
/* Chop the last characters in tmp_value that isn't in res2 */
tmp_value
.
length
((
uint32
)
(
res2
->
ptr
()
-
tmp_value
.
ptr
())
+
res2
->
length
());
/* Place res2 at start of tmp_value, remove chars before res2 */
if
(
tmp_value
.
replace
(
0
,(
uint32
)
(
res2
->
ptr
()
-
tmp_value
.
ptr
()),
*
res
))
goto
null
;
res
=
&
tmp_value
;
use_as_buff
=
str
;
// Put next arg here
}
else
{
// Two big const strings
/*
NOTE: We should be prudent in the initial allocation unit -- the
size of the arguments is a function of data distribution, which
can be any. Instead of overcommitting at the first row, we grow
the allocated amount by the factor of 2. This ensures that no
more than 25% of memory will be overcommitted on average.
*/
uint
concat_len
=
res
->
length
()
+
res2
->
length
();
if
(
tmp_value
.
alloced_length
()
<
concat_len
)
{
if
(
tmp_value
.
alloced_length
()
==
0
)
{
if
(
tmp_value
.
alloc
(
concat_len
))
goto
null
;
}
else
{
uint
new_len
=
MY_MAX
(
tmp_value
.
alloced_length
()
*
2
,
concat_len
);
if
(
tmp_value
.
realloc
(
new_len
))
goto
null
;
}
}
if
(
res
!=
str
)
str
->
copy
(
res
->
ptr
(),
res
->
length
(),
res
->
charset
());
if
(
tmp_value
.
copy
(
*
res
)
||
tmp_value
.
append
(
*
res2
))
goto
null
;
res
=
&
tmp_value
;
use_as_buff
=
str
;
}
is_const
=
0
;
for
(
uint
i
=
1
;
i
<
arg_count
;
i
++
)
{
uint
concat_len
;
if
(
!
(
res
=
args
[
i
]
->
val_str
(
&
tmp_value
)))
goto
null
;
if
(
res
->
length
()
==
0
)
continue
;
if
((
concat_len
=
str
->
length
()
+
res
->
length
())
>
thd
->
variables
.
max_allowed_packet
)
{
push_warning_printf
(
thd
,
Sql_condition
::
WARN_LEVEL_WARN
,
ER_WARN_ALLOWED_PACKET_OVERFLOWED
,
ER
(
ER_WARN_ALLOWED_PACKET_OVERFLOWED
),
func_name
(),
thd
->
variables
.
max_allowed_packet
);
goto
null
;
}
DBUG_ASSERT
(
!
res
->
uses_buffer_owned_by
(
str
));
DBUG_ASSERT
(
!
str
->
uses_buffer_owned_by
(
res
));
if
(
realloc_result
(
str
,
concat_len
)
||
str
->
append
(
*
res
))
goto
null
;
}
res
->
set_charset
(
collation
.
collation
);
return
res
;
str
->
set_charset
(
collation
.
collation
);
return
str
;
null:
null_value
=
1
;
...
...
sql/item_strfunc.h
View file @
c4a908cb
...
...
@@ -156,6 +156,7 @@ class Item_func_aes_decrypt :public Item_str_func
class
Item_func_concat
:
public
Item_str_func
{
String
tmp_value
;
bool
realloc_result
(
String
*
str
,
uint
length
)
const
;
public:
Item_func_concat
(
List
<
Item
>
&
list
)
:
Item_str_func
(
list
)
{}
Item_func_concat
(
Item
*
a
,
Item
*
b
)
:
Item_str_func
(
a
,
b
)
{}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment