summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc7
-rw-r--r--sql/field.h7
-rw-r--r--sql/field_conv.cc9
-rw-r--r--sql/filesort.cc5
-rw-r--r--sql/ha_innodb.cc25
-rw-r--r--sql/ha_myisam.cc37
-rw-r--r--sql/ha_myisammrg.h3
-rw-r--r--sql/ha_ndbcluster.cc11
-rw-r--r--sql/handler.cc6
-rw-r--r--sql/item.cc75
-rw-r--r--sql/item.h31
-rw-r--r--sql/item_cmpfunc.cc130
-rw-r--r--sql/item_cmpfunc.h17
-rw-r--r--sql/item_func.cc14
-rw-r--r--sql/item_strfunc.cc19
-rw-r--r--sql/item_strfunc.h6
-rw-r--r--sql/item_subselect.cc3
-rw-r--r--sql/lex.h4
-rw-r--r--sql/lex_symbol.h2
-rw-r--r--sql/log.cc96
-rw-r--r--sql/log_event.cc5
-rw-r--r--sql/mysql_priv.h33
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/slave.cc3
-rw-r--r--sql/sp_head.cc23
-rw-r--r--sql/sp_head.h29
-rw-r--r--sql/sp_pcontext.cc90
-rw-r--r--sql/sp_pcontext.h61
-rw-r--r--sql/spatial.h43
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_base.cc143
-rw-r--r--sql/sql_class.cc14
-rw-r--r--sql/sql_class.h22
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc90
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc66
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc54
-rw-r--r--sql/sql_table.cc4
-rw-r--r--sql/sql_union.cc6
-rw-r--r--sql/sql_update.cc6
-rw-r--r--sql/sql_yacc.yy60
49 files changed, 905 insertions, 390 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 352f08e40ce..f80bf12db92 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1036,6 +1036,7 @@ bool Field::type_can_have_key_part(enum enum_field_types type)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_GEOMETRY:
return TRUE;
default:
return FALSE;
@@ -1277,12 +1278,12 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
String *Field::val_int_as_str(String *val_buffer, my_bool unsigned_val)
{
CHARSET_INFO *cs= &my_charset_bin;
- uint length= 21;
+ uint length;
longlong value= val_int();
- if (val_buffer->alloc(length))
+ if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
return 0;
length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
- length,
+ MY_INT64_NUM_DECIMAL_DIGITS,
unsigned_val ? 10 : -10,
value);
val_buffer->length(length);
diff --git a/sql/field.h b/sql/field.h
index 32553573433..eb00899cf54 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -225,7 +225,7 @@ public:
ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
}
inline void move_field(char *ptr_arg) { ptr=ptr_arg; }
- inline void move_field(my_ptrdiff_t ptr_diff)
+ virtual inline void move_field(my_ptrdiff_t ptr_diff)
{
ptr=ADD_TO_PTR(ptr,ptr_diff,char*);
if (null_ptr)
@@ -1410,6 +1410,11 @@ public:
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
char *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
+ inline void move_field(my_ptrdiff_t ptr_diff)
+ {
+ Field::move_field(ptr_diff);
+ bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*);
+ }
void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
{
bit_ptr= bit_ptr_arg;
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index dbe58d804ad..32180f0a93e 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -337,6 +337,13 @@ static void do_field_real(Copy_field *copy)
}
+static void do_field_decimal(Copy_field *copy)
+{
+ my_decimal value;
+ copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
+}
+
+
/*
string copy for single byte characters set when to string is shorter than
from string
@@ -581,6 +588,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
if (to->real_type() == FIELD_TYPE_BIT ||
from->real_type() == FIELD_TYPE_BIT)
return do_field_int;
+ if (to->result_type() == DECIMAL_RESULT)
+ return do_field_decimal;
// Check if identical fields
if (from->result_type() == STRING_RESULT)
{
diff --git a/sql/filesort.cc b/sql/filesort.cc
index e40c492fe8e..23d652cb8cc 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1298,7 +1298,10 @@ sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
}
else
{
- switch ((sortorder->result_type=sortorder->item->result_type())) {
+ sortorder->result_type= sortorder->item->result_type();
+ if (sortorder->item->result_as_longlong())
+ sortorder->result_type= INT_RESULT;
+ switch (sortorder->result_type) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 8a35ff000a8..217f59d4b7e 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -6066,6 +6066,15 @@ ha_innobase::external_lock(
trx->isolation_level = innobase_map_isolation_level(
(enum_tx_isolation)
thd->variables.tx_isolation);
+
+ if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
+ && trx->global_read_view) {
+
+ /* At low transaction isolation levels we let
+ each consistent read set its own snapshot */
+
+ read_view_close_for_mysql(trx);
+ }
}
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
@@ -6391,16 +6400,16 @@ innodb_mutex_show_status(
#ifdef UNIV_DEBUG
field_list.push_back(new Item_empty_string("Mutex", FN_REFLEN));
field_list.push_back(new Item_empty_string("Module", FN_REFLEN));
- field_list.push_back(new Item_uint("Count", 21));
- field_list.push_back(new Item_uint("Spin_waits", 21));
- field_list.push_back(new Item_uint("Spin_rounds", 21));
- field_list.push_back(new Item_uint("OS_waits", 21));
- field_list.push_back(new Item_uint("OS_yields", 21));
- field_list.push_back(new Item_uint("OS_waits_time", 21));
+ field_list.push_back(new Item_uint("Count", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("Spin_waits", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("Spin_rounds", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("OS_waits", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("OS_yields", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("OS_waits_time", MY_INT64_NUM_DECIMAL_DIGITS));
#else /* UNIV_DEBUG */
field_list.push_back(new Item_empty_string("File", FN_REFLEN));
- field_list.push_back(new Item_uint("Line", 21));
- field_list.push_back(new Item_uint("OS_waits", 21));
+ field_list.push_back(new Item_uint("Line", MY_INT64_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_uint("OS_waits", MY_INT64_NUM_DECIMAL_DIGITS));
#endif /* UNIV_DEBUG */
if (protocol->send_fields(&field_list,
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index dd00c91e4af..10d3dbb2ec5 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -342,6 +342,12 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
RETURN VALUE
0 - Equal definitions.
1 - Different definitions.
+
+ TODO
+ - compare FULLTEXT keys;
+ - compare SPATIAL keys;
+ - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
+ (should be corretly detected in table2myisam).
*/
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
@@ -367,6 +373,28 @@ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
{
HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
+ if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
+ continue;
+ else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
+ t2_keyinfo[i].flag & HA_FULLTEXT)
+ {
+ DBUG_PRINT("error", ("Key %d has different definition", i));
+ DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
+ test(t1_keyinfo[i].flag & HA_FULLTEXT),
+ test(t2_keyinfo[i].flag & HA_FULLTEXT)));
+ DBUG_RETURN(1);
+ }
+ if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
+ continue;
+ else if (t1_keyinfo[i].flag & HA_SPATIAL ||
+ t2_keyinfo[i].flag & HA_SPATIAL)
+ {
+ DBUG_PRINT("error", ("Key %d has different definition", i));
+ DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
+ test(t1_keyinfo[i].flag & HA_SPATIAL),
+ test(t2_keyinfo[i].flag & HA_SPATIAL)));
+ DBUG_RETURN(1);
+ }
if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
{
@@ -403,7 +431,14 @@ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
{
MI_COLUMNDEF *t1_rec= &t1_recinfo[i];
MI_COLUMNDEF *t2_rec= &t2_recinfo[i];
- if (t1_rec->type != t2_rec->type ||
+ /*
+ FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
+ see NOTE1 in mi_create.c
+ */
+ if ((t1_rec->type != t2_rec->type &&
+ !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
+ t1_rec->length == 1 &&
+ t2_rec->type == (int) FIELD_NORMAL)) ||
t1_rec->length != t2_rec->length ||
t1_rec->null_bit != t2_rec->null_bit)
{
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index e546dfee699..16c734e2682 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -36,8 +36,7 @@ class ha_myisammrg: public handler
{
return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_READ_RND_SAME |
HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
- HA_CAN_INSERT_DELAYED | HA_ANY_INDEX_MAY_BE_UNIQUE |
- HA_CAN_BIT_FIELD);
+ HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD);
}
ulong index_flags(uint inx, uint part, bool all_parts) const
{
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 7a9c7d0d021..d2a242a6b01 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -952,7 +952,7 @@ int ha_ndbcluster::get_metadata(const char *path)
DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
do {
- const void *data, *pack_data;
+ const void *data= NULL, *pack_data= NULL;
uint length, pack_length;
if (!(tab= dict->getTable(m_tabname)))
@@ -3751,7 +3751,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
if ((my_errno= build_index_list(ndb, table, ILBP_OPEN)))
DBUG_RETURN(my_errno);
- const void *data, *pack_data;
+ const void *data= NULL, *pack_data= NULL;
uint length, pack_length;
if (readfrm(table->s->path, &data, &length) ||
packfrm(data, length, &pack_data, &pack_length) ||
@@ -4340,7 +4340,7 @@ int ha_ndbcluster::create(const char *name,
NDBTAB tab;
NDBCOL col;
uint pack_length, length, i, pk_length= 0;
- const void *data, *pack_data;
+ const void *data= NULL, *pack_data= NULL;
char name2[FN_HEADLEN];
bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
@@ -4375,8 +4375,11 @@ int ha_ndbcluster::create(const char *name,
if (readfrm(name, &data, &length))
DBUG_RETURN(1);
if (packfrm(data, length, &pack_data, &pack_length))
+ {
+ my_free((char*)data, MYF(0));
DBUG_RETURN(2);
-
+ }
+
DBUG_PRINT("info", ("setFrm data: 0x%lx len: %d", (long) pack_data, pack_length));
tab.setFrm(pack_data, pack_length);
my_free((char*)data, MYF(0));
diff --git a/sql/handler.cc b/sql/handler.cc
index 5a27e470d70..524f47209dc 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1082,9 +1082,9 @@ bool mysql_xa_recover(THD *thd)
XID_STATE *xs;
DBUG_ENTER("mysql_xa_recover");
- field_list.push_back(new Item_int("formatID",0,11));
- field_list.push_back(new Item_int("gtrid_length",0,11));
- field_list.push_back(new Item_int("bqual_length",0,11));
+ field_list.push_back(new Item_int("formatID", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_int("gtrid_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+ field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
if (protocol->send_fields(&field_list,
diff --git a/sql/item.cc b/sql/item.cc
index 92008a344ef..3174274b79f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -148,7 +148,7 @@ void
Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
{
item->decimals= 0;
- item->max_length= 21;
+ item->max_length= MY_INT64_NUM_DECIMAL_DIGITS;
item->unsigned_flag= 0;
}
@@ -1758,9 +1758,10 @@ void Item_ident::print(String *str)
}
}
- if (!table_name || !field_name)
+ if (!table_name || !field_name || !field_name[0])
{
- const char *nm= field_name ? field_name : name ? name : "tmp_field";
+ const char *nm= (field_name && field_name[0]) ?
+ field_name : name ? name : "tmp_field";
append_identifier(thd, str, nm, (uint) strlen(nm));
return;
}
@@ -2491,7 +2492,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
item_result_type= REAL_RESULT;
break;
case INT_RESULT:
- set_int(*(longlong*)entry->value, 21);
+ set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
item_type= Item::INT_ITEM;
item_result_type= INT_RESULT;
break;
@@ -3320,7 +3321,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
ORDER *group_list= (ORDER*) select->group_list.first;
bool ambiguous_fields= FALSE;
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
/*
Search for a column or derived column named as 'ref' in the SELECT
@@ -3328,8 +3329,10 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
*/
if (!(select_ref= find_item_in_list(ref, *(select->get_item_list()),
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used)))
+ &resolution)))
return NULL; /* Some error occurred. */
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ ref->alias_name_used= TRUE;
/* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
if (select->having_fix_field && !ref->with_sum_func && group_list)
@@ -3439,7 +3442,12 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*/
Name_resolution_context *last_checked_context= context;
Item **ref= (Item **) not_found_item;
- Name_resolution_context *outer_context= context->outer_context;
+ SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
+ Name_resolution_context *outer_context= 0;
+ /* Currently derived tables cannot be correlated */
+ if (current_sel->master_unit()->first_select()->linkage !=
+ DERIVED_TABLE_TYPE)
+ outer_context= context->outer_context;
for (;
outer_context;
outer_context= outer_context->outer_context)
@@ -3630,9 +3638,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
new Item_ref(context, ref, (char*) table_name,
- (char*) field_name) :
+ (char*) field_name, alias_name_used) :
new Item_direct_ref(context, ref, (char*) table_name,
- (char*) field_name));
+ (char*) field_name, alias_name_used));
*ref= save;
if (!rf)
return -1;
@@ -3750,12 +3758,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (thd->lex->current_select->is_item_list_lookup)
{
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used);
+ &resolution);
if (!res)
return 1;
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ alias_name_used= TRUE;
if (res != (Item **)not_found_item)
{
if ((*res)->type() == Item::FIELD_ITEM)
@@ -4065,7 +4075,9 @@ bool Item_field::set_no_const_sub(byte *arg)
DESCRIPTION
The function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field
- object refers to (belongs to).
+ object refers to (belongs to) unless item_equal contains a constant
+ item. In this case the function returns this constant item,
+ (if the substitution does not require conversion).
If the Item_field object does not refer any Item_equal object
'this' is returned
@@ -4074,7 +4086,8 @@ bool Item_field::set_no_const_sub(byte *arg)
of the thransformer method.
RETURN VALUES
- pointer to a replacement Item_field if there is a better equal item;
+ pointer to a replacement Item_field if there is a better equal item or
+ a pointer to a constant equal item;
this - otherwise.
*/
@@ -4082,6 +4095,14 @@ Item *Item_field::replace_equal_field(byte *arg)
{
if (item_equal)
{
+ Item *const_item= item_equal->get_const();
+ if (const_item)
+ {
+ if (cmp_context != (Item_result)-1 &&
+ const_item->cmp_context != cmp_context)
+ return this;
+ return const_item;
+ }
Item_field *subst= item_equal->get_first();
if (subst && !field->eq(subst->field))
return subst;
@@ -4907,12 +4928,30 @@ Item *Item_field::update_value_transformer(byte *select_arg)
}
+void Item_field::print(String *str)
+{
+ if (field && field->table->const_table)
+ {
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff),str->charset());
+ field->val_str(&tmp);
+ str->append('\'');
+ str->append(tmp);
+ str->append('\'');
+ return;
+ }
+ Item_ident::print(str);
+}
+
+
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
- const char *field_name_arg)
+ const char *field_name_arg,
+ bool alias_name_used_arg)
:Item_ident(context_arg, NullS, table_name_arg, field_name_arg),
result_field(0), ref(item)
{
+ alias_name_used= alias_name_used_arg;
/*
This constructor used to create some internals references over fixed items
*/
@@ -5195,11 +5234,13 @@ void Item_ref::set_properties()
*/
with_sum_func= (*ref)->with_sum_func;
unsigned_flag= (*ref)->unsigned_flag;
+ fixed= 1;
+ if (alias_name_used)
+ return;
if ((*ref)->type() == FIELD_ITEM)
alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
else
alias_name_used= TRUE; // it is not field, so it is was resolved by alias
- fixed= 1;
}
@@ -5217,7 +5258,7 @@ void Item_ref::print(String *str)
if (ref)
{
if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
- ref_type() != OUTER_REF && name && alias_name_used)
+ !table_name && name && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, name, (uint) strlen(name));
@@ -6546,7 +6587,7 @@ uint32 Item_type_holder::display_length(Item *item)
case MYSQL_TYPE_SHORT:
return 6;
case MYSQL_TYPE_LONG:
- return 11;
+ return MY_INT32_NUM_DECIMAL_DIGITS;
case MYSQL_TYPE_FLOAT:
return 25;
case MYSQL_TYPE_DOUBLE:
diff --git a/sql/item.h b/sql/item.h
index 833bebdee7e..786d65ff6f4 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1303,6 +1303,7 @@ public:
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);
+ void print(String *str);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -1494,11 +1495,14 @@ class Item_int :public Item_num
{
public:
longlong value;
- Item_int(int32 i,uint length=11) :value((longlong) i)
+ Item_int(int32 i,uint length= MY_INT32_NUM_DECIMAL_DIGITS)
+ :value((longlong) i)
{ max_length=length; fixed= 1; }
- Item_int(longlong i,uint length=21) :value(i)
+ Item_int(longlong i,uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+ :value(i)
{ max_length=length; fixed= 1; }
- Item_int(ulonglong i, uint length= 21) :value((longlong)i)
+ Item_int(ulonglong i, uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+ :value((longlong)i)
{ max_length=length; fixed= 1; unsigned_flag= 1; }
Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; }
@@ -1712,7 +1716,11 @@ public:
str_value.length(), collation.collation);
}
Item *safe_charset_converter(CHARSET_INFO *tocs);
- inline void append(char *str, uint length) { str_value.append(str, length); }
+ inline void append(char *str, uint length)
+ {
+ str_value.append(str, length);
+ max_length= str_value.numchars() * collation.collation->mbmaxlen;
+ }
void print(String *str);
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
@@ -1774,7 +1782,10 @@ public:
Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
double val_real()
- { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); }
+ {
+ DBUG_ASSERT(fixed == 1);
+ return (double) (ulonglong) Item_hex_string::val_int();
+ }
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
@@ -1848,7 +1859,8 @@ public:
with Bar, and if we have a more broader set of problems like this.
*/
Item_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg);
+ const char *table_name_arg, const char *field_name_arg,
+ bool alias_name_used_arg= FALSE);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
@@ -1923,8 +1935,11 @@ class Item_direct_ref :public Item_ref
public:
Item_direct_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg,
- const char *field_name_arg)
- :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ const char *field_name_arg,
+ bool alias_name_used_arg= FALSE)
+ :Item_ref(context_arg, item, table_name_arg,
+ field_name_arg, alias_name_used_arg)
+ {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index edae81b8e2d..3fb19927404 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2155,9 +2155,100 @@ void Item_func_coalesce::fix_length_and_dec()
Classes and function for the IN operator
****************************************************************************/
-static int cmp_longlong(void *cmp_arg, longlong *a,longlong *b)
+/*
+ Determine which of the signed longlong arguments is bigger
+
+ SYNOPSIS
+ cmp_longs()
+ a_val left argument
+ b_val right argument
+
+ DESCRIPTION
+ This function will compare two signed longlong arguments
+ and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+static inline int cmp_longs (longlong a_val, longlong b_val)
{
- return *a < *b ? -1 : *a == *b ? 0 : 1;
+ return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
+}
+
+
+/*
+ Determine which of the unsigned longlong arguments is bigger
+
+ SYNOPSIS
+ cmp_ulongs()
+ a_val left argument
+ b_val right argument
+
+ DESCRIPTION
+ This function will compare two unsigned longlong arguments
+ and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val)
+{
+ return a_val < b_val ? -1 : a_val == b_val ? 0 : 1;
+}
+
+
+/*
+ Compare two integers in IN value list format (packed_longlong)
+
+ SYNOPSIS
+ cmp_longlong()
+ cmp_arg an argument passed to the calling function (qsort2)
+ a left argument
+ b right argument
+
+ DESCRIPTION
+ This function will compare two integer arguments in the IN value list
+ format and will return -1, 0, or 1 if left argument is smaller than,
+ equal to or greater than the right argument.
+ It's used in sorting the IN values list and finding an element in it.
+ Depending on the signedness of the arguments cmp_longlong() will
+ compare them as either signed (using cmp_longs()) or unsigned (using
+ cmp_ulongs()).
+
+ RETURN VALUE
+ -1 left argument is smaller than the right argument.
+ 0 left argument is equal to the right argument.
+ 1 left argument is greater than the right argument.
+*/
+int cmp_longlong(void *cmp_arg,
+ in_longlong::packed_longlong *a,
+ in_longlong::packed_longlong *b)
+{
+ if (a->unsigned_flag != b->unsigned_flag)
+ {
+ /*
+ One of the args is unsigned and is too big to fit into the
+ positive signed range. Report no match.
+ */
+ if (a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX ||
+ b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX)
+ return a->unsigned_flag ? 1 : -1;
+ /*
+ Although the signedness differs both args can fit into the signed
+ positive range. Make them signed and compare as usual.
+ */
+ return cmp_longs (a->val, b->val);
+ }
+ if (a->unsigned_flag)
+ return cmp_ulongs ((ulonglong) a->val, (ulonglong) b->val);
+ else
+ return cmp_longs (a->val, b->val);
}
static int cmp_double(void *cmp_arg, double *a,double *b)
@@ -2282,19 +2373,23 @@ void in_row::set(uint pos, Item *item)
}
in_longlong::in_longlong(uint elements)
- :in_vector(elements,sizeof(longlong),(qsort2_cmp) cmp_longlong, 0)
+ :in_vector(elements,sizeof(packed_longlong),(qsort2_cmp) cmp_longlong, 0)
{}
void in_longlong::set(uint pos,Item *item)
{
- ((longlong*) base)[pos]=item->val_int();
+ struct packed_longlong *buff= &((packed_longlong*) base)[pos];
+
+ buff->val= item->val_int();
+ buff->unsigned_flag= item->unsigned_flag;
}
byte *in_longlong::get_value(Item *item)
{
- tmp= item->val_int();
+ tmp.val= item->val_int();
if (item->null_value)
return 0;
+ tmp.unsigned_flag= item->unsigned_flag;
return (byte*) &tmp;
}
@@ -2615,6 +2710,31 @@ void Item_func_in::fix_length_and_dec()
*/
if (const_itm && !nulls_in_row())
{
+ /*
+ IN must compare INT/DATE/DATETIME/TIMESTAMP columns and constants
+ as int values (the same way as equality does).
+ So we must check here if the column on the left and all the constant
+ values on the right can be compared as integers and adjust the
+ comparison type accordingly.
+ */
+ if (args[0]->real_item()->type() == FIELD_ITEM &&
+ thd->lex->sql_command != SQLCOM_CREATE_VIEW &&
+ thd->lex->sql_command != SQLCOM_SHOW_CREATE &&
+ cmp_type != INT_RESULT)
+ {
+ Field *field= ((Item_field*) (args[0]->real_item()))->field;
+ if (field->can_be_compared_as_longlong())
+ {
+ bool all_converted= TRUE;
+ for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if (!convert_constant_item (thd, field, &arg[0]))
+ all_converted= FALSE;
+ }
+ if (all_converted)
+ cmp_type= INT_RESULT;
+ }
+ }
switch (cmp_type) {
case STRING_RESULT:
array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 319c6c2a36f..f6c6f612c5b 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -820,7 +820,16 @@ public:
class in_longlong :public in_vector
{
- longlong tmp;
+ /*
+ Here we declare a temporary variable (tmp) of the same type as the
+ elements of this vector. tmp is used in finding if a given value is in
+ the list.
+ */
+ struct packed_longlong
+ {
+ longlong val;
+ longlong unsigned_flag; // Use longlong, not bool, to preserve alignment
+ } tmp;
public:
in_longlong(uint elements);
void set(uint pos,Item *item);
@@ -836,8 +845,12 @@ public:
}
void value_to_item(uint pos, Item *item)
{
- ((Item_int*)item)->value= ((longlong*)base)[pos];
+ ((Item_int*) item)->value= ((packed_longlong*) base)[pos].val;
+ ((Item_int*) item)->unsigned_flag= (my_bool)
+ ((packed_longlong*) base)[pos].unsigned_flag;
}
+
+ friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
class in_double :public in_vector
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e41bf25e8e9..3d92be5e9d2 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -409,8 +409,13 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
if (item->type() != FUNC_ITEM)
return 0;
Item_func *item_func=(Item_func*) item;
- if (arg_count != item_func->arg_count ||
- func_name() != item_func->func_name())
+ Item_func::Functype func_type;
+ if ((func_type= functype()) != item_func->functype() ||
+ arg_count != item_func->arg_count ||
+ (func_type != Item_func::FUNC_SP &&
+ func_name() != item_func->func_name()) ||
+ (func_type == Item_func::FUNC_SP &&
+ my_strcasecmp(system_charset_info, func_name(), item_func->func_name())))
return 0;
for (uint i=0; i < arg_count ; i++)
if (!args[i]->eq(item_func->args[i], binary_cmp))
@@ -426,7 +431,7 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
switch (result_type()) {
case INT_RESULT:
- if (max_length > 11)
+ if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
res= new Field_longlong(max_length, maybe_null, name, t_arg,
unsigned_flag);
else
@@ -2316,7 +2321,8 @@ longlong Item_func_coercibility::val_int()
void Item_func_locate::fix_length_and_dec()
{
- maybe_null=0; max_length=11;
+ maybe_null= 0;
+ max_length= MY_INT32_NUM_DECIMAL_DIGITS;
agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 95df89d881d..a7075a5c3a0 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -967,18 +967,18 @@ String *Item_func_insert::val_str(String *str)
args[3]->null_value)
goto null; /* purecov: inspected */
- if ((start < 0) || (start > res->length() + 1))
+ if ((start < 0) || (start > res->length()))
return res; // Wrong param; skip insert
- if ((length < 0) || (length > res->length() + 1))
- length= res->length() + 1;
+ if ((length < 0) || (length > res->length()))
+ length= res->length();
/* start and length are now sufficiently valid to pass to charpos function */
start= res->charpos((int) start);
length= res->charpos((int) length, (uint32) start);
/* Re-testing with corrected params */
- if (start > res->length() + 1)
- return res; // Wrong param; skip insert
+ if (start > res->length())
+ return res; /* purecov: inspected */ // Wrong param; skip insert
if (length > res->length() - start)
length= res->length() - start;
@@ -1184,11 +1184,10 @@ void Item_func_substr::fix_length_and_dec()
if (args[1]->const_item())
{
int32 start= (int32) args[1]->val_int();
- start= (int32)((start < 0) ? max_length + start : start - 1);
- if (start < 0 || start >= (int32) max_length)
- max_length=0; /* purecov: inspected */
+ if (start < 0)
+ max_length= ((uint)(-start) > max_length) ? 0 : (uint)(-start);
else
- max_length-= (uint) start;
+ max_length-= min((uint)(start - 1), max_length);
}
if (arg_count == 3 && args[2]->const_item())
{
@@ -2243,7 +2242,7 @@ String *Item_func_repeat::val_str(String *str)
goto err; // string and/or delim are null
null_value= 0;
- if (count == 0 || count < 0 && !args[1]->unsigned_flag)
+ if (count <= 0 && (count == 0 || !args[1]->unsigned_flag))
return &my_empty_string;
/* Assumes that the maximum length of a String is < INT_MAX32. */
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 60547d00a5c..778ea6e9496 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -605,7 +605,11 @@ class Item_func_unhex :public Item_str_func
{
String tmp_value;
public:
- Item_func_unhex(Item *a) :Item_str_func(a) {}
+ Item_func_unhex(Item *a) :Item_str_func(a)
+ {
+ /* there can be bad hex strings */
+ maybe_null= 1;
+ }
const char *func_name() const { return "unhex"; }
String *val_str(String *);
void fix_length_and_dec()
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 12ae0c026eb..b3744d6eb96 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1037,7 +1037,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Item *having= item, *orig_item= item;
select_lex->item_list.empty();
select_lex->item_list.push_back(new Item_int("Not_used",
- (longlong) 1, 21));
+ (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
item= func->create(expr, item);
diff --git a/sql/lex.h b/sql/lex.h
index 5299be89d35..352d80da5c6 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -32,10 +32,10 @@ SYM_GROUP sym_group_rtree= {"RTree keys", "HAVE_RTREE_KEYS"};
#define SYM(A) SYM_OR_NULL(A),0,0,&sym_group_common
#define F_SYM(A) SYM_OR_NULL(A)
-#define CREATE_FUNC(A) (void *)(SYM_OR_NULL(A)), &sym_group_common
+#define CREATE_FUNC(A) (void (*)())(SYM_OR_NULL(A)), &sym_group_common
#ifdef HAVE_SPATIAL
-#define CREATE_FUNC_GEOM(A) (void *)(SYM_OR_NULL(A)), &sym_group_geom
+#define CREATE_FUNC_GEOM(A) (void (*)())(SYM_OR_NULL(A)), &sym_group_geom
#else
#define CREATE_FUNC_GEOM(A) 0, &sym_group_geom
#endif
diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h
index 5d929508030..c87cdb4ec43 100644
--- a/sql/lex_symbol.h
+++ b/sql/lex_symbol.h
@@ -25,7 +25,7 @@ typedef struct st_symbol {
const char *name;
uint tok;
uint length;
- void *create_func;
+ void (*create_func)();
struct st_sym_group *group;
} SYMBOL;
diff --git a/sql/log.cc b/sql/log.cc
index 7d0bef5ca2c..c2b4eb1a441 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -283,7 +283,7 @@ err:
#ifdef __NT__
static int eventSource = 0;
-void setup_windows_event_source()
+static void setup_windows_event_source()
{
HKEY hRegKey= NULL;
DWORD dwError= 0;
@@ -2229,37 +2229,6 @@ static bool test_if_number(register const char *str,
} /* test_if_number */
-void print_buffer_to_file(enum loglevel level, const char *buffer)
-{
- time_t skr;
- struct tm tm_tmp;
- struct tm *start;
- DBUG_ENTER("print_buffer_to_file");
- DBUG_PRINT("enter",("buffer: %s", buffer));
-
- VOID(pthread_mutex_lock(&LOCK_error_log));
-
- skr=time(NULL);
- localtime_r(&skr, &tm_tmp);
- start=&tm_tmp;
- fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
- start->tm_year % 100,
- start->tm_mon+1,
- start->tm_mday,
- start->tm_hour,
- start->tm_min,
- start->tm_sec,
- (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
- "Warning" : "Note"),
- buffer);
-
- fflush(stderr);
-
- VOID(pthread_mutex_unlock(&LOCK_error_log));
- DBUG_VOID_RETURN;
-}
-
-
void sql_perror(const char *message)
{
#ifdef HAVE_STRERROR
@@ -2326,23 +2295,15 @@ void MYSQL_LOG::signal_update()
}
#ifdef __NT__
-void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
- uint length, int buffLen)
+static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
+ size_t length, size_t buffLen)
{
HANDLE event;
- char *buffptr;
- LPCSTR *buffmsgptr;
+ char *buffptr= buff;
DBUG_ENTER("print_buffer_to_nt_eventlog");
- buffptr= buff;
- if (length > (uint)(buffLen-5))
- {
- char *newBuff= new char[length + 5];
- strcpy(newBuff, buff);
- buffptr= newBuff;
- }
- strmov(buffptr+length, "\r\n\r\n");
- buffmsgptr= (LPCSTR*) &buffptr; // Keep windows happy
+ /* Add ending CR/LF's to string, overwrite last chars if necessary */
+ strmov(buffptr+min(length, buffLen-5), "\r\n\r\n");
setup_windows_event_source();
if ((event= RegisterEventSource(NULL,"MySQL")))
@@ -2350,24 +2311,20 @@ void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
switch (level) {
case ERROR_LEVEL:
ReportEvent(event, EVENTLOG_ERROR_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
- buffmsgptr, NULL);
+ (LPCSTR*)&buffptr, NULL);
break;
case WARNING_LEVEL:
ReportEvent(event, EVENTLOG_WARNING_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
- buffmsgptr, NULL);
+ (LPCSTR*) &buffptr, NULL);
break;
case INFORMATION_LEVEL:
ReportEvent(event, EVENTLOG_INFORMATION_TYPE, 0, MSG_DEFAULT, NULL, 1,
- 0, buffmsgptr, NULL);
+ 0, (LPCSTR*) &buffptr, NULL);
break;
}
DeregisterEventSource(event);
}
- /* if we created a string buffer, then delete it */
- if (buffptr != buff)
- delete[] buffptr;
-
DBUG_VOID_RETURN;
}
#endif /* __NT__ */
@@ -2399,13 +2356,44 @@ void vprint_msg_to_log(enum loglevel level __attribute__((unused)),
va_list argsi __attribute__((unused)))
{}
#else /*!EMBEDDED_LIBRARY*/
+static void print_buffer_to_file(enum loglevel level, const char *buffer)
+{
+ time_t skr;
+ struct tm tm_tmp;
+ struct tm *start;
+ DBUG_ENTER("print_buffer_to_file");
+ DBUG_PRINT("enter",("buffer: %s", buffer));
+
+ VOID(pthread_mutex_lock(&LOCK_error_log));
+
+ skr=time(NULL);
+ localtime_r(&skr, &tm_tmp);
+ start=&tm_tmp;
+ fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec,
+ (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
+ "Warning" : "Note"),
+ buffer);
+
+ fflush(stderr);
+
+ VOID(pthread_mutex_unlock(&LOCK_error_log));
+ DBUG_VOID_RETURN;
+}
+
+
void vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
{
char buff[1024];
- uint length;
+ size_t length;
DBUG_ENTER("vprint_msg_to_log");
- length= my_vsnprintf(buff, sizeof(buff)-5, format, args);
+ length= my_vsnprintf(buff, sizeof(buff), format, args);
print_buffer_to_file(level, buff);
#ifdef __NT__
diff --git a/sql/log_event.cc b/sql/log_event.cc
index dbf69acf70a..e272140c080 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -541,12 +541,13 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
void Log_event::init_show_field_list(List<Item>* field_list)
{
field_list->push_back(new Item_empty_string("Log_name", 20));
- field_list->push_back(new Item_return_int("Pos", 11,
+ field_list->push_back(new Item_return_int("Pos", MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Event_type", 20));
field_list->push_back(new Item_return_int("Server_id", 10,
MYSQL_TYPE_LONG));
- field_list->push_back(new Item_return_int("End_log_pos", 11,
+ field_list->push_back(new Item_return_int("End_log_pos",
+ MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Info", 20));
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1ffbc1243e9..de567eacbeb 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -417,8 +417,9 @@ MY_LOCALE *my_locale_by_number(uint number);
updated (to store more bytes on disk).
NOTE: When adding new SQL_MODE types, make sure to also add them to
- ../scripts/mysql_create_system_tables.sh and
- ../scripts/mysql_fix_privilege_tables.sql
+ the scripts used for creating the MySQL system tables
+ in scripts/mysql_system_tables.sql and scripts/mysql_system_tables_fix.sql
+
*/
#define RAID_BLOCK_SIZE 1024
@@ -835,7 +836,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
List<Item> &fields, List_item *values,
List<Item> &update_fields,
List<Item> &update_values, enum_duplicates duplic,
- COND **where, bool select_insert);
+ COND **where, bool select_insert,
+ bool check_fields, bool abort_on_warning);
bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
@@ -1020,9 +1022,29 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond, int *error);
extern Item **not_found_item;
+
+/*
+ This enumeration type is used only by the function find_item_in_list
+ to return the info on how an item has been resolved against a list
+ of possibly aliased items.
+ The item can be resolved:
+ - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS)
+ - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS)
+ - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS)
+ - ignoring the alias name in cases when SQL requires to ignore aliases
+ (e.g. when the resolved field reference contains a table name or
+ when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS)
+*/
+enum enum_resolution_type {
+ NOT_RESOLVED=0,
+ RESOLVED_IGNORING_ALIAS,
+ RESOLVED_BEHIND_ALIAS,
+ RESOLVED_WITH_NO_ALIAS,
+ RESOLVED_AGAINST_ALIAS
+};
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
- bool *unaliased);
+ enum_resolution_type *resolution);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd, Name_resolution_context *context,
@@ -1078,7 +1100,8 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
st_table_list *TABLE_LIST::*link,
const char *db_name,
const char *table_name);
-TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list);
+TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9a7928b214f..99d66134405 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1681,6 +1681,12 @@ void end_thread(THD *thd, bool put_in_cache)
thd->real_id=pthread_self();
thd->thread_stack= (char*) &thd; // For store_globals
(void) thd->store_globals();
+ /*
+ THD::mysys_var::abort is associated with physical thread rather
+ than with THD object. So we need to reset this flag before using
+ this thread for handling of new THD object/connection.
+ */
+ thd->mysys_var->abort= 0;
thd->thr_create_time= time(NULL);
threads.append(thd);
pthread_mutex_unlock(&LOCK_thread_count);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index dfb3af87c29..0e284850cbe 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7504,7 +7504,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
if ((join->tables != 1) || /* The query must reference one table. */
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
(!join->select_distinct)) ||
- (thd->lex->select_lex.olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
+ (join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
DBUG_RETURN(NULL);
if (table->s->keys == 0) /* There are no indexes to use. */
DBUG_RETURN(NULL);
diff --git a/sql/slave.cc b/sql/slave.cc
index 9d466ce5dad..ba8c3ff902a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -25,6 +25,7 @@
#include <thr_alarm.h>
#include <my_dir.h>
#include <sql_common.h>
+#include <errmsg.h>
#define MAX_SLAVE_RETRY_PAUSE 5
bool use_slave_mask = 0;
@@ -3609,7 +3610,7 @@ after reconnect");
if (event_len == packet_error)
{
uint mysql_error_number= mysql_errno(mysql);
- if (mysql_error_number == ER_NET_PACKET_TOO_LARGE)
+ if (mysql_error_number == CR_NET_PACKET_TOO_LARGE)
{
sql_print_error("\
Log entry on master is longer than max_allowed_packet (%ld) on \
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index baeedc1c9b3..1f44fa6639c 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -470,7 +470,7 @@ sp_head::init(LEX *lex)
{
DBUG_ENTER("sp_head::init");
- lex->spcont= m_pcont= new sp_pcontext(NULL);
+ lex->spcont= m_pcont= new sp_pcontext();
/*
Altough trg_table_fields list is used only in triggers we init for all
@@ -1078,7 +1078,7 @@ sp_head::execute(THD *thd)
case SP_HANDLER_CONTINUE:
thd->restore_active_arena(&execute_arena, &backup_arena);
thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
- ctx->push_hstack(ip);
+ ctx->push_hstack(i->get_cont_dest());
// Fall through
default:
ip= hip;
@@ -1087,6 +1087,7 @@ sp_head::execute(THD *thd)
ctx->enter_handler(hip);
thd->clear_error();
thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
continue;
}
}
@@ -2394,7 +2395,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
reinit_stmt_before_use(thd, m_lex);
if (open_tables)
- res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables, nextp);
+ res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
if (!res)
res= instr->exec_core(thd, nextp);
@@ -2443,8 +2444,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
sp_instr class functions
*/
-int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
- uint *nextp)
+int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
int result;
@@ -2454,19 +2454,16 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
*/
if (check_table_access(thd, SELECT_ACL, tables, 0)
|| open_and_lock_tables(thd, tables))
- {
- get_cont_dest(nextp);
result= -1;
- }
else
result= 0;
return result;
}
-void sp_instr::get_cont_dest(uint *nextp)
+uint sp_instr::get_cont_dest()
{
- *nextp= m_ip+1;
+ return (m_ip+1);
}
@@ -2654,9 +2651,9 @@ sp_instr_set_trigger_field::print(String *str)
sp_instr_opt_meta
*/
-void sp_instr_opt_meta::get_cont_dest(uint *nextp)
+uint sp_instr_opt_meta::get_cont_dest()
{
- *nextp= m_cont_dest;
+ return m_cont_dest;
}
@@ -2748,7 +2745,6 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp)
if (! it)
{
res= -1;
- *nextp = m_cont_dest;
}
else
{
@@ -3317,7 +3313,6 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
spcont->clear_handler();
thd->spcont= spcont;
}
- *nextp= m_cont_dest; /* For continue handler */
}
else
*nextp= m_ip+1;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 10eada43721..901b7a19c39 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -107,8 +107,6 @@ public:
/* Possible values of m_flags */
enum {
HAS_RETURN= 1, // For FUNCTIONs only: is set if has RETURN
- IN_SIMPLE_CASE= 2, // Is set if parsing a simple CASE
- IN_HANDLER= 4, // Is set if the parser is in a handler body
MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s)
CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE
IS_INVOKED= 32, // Is set if this sp_head is being used
@@ -449,13 +447,15 @@ public:
thd Thread handle
nextp OUT index of the next instruction to execute. (For most
instructions this will be the instruction following this
- one).
-
- RETURN
- 0 on success,
- other if some error occured
+ one). Note that this parameter is undefined in case of
+ errors, use get_cont_dest() to find the continuation
+ instruction for CONTINUE error handlers.
+
+ RETURN
+ 0 on success,
+ other if some error occurred
*/
-
+
virtual int execute(THD *thd, uint *nextp) = 0;
/**
@@ -463,22 +463,17 @@ public:
Open and lock the tables used by this statement, as a pre-requisite
to execute the core logic of this instruction with
<code>exec_core()</code>.
- If this statement fails, the next instruction to execute is also returned.
- This is useful when a user defined SQL continue handler needs to be
- executed.
@param thd the current thread
@param tables the list of tables to open and lock
- @param nextp the continuation instruction, returned to the caller if this
- method fails.
@return zero on success, non zero on failure.
*/
- int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, uint *nextp);
+ int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
/**
Get the continuation destination of this instruction.
- @param nextp the continuation destination (output)
+ @return the continuation destination
*/
- virtual void get_cont_dest(uint *nextp);
+ virtual uint get_cont_dest();
/*
Execute core function of instruction after all preparations (e.g.
@@ -744,7 +739,7 @@ public:
virtual void set_destination(uint old_dest, uint new_dest)
= 0;
- virtual void get_cont_dest(uint *nextp);
+ virtual uint get_cont_dest();
protected:
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 6229cf14604..780243cc79f 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -25,6 +25,11 @@
#include "sp_pcontext.h"
#include "sp_head.h"
+/* Initial size for the dynamic arrays in sp_pcontext */
+#define PCONTEXT_ARRAY_INIT_ALLOC 16
+/* Increment size for the dynamic arrays in sp_pcontext */
+#define PCONTEXT_ARRAY_INCREMENT_ALLOC 8
+
/*
Sanity check for SQLSTATEs. Will not check if it's really an existing
state (there are just too many), but will check length and bad characters.
@@ -49,28 +54,61 @@ sp_cond_check(LEX_STRING *sqlstate)
return TRUE;
}
-sp_pcontext::sp_pcontext(sp_pcontext *prev)
- :Sql_alloc(), m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
- m_context_handlers(0), m_parent(prev), m_pboundary(0)
+sp_pcontext::sp_pcontext()
+ : Sql_alloc(),
+ m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
+ m_context_handlers(0), m_parent(NULL), m_pboundary(0),
+ m_label_scope(LABEL_DEFAULT_SCOPE)
{
- VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *), 16, 8));
- VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int), 16, 8));
- VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *), 16, 8));
- VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING), 16, 8));
- VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *), 16, 8));
+ VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
m_label.empty();
m_children.empty();
- if (!prev)
- {
- m_var_offset= m_cursor_offset= 0;
- m_num_case_exprs= 0;
- }
- else
- {
- m_var_offset= prev->m_var_offset + prev->m_max_var_index;
- m_cursor_offset= prev->current_cursor_count();
- m_num_case_exprs= prev->get_num_case_exprs();
- }
+
+ m_var_offset= m_cursor_offset= 0;
+ m_num_case_exprs= 0;
+}
+
+sp_pcontext::sp_pcontext(sp_pcontext *prev, label_scope_type label_scope)
+ : Sql_alloc(),
+ m_max_var_index(0), m_max_cursor_index(0), m_max_handler_index(0),
+ m_context_handlers(0), m_parent(prev), m_pboundary(0),
+ m_label_scope(label_scope)
+{
+ VOID(my_init_dynamic_array(&m_vars, sizeof(sp_variable_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_case_expr_id_lst, sizeof(int),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_conds, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_cursors, sizeof(LEX_STRING),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ VOID(my_init_dynamic_array(&m_handlers, sizeof(sp_cond_type_t *),
+ PCONTEXT_ARRAY_INIT_ALLOC,
+ PCONTEXT_ARRAY_INCREMENT_ALLOC));
+ m_label.empty();
+ m_children.empty();
+
+ m_var_offset= prev->m_var_offset + prev->m_max_var_index;
+ m_cursor_offset= prev->current_cursor_count();
+ m_num_case_exprs= prev->get_num_case_exprs();
}
void
@@ -92,9 +130,9 @@ sp_pcontext::destroy()
}
sp_pcontext *
-sp_pcontext::push_context()
+sp_pcontext::push_context(label_scope_type label_scope)
{
- sp_pcontext *child= new sp_pcontext(this);
+ sp_pcontext *child= new sp_pcontext(this, label_scope);
if (child)
m_children.push_back(child);
@@ -257,7 +295,15 @@ sp_pcontext::find_label(char *name)
if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
return lab;
- if (m_parent)
+ /*
+ Note about exception handlers.
+ See SQL:2003 SQL/PSM (ISO/IEC 9075-4:2003),
+ section 13.1 <compound statement>,
+ syntax rule 4.
+ In short, a DECLARE HANDLER block can not refer
+ to labels from the parent context, as they are out of scope.
+ */
+ if (m_parent && (m_label_scope == LABEL_DEFAULT_SCOPE))
return m_parent->find_label(name);
return NULL;
}
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index b2cdd5e689c..5bffda79f98 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -88,16 +88,33 @@ typedef struct sp_cond
sp_cond_type_t *val;
} sp_cond_t;
+/**
+ The scope of a label in Stored Procedures,
+ for name resolution of labels in a parsing context.
+*/
+enum label_scope_type
+{
+ /**
+ The labels declared in a parent context are in scope.
+ */
+ LABEL_DEFAULT_SCOPE,
+ /**
+ The labels declared in a parent context are not in scope.
+ */
+ LABEL_HANDLER_SCOPE
+};
-/*
- The parse-time context, used to keep track on declared variables/parameters,
+/**
+ The parse-time context, used to keep track of declared variables/parameters,
conditions, handlers, cursors and labels, during parsing.
sp_contexts are organized as a tree, with one object for each begin-end
- block, plus a root-context for the parameters.
+ block, one object for each exception handler,
+ plus a root-context for the parameters.
This is used during parsing for looking up defined names (e.g. declared
variables and visible labels), for error checking, and to calculate offsets
to be used at runtime. (During execution variable values, active handlers
and cursors, etc, are referred to by an index in a stack.)
+ Parsing contexts for exception handlers limit the visibility of labels.
The pcontext tree is also kept during execution and is used for error
checking (e.g. correct number of parameters), and in the future, used by
the debugger.
@@ -105,21 +122,30 @@ typedef struct sp_cond
class sp_pcontext : public Sql_alloc
{
- sp_pcontext(const sp_pcontext &); /* Prevent use of these */
- void operator=(sp_pcontext &);
+public:
- public:
-
- sp_pcontext(sp_pcontext *prev);
+ /**
+ Constructor.
+ Builds a parsing context root node.
+ */
+ sp_pcontext();
// Free memory
void
destroy();
+ /**
+ Create and push a new context in the tree.
+ @param label_scope label scope for the new parsing context
+ @return the node created
+ */
sp_pcontext *
- push_context();
+ push_context(label_scope_type label_scope);
- // Returns the previous context, not the one we pop
+ /**
+ Pop a node from the parsing context tree.
+ @return the parent node
+ */
sp_pcontext *
pop_context();
@@ -363,6 +389,13 @@ class sp_pcontext : public Sql_alloc
protected:
+ /**
+ Constructor for a tree node.
+ @param prev the parent parsing context
+ @param label_scope label_scope for this parsing context
+ */
+ sp_pcontext(sp_pcontext *prev, label_scope_type label_scope);
+
/*
m_max_var_index -- number of variables (including all types of arguments)
in this context including all children contexts.
@@ -416,6 +449,14 @@ private:
List<sp_pcontext> m_children; // Children contexts, used for destruction
+ /**
+ Scope of labels for this parsing context.
+ */
+ label_scope_type m_label_scope;
+
+private:
+ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
+ void operator=(sp_pcontext &);
}; // class sp_pcontext : public Sql_alloc
diff --git a/sql/spatial.h b/sql/spatial.h
index 86232fcd524..837ae153310 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -144,15 +144,46 @@ struct MBR
return (xmin<x) && (xmax>x) && (ymin<y) && (ymax>y);
}
+ /**
+ The dimension maps to an integer as:
+ - Polygon -> 2
+ - Horizontal or vertical line -> 1
+ - Point -> 0
+ - Invalid MBR -> -1
+ */
+ int dimension() const
+ {
+ int d= 0;
+
+ if (xmin > xmax)
+ return -1;
+ else if (xmin < xmax)
+ d++;
+
+ if (ymin > ymax)
+ return -1;
+ else if (ymin < ymax)
+ d++;
+
+ return d;
+ }
+
int overlaps(const MBR *mbr)
{
- int lb= mbr->inner_point(xmin, ymin);
- int rb= mbr->inner_point(xmax, ymin);
- int rt= mbr->inner_point(xmax, ymax);
- int lt= mbr->inner_point(xmin, ymax);
+ /*
+ overlaps() requires that some point inside *this is also inside
+ *mbr, and that both geometries and their intersection are of the
+ same dimension.
+ */
+ int d = dimension();
+
+ if (d != mbr->dimension() || d <= 0 || contains(mbr) || within(mbr))
+ return 0;
+
+ MBR intersection(max(xmin, mbr->xmin), max(ymin, mbr->ymin),
+ min(xmax, mbr->xmax), min(ymax, mbr->ymax));
- int a = lb+rb+rt+lt;
- return (a>0) && (a<4) && (!within(mbr));
+ return (d == intersection.dimension());
}
};
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 298fb61d5f0..ee15f95f305 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -5882,6 +5882,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_user_privileges");
+ if (!initialized)
+ DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_users.elements ; counter++)
@@ -5941,6 +5943,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char *curr_host= thd->security_ctx->priv_host_name();
DBUG_ENTER("fill_schema_schema_privileges");
+ if (!initialized)
+ DBUG_RETURN(0);
pthread_mutex_lock(&acl_cache->lock);
for (counter=0 ; counter < acl_dbs.elements ; counter++)
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index cf2b9ce66a9..d08f2663af5 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -43,7 +43,7 @@
don't forget to update
1. static struct show_privileges_st sys_privileges[]
2. static const char *command_array[] and static uint command_lengths[]
- 3. mysql_create_system_tables.sh, mysql_fix_privilege_tables.sql
+ 3. mysql_system_tables.sql and mysql_system_tables_fix.sql
4. acl_init() or whatever - to define behaviour for old privilege tables
5. sql_yacc.yy - for GRANT/REVOKE to work
*/
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 6f114165fa6..97cb2d00689 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -849,6 +849,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
thd thread handle
table table which should be checked
table_list list of tables
+ check_alias whether to check tables' aliases
NOTE: to exclude derived tables from check we use following mechanism:
a) during derived table processing set THD::derived_tables_processing
@@ -876,10 +877,11 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
0 if table is unique
*/
-TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
+TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
+ bool check_alias)
{
TABLE_LIST *res;
- const char *d_name, *t_name;
+ const char *d_name, *t_name, *t_alias;
DBUG_ENTER("unique_table");
DBUG_PRINT("enter", ("table alias: %s", table->alias));
@@ -907,6 +909,7 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
}
d_name= table->db;
t_name= table->table_name;
+ t_alias= table->alias;
DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
for (;;)
@@ -914,6 +917,9 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
((!res->table || res->table != table->table) &&
+ (!check_alias || !(lower_case_table_names ?
+ my_strcasecmp(files_charset_info, t_alias, res->alias) :
+ strcmp(t_alias, res->alias))) &&
res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
!res->prelocking_placeholder))
break;
@@ -3654,10 +3660,13 @@ find_field_in_tables(THD *thd, Item_ident *item,
return not_found_item, report other errors,
return 0
IGNORE_ERRORS Do not report errors, return 0 if error
- unaliased Set to true if item is field which was found
- by original field name and not by its alias
- in item list. Set to false otherwise.
-
+ resolution Set to the resolution type if the item is found
+ (it says whether the item is resolved
+ against an alias name,
+ or as a field name without alias,
+ or as a field hidden by alias,
+ or ignoring alias)
+
RETURN VALUES
0 Item is not found or item is not unique,
error message is reported
@@ -3673,7 +3682,8 @@ Item **not_found_item= (Item**) 0x1;
Item **
find_item_in_list(Item *find, List<Item> &items, uint *counter,
- find_item_error_report_type report_error, bool *unaliased)
+ find_item_error_report_type report_error,
+ enum_resolution_type *resolution)
{
List_iterator<Item> li(items);
Item **found=0, **found_unaliased= 0, *item;
@@ -3687,10 +3697,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
*/
bool is_ref_by_name= 0;
uint unaliased_counter;
-
LINT_INIT(unaliased_counter); // Dependent on found_unaliased
- *unaliased= FALSE;
+ *resolution= NOT_RESOLVED;
is_ref_by_name= (find->type() == Item::FIELD_ITEM ||
find->type() == Item::REF_ITEM);
@@ -3757,63 +3766,77 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
}
found_unaliased= li.ref();
unaliased_counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
if (db_name)
break; // Perfect match
}
}
- else if (!my_strcasecmp(system_charset_info, item_field->name,
- field_name))
- {
- /*
- If table name was not given we should scan through aliases
- (or non-aliased fields) first. We are also checking unaliased
- name of the field in then next else-if, to be able to find
- instantly field (hidden by alias) if no suitable alias (or
- non-aliased field) was found.
- */
- if (found)
- {
- if ((*found)->eq(item, 0))
- continue; // Same field twice
- if (report_error != IGNORE_ERRORS)
- my_error(ER_NON_UNIQ_ERROR, MYF(0),
- find->full_name(), current_thd->where);
- return (Item**) 0;
- }
- found= li.ref();
- *counter= i;
- }
- else if (!my_strcasecmp(system_charset_info, item_field->field_name,
- field_name))
+ else
{
- /*
- We will use un-aliased field or react on such ambiguities only if
- we won't be able to find aliased field.
- Again if we have ambiguity with field outside of select list
- we should prefer fields from select list.
- */
- if (found_unaliased)
+ int fname_cmp= my_strcasecmp(system_charset_info,
+ item_field->field_name,
+ field_name);
+ if (!my_strcasecmp(system_charset_info,
+ item_field->name,field_name))
{
- if ((*found_unaliased)->eq(item, 0))
- continue; // Same field twice
- found_unaliased_non_uniq= 1;
+ /*
+ If table name was not given we should scan through aliases
+ and non-aliased fields first. We are also checking unaliased
+ name of the field in then next else-if, to be able to find
+ instantly field (hidden by alias) if no suitable alias or
+ non-aliased field was found.
+ */
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ *resolution= fname_cmp ? RESOLVED_AGAINST_ALIAS:
+ RESOLVED_WITH_NO_ALIAS;
}
- else
+ else if (!fname_cmp)
{
+ /*
+ We will use non-aliased field or react on such ambiguities only if
+ we won't be able to find aliased field.
+ Again if we have ambiguity with field outside of select list
+ we should prefer fields from select list.
+ */
+ if (found_unaliased)
+ {
+ if ((*found_unaliased)->eq(item, 0))
+ continue; // Same field twice
+ found_unaliased_non_uniq= 1;
+ }
found_unaliased= li.ref();
unaliased_counter= i;
}
}
}
- else if (!table_name && (find->eq(item,0) ||
- is_ref_by_name && find->name && item->name &&
- !my_strcasecmp(system_charset_info,
- item->name,find->name)))
- {
- found= li.ref();
- *counter= i;
- break;
- }
+ else if (!table_name)
+ {
+ if (is_ref_by_name && find->name && item->name &&
+ !my_strcasecmp(system_charset_info,item->name,find->name))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_AGAINST_ALIAS;
+ break;
+ }
+ else if (find->eq(item,0))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
+ break;
+ }
+ }
}
if (!found)
{
@@ -3828,7 +3851,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
found= found_unaliased;
*counter= unaliased_counter;
- *unaliased= TRUE;
+ *resolution= RESOLVED_BEHIND_ALIAS;
}
}
if (found)
@@ -4559,7 +4582,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Item_int do not need fix_fields() because it is basic constant.
*/
- it.replace(new Item_int("Not_used", (longlong) 1, 21));
+ it.replace(new Item_int("Not_used", (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
}
else if (insert_fields(thd, ((Item_field*) item)->context,
((Item_field*) item)->db_name,
@@ -4606,12 +4630,15 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
bool save_set_query_id= thd->set_query_id;
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
List_iterator<Item> it(fields);
+ bool save_is_item_list_lookup;
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
if (allow_sum_func)
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
thd->where= THD::DEFAULT_WHERE;
+ save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup;
+ thd->lex->current_select->is_item_list_lookup= 0;
/*
To prevent fail on forward lookup we fill it with zerows,
@@ -4634,6 +4661,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
thd->lex->allow_sum_func= save_allow_sum_func;
thd->set_query_id= save_set_query_id;
DBUG_RETURN(TRUE); /* purecov: inspected */
@@ -4646,6 +4674,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->used_tables|= item->used_tables();
thd->lex->current_select->cur_pos_in_select_list++;
}
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
thd->lex->allow_sum_func= save_allow_sum_func;
@@ -5142,6 +5171,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
*/
bool it_is_update= (select_lex == &thd->lex->select_lex) &&
thd->lex->which_check_option_applicable();
+ bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
+ select_lex->is_item_list_lookup= 0;
DBUG_ENTER("setup_conds");
if (select_lex->conds_processed_with_permanent_arena ||
@@ -5216,9 +5247,11 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
select_lex->where= *conds;
select_lex->conds_processed_with_permanent_arena= 1;
}
+ thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
DBUG_RETURN(test(thd->net.report_error));
err_no_arena:
+ select_lex->is_item_list_lookup= save_is_item_list_lookup;
DBUG_RETURN(1);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 8c276d40cdf..8dea9383f34 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1224,7 +1224,6 @@ bool select_export::send_data(List<Item> &items)
}
row_count++;
Item *item;
- char *buff_ptr=buff;
uint used_length=0,items_left=items.elements;
List_iterator_fast<Item> li(items);
@@ -1324,19 +1323,18 @@ bool select_export::send_data(List<Item> &items)
goto err;
}
}
- buff_ptr=buff; // Place separators here
if (res && (!exchange->opt_enclosed || result_type == STRING_RESULT))
{
- memcpy(buff_ptr,exchange->enclosed->ptr(),exchange->enclosed->length());
- buff_ptr+=exchange->enclosed->length();
+ if (my_b_write(&cache, (byte*) exchange->enclosed->ptr(),
+ exchange->enclosed->length()))
+ goto err;
}
if (--items_left)
{
- memcpy(buff_ptr,exchange->field_term->ptr(),field_term_length);
- buff_ptr+=field_term_length;
+ if (my_b_write(&cache, (byte*) exchange->field_term->ptr(),
+ field_term_length))
+ goto err;
}
- if (my_b_write(&cache,(byte*) buff,(uint) (buff_ptr-buff)))
- goto err;
}
if (my_b_write(&cache,(byte*) exchange->line_term->ptr(),
exchange->line_term->length()))
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 995b5ac0bde..99803802001 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -356,13 +356,25 @@ public:
inline uint32 get_open_count() { return open_count; }
};
-
+/*
+ The COPY_INFO structure is used by INSERT/REPLACE code.
+ The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY
+ UPDATE code:
+ If a row is inserted then the copied variable is incremented.
+ If a row is updated by the INSERT ... ON DUPLICATE KEY UPDATE and the
+ new data differs from the old one then the copied and the updated
+ variables are incremented.
+ The touched variable is incremented if a row was touched by the update part
+ of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row
+ was actually changed or not.
+*/
typedef struct st_copy_info {
- ha_rows records;
- ha_rows deleted;
- ha_rows updated;
- ha_rows copied;
+ ha_rows records; /* Number of processed records */
+ ha_rows deleted; /* Number of deleted records */
+ ha_rows updated; /* Number of updated records */
+ ha_rows copied; /* Number of copied records */
ha_rows error_count;
+ ha_rows touched; /* Number of touched records */
enum enum_duplicates handle_duplicates;
int escape_char, last_errno;
bool ignore;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 749ee04493b..fe89f0f28f0 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -371,7 +371,7 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
}
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{
update_non_unique_table_error(table_list, "DELETE", duplicate);
DBUG_RETURN(TRUE);
@@ -468,7 +468,7 @@ bool mysql_multi_delete_prepare(THD *thd)
{
TABLE_LIST *duplicate;
if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
- lex->query_tables)))
+ lex->query_tables, 0)))
{
update_non_unique_table_error(target_tbl->correspondent_table,
"DELETE", duplicate);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c7eb68ede07..d9d32d14321 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -473,10 +473,15 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->proc_info="init";
thd->used_tables=0;
values= its++;
+ value_count= values->elements;
if (mysql_prepare_insert(thd, table_list, table, fields, values,
update_fields, update_values, duplic, &unused_conds,
- FALSE))
+ FALSE,
+ (fields.elements || !value_count),
+ !ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES))))
goto abort;
/* mysql_prepare_insert set table_list->table if it was not set */
@@ -502,7 +507,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- value_count= values->elements;
while ((values= its++))
{
counter++;
@@ -522,7 +526,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/*
Fill in the given fields and dump it to the table file
*/
- info.records= info.deleted= info.copied= info.updated= 0;
+ info.records= info.deleted= info.copied= info.updated= info.touched= 0;
info.ignore= ignore;
info.handle_duplicates=duplic;
info.update_fields= &update_fields;
@@ -581,17 +585,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
table->file->start_bulk_insert(values_list.elements);
thd->no_trans_update= 0;
- thd->abort_on_warning= (!ignore &&
- (thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES |
- MODE_STRICT_ALL_TABLES)));
-
- if ((fields.elements || !value_count) &&
- check_that_all_fields_are_given_values(thd, table, table_list))
- {
- /* thd->net.report_error is now set, which will abort the next loop */
- error= 1;
- }
+ thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES)));
mark_fields_used_by_triggers_for_insert_stmt(thd, table, duplic);
@@ -767,8 +763,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
(!table->triggers || !table->triggers->has_delete_triggers()))
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- /* Reset value of LAST_INSERT_ID if no rows where inserted */
- if (!info.copied && thd->insert_id_used)
+ /* Reset value of LAST_INSERT_ID if no rows were inserted or touched */
+ if (!info.copied && !info.touched && thd->insert_id_used)
{
thd->insert_id(0);
id=0;
@@ -963,6 +959,10 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
be taken from table_list->table)
where Where clause (for insert ... select)
select_insert TRUE if INSERT ... SELECT statement
+ check_fields TRUE if need to check that all INSERT fields are
+ given values.
+ abort_on_warning whether to report if some INSERT field is not
+ assigned as an error (TRUE) or as a warning (FALSE).
TODO (in far future)
In cases of:
@@ -983,7 +983,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
TABLE *table, List<Item> &fields, List_item *values,
List<Item> &update_fields, List<Item> &update_values,
enum_duplicates duplic,
- COND **where, bool select_insert)
+ COND **where, bool select_insert,
+ bool check_fields, bool abort_on_warning)
{
SELECT_LEX *select_lex= &thd->lex->select_lex;
Name_resolution_context *context= &select_lex->context;
@@ -1046,10 +1047,22 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- if (!(res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, *values, 0, 0, 0))
- && duplic == DUP_UPDATE)
+ res= check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view, &map) ||
+ setup_fields(thd, 0, *values, 0, 0, 0);
+
+ if (!res && check_fields)
+ {
+ bool saved_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= abort_on_warning;
+ res= check_that_all_fields_are_given_values(thd,
+ table ? table :
+ context->table_list->table,
+ context->table_list);
+ thd->abort_on_warning= saved_abort_on_warning;
+ }
+
+ if (!res && duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
res= check_update_fields(thd, context->table_list, update_fields, &map);
@@ -1073,7 +1086,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
{
Item *fake_conds= 0;
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 1)))
{
update_non_unique_table_error(table_list, "INSERT", duplicate);
DBUG_RETURN(TRUE);
@@ -1221,21 +1234,23 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
goto err;
}
+
+ if (table->next_number_field)
+ table->file->adjust_next_insert_id_after_explicit_value(
+ table->next_number_field->val_int());
+ info->touched++;
+
if ((table->file->table_flags() & HA_PARTIAL_COLUMN_READ) ||
compare_record(table, thd->query_id))
{
info->updated++;
-
- if (table->next_number_field)
- table->file->adjust_next_insert_id_after_explicit_value(
- table->next_number_field->val_int());
-
trg_error= (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER,
TRUE));
info->copied++;
}
+
goto ok_or_after_trg_err;
}
else /* DUP_REPLACE */
@@ -2324,7 +2339,7 @@ bool mysql_insert_select_prepare(THD *thd)
lex->query_tables->table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates,
- &select_lex->where, TRUE))
+ &select_lex->where, TRUE, FALSE, FALSE))
DBUG_RETURN(TRUE);
/*
@@ -2386,7 +2401,18 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
!insert_into_view, &map) ||
setup_fields(thd, 0, values, 0, 0, 0);
- if (info.handle_duplicates == DUP_UPDATE)
+ if (!res && fields->elements)
+ {
+ bool saved_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning= !info.ignore && (thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES |
+ MODE_STRICT_ALL_TABLES));
+ res= check_that_all_fields_are_given_values(thd, table_list->table,
+ table_list);
+ thd->abort_on_warning= saved_abort_on_warning;
+ }
+
+ if (info.handle_duplicates == DUP_UPDATE && !res)
{
Name_resolution_context *context= &lex->select_lex.context;
Name_resolution_context_state ctx_state;
@@ -2453,7 +2479,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
query
*/
if (!(lex->current_select->options & OPTION_BUFFER_RESULT) &&
- unique_table(thd, table_list, table_list->next_global))
+ unique_table(thd, table_list, table_list->next_global, 0))
{
/* Using same table for INSERT and SELECT */
lex->current_select->options|= OPTION_BUFFER_RESULT;
@@ -2497,9 +2523,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
- res= ((fields->elements &&
- check_that_all_fields_are_given_values(thd, table, table_list)) ||
- table_list->prepare_where(thd, 0, TRUE) ||
+ res= (table_list->prepare_where(thd, 0, TRUE) ||
table_list->prepare_check_option(thd));
if (!res)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 4c0ab7a8e54..3be844b6761 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1206,6 +1206,7 @@ void st_select_lex::init_select()
is_correlated= 0;
cur_pos_in_select_list= UNDEF_POS;
non_agg_fields.empty();
+ cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty();
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b8be619c0c8..de7de0d46e9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -488,6 +488,8 @@ public:
Item *where, *having; /* WHERE & HAVING clauses */
Item *prep_where; /* saved WHERE clause for prepared statement processing */
Item *prep_having;/* saved HAVING clause for prepared statement processing */
+ /* Saved values of the WHERE and HAVING clauses*/
+ Item::cond_result cond_value, having_value;
/* point on lex in which it was created, used in view subquery detection */
st_lex *parent_lex;
enum olap_type olap;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 7ed1a900fba..3f67a0c3f5d 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -176,7 +176,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table is marked to be 'used for insert' in which case we should never
mark this table as as 'const table' (ie, one that has only one row).
*/
- if (unique_table(thd, table_list, table_list->next_global))
+ if (unique_table(thd, table_list, table_list->next_global, 0))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 03c37e4dba9..1b8bfd38fc4 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1604,7 +1604,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_ENTER("dispatch_command");
if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
+ {
thd->killed= THD::NOT_KILLED;
+ thd->mysys_var->abort= 0;
+ }
thd->command=command;
/*
@@ -3023,7 +3026,7 @@ mysql_execute_command(THD *thd)
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, create_table, select_tables)))
+ if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
{
update_non_unique_table_error(create_table, "CREATE", duplicate);
res= 1;
@@ -3039,7 +3042,7 @@ mysql_execute_command(THD *thd)
tab= tab->next_local)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, tab, select_tables)))
+ if ((duplicate= unique_table(thd, tab, select_tables, 0)))
{
update_non_unique_table_error(tab, "CREATE", duplicate);
res= 1;
@@ -5402,7 +5405,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{
uint found=0;
ulong found_access=0;
-#ifndef EMBEDDED_LIBRARY
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
TABLE_LIST *org_tables= tables;
#endif
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 33a57e8bea6..85092f14624 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1070,7 +1070,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
if (mysql_prepare_insert(thd, table_list, table_list->table,
fields, values, update_fields, update_values,
- duplic, &unused_conds, FALSE))
+ duplic, &unused_conds, FALSE, FALSE, FALSE))
goto error;
value_count= values->elements;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5202f35f4de..35e6a7da0aa 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -396,6 +396,7 @@ JOIN::prepare(Item ***rref_pointer_array,
join_list= &select_lex->top_join_list;
union_part= (unit_arg->first_select()->next_select() != 0);
+ thd->lex->current_select->is_item_list_lookup= 1;
/*
If we have already executed SELECT, then it have not sense to prevent
its table from update (see unique_table())
@@ -455,6 +456,17 @@ JOIN::prepare(Item ***rref_pointer_array,
select_lex->fix_prepare_information(thd, &conds, &having);
+ if (order)
+ {
+ ORDER *ord;
+ for (ord= order; ord; ord= ord->next)
+ {
+ Item *item= *ord->item;
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ item->split_sum_func(thd, ref_pointer_array, all_fields);
+ }
+ }
+
if (having && having->with_sum_func)
having->split_sum_func2(thd, ref_pointer_array, all_fields,
&having, TRUE);
@@ -748,7 +760,6 @@ JOIN::optimize()
}
{
- Item::cond_result having_value;
having= optimize_cond(this, having, join_list, &having_value);
if (thd->net.report_error)
{
@@ -756,6 +767,10 @@ JOIN::optimize()
DBUG_PRINT("error",("Error from optimize_cond"));
DBUG_RETURN(1);
}
+ if (select_lex->where)
+ select_lex->cond_value= cond_value;
+ if (select_lex->having)
+ select_lex->having_value= having_value;
if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
@@ -896,6 +911,7 @@ JOIN::optimize()
conds->update_used_tables();
DBUG_EXECUTE("where", print_where(conds, "after substitute_best_equal"););
}
+
/*
Permorm the the optimization on fields evaluation mentioned above
for all on expressions.
@@ -7605,6 +7621,10 @@ static COND* substitute_for_best_equal_field(COND *cond,
break;
}
}
+ if (cond->type() == Item::COND_ITEM &&
+ !((Item_cond*)cond)->argument_list()->elements)
+ cond= new Item_int((int32)cond->val_bool());
+
}
else if (cond->type() == Item::FUNC_ITEM &&
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
@@ -7983,9 +8003,14 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
*/
expr= simplify_joins(join, &nested_join->join_list,
expr, FALSE);
- table->on_expr= expr;
- if (!table->prep_on_expr)
+
+ if (!table->prep_on_expr || expr != table->on_expr)
+ {
+ DBUG_ASSERT(expr);
+
+ table->on_expr= expr;
table->prep_on_expr= expr->copy_andor_structure(join->thd);
+ }
}
nested_join->used_tables= (table_map) 0;
nested_join->not_null_tables=(table_map) 0;
@@ -7995,7 +8020,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
else
{
- if (!(table->prep_on_expr))
+ if (!table->prep_on_expr)
table->prep_on_expr= table->on_expr;
used_tables= table->table->map;
if (conds)
@@ -8486,7 +8511,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
thd->current_insert_id,
- 21))))
+ MY_INT64_NUM_DECIMAL_DIGITS))))
{
/*
Set THD::last_insert_id_used_bin_log manually, as this
@@ -8752,7 +8777,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
break;
case INT_RESULT:
/* Select an integer type with the minimal fit precision */
- if (item->max_length > 11)
+ if (item->max_length > MY_INT32_NUM_DECIMAL_DIGITS)
new_field=new Field_longlong(item->max_length, maybe_null,
item->name, table, item->unsigned_flag);
else
@@ -13158,7 +13183,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **select_item; /* The corresponding item from the SELECT clause. */
Field *from_field; /* The corresponding field from the FROM clause. */
uint counter;
- bool unaliased;
+ enum_resolution_type resolution;
/*
Local SP variables may be int but are expressions, not positions.
@@ -13181,7 +13206,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
select_item= find_item_in_list(order_item, fields, &counter,
- REPORT_EXCEPT_NOT_FOUND, &unaliased);
+ REPORT_EXCEPT_NOT_FOUND, &resolution);
if (!select_item)
return TRUE; /* The item is not unique, or some other error occured. */
@@ -13195,7 +13220,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
original field name, we should additionaly check if we have conflict
for this name (in case if we would perform lookup in all tables).
*/
- if (unaliased && !order_item->fixed &&
+ if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed &&
order_item->fix_fields(thd, order->item))
return TRUE;
@@ -13265,16 +13290,11 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
*/
- thd->lex->current_select->is_item_list_lookup= 1;
if (!order_item->fixed &&
(order_item->fix_fields(thd, order->item) ||
(order_item= *order->item)->check_cols(1) ||
thd->is_fatal_error))
- {
- thd->lex->current_select->is_item_list_lookup= 0;
return TRUE; /* Wrong field. */
- }
- thd->lex->current_select->is_item_list_lookup= 0;
uint el= all_fields.elements;
all_fields.push_front(order_item); /* Add new field to field list. */
@@ -13429,7 +13449,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
thd->set_query_id=1; // Not really needed, but...
uint counter;
- bool not_used;
+ enum_resolution_type not_used;
for (; new_field ; new_field= new_field->next)
{
if ((item= find_item_in_list(*new_field->item, fields, &counter,
@@ -14959,7 +14979,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* Add "rows" field to item_list. */
item_list.push_back(new Item_int((longlong) (ulonglong)
join->best_positions[i]. records_read,
- 21));
+ MY_INT64_NUM_DECIMAL_DIGITS));
/* Build "Extra" field and add it to item_list. */
my_bool key_read=table->key_read;
if ((tab->type == JT_NEXT || tab->type == JT_CONST) &&
@@ -15328,10 +15348,13 @@ void st_select_lex::print(THD *thd, String *str)
Item *cur_where= where;
if (join)
cur_where= join->conds;
- if (cur_where)
+ if (cur_where || cond_value != Item::COND_UNDEF)
{
str->append(STRING_WITH_LEN(" where "));
- cur_where->print(str);
+ if (cur_where)
+ cur_where->print(str);
+ else
+ str->append(cond_value != Item::COND_FALSE ? "1" : "0");
}
// group by & olap
@@ -15357,10 +15380,13 @@ void st_select_lex::print(THD *thd, String *str)
if (join)
cur_having= join->having;
- if (cur_having)
+ if (cur_having || having_value != Item::COND_UNDEF)
{
str->append(STRING_WITH_LEN(" having "));
- cur_having->print(str);
+ if (cur_having)
+ cur_having->print(str);
+ else
+ str->append(having_value != Item::COND_FALSE ? "1" : "0");
}
if (order_list.elements)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index a17d7fcb362..27ca633fdb5 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -292,7 +292,7 @@ public:
bool need_tmp, hidden_group_fields;
DYNAMIC_ARRAY keyuse;
- Item::cond_result cond_value;
+ Item::cond_result cond_value, having_value;
List<Item> all_fields; // to store all fields that used in query
//Above list changed to use temporary table
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index c4b06934fc3..0c9ea7b0bbf 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -205,7 +205,8 @@ bool mysqld_show_column_types(THD *thd)
DBUG_ENTER("mysqld_show_column_types");
field_list.push_back(new Item_empty_string("Type",30));
- field_list.push_back(new Item_int("Size",(longlong) 1,21));
+ field_list.push_back(new Item_int("Size",(longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("Min_Value",20));
field_list.push_back(new Item_empty_string("Max_Value",20));
field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
@@ -992,7 +993,7 @@ store_create_info(THD *thd, TABLE_LIST *table_list, String *packet)
if (key_part->field &&
(key_part->length !=
table->field[key_part->fieldnr-1]->key_length() &&
- !(key_info->flags & HA_FULLTEXT)))
+ !(key_info->flags & (HA_FULLTEXT | HA_SPATIAL))))
{
buff[0] = '(';
char* end=int10_to_str((long) key_part->length /
@@ -1284,7 +1285,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_list_processes");
- field_list.push_back(new Item_int("Id",0,11));
+ field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
field_list.push_back(new Item_empty_string("User",16));
field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
@@ -3601,7 +3602,16 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(0);
}
break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC,
+ fields_info->field_length)) == NULL)
+ DBUG_RETURN(NULL);
+ break;
default:
+ /* Don't let unimplemented types pass through. Could be a grave error. */
+ DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);
+
/* this should be changed when Item_empty_string is fixed(in 4.1) */
if (!(item= new Item_empty_string("", 0, cs)))
{
@@ -4038,20 +4048,25 @@ ST_FIELD_INFO tables_fields_info[]=
{"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
{"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
- {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
+ {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Version"},
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
- {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
+ {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Rows"},
+ {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ "Avg_row_length"},
+ {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ "Data_length"},
+ {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ "Max_data_length"},
+ {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ "Index_length"},
+ {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
+ {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ "Auto_increment"},
{"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
{"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
{"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
{"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
+ {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
{"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
{"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -4064,14 +4079,15 @@ ST_FIELD_INFO columns_fields_info[]=
{"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
- {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
+ {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 0, 0},
{"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
{"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
{"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+ 0},
+ {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
+ {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
{"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
@@ -4097,7 +4113,7 @@ ST_FIELD_INFO collation_fields_info[]=
{
{"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
{"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
- {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
+ {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Id"},
{"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
{"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
{"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
@@ -4150,7 +4166,7 @@ ST_FIELD_INFO stat_fields_info[]=
{"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
{"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
{"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
- {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
+ {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
{"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
{"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
{"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 512d990347f..c75aff7fab6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1344,6 +1344,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (!f_is_geom(sql_field->pack_flag) &&
(column->length > length ||
+ !Field::type_can_have_key_part (sql_field->sql_type) ||
((f_is_packed(sql_field->pack_flag) ||
((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
@@ -4146,7 +4147,8 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
item->maybe_null= 1;
- field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
+ field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
+ MY_INT64_NUM_DECIMAL_DIGITS));
item->maybe_null= 1;
if (protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 16df0059217..1ec724a6338 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -621,6 +621,12 @@ bool st_select_lex_unit::cleanup()
join->tables= 0;
}
error|= fake_select_lex->cleanup();
+ if (fake_select_lex->order_list.elements)
+ {
+ ORDER *ord;
+ for (ord= (ORDER*)fake_select_lex->order_list.first; ord; ord= ord->next)
+ (*ord->item)->cleanup();
+ }
}
DBUG_RETURN(error);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e203d8ebd4a..27d38114885 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -640,7 +640,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
/* Check that we are not using table that we are updating in a sub select */
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
+ if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
@@ -867,7 +867,7 @@ reopen_tables:
tl->lock_type != TL_READ_NO_INSERT)
{
TABLE_LIST *duplicate;
- if ((duplicate= unique_table(thd, tl, table_list)))
+ if ((duplicate= unique_table(thd, tl, table_list, 0)))
{
update_non_unique_table_error(table_list, "UPDATE", duplicate);
DBUG_RETURN(TRUE);
@@ -1086,7 +1086,7 @@ static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab,
List<Item> *fields)
{
TABLE *table= join_tab->table;
- if (unique_table(thd, table_ref, all_tables))
+ if (unique_table(thd, table_ref, all_tables, 0))
return 0;
switch (join_tab->type) {
case JT_SYSTEM:
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index d07234ff2bd..3e9c7ba7344 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1092,7 +1092,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
key_alg opt_btree_or_rtree
%type <string_list>
- key_usage_list using_list
+ key_usage_list key_usage_list_inner using_list
%type <key_part>
key_part
@@ -2006,6 +2006,9 @@ sp_decl:
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
+
+ lex->spcont= lex->spcont->push_context(LABEL_HANDLER_SCOPE);
+
sp_pcontext *ctx= lex->spcont;
sp_instr_hpush_jump *i=
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
@@ -2013,7 +2016,6 @@ sp_decl:
sp->add_instr(i);
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
- sp->m_flags|= sp_head::IN_HANDLER;
}
sp_hcond_list sp_proc_stmt
{
@@ -2037,10 +2039,12 @@ sp_decl:
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
}
lex->sphead->backpatch(hlab);
- sp->m_flags&= ~sp_head::IN_HANDLER;
+
+ lex->spcont= ctx->pop_context();
+
$$.vars= $$.conds= $$.curs= 0;
$$.hndlrs= $6;
- ctx->add_handlers($6);
+ lex->spcont->add_handlers($6);
}
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
{
@@ -2103,11 +2107,18 @@ sp_handler_type:
;
sp_hcond_list:
+ sp_hcond_element
+ { $$= 1; }
+ | sp_hcond_list ',' sp_hcond_element
+ { $$+= 1; }
+ ;
+
+sp_hcond_element:
sp_hcond
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
+ sp_pcontext *ctx= lex->spcont->parent_context();
if (ctx->find_handler($1))
{
@@ -2121,28 +2132,6 @@ sp_hcond_list:
i->add_condition($1);
ctx->push_handler($1);
- $$= 1;
- }
- }
- | sp_hcond_list ',' sp_hcond
- {
- LEX *lex= Lex;
- sp_head *sp= lex->sphead;
- sp_pcontext *ctx= lex->spcont;
-
- if (ctx->find_handler($3))
- {
- my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
- MYSQL_YYABORT;
- }
- else
- {
- sp_instr_hpush_jump *i=
- (sp_instr_hpush_jump *)sp->last_instruction();
-
- i->add_condition($3);
- ctx->push_handler($3);
- $$= $1 + 1;
}
}
;
@@ -2687,7 +2676,7 @@ sp_unlabeled_control:
sp_label_t *lab= lex->spcont->last_label();
lab->type= SP_LAB_BEGIN;
- lex->spcont= lex->spcont->push_context();
+ lex->spcont= lex->spcont->push_context(LABEL_DEFAULT_SCOPE);
}
sp_decls
sp_proc_stmts
@@ -5899,6 +5888,10 @@ opt_outer:
/* empty */ {}
| OUTER {};
+opt_for_join:
+ /* empty */
+ | FOR_SYM JOIN_SYM;
+
opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
@@ -5914,15 +5907,20 @@ opt_key_definition:
sel->use_index_ptr= &sel->use_index;
sel->table_join_options|= TL_OPTION_FORCE_INDEX;
}
- | IGNORE_SYM key_usage_list
+ | IGNORE_SYM key_or_index opt_for_join key_usage_list_inner
{
SELECT_LEX *sel= Select;
- sel->ignore_index= *$2;
+ sel->ignore_index= *$4;
sel->ignore_index_ptr= &sel->ignore_index;
};
key_usage_list:
- key_or_index { Select->interval_list.empty(); }
+ key_or_index key_usage_list_inner
+ { $$= $2; }
+ ;
+
+key_usage_list_inner:
+ { Select->interval_list.empty(); }
'(' key_list_or_empty ')'
{ $$= &Select->interval_list; }
;