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_secure_installation
|
||||||
scripts/mysql_setpermission
|
scripts/mysql_setpermission
|
||||||
scripts/mysql_tableinfo
|
scripts/mysql_tableinfo
|
||||||
|
scripts/mysql_upgrade
|
||||||
scripts/mysql_zap
|
scripts/mysql_zap
|
||||||
scripts/mysqlaccess
|
scripts/mysqlaccess
|
||||||
scripts/mysqlbug
|
scripts/mysqlbug
|
||||||
@ -1613,4 +1614,3 @@ vio/viotest-sslconnect.cpp
|
|||||||
vio/viotest.cpp
|
vio/viotest.cpp
|
||||||
zlib/*.ds?
|
zlib/*.ds?
|
||||||
zlib/*.vcproj
|
zlib/*.vcproj
|
||||||
scripts/mysql_upgrade
|
|
||||||
|
@ -1023,3 +1023,10 @@ select format(d, 2) from t1;
|
|||||||
format(d, 2)
|
format(d, 2)
|
||||||
NULL
|
NULL
|
||||||
drop table t1;
|
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
|
a
|
||||||
select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
|
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)
|
b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)
|
||||||
8 7.5
|
8 7.5000
|
||||||
8 4.5
|
8 4.5000
|
||||||
9 7.5
|
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;
|
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
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY t4 ALL NULL NULL NULL NULL 3
|
1 PRIMARY t4 ALL NULL NULL NULL NULL 3
|
||||||
|
@ -42,7 +42,6 @@ rpl_row_basic_3innodb : Bug #17385
|
|||||||
rpl_sp : Bug#16456
|
rpl_sp : Bug#16456
|
||||||
rpl_until : Unstable test case, bug#15886
|
rpl_until : Unstable test case, bug#15886
|
||||||
sp-goto : GOTO is currently is disabled - will be fixed in the future
|
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_blob : Bug #17505
|
||||||
rpl_ndb_blob2 : Bug #17505
|
rpl_ndb_blob2 : Bug #17505
|
||||||
rpl_ndb_log : results are not deterministic
|
rpl_ndb_log : results are not deterministic
|
||||||
|
@ -676,4 +676,12 @@ insert into t1 values (null);
|
|||||||
select format(d, 2) from t1;
|
select format(d, 2) from t1;
|
||||||
drop table 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
|
# 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.
|
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)
|
bool Item_field::fix_fields(THD *thd, Item **reference)
|
||||||
{
|
{
|
||||||
enum_parsing_place place= NO_MATTER;
|
|
||||||
DBUG_ASSERT(fixed == 0);
|
DBUG_ASSERT(fixed == 0);
|
||||||
if (!field) // If field is not checked
|
if (!field) // If field is not checked
|
||||||
{
|
{
|
||||||
bool upward_lookup= FALSE;
|
|
||||||
Field *from_field= (Field *)not_found_field;
|
Field *from_field= (Field *)not_found_field;
|
||||||
|
bool outer_fixed= false;
|
||||||
/*
|
/*
|
||||||
In case of view, find_field_in_tables() write pointer to view field
|
In case of view, find_field_in_tables() write pointer to view field
|
||||||
expression to 'reference', i.e. it substitute that expression instead
|
expression to 'reference', i.e. it substitute that expression instead
|
||||||
@ -3278,7 +3523,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
TRUE)) ==
|
TRUE)) ==
|
||||||
not_found_field)
|
not_found_field)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
/* Look up in current select's item_list to find aliased fields */
|
/* Look up in current select's item_list to find aliased fields */
|
||||||
if (thd->lex->current_select->is_item_list_lookup)
|
if (thd->lex->current_select->is_item_list_lookup)
|
||||||
{
|
{
|
||||||
@ -3293,197 +3538,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
|
||||||
/*
|
goto error;
|
||||||
If there are outer contexts (outer selects, but current select is
|
else if (!ret)
|
||||||
not derived table or view) try to resolve this reference in the
|
return FALSE;
|
||||||
outer contexts.
|
outer_fixed= TRUE;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!from_field)
|
else if (!from_field)
|
||||||
goto error;
|
goto error;
|
||||||
@ -3503,6 +3562,17 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
if (from_field == view_ref_found)
|
if (from_field == view_ref_found)
|
||||||
return FALSE;
|
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);
|
set_field(from_field);
|
||||||
if (thd->lex->in_sum_func &&
|
if (thd->lex->in_sum_func &&
|
||||||
thd->lex->in_sum_func->nest_level ==
|
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 (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->used_tables_cache|= from_field->table->map;
|
||||||
prev_subselect_item->const_item_cache= 0;
|
prev_subselect_item->const_item_cache= 0;
|
||||||
break;
|
break;
|
||||||
|
@ -1205,6 +1205,7 @@ public:
|
|||||||
inline uint32 max_disp_length() { return field->max_length(); }
|
inline uint32 max_disp_length() { return field->max_length(); }
|
||||||
Item_field *filed_for_view_update() { return this; }
|
Item_field *filed_for_view_update() { return this; }
|
||||||
Item *safe_charset_converter(CHARSET_INFO *tocs);
|
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_default_value;
|
||||||
friend class Item_insert_value;
|
friend class Item_insert_value;
|
||||||
friend class st_select_lex_unit;
|
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)
|
String *Item_func_substr_index::val_str(String *str)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
String *res =args[0]->val_str(str);
|
String *res= args[0]->val_str(str);
|
||||||
String *delimeter =args[1]->val_str(&tmp_value);
|
String *delimiter= args[1]->val_str(&tmp_value);
|
||||||
int32 count = (int32) args[2]->val_int();
|
int32 count= (int32) args[2]->val_int();
|
||||||
uint offset;
|
uint offset;
|
||||||
|
|
||||||
if (args[0]->null_value || args[1]->null_value || args[2]->null_value)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
null_value=0;
|
null_value=0;
|
||||||
uint delimeter_length=delimeter->length();
|
uint delimiter_length= delimiter->length();
|
||||||
if (!res->length() || !delimeter_length || !count)
|
if (!res->length() || !delimiter_length || !count)
|
||||||
return &my_empty_string; // Wrong parameters
|
return &my_empty_string; // Wrong parameters
|
||||||
|
|
||||||
res->set_charset(collation.collation);
|
res->set_charset(collation.collation);
|
||||||
@ -1148,11 +1148,11 @@ String *Item_func_substr_index::val_str(String *str)
|
|||||||
#ifdef USE_MB
|
#ifdef USE_MB
|
||||||
if (use_mb(res->charset()))
|
if (use_mb(res->charset()))
|
||||||
{
|
{
|
||||||
const char *ptr=res->ptr();
|
const char *ptr= res->ptr();
|
||||||
const char *strend = ptr+res->length();
|
const char *strend= ptr+res->length();
|
||||||
const char *end=strend-delimeter_length+1;
|
const char *end= strend-delimiter_length+1;
|
||||||
const char *search=delimeter->ptr();
|
const char *search= delimiter->ptr();
|
||||||
const char *search_end=search+delimeter_length;
|
const char *search_end= search+delimiter_length;
|
||||||
int32 n=0,c=count,pass;
|
int32 n=0,c=count,pass;
|
||||||
register uint32 l;
|
register uint32 l;
|
||||||
for (pass=(count>0);pass<2;++pass)
|
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 (*i++ != *j++) goto skip;
|
||||||
if (pass==0) ++n;
|
if (pass==0) ++n;
|
||||||
else if (!--c) break;
|
else if (!--c) break;
|
||||||
ptr+=delimeter_length;
|
ptr+= delimiter_length;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
skip:
|
skip:
|
||||||
@ -1189,7 +1189,7 @@ String *Item_func_substr_index::val_str(String *str)
|
|||||||
}
|
}
|
||||||
else /* return right part */
|
else /* return right part */
|
||||||
{
|
{
|
||||||
ptr+=delimeter_length;
|
ptr+= delimiter_length;
|
||||||
tmp_value.set(*res,(ulong) (ptr-res->ptr()), (ulong) (strend-ptr));
|
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)
|
if (count > 0)
|
||||||
{ // start counting from the beginning
|
{ // 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
|
return res; // Didn't find, return org string
|
||||||
if (!--count)
|
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
|
address space less than where the found substring is located
|
||||||
in res
|
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
|
return res; // Didn't find, return org string
|
||||||
/*
|
/*
|
||||||
At this point, we've searched for the substring
|
At this point, we've searched for the substring
|
||||||
@ -1231,13 +1231,19 @@ String *Item_func_substr_index::val_str(String *str)
|
|||||||
*/
|
*/
|
||||||
if (!++count)
|
if (!++count)
|
||||||
{
|
{
|
||||||
offset+=delimeter_length;
|
offset+= delimiter_length;
|
||||||
tmp_value.set(*res,offset,res->length()- offset);
|
tmp_value.set(*res,offset,res->length()- offset);
|
||||||
break;
|
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);
|
return (&tmp_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,7 @@ public:
|
|||||||
friend class select_subselect;
|
friend class select_subselect;
|
||||||
friend class Item_in_optimizer;
|
friend class Item_in_optimizer;
|
||||||
friend bool Item_field::fix_fields(THD *, Item **);
|
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 bool Item_ref::fix_fields(THD *, Item **);
|
||||||
friend void mark_select_range_as_dependent(THD*,
|
friend void mark_select_range_as_dependent(THD*,
|
||||||
st_select_lex*, st_select_lex*,
|
st_select_lex*, st_select_lex*,
|
||||||
|
Reference in New Issue
Block a user