summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorgkodinov/kgeorge@macbook.gmz <>2007-01-23 12:34:50 +0200
committergkodinov/kgeorge@macbook.gmz <>2007-01-23 12:34:50 +0200
commit17a0207ecee35c82e0a488b900d0e6279a596577 (patch)
treeef50ee2680b393a9652b2c98dfe15de22de7f795 /sql
parentc9df1caac83eac107acb0acfecf3b0a950e7ffa5 (diff)
parent884713fb08418ae819ba39a5429a3dd18586c423 (diff)
downloadmariadb-git-17a0207ecee35c82e0a488b900d0e6279a596577.tar.gz
Merge macbook.gmz:/Users/kgeorge/mysql/work/mysql-5.0-opt
into macbook.gmz:/Users/kgeorge/mysql/work/merge-5.1-opt
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc23
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.cc16
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/item_func.cc9
-rw-r--r--sql/item_strfunc.cc13
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc93
-rw-r--r--sql/sql_lex.cc14
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc101
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_union.cc1
-rw-r--r--sql/sql_update.cc2
18 files changed, 245 insertions, 65 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 83be426d8b5..6ccfd4b4647 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3503,6 +3503,16 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
if (*from_field)
{
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ /*
+ As this is an outer field it should be added to the list of
+ non aggregated fields of the outer select.
+ */
+ marker= select->cur_pos_in_select_list;
+ select->non_agg_fields.push_back(this);
+ }
if (*from_field != view_ref_found)
{
prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
@@ -3705,10 +3715,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
bool Item_field::fix_fields(THD *thd, Item **reference)
{
DBUG_ASSERT(fixed == 0);
+ Field *from_field= (Field *)not_found_field;
+ bool outer_fixed= false;
+
if (!field) // If field is not checked
{
- 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
@@ -3800,6 +3811,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
goto error;
if (!ret)
return FALSE;
+ outer_fixed= 1;
}
set_field(from_field);
@@ -3859,6 +3871,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
}
#endif
fixed= 1;
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
+ !outer_fixed && !thd->lex->in_sum_func &&
+ thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS)
+ {
+ thd->lex->current_select->non_agg_fields.push_back(this);
+ marker= thd->lex->current_select->cur_pos_in_select_list;
+ }
return FALSE;
error:
diff --git a/sql/item.h b/sql/item.h
index c962e36aa2b..7100cf9a997 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -482,7 +482,8 @@ public:
Item *next;
uint32 max_length;
uint name_length; /* Length of name */
- uint8 marker, decimals;
+ int8 marker;
+ uint8 decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
@@ -2373,6 +2374,9 @@ public:
bool fix_fields(THD *, Item **);
void print(String *str);
table_map used_tables() const { return (table_map)0L; }
+ Field *get_tmp_table_field() { return 0; }
+ Item *copy_or_same(THD *thd) { return this; }
+ Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
void cleanup();
private:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 3a615d4c10a..3a887e6dda6 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -176,6 +176,22 @@ longlong Item_func_not::val_int()
}
/*
+ We put any NOT expression into parenthesis to avoid
+ possible problems with internal view representations where
+ any '!' is converted to NOT. It may cause a problem if
+ '!' is used in an expression together with other operators
+ whose precedence is lower than the precedence of '!' yet
+ higher than the precedence of NOT.
+*/
+
+void Item_func_not::print(String *str)
+{
+ str->append('(');
+ Item_func::print(str);
+ str->append(')');
+}
+
+/*
special NOT for ALL subquery
*/
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index a51cc0d4b30..899d29d4786 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -271,6 +271,7 @@ public:
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
bool check_partition_func_processor(byte *int_arg) {return FALSE;}
+ void print(String *str);
};
class Item_maxmin_subselect;
@@ -1033,6 +1034,11 @@ public:
class Item_func_in :public Item_func_opt_neg
{
public:
+ Item_result cmp_type;
+ /*
+ an array of values when the right hand arguments of IN
+ are all SQL constant and there are no nulls
+ */
in_vector *array;
bool have_null;
Item_result left_result_type;
@@ -1064,7 +1070,7 @@ public:
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
- { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
+ { return OPTIMIZE_KEY; }
void print(String *str);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 37778acd962..c068c3e1743 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2746,25 +2746,28 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func,
if (arguments[i]->const_item())
{
- if (arguments[i]->null_value)
- continue;
-
switch (arguments[i]->result_type())
{
case STRING_RESULT:
case DECIMAL_RESULT:
{
String *res= arguments[i]->val_str(&buffers[i]);
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= (char*) res->ptr();
break;
}
case INT_RESULT:
*((longlong*) to)= arguments[i]->val_int();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(longlong));
break;
case REAL_RESULT:
*((double*) to)= arguments[i]->val_real();
+ if (arguments[i]->null_value)
+ continue;
f_args.args[i]= to;
to+= ALIGN_SIZE(sizeof(double));
break;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 89a85a19f56..76c3c1da11e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1706,6 +1706,19 @@ String *Item_func_encode::val_str(String *str)
return res;
}
+void Item_func_encode::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+ args[0]->print(str);
+ str->append(',');
+ str->append('\'');
+ str->append(seed);
+ str->append('\'');
+ str->append(')');
+}
+
+
String *Item_func_decode::val_str(String *str)
{
String *res;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index ae11e001551..1d4020a0fc8 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -360,12 +360,16 @@ public:
class Item_func_encode :public Item_str_func
{
+ protected:
+ SQL_CRYPT sql_crypt;
+ String seed;
public:
Item_func_encode(Item *a, Item *seed):
Item_str_func(a, seed) {}
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "encode"; }
+ void print(String *str);
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a6174b80d86..241f40f1426 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -415,7 +415,11 @@ MY_LOCALE *my_locale_by_name(const char *name);
#define UNCACHEABLE_EXPLAIN 8
/* Don't evaluate subqueries in prepare even if they're not correlated */
#define UNCACHEABLE_PREPARE 16
+/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
+#define UNCACHEABLE_UNITED 32
+/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
+#define UNDEF_POS (-1)
#ifdef EXTRA_DEBUG
/*
Sync points allow us to force the server to reach a certain line of code
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 75e019ccb63..40375134aff 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -5327,6 +5327,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
Item **ref= ref_pointer_array;
+ thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
@@ -5343,7 +5344,10 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
thd->used_tables|= item->used_tables();
+ thd->lex->current_select->cur_pos_in_select_list++;
}
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
+
thd->lex->allow_sum_func= save_allow_sum_func;
thd->mark_used_columns= save_mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index df313d8040c..e3405d9c9d9 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -153,7 +153,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (order && order->elements)
{
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
TABLE_LIST tables;
List<Item> fields;
@@ -173,7 +173,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
}
- if (!select && limit != HA_POS_ERROR)
+ if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);
if (usable_index == MAX_KEY)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ccacd71a614..f15ee194055 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -81,6 +81,65 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
#endif
+/*
+ Check that insert/update fields are from the same single table of a view.
+
+ SYNOPSIS
+ check_view_single_update()
+ fields The insert/update fields to be checked.
+ view The view for insert.
+ map [in/out] The insert table map.
+
+ DESCRIPTION
+ This function is called in 2 cases:
+ 1. to check insert fields. In this case *map will be set to 0.
+ Insert fields are checked to be all from the same single underlying
+ table of the given view. Otherwise the error is thrown. Found table
+ map is returned in the map parameter.
+ 2. to check update fields of the ON DUPLICATE KEY UPDATE clause.
+ In this case *map contains table_map found on the previous call of
+ the function to check insert fields. Update fields are checked to be
+ from the same table as the insert fields.
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
+ table_map *map)
+{
+ /* it is join view => we need to find the table for update */
+ List_iterator_fast<Item> it(fields);
+ Item *item;
+ TABLE_LIST *tbl= 0; // reset for call to check_single_table()
+ table_map tables= 0;
+
+ while ((item= it++))
+ tables|= item->used_tables();
+
+ /* Check found map against provided map */
+ if (*map)
+ {
+ if (tables != *map)
+ goto error;
+ return FALSE;
+ }
+
+ if (view->check_single_table(&tbl, tables, view) || tbl == 0)
+ goto error;
+
+ view->table= tbl->table;
+ *map= tables;
+
+ return FALSE;
+
+error:
+ my_error(ER_VIEW_MULTIUPDATE, MYF(0),
+ view->view_db.str, view->view_name.str);
+ return TRUE;
+}
+
/*
Check if insert fields are correct.
@@ -105,7 +164,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- bool check_unique)
+ bool check_unique, table_map *map)
{
TABLE *table= table_list->table;
@@ -183,21 +242,9 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
- /* it is join view => we need to find table for update */
- List_iterator_fast<Item> it(fields);
- Item *item;
- TABLE_LIST *tbl= 0; // reset for call to check_single_table()
- table_map map= 0;
-
- while ((item= it++))
- map|= item->used_tables();
- if (table_list->check_single_table(&tbl, map, table_list) || tbl == 0)
- {
- my_error(ER_VIEW_MULTIUPDATE, MYF(0),
- table_list->view_db.str, table_list->view_name.str);
+ if (check_view_single_update(fields, table_list, map))
return -1;
- }
- table_list->table= table= tbl->table;
+ table= table_list->table;
}
if (check_unique && thd->dup_field)
@@ -255,7 +302,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
- List<Item> &update_fields)
+ List<Item> &update_fields, table_map *map)
{
TABLE *table= insert_table_list->table;
my_bool timestamp_mark;
@@ -276,6 +323,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
return -1;
+ if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
+ check_view_single_update(update_fields, insert_table_list, map))
+ return -1;
+
if (table->timestamp_field)
{
/* Don't set timestamp column if this is modified. */
@@ -892,6 +943,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
Name_resolution_context_state ctx_state;
bool insert_into_view= (table_list->view != 0);
bool res= 0;
+ table_map map= 0;
DBUG_ENTER("mysql_prepare_insert");
DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
(ulong)table_list, (ulong)table,
@@ -940,12 +992,12 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
/* Prepare the fields in the statement. */
if (values &&
!(res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view) ||
+ !insert_into_view, &map) ||
setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) &&
duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields);
+ res= check_update_fields(thd, context->table_list, update_fields, &map);
select_lex->no_wrap_view_item= FALSE;
/*
When we are not using GROUP BY we can refer to other tables in the
@@ -2406,6 +2458,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
LEX *lex= thd->lex;
int res;
+ table_map map= 0;
SELECT_LEX *lex_current_select_save= lex->current_select;
DBUG_ENTER("select_insert::prepare");
@@ -2418,7 +2471,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
lex->current_select= &lex->select_lex;
res= check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view) ||
+ !insert_into_view, &map) ||
setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
if (info.handle_duplicates == DUP_UPDATE)
@@ -2436,7 +2489,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->select_lex.no_wrap_view_item= TRUE;
res= res || check_update_fields(thd, context->table_list,
- *info.update_fields);
+ *info.update_fields, &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
When we are not using GROUP BY we can refer to other tables in the
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 18d30494701..9c59b98f4e6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1209,6 +1209,8 @@ void st_select_lex::init_select()
offset_limit= 0; /* denotes the default offset = 0 */
with_sum_func= 0;
is_correlated= 0;
+ cur_pos_in_select_list= UNDEF_POS;
+ non_agg_fields.empty();
}
/*
@@ -1398,9 +1400,17 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last)
if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
{
// Select is dependent of outer select
- s->uncacheable|= UNCACHEABLE_DEPENDENT;
+ s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
SELECT_LEX_UNIT *munit= s->master_unit();
- munit->uncacheable|= UNCACHEABLE_DEPENDENT;
+ munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) |
+ UNCACHEABLE_DEPENDENT;
+ for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select())
+ {
+ if (sl != s &&
+ !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED)))
+ sl->uncacheable|= UNCACHEABLE_UNITED;
+ }
}
is_correlated= TRUE;
this->master_unit()->item->is_correlated= TRUE;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 12e41d12899..b32ee779681 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -616,6 +616,10 @@ public:
bool no_wrap_view_item;
/* exclude this select from check of unique_table() */
bool exclude_from_table_unique_test;
+ /* List of fields that aren't under an aggregate function */
+ List<Item_field> non_agg_fields;
+ /* index in the select list of the expression currently being fixed */
+ int cur_pos_in_select_list;
void init_query();
void init_select();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 92366332dcd..211b63c1014 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1677,7 +1677,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_INSERT:
res= mysql_test_insert(stmt, tables, lex->field_list,
lex->many_values,
- select_lex->item_list, lex->value_list,
+ lex->update_list, lex->value_list,
lex->duplicates);
break;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 636b0d85c90..5b765e076c3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8954,8 +8954,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
if (type != Item::FIELD_ITEM &&
item->real_item()->type() == Item::FIELD_ITEM &&
- (item->type() != Item::REF_ITEM ||
- !((Item_ref *) item)->depended_from))
+ !((Item_ref *) item)->depended_from)
{
orig_item= item;
item= item->real_item();
@@ -12499,7 +12498,7 @@ static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
{
- uint length;
+ uint length= 0;
ha_rows examined_rows;
TABLE *table;
SQL_SELECT *select;
@@ -12520,8 +12519,10 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
!(join->select_options & SELECT_BIG_RESULT)) &&
test_if_skip_sort_order(tab,order,select_limit,0))
DBUG_RETURN(0);
+ for (ORDER *ord= join->order; ord; ord= ord->next)
+ length++;
if (!(join->sortorder=
- make_unireg_sortorder(order,&length,join->sortorder)))
+ make_unireg_sortorder(order, &length, join->sortorder)))
goto err; /* purecov: inspected */
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
@@ -12929,8 +12930,10 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
for (ORDER *tmp = order; tmp; tmp=tmp->next)
count++;
if (!sortorder)
- sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
- pos=sort=sortorder;
+ sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD) *
+ (max(count, *length) + 1));
+ pos= sort= sortorder;
+
if (!pos)
return 0;
@@ -13458,49 +13461,83 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
bool *hidden_group_fields)
{
*hidden_group_fields=0;
+ ORDER *ord;
+
if (!order)
return 0; /* Everything is ok */
- if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
- {
- Item *item;
- List_iterator<Item> li(fields);
- while ((item=li++))
- item->marker=0; /* Marker that field is not used */
- }
uint org_fields=all_fields.elements;
thd->where="group statement";
- for (; order; order=order->next)
+ for (ord= order; ord; ord= ord->next)
{
- if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
+ if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
all_fields, TRUE))
return 1;
- (*order->item)->marker=1; /* Mark found */
- if ((*order->item)->with_sum_func)
+ (*ord->item)->marker= UNDEF_POS; /* Mark found */
+ if ((*ord->item)->with_sum_func)
{
- my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*order->item)->full_name());
+ my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
return 1;
}
}
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
{
- /* Don't allow one to use fields that is not used in GROUP BY */
+ /*
+ Don't allow one to use fields that is not used in GROUP BY
+ For each select a list of field references that aren't under an
+ aggregate function is created. Each field in this list keeps the
+ position of the select list expression which it belongs to.
+
+ First we check an expression from the select list against the GROUP BY
+ list. If it's found there then it's ok. It's also ok if this expression
+ is a constant or an aggregate function. Otherwise we scan the list
+ of non-aggregated fields and if we'll find at least one field reference
+ that belongs to this expression and doesn't occur in the GROUP BY list
+ we throw an error. If there are no fields in the created list for a
+ select list expression this means that all fields in it are used under
+ aggregate functions.
+ */
Item *item;
+ Item_field *field;
+ int cur_pos_in_select_list= 0;
List_iterator<Item> li(fields);
+ List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields);
- while ((item=li++))
+ field= naf_it++;
+ while (field && (item=li++))
{
- if (item->type() != Item::SUM_FUNC_ITEM && !item->marker &&
- !item->const_item())
+ if (item->type() != Item::SUM_FUNC_ITEM && item->marker >= 0 &&
+ !item->const_item() &&
+ !(item->real_item()->type() == Item::FIELD_ITEM &&
+ item->used_tables() & OUTER_REF_TABLE_BIT))
{
- /*
- TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
- ER_NON_GROUPING_FIELD_USED
- */
- my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), item->full_name());
- return 1;
+ while (field)
+ {
+ /* Skip fields from previous expressions. */
+ if (field->marker < cur_pos_in_select_list)
+ goto next_field;
+ /* Found a field from the next expression. */
+ if (field->marker > cur_pos_in_select_list)
+ break;
+ /*
+ Check whether the field occur in the GROUP BY list.
+ Throw the error later if the field isn't found.
+ */
+ for (ord= order; ord; ord= ord->next)
+ if ((*ord->item)->eq((Item*)field, 0))
+ goto next_field;
+ /*
+ TODO: change ER_WRONG_FIELD_WITH_GROUP to more detailed
+ ER_NON_GROUPING_FIELD_USED
+ */
+ my_error(ER_WRONG_FIELD_WITH_GROUP, MYF(0), field->full_name());
+ return 1;
+next_field:
+ field= naf_it++;
+ }
}
+ cur_pos_in_select_list++;
}
}
if (org_fields != all_fields.elements)
@@ -13626,10 +13663,12 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
param->quick_group=1;
while ((field=li++))
{
- Item::Type type=field->real_item()->type();
- if (type == Item::FIELD_ITEM)
+ Item::Type type=field->type();
+ Item::Type real_type= field->real_item()->type();
+ if (type == Item::FIELD_ITEM || (real_type == Item::FIELD_ITEM &&
+ !((Item_ref *) field)->depended_from))
param->field_count++;
- else if (type == Item::SUM_FUNC_ITEM)
+ else if (real_type == Item::SUM_FUNC_ITEM)
{
if (! field->const_item())
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 7057c783701..7c3bf6ca304 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6684,7 +6684,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
Copy_field *copy,*copy_end;
ulong found_count,delete_count;
THD *thd= current_thd;
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
READ_RECORD info;
TABLE_LIST tables;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index e9e244676d1..985982d48de 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -734,6 +734,7 @@ bool st_select_lex::cleanup()
{
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
}
+ non_agg_fields.empty();
DBUG_RETURN(error);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 9952a4f534b..2e956a3ea74 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -320,7 +320,7 @@ int mysql_update(THD *thd,
to update
NOTE: filesort will call table->prepare_for_position()
*/
- uint length;
+ uint length= 0;
SORT_FIELD *sortorder;
ha_rows examined_rows;