summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorigor@olga.mysql.com <>2007-02-16 09:39:08 -0800
committerigor@olga.mysql.com <>2007-02-16 09:39:08 -0800
commitf5888a8d10b5aa3ac897ef528e031131a642bc0e (patch)
tree60b3d32cd44dda217a9477932c254b2f9ea2b800 /sql
parenta2d4a042d098fb01183c9b47e9ac6194997007ba (diff)
parent31d63b7971c02ec6ebb31ad907b7862200fe3c39 (diff)
downloadmariadb-git-f5888a8d10b5aa3ac897ef528e031131a642bc0e.tar.gz
Merge ibabaev@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into olga.mysql.com:/home/igor/mysql-5.0-opt
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc45
-rw-r--r--sql/item.h2
-rw-r--r--sql/sql_insert.cc16
-rw-r--r--sql/sql_select.cc6
4 files changed, 66 insertions, 3 deletions
diff --git a/sql/item.cc b/sql/item.cc
index b4a7820eabf..e97b9f504cd 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4809,6 +4809,51 @@ void Item_field::update_null_value()
}
+/*
+ Add the field to the select list and substitute it for the reference to
+ the field.
+
+ SYNOPSIS
+ Item_field::update_value_transformer()
+ select_arg current select
+
+ DESCRIPTION
+ If the field doesn't belong to the table being inserted into then it is
+ added to the select list, pointer to it is stored in the ref_pointer_array
+ of the select and the field itself is substituted for the Item_ref object.
+ This is done in order to get correct values from update fields that
+ belongs to the SELECT part in the INSERT .. SELECT .. ON DUPLICATE KEY
+ UPDATE statement.
+
+ RETURN
+ 0 if error occured
+ ref if all conditions are met
+ this field otherwise
+*/
+
+Item *Item_field::update_value_transformer(byte *select_arg)
+{
+ SELECT_LEX *select= (SELECT_LEX*)select_arg;
+ DBUG_ASSERT(fixed);
+
+ if (field->table != select->context.table_list->table &&
+ type() != Item::TRIGGER_FIELD_ITEM)
+ {
+ List<Item> *all_fields= &select->join->all_fields;
+ Item **ref_pointer_array= select->ref_pointer_array;
+ int el= all_fields->elements;
+ Item_ref *ref;
+
+ ref_pointer_array[el]= (Item*)this;
+ all_fields->push_front((Item*)this);
+ ref= new Item_ref(&select->context, ref_pointer_array + el,
+ table_name, field_name);
+ return ref;
+ }
+ return this;
+}
+
+
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
const char *field_name_arg)
diff --git a/sql/item.h b/sql/item.h
index 6c41aa09f80..c254578f780 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -817,6 +817,7 @@ public:
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *update_value_transformer(byte *select_arg) { return this; }
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
@@ -1295,6 +1296,7 @@ public:
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);
+ virtual Item *update_value_transformer(byte *select_arg);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 39d7f8e9b58..542f47294e5 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2388,7 +2388,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
next_name_resolution_table= ctx_state.save_next_local;
}
res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
+ if (!res)
+ {
+ /*
+ Traverse the update values list and substitute fields from the
+ select for references (Item_ref objects) to them. This is done in
+ order to get correct values from those fields when the select
+ employs a temporary table.
+ */
+ List_iterator<Item> li(*info.update_values);
+ Item *item;
+ while ((item= li++))
+ {
+ item->transform(&Item::update_value_transformer,
+ (byte*)lex->current_select);
+ }
+ }
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 93f5092fd60..5b61c55219d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -482,6 +482,9 @@ JOIN::prepare(Item ***rref_pointer_array,
}
}
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
+ goto err; /* purecov: inspected */
+
/* Init join struct */
count_field_types(&tmp_table_param, all_fields, 0);
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
@@ -495,9 +498,6 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- if (!procedure && result && result->prepare(fields_list, unit_arg))
- goto err; /* purecov: inspected */
-
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
goto err;
if (alloc_func_list())