mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge mysql.com:/home/jimw/my/mysql-5.0-clean
into mysql.com:/home/jimw/my/mysql-5.1-clean BitKeeper/etc/ignore: auto-union mysql-test/r/func_str.result: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_strfunc.cc: Auto merged mysql-test/t/disabled.def: Resolve conflict
This commit is contained in:
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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.5000
|
||||
8 4.5000
|
||||
9 7.5000
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
477
sql/item.cc
477
sql/item.cc
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 *delimeter =args[1]->val_str(&tmp_value);
|
||||
int32 count = (int32) args[2]->val_int();
|
||||
String *res= args[0]->val_str(str);
|
||||
String *delimiter= 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 delimeter_length=delimeter->length();
|
||||
if (!res->length() || !delimeter_length || !count)
|
||||
uint delimiter_length= delimiter->length();
|
||||
if (!res->length() || !delimiter_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-delimeter_length+1;
|
||||
const char *search=delimeter->ptr();
|
||||
const char *search_end=search+delimeter_length;
|
||||
const char *ptr= res->ptr();
|
||||
const char *strend= ptr+res->length();
|
||||
const char *end= strend-delimiter_length+1;
|
||||
const char *search= delimiter->ptr();
|
||||
const char *search_end= search+delimiter_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+=delimeter_length;
|
||||
ptr+= delimiter_length;
|
||||
continue;
|
||||
}
|
||||
skip:
|
||||
@ -1189,7 +1189,7 @@ String *Item_func_substr_index::val_str(String *str)
|
||||
}
|
||||
else /* return right part */
|
||||
{
|
||||
ptr+=delimeter_length;
|
||||
ptr+= delimiter_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+=delimeter_length)
|
||||
for (offset=0; ; offset+= delimiter_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+=delimeter_length;
|
||||
offset+= delimiter_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);
|
||||
}
|
||||
|
||||
|
@ -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*,
|
||||
|
Reference in New Issue
Block a user