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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
30c343a0
Commit
30c343a0
authored
Feb 17, 2006
by
jimw@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge mysql.com:/home/jimw/my/mysql-5.0-clean
into mysql.com:/home/jimw/my/mysql-5.1-clean
parents
10b96ec4
7182785f
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
326 additions
and
215 deletions
+326
-215
.bzrignore
.bzrignore
+1
-1
mysql-test/r/func_str.result
mysql-test/r/func_str.result
+7
-0
mysql-test/r/subselect.result
mysql-test/r/subselect.result
+3
-3
mysql-test/t/disabled.def
mysql-test/t/disabled.def
+0
-1
mysql-test/t/func_str.test
mysql-test/t/func_str.test
+8
-0
sql/item.cc
sql/item.cc
+283
-194
sql/item.h
sql/item.h
+1
-0
sql/item_strfunc.cc
sql/item_strfunc.cc
+22
-16
sql/item_subselect.h
sql/item_subselect.h
+1
-0
No files found.
.bzrignore
View file @
30c343a0
...
...
@@ -934,6 +934,7 @@ scripts/mysql_install_db
scripts/mysql_secure_installation
scripts/mysql_setpermission
scripts/mysql_tableinfo
scripts/mysql_upgrade
scripts/mysql_zap
scripts/mysqlaccess
scripts/mysqlbug
...
...
@@ -1613,4 +1614,3 @@ vio/viotest-sslconnect.cpp
vio/viotest.cpp
zlib/*.ds?
zlib/*.vcproj
scripts/mysql_upgrade
mysql-test/r/func_str.result
View file @
30c343a0
...
...
@@ -1023,3 +1023,10 @@ select format(d, 2) from t1;
format(d, 2)
NULL
drop table t1;
create table t1 (c varchar(40));
insert into t1 values ('y,abc'),('y,abc');
select c, substring_index(lcase(c), @q:=',', -1) as res from t1;
c res
y,abc abc
y,abc abc
drop table t1;
mysql-test/r/subselect.result
View file @
30c343a0
...
...
@@ -215,9 +215,9 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from
a
select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)
8 7.5
8 4.5
9 7.5
8 7.5
000
8 4.5
000
9 7.5
000
explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t4 ALL NULL NULL NULL NULL 3
...
...
mysql-test/t/disabled.def
View file @
30c343a0
...
...
@@ -42,7 +42,6 @@ rpl_row_basic_3innodb : Bug #17385
rpl_sp : Bug#16456
rpl_until : Unstable test case, bug#15886
sp-goto : GOTO is currently is disabled - will be fixed in the future
subselect : Bug#15706 (ps mode) [PATCH PENDING]
rpl_ndb_blob : Bug #17505
rpl_ndb_blob2 : Bug #17505
rpl_ndb_log : results are not deterministic
mysql-test/t/func_str.test
View file @
30c343a0
...
...
@@ -676,4 +676,12 @@ insert into t1 values (null);
select
format
(
d
,
2
)
from
t1
;
drop
table
t1
;
#
# Bug #14676: substring_index() returns incorrect results
#
create
table
t1
(
c
varchar
(
40
));
insert
into
t1
values
(
'y,abc'
),(
'y,abc'
);
select
c
,
substring_index
(
lcase
(
c
),
@
q
:=
','
,
-
1
)
as
res
from
t1
;
drop
table
t1
;
# End of 5.0 tests
sql/item.cc
View file @
30c343a0
...
...
@@ -3211,6 +3211,252 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
}
/*
Resolve the name of an outer select column reference.
SYNOPSIS
Item_field::fix_outer_field()
thd [in] current thread
from_field [in/out] found field reference or (Field*)not_found_field
reference [in/out] view column if this item was resolved to a view column
DESCRIPTION
The method resolves the column reference represented by 'this' as a column
present in outer selects that contain current select.
NOTES
This is the inner loop of Item_field::fix_fields:
for each outer query Q_k beginning from the inner-most one
{
search for a column or derived column named col_ref_i
[in table T_j] in the FROM clause of Q_k;
if such a column is not found
Search for a column or derived column named col_ref_i
[in table T_j] in the SELECT and GROUP clauses of Q_k.
}
IMPLEMENTATION
In prepared statements, because of cache, find_field_in_tables()
can resolve fields even if they don't belong to current context.
In this case this method only finds appropriate context and marks
current select as dependent. The found reference of field should be
provided in 'from_field'.
RETURN
1 - column succefully resolved and fix_fields() should continue.
0 - column fully fixed and fix_fields() should return FALSE
-1 - error occured
*/
int
Item_field
::
fix_outer_field
(
THD
*
thd
,
Field
**
from_field
,
Item
**
reference
)
{
enum_parsing_place
place
=
NO_MATTER
;
bool
field_found
=
(
*
from_field
!=
not_found_field
);
bool
upward_lookup
=
FALSE
;
/*
If there are outer contexts (outer selects, but current select is
not derived table or view) try to resolve this reference in the
outer contexts.
We treat each subselect as a separate namespace, so that different
subselects may contain columns with the same names. The subselects
are searched starting from the innermost.
*/
Name_resolution_context
*
last_checked_context
=
context
;
Item
**
ref
=
(
Item
**
)
not_found_item
;
Name_resolution_context
*
outer_context
=
context
->
outer_context
;
for
(;
outer_context
;
outer_context
=
outer_context
->
outer_context
)
{
SELECT_LEX
*
select
=
outer_context
->
select_lex
;
Item_subselect
*
prev_subselect_item
=
last_checked_context
->
select_lex
->
master_unit
()
->
item
;
last_checked_context
=
outer_context
;
upward_lookup
=
TRUE
;
place
=
prev_subselect_item
->
parsing_place
;
/*
If outer_field is set, field was already found by first call
to find_field_in_tables(). Only need to find appropriate context.
*/
if
(
field_found
&&
outer_context
->
select_lex
!=
cached_table
->
select_lex
)
continue
;
/*
In case of a view, find_field_in_tables() writes the pointer to
the found view field into '*reference', in other words, it
substitutes this Item_field with the found expression.
*/
if
(
field_found
||
(
*
from_field
=
find_field_in_tables
(
thd
,
this
,
outer_context
->
first_name_resolution_table
,
outer_context
->
last_name_resolution_table
,
reference
,
IGNORE_EXCEPT_NON_UNIQUE
,
TRUE
,
TRUE
))
!=
not_found_field
)
{
if
(
*
from_field
)
{
if
(
*
from_field
!=
view_ref_found
)
{
prev_subselect_item
->
used_tables_cache
|=
(
*
from_field
)
->
table
->
map
;
prev_subselect_item
->
const_item_cache
=
0
;
if
(
thd
->
lex
->
in_sum_func
&&
thd
->
lex
->
in_sum_func
->
nest_level
==
thd
->
lex
->
current_select
->
nest_level
)
{
Item
::
Type
type
=
(
*
reference
)
->
type
();
set_if_bigger
(
thd
->
lex
->
in_sum_func
->
max_arg_level
,
select
->
nest_level
);
set_field
(
*
from_field
);
fixed
=
1
;
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
((
type
==
REF_ITEM
||
type
==
FIELD_ITEM
)
?
(
Item_ident
*
)
(
*
reference
)
:
0
));
return
0
;
}
}
else
{
Item
::
Type
type
=
(
*
reference
)
->
type
();
prev_subselect_item
->
used_tables_cache
|=
(
*
reference
)
->
used_tables
();
prev_subselect_item
->
const_item_cache
&=
(
*
reference
)
->
const_item
();
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
((
type
==
REF_ITEM
||
type
==
FIELD_ITEM
)
?
(
Item_ident
*
)
(
*
reference
)
:
0
));
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
does it by assigning the new value to *reference), so now
we can return from this function.
*/
return
0
;
}
}
break
;
}
/* Search in SELECT and GROUP lists of the outer select. */
if
(
outer_context
->
resolve_in_select_list
)
{
if
(
!
(
ref
=
resolve_ref_in_select_and_group
(
thd
,
this
,
select
)))
return
-
1
;
/* Some error occurred (e.g. ambiguous names). */
if
(
ref
!=
not_found_item
)
{
DBUG_ASSERT
(
*
ref
&&
(
*
ref
)
->
fixed
);
prev_subselect_item
->
used_tables_cache
|=
(
*
ref
)
->
used_tables
();
prev_subselect_item
->
const_item_cache
&=
(
*
ref
)
->
const_item
();
break
;
}
}
/*
Reference is not found in this select => this subquery depend on
outer select (or we just trying to find wrong identifier, in this
case it does not matter which used tables bits we set)
*/
prev_subselect_item
->
used_tables_cache
|=
OUTER_REF_TABLE_BIT
;
prev_subselect_item
->
const_item_cache
=
0
;
}
DBUG_ASSERT
(
ref
!=
0
);
if
(
!*
from_field
)
return
-
1
;
if
(
ref
==
not_found_item
&&
*
from_field
==
not_found_field
)
{
if
(
upward_lookup
)
{
// We can't say exactly what absent table or field
my_error
(
ER_BAD_FIELD_ERROR
,
MYF
(
0
),
full_name
(),
thd
->
where
);
}
else
{
/* Call find_field_in_tables only to report the error */
find_field_in_tables
(
thd
,
this
,
context
->
first_name_resolution_table
,
context
->
last_name_resolution_table
,
reference
,
REPORT_ALL_ERRORS
,
!
any_privileges
&&
TRUE
,
TRUE
);
}
return
-
1
;
}
else
if
(
ref
!=
not_found_item
)
{
Item
*
save
;
Item_ref
*
rf
;
/* Should have been checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT
(
*
ref
&&
(
*
ref
)
->
fixed
);
/*
Here, a subset of actions performed by Item_ref::set_properties
is not enough. So we pass ptr to NULL into Item_[direct]_ref
constructor, so no initialization is performed, and call
fix_fields() below.
*/
save
=
*
ref
;
*
ref
=
NULL
;
// Don't call set_properties()
rf
=
(
place
==
IN_HAVING
?
new
Item_ref
(
context
,
ref
,
(
char
*
)
table_name
,
(
char
*
)
field_name
)
:
new
Item_direct_ref
(
context
,
ref
,
(
char
*
)
table_name
,
(
char
*
)
field_name
));
*
ref
=
save
;
if
(
!
rf
)
return
-
1
;
thd
->
change_item_tree
(
reference
,
rf
);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT
(
!
rf
->
fixed
);
// Assured by Item_ref()
if
(
rf
->
fix_fields
(
thd
,
reference
)
||
rf
->
check_cols
(
1
))
return
-
1
;
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
rf
);
return
0
;
}
else
{
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
this
);
if
(
last_checked_context
->
select_lex
->
having_fix_field
)
{
Item_ref
*
rf
;
rf
=
new
Item_ref
(
context
,
(
cached_table
->
db
[
0
]
?
cached_table
->
db
:
0
),
(
char
*
)
cached_table
->
alias
,
(
char
*
)
field_name
);
if
(
!
rf
)
return
-
1
;
thd
->
change_item_tree
(
reference
,
rf
);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT
(
!
rf
->
fixed
);
// Assured by Item_ref()
if
(
rf
->
fix_fields
(
thd
,
reference
)
||
rf
->
check_cols
(
1
))
return
-
1
;
return
0
;
}
}
return
1
;
}
/*
Resolve the name of a column reference.
...
...
@@ -3258,12 +3504,11 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
bool
Item_field
::
fix_fields
(
THD
*
thd
,
Item
**
reference
)
{
enum_parsing_place
place
=
NO_MATTER
;
DBUG_ASSERT
(
fixed
==
0
);
if
(
!
field
)
// If field is not checked
{
bool
upward_lookup
=
FALSE
;
Field
*
from_field
=
(
Field
*
)
not_found_field
;
bool
outer_fixed
=
false
;
/*
In case of view, find_field_in_tables() write pointer to view field
expression to 'reference', i.e. it substitute that expression instead
...
...
@@ -3278,7 +3523,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
TRUE
))
==
not_found_field
)
{
int
ret
;
/* Look up in current select's item_list to find aliased fields */
if
(
thd
->
lex
->
current_select
->
is_item_list_lookup
)
{
...
...
@@ -3293,197 +3538,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
return
0
;
}
}
/*
If there are outer contexts (outer selects, but current select is
not derived table or view) try to resolve this reference in the
outer contexts.
We treat each subselect as a separate namespace, so that different
subselects may contain columns with the same names. The subselects
are searched starting from the innermost.
*/
Name_resolution_context
*
last_checked_context
=
context
;
Item
**
ref
=
(
Item
**
)
not_found_item
;
Name_resolution_context
*
outer_context
=
context
->
outer_context
;
for
(;
outer_context
;
outer_context
=
outer_context
->
outer_context
)
{
SELECT_LEX
*
select
=
outer_context
->
select_lex
;
Item_subselect
*
prev_subselect_item
=
last_checked_context
->
select_lex
->
master_unit
()
->
item
;
last_checked_context
=
outer_context
;
upward_lookup
=
TRUE
;
place
=
prev_subselect_item
->
parsing_place
;
/*
In case of a view, find_field_in_tables() writes the pointer to
the found view field into '*reference', in other words, it
substitutes this Item_field with the found expression.
*/
if
((
from_field
=
find_field_in_tables
(
thd
,
this
,
outer_context
->
first_name_resolution_table
,
outer_context
->
last_name_resolution_table
,
reference
,
IGNORE_EXCEPT_NON_UNIQUE
,
TRUE
,
TRUE
))
!=
not_found_field
)
{
if
(
from_field
)
{
if
(
from_field
!=
view_ref_found
)
{
prev_subselect_item
->
used_tables_cache
|=
from_field
->
table
->
map
;
prev_subselect_item
->
const_item_cache
=
0
;
if
(
thd
->
lex
->
in_sum_func
&&
thd
->
lex
->
in_sum_func
->
nest_level
==
thd
->
lex
->
current_select
->
nest_level
)
{
Item
::
Type
type
=
(
*
reference
)
->
type
();
set_if_bigger
(
thd
->
lex
->
in_sum_func
->
max_arg_level
,
select
->
nest_level
);
set_field
(
from_field
);
fixed
=
1
;
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
((
type
==
REF_ITEM
||
type
==
FIELD_ITEM
)
?
(
Item_ident
*
)
(
*
reference
)
:
0
));
return
FALSE
;
}
}
else
{
Item
::
Type
type
=
(
*
reference
)
->
type
();
prev_subselect_item
->
used_tables_cache
|=
(
*
reference
)
->
used_tables
();
prev_subselect_item
->
const_item_cache
&=
(
*
reference
)
->
const_item
();
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
((
type
==
REF_ITEM
||
type
==
FIELD_ITEM
)
?
(
Item_ident
*
)
(
*
reference
)
:
0
));
/*
A reference to a view field had been found and we
substituted it instead of this Item (find_field_in_tables
does it by assigning the new value to *reference), so now
we can return from this function.
*/
return
FALSE
;
}
}
break
;
}
/* Search in SELECT and GROUP lists of the outer select. */
if
(
outer_context
->
resolve_in_select_list
)
{
if
(
!
(
ref
=
resolve_ref_in_select_and_group
(
thd
,
this
,
select
)))
goto
error
;
/* Some error occurred (e.g. ambiguous names). */
if
(
ref
!=
not_found_item
)
{
DBUG_ASSERT
(
*
ref
&&
(
*
ref
)
->
fixed
);
prev_subselect_item
->
used_tables_cache
|=
(
*
ref
)
->
used_tables
();
prev_subselect_item
->
const_item_cache
&=
(
*
ref
)
->
const_item
();
break
;
}
}
/*
Reference is not found in this select => this subquery depend on
outer select (or we just trying to find wrong identifier, in this
case it does not matter which used tables bits we set)
*/
prev_subselect_item
->
used_tables_cache
|=
OUTER_REF_TABLE_BIT
;
prev_subselect_item
->
const_item_cache
=
0
;
}
DBUG_ASSERT
(
ref
!=
0
);
if
(
!
from_field
)
goto
error
;
if
(
ref
==
not_found_item
&&
from_field
==
not_found_field
)
{
if
(
upward_lookup
)
{
// We can't say exactly what absent table or field
my_error
(
ER_BAD_FIELD_ERROR
,
MYF
(
0
),
full_name
(),
thd
->
where
);
}
else
{
/* Call find_field_in_tables only to report the error */
find_field_in_tables
(
thd
,
this
,
context
->
first_name_resolution_table
,
context
->
last_name_resolution_table
,
reference
,
REPORT_ALL_ERRORS
,
!
any_privileges
&&
TRUE
,
TRUE
);
}
goto
error
;
}
else
if
(
ref
!=
not_found_item
)
{
Item
*
save
;
Item_ref
*
rf
;
/* Should have been checked in resolve_ref_in_select_and_group(). */
DBUG_ASSERT
(
*
ref
&&
(
*
ref
)
->
fixed
);
/*
Here, a subset of actions performed by Item_ref::set_properties
is not enough. So we pass ptr to NULL into Item_[direct]_ref
constructor, so no initialization is performed, and call
fix_fields() below.
*/
save
=
*
ref
;
*
ref
=
NULL
;
// Don't call set_properties()
rf
=
(
place
==
IN_HAVING
?
new
Item_ref
(
context
,
ref
,
(
char
*
)
table_name
,
(
char
*
)
field_name
)
:
new
Item_direct_ref
(
context
,
ref
,
(
char
*
)
table_name
,
(
char
*
)
field_name
));
*
ref
=
save
;
if
(
!
rf
)
goto
error
;
thd
->
change_item_tree
(
reference
,
rf
);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT
(
!
rf
->
fixed
);
// Assured by Item_ref()
if
(
rf
->
fix_fields
(
thd
,
reference
)
||
rf
->
check_cols
(
1
))
goto
error
;
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
rf
);
return
FALSE
;
}
else
{
mark_as_dependent
(
thd
,
last_checked_context
->
select_lex
,
context
->
select_lex
,
this
,
this
);
if
(
last_checked_context
->
select_lex
->
having_fix_field
)
{
Item_ref
*
rf
;
rf
=
new
Item_ref
(
context
,
(
cached_table
->
db
[
0
]
?
cached_table
->
db
:
0
),
(
char
*
)
cached_table
->
alias
,
(
char
*
)
field_name
);
if
(
!
rf
)
goto
error
;
thd
->
change_item_tree
(
reference
,
rf
);
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
DBUG_ASSERT
(
!
rf
->
fixed
);
// Assured by Item_ref()
if
(
rf
->
fix_fields
(
thd
,
reference
)
||
rf
->
check_cols
(
1
))
goto
error
;
return
FALSE
;
}
}
if
((
ret
=
fix_outer_field
(
thd
,
&
from_field
,
reference
))
<
0
)
goto
error
;
else
if
(
!
ret
)
return
FALSE
;
outer_fixed
=
TRUE
;
}
else
if
(
!
from_field
)
goto
error
;
...
...
@@ -3503,6 +3562,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if
(
from_field
==
view_ref_found
)
return
FALSE
;
if
(
!
outer_fixed
&&
cached_table
&&
cached_table
->
select_lex
&&
context
->
select_lex
&&
cached_table
->
select_lex
!=
context
->
select_lex
)
{
int
ret
;
if
((
ret
=
fix_outer_field
(
thd
,
&
from_field
,
reference
))
<
0
)
goto
error
;
else
if
(
!
ret
)
return
FALSE
;
}
set_field
(
from_field
);
if
(
thd
->
lex
->
in_sum_func
&&
thd
->
lex
->
in_sum_func
->
nest_level
==
...
...
@@ -4655,6 +4725,25 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
}
if
(
from_field
!=
not_found_field
)
{
if
(
cached_table
&&
cached_table
->
select_lex
&&
outer_context
->
select_lex
&&
cached_table
->
select_lex
!=
outer_context
->
select_lex
)
{
/*
Due to cache, find_field_in_tables() can return field which
doesn't belong to provided outer_context. In this case we have
to find proper field context in order to fix field correcly.
*/
do
{
outer_context
=
outer_context
->
outer_context
;
select
=
outer_context
->
select_lex
;
prev_subselect_item
=
last_checked_context
->
select_lex
->
master_unit
()
->
item
;
last_checked_context
=
outer_context
;
}
while
(
outer_context
&&
outer_context
->
select_lex
&&
cached_table
->
select_lex
!=
outer_context
->
select_lex
);
}
prev_subselect_item
->
used_tables_cache
|=
from_field
->
table
->
map
;
prev_subselect_item
->
const_item_cache
=
0
;
break
;
...
...
sql/item.h
View file @
30c343a0
...
...
@@ -1205,6 +1205,7 @@ public:
inline
uint32
max_disp_length
()
{
return
field
->
max_length
();
}
Item_field
*
filed_for_view_update
()
{
return
this
;
}
Item
*
safe_charset_converter
(
CHARSET_INFO
*
tocs
);
int
fix_outer_field
(
THD
*
thd
,
Field
**
field
,
Item
**
reference
);
friend
class
Item_default_value
;
friend
class
Item_insert_value
;
friend
class
st_select_lex_unit
;
...
...
sql/item_strfunc.cc
View file @
30c343a0
...
...
@@ -1128,9 +1128,9 @@ void Item_func_substr_index::fix_length_and_dec()
String
*
Item_func_substr_index
::
val_str
(
String
*
str
)
{
DBUG_ASSERT
(
fixed
==
1
);
String
*
res
=
args
[
0
]
->
val_str
(
str
);
String
*
delim
eter
=
args
[
1
]
->
val_str
(
&
tmp_value
);
int32
count
=
(
int32
)
args
[
2
]
->
val_int
();
String
*
res
=
args
[
0
]
->
val_str
(
str
);
String
*
delim
iter
=
args
[
1
]
->
val_str
(
&
tmp_value
);
int32
count
=
(
int32
)
args
[
2
]
->
val_int
();
uint
offset
;
if
(
args
[
0
]
->
null_value
||
args
[
1
]
->
null_value
||
args
[
2
]
->
null_value
)
...
...
@@ -1139,8 +1139,8 @@ String *Item_func_substr_index::val_str(String *str)
return
0
;
}
null_value
=
0
;
uint
delim
eter_length
=
delime
ter
->
length
();
if
(
!
res
->
length
()
||
!
delim
e
ter_length
||
!
count
)
uint
delim
iter_length
=
delimi
ter
->
length
();
if
(
!
res
->
length
()
||
!
delim
i
ter_length
||
!
count
)
return
&
my_empty_string
;
// Wrong parameters
res
->
set_charset
(
collation
.
collation
);
...
...
@@ -1148,11 +1148,11 @@ String *Item_func_substr_index::val_str(String *str)
#ifdef USE_MB
if
(
use_mb
(
res
->
charset
()))
{
const
char
*
ptr
=
res
->
ptr
();
const
char
*
strend
=
ptr
+
res
->
length
();
const
char
*
end
=
strend
-
delime
ter_length
+
1
;
const
char
*
search
=
delime
ter
->
ptr
();
const
char
*
search_end
=
search
+
delime
ter_length
;
const
char
*
ptr
=
res
->
ptr
();
const
char
*
strend
=
ptr
+
res
->
length
();
const
char
*
end
=
strend
-
delimi
ter_length
+
1
;
const
char
*
search
=
delimi
ter
->
ptr
();
const
char
*
search_end
=
search
+
delimi
ter_length
;
int32
n
=
0
,
c
=
count
,
pass
;
register
uint32
l
;
for
(
pass
=
(
count
>
0
);
pass
<
2
;
++
pass
)
...
...
@@ -1167,7 +1167,7 @@ String *Item_func_substr_index::val_str(String *str)
if
(
*
i
++
!=
*
j
++
)
goto
skip
;
if
(
pass
==
0
)
++
n
;
else
if
(
!--
c
)
break
;
ptr
+=
delime
ter_length
;
ptr
+=
delimi
ter_length
;
continue
;
}
skip:
...
...
@@ -1189,7 +1189,7 @@ String *Item_func_substr_index::val_str(String *str)
}
else
/* return right part */
{
ptr
+=
delime
ter_length
;
ptr
+=
delimi
ter_length
;
tmp_value
.
set
(
*
res
,(
ulong
)
(
ptr
-
res
->
ptr
()),
(
ulong
)
(
strend
-
ptr
));
}
}
...
...
@@ -1200,9 +1200,9 @@ String *Item_func_substr_index::val_str(String *str)
{
if
(
count
>
0
)
{
// start counting from the beginning
for
(
offset
=
0
;;
offset
+=
delime
ter_length
)
for
(
offset
=
0
;
;
offset
+=
delimi
ter_length
)
{
if
((
int
)
(
offset
=
res
->
strstr
(
*
delimeter
,
offset
))
<
0
)
if
((
int
)
(
offset
=
res
->
strstr
(
*
delimiter
,
offset
))
<
0
)
return
res
;
// Didn't find, return org string
if
(
!--
count
)
{
...
...
@@ -1223,7 +1223,7 @@ String *Item_func_substr_index::val_str(String *str)
address space less than where the found substring is located
in res
*/
if
((
int
)
(
offset
=
res
->
strrstr
(
*
delimeter
,
offset
))
<
0
)
if
((
int
)
(
offset
=
res
->
strrstr
(
*
delimiter
,
offset
))
<
0
)
return
res
;
// Didn't find, return org string
/*
At this point, we've searched for the substring
...
...
@@ -1231,13 +1231,19 @@ String *Item_func_substr_index::val_str(String *str)
*/
if
(
!++
count
)
{
offset
+=
delime
ter_length
;
offset
+=
delimi
ter_length
;
tmp_value
.
set
(
*
res
,
offset
,
res
->
length
()
-
offset
);
break
;
}
}
}
}
/*
We always mark tmp_value as const so that if val_str() is called again
on this object, we don't disrupt the contents of tmp_value when it was
derived from another String.
*/
tmp_value
.
mark_as_const
();
return
(
&
tmp_value
);
}
...
...
sql/item_subselect.h
View file @
30c343a0
...
...
@@ -125,6 +125,7 @@ public:
friend
class
select_subselect
;
friend
class
Item_in_optimizer
;
friend
bool
Item_field
::
fix_fields
(
THD
*
,
Item
**
);
friend
int
Item_field
::
fix_outer_field
(
THD
*
,
Field
**
,
Item
**
);
friend
bool
Item_ref
::
fix_fields
(
THD
*
,
Item
**
);
friend
void
mark_select_range_as_dependent
(
THD
*
,
st_select_lex
*
,
st_select_lex
*
,
...
...
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