Below is the list of changes that have just been committed into a local
5.0 repository of dlenev. When dlenev does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://www.mysql.com/doc/I/n/Installing_source_tree.html
ChangeSet
1.1684 04/11/24 11:44:57 dlenev@stripped +13 -0
Merge of tree with fix for bug #5888 with main tree
sql/sql_yacc.yy
1.322 04/11/24 11:44:53 dlenev@stripped +1 -3
Manual merge
sql/sql_trigger.cc
1.9 04/11/24 11:44:53 dlenev@stripped +12 -0
Manual merge
sql/sql_lex.cc
1.118 04/11/24 11:44:53 dlenev@stripped +0 -0
Manual merge
sql/sql_trigger.h
1.3 04/11/24 11:36:29 dlenev@stripped +0 -0
Auto merged
sql/sql_parse.cc
1.377 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/sql_lex.h
1.149 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/sp_head.h
1.49 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/sp_head.cc
1.105 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/mysql_priv.h
1.237 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/item.h
1.82 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
sql/item.cc
1.93 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
mysql-test/t/trigger.test
1.6 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
mysql-test/r/trigger.result
1.4 04/11/24 11:36:28 dlenev@stripped +0 -0
Auto merged
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: dlenev
# Host: brandersnatch.localdomain
# Root: /home/dlenev/src/mysql-5.0-trg/RESYNC
--- 1.92/sql/item.cc Sat Nov 20 22:17:29 2004
+++ 1.93/sql/item.cc Wed Nov 24 11:36:28 2004
@@ -3152,16 +3152,12 @@
NOTE
This function does almost the same as fix_fields() for Item_field
but is invoked during trigger definition parsing and takes TABLE
- object as its argument.
-
- RETURN VALUES
- 0 ok
- 1 field was not found.
+ object as its argument. If proper field was not found in table
+ error will be reported at fix_fields() time.
*/
-bool Item_trigger_field::setup_field(THD *thd, TABLE *table,
+void Item_trigger_field::setup_field(THD *thd, TABLE *table,
enum trg_event_type event)
{
- bool result= 1;
uint field_idx= (uint)-1;
bool save_set_query_id= thd->set_query_id;
@@ -3175,12 +3171,9 @@
field= (row_version == OLD_ROW && event == TRG_EVENT_UPDATE) ?
table->triggers->old_field[field_idx] :
table->field[field_idx];
- result= 0;
}
thd->set_query_id= save_set_query_id;
-
- return result;
}
@@ -3204,10 +3197,18 @@
FIXME may be we still should bother about permissions here.
*/
DBUG_ASSERT(fixed == 0);
- // QQ: May be this should be moved to setup_field?
- set_field(field);
- fixed= 1;
- return 0;
+
+ if (field)
+ {
+ // QQ: May be this should be moved to setup_field?
+ set_field(field);
+ fixed= 1;
+ return 0;
+ }
+
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name,
+ (row_version == NEW_ROW) ? "NEW" : "OLD");
+ return 1;
}
--- 1.81/sql/item.h Tue Oct 26 18:05:16 2004
+++ 1.82/sql/item.h Wed Nov 24 11:36:28 2004
@@ -32,12 +32,32 @@
enum Derivation
{
+ DERIVATION_IGNORABLE= 4,
DERIVATION_COERCIBLE= 3,
DERIVATION_IMPLICIT= 2,
DERIVATION_NONE= 1,
DERIVATION_EXPLICIT= 0
};
+/*
+ Flags for collation aggregation modes:
+ MY_COLL_ALLOW_SUPERSET_CONV - allow conversion to a superset
+ MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
+ (i.e. constant).
+ MY_COLL_ALLOW_CONV - allow any kind of conversion
+ (combintion of the above two)
+ MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE
+ (e.g. when aggregating for comparison)
+ MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV
+ and MY_COLL_DISALLOW_NONE
+*/
+
+#define MY_COLL_ALLOW_SUPERSET_CONV 1
+#define MY_COLL_ALLOW_COERCIBLE_CONV 2
+#define MY_COLL_ALLOW_CONV 3
+#define MY_COLL_DISALLOW_NONE 4
+#define MY_COLL_CMP_CONV 7
+
class DTCollation {
public:
CHARSET_INFO *collation;
@@ -73,13 +93,14 @@
{ collation= collation_arg; }
void set(Derivation derivation_arg)
{ derivation= derivation_arg; }
- bool aggregate(DTCollation &dt, bool superset_conversion= FALSE);
- bool set(DTCollation &dt1, DTCollation &dt2, bool superset_conversion= FALSE)
- { set(dt1); return aggregate(dt2, superset_conversion); }
+ bool aggregate(DTCollation &dt, uint flags= 0);
+ bool set(DTCollation &dt1, DTCollation &dt2, uint flags= 0)
+ { set(dt1); return aggregate(dt2, flags); }
const char *derivation_name() const
{
switch(derivation)
{
+ case DERIVATION_IGNORABLE: return "IGNORABLE";
case DERIVATION_COERCIBLE: return "COERCIBLE";
case DERIVATION_IMPLICIT: return "IMPLICIT";
case DERIVATION_EXPLICIT: return "EXPLICIT";
@@ -99,7 +120,8 @@
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr,size_t size) {} /*lint -e715 */
+ static void operator delete(void *ptr,size_t size) {}
+ static void operator delete(void *ptr,size_t size, MEM_ROOT *mem_root) {}
enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM,
INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
@@ -166,7 +188,7 @@
virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
- virtual double val()=0;
+ virtual double val_real()=0;
virtual longlong val_int()=0;
/*
Return string representation of this item object.
@@ -197,7 +219,7 @@
virtual Field *get_tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
- virtual double val_result() { return val(); }
+ virtual double val_result() { return val_real(); }
virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); }
/* bit map of tables used by item */
@@ -219,7 +241,8 @@
a constant expression
*/
virtual bool basic_const_item() const { return 0; }
- virtual Item *new_item() { return 0; } /* Only for const items */
+ /* cloning of constant items (0 if it is not const) */
+ virtual Item *new_item() { return 0; }
virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
@@ -237,17 +260,37 @@
virtual void print(String *str_arg) { str_arg->append(full_name()); }
void print_item_w_name(String *);
virtual void update_used_tables() {}
- virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {}
+ virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
+ List<Item> &fields) {}
virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
+ /*
+ This function is used only in Item_func_isnull/Item_func_isnotnull
+ (implementations of IS NULL/IS NOT NULL clauses). Item_func_is{not}null
+ calls this method instead of one of val/result*() methods, which
+ normally will set null_value. This allows to determine nullness of
+ a complex expression without fully evaluating it.
+ Any new item which can be NULL must implement this call.
+ */
virtual bool is_null() { return 0; }
+ /*
+ it is "top level" item of WHERE clause and we do not need correct NULL
+ handling
+ */
virtual void top_level_item() {}
+ /*
+ set field of temporary table for Item which can be switched on temporary
+ table during query processing (groupping and so on)
+ */
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
virtual bool is_bool_func() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
+ /*
+ set value of aggegate function in case of no rows for groupping were found
+ */
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
virtual Item *copy_andor_structure(THD *thd) { return this; }
@@ -269,8 +312,10 @@
virtual bool remove_dependence_processor(byte * arg) { return 0; }
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
+ virtual bool cleanup_processor(byte *arg);
virtual bool collect_item_field_processor(byte * arg) { return 0; }
virtual Item *equal_fields_propagator(byte * arg) { return this; }
+ virtual Item *set_no_const_sub(byte *arg) { return this; }
virtual bool replace_equal_field_processor(byte * arg) { return 0; }
virtual Item *this_item() { return this; } /* For SPs mostly. */
@@ -290,6 +335,7 @@
virtual Item_field *filed_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
+ virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
void delete_self()
{
cleanup();
@@ -326,10 +372,10 @@
// the item in the frame
enum Type type() const;
- inline double val()
+ inline double val_real()
{
Item *it= this_item();
- double ret= it->val();
+ double ret= it->val_real();
Item::null_value= it->null_value;
return ret;
}
@@ -407,6 +453,7 @@
class st_select_lex;
class Item_ident :public Item
{
+protected:
/*
We have to store initial values of db_name, table_name and field_name
to be able to restore them during cleanup() because they can be
@@ -416,7 +463,6 @@
const char *orig_db_name;
const char *orig_table_name;
const char *orig_field_name;
- Item **changed_during_fix_field;
public:
const char *db_name;
const char *table_name;
@@ -439,8 +485,6 @@
Item_ident(THD *thd, Item_ident *item);
const char *full_name() const;
void cleanup();
- void register_item_tree_changing(Item **ref)
- { changed_during_fix_field= ref; }
bool remove_dependence_processor(byte * arg);
void print(String *str);
@@ -474,23 +518,32 @@
field(0), result_field(0), item_equal(0), no_const_subst(0),
have_privileges(0), any_privileges(0)
{ collation.set(DERIVATION_IMPLICIT); }
- // Constructor need to process subselect with temporary tables (see Item)
+ /*
+ Constructor needed to process subselect with temporary tables (see Item)
+ */
Item_field(THD *thd, Item_field *item);
/*
- Constructor used inside setup_wild(), ensures that field and table
- names will live as long as Item_field (important in prep. stmt.)
+ Constructor used inside setup_wild(), ensures that field, table,
+ and database names will live as long as Item_field (this is important
+ in prepared statements).
*/
Item_field(THD *thd, Field *field);
+ /*
+ If this constructor is used, fix_fields() won't work, because
+ db_name, table_name and column_name are unknown. It's necessary to call
+ reset_field() before fix_fields() for all fields created this way.
+ */
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- double val();
+ double val_real();
longlong val_int();
String *val_str(String*);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
bool send(Protocol *protocol, String *str_arg);
+ void reset_field(Field *f);
bool fix_fields(THD *, struct st_table_list *, Item **);
void make_field(Send_field *tmp_field);
int save_in_field(Field *field,bool no_conversions);
@@ -515,9 +568,11 @@
void cleanup();
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg);
+ Item *set_no_const_sub(byte *arg);
bool replace_equal_field_processor(byte *arg);
inline uint32 max_disp_length() { return field->max_length(); }
Item_field *filed_for_view_update() { return this; }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
friend class Item_default_value;
friend class Item_insert_value;
friend class st_select_lex_unit;
@@ -532,10 +587,11 @@
max_length= 0;
name= name_par ? name_par : (char*) "NULL";
fixed= 1;
+ collation.set(&my_charset_bin, DERIVATION_IGNORABLE);
}
enum Type type() const { return NULL_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
- double val();
+ double val_real();
longlong val_int();
String *val_str(String *str);
int save_in_field(Field *field, bool no_conversions);
@@ -549,6 +605,7 @@
Item *new_item() { return new Item_null(name); }
bool is_null() { return 1; }
void print(String *str) { str->append("NULL", 4); }
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
};
@@ -623,7 +680,7 @@
enum Type type() const { return item_type; }
enum_field_types field_type() const { return param_type; }
- double val();
+ double val_real();
longlong val_int();
String *val_str(String*);
bool get_time(TIME *tm);
@@ -661,6 +718,8 @@
void print(String *str);
/* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; }
+ bool is_null()
+ { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
};
class Item_int :public Item_num
@@ -680,7 +739,7 @@
enum Item_result result_type () const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
String *val_str(String*);
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
@@ -709,7 +768,7 @@
Item_uint(const char *str_arg, uint length);
Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ unsigned_flag= 1; }
- double val()
+ double val_real()
{ DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
String *val_str(String*);
Item *new_item() { return new Item_uint(name,max_length); }
@@ -738,7 +797,7 @@
int save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
- double val() { DBUG_ASSERT(fixed == 1); return value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -809,7 +868,7 @@
fixed= 1;
}
enum Type type() const { return STRING_ITEM; }
- double val()
+ double val_real()
{
DBUG_ASSERT(fixed == 1);
int err;
@@ -838,6 +897,7 @@
return new Item_string(name, str_value.ptr(),
str_value.length(), &my_charset_bin);
}
+ Item *safe_charset_converter(CHARSET_INFO *tocs);
String *const_string() { return &str_value; }
inline void append(char *str, uint length) { str_value.append(str, length); }
void print(String *str);
@@ -873,8 +933,8 @@
class Item_empty_string :public Item_string
{
public:
- Item_empty_string(const char *header,uint length) :Item_string("",0,
- &my_charset_bin)
+ Item_empty_string(const char *header,uint length, CHARSET_INFO *cs= NULL) :
+ Item_string("",0, cs ? cs : &my_charset_bin)
{ name=(char*) header; max_length=length;}
void make_field(Send_field *field);
};
@@ -898,7 +958,7 @@
public:
Item_varbinary(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
- double val()
+ double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_varbinary::val_int(); }
longlong val_int();
bool basic_const_item() const { return 1; }
@@ -931,6 +991,7 @@
{
save_in_field(result_field, no_conversions);
}
+ void cleanup();
};
@@ -939,24 +1000,17 @@
public:
Field *result_field; /* Save result here */
Item **ref;
- Item **hook_ptr; /* These two to restore */
- Item *orig_item; /* things in 'cleanup()' */
- Item_ref(Item **hook, Item *original,const char *db_par,
- const char *table_name_par, const char *field_name_par)
- :Item_ident(db_par, table_name_par, field_name_par), result_field(0),
- ref(0), hook_ptr(hook), orig_item(original) {}
- Item_ref(Item **item, Item **hook,
- const char *table_name_par, const char *field_name_par)
- :Item_ident(NullS, table_name_par, field_name_par), result_field(0),
- ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {}
- // Constructor need to process subselect with temporary tables (see Item)
- Item_ref(THD *thd, Item_ref *item, Item **hook)
- :Item_ident(thd, item), result_field(item->result_field), ref(item->ref),
- hook_ptr(hook), orig_item(hook ? *hook : 0) {}
+ Item_ref(const char *db_par, const char *table_name_par,
+ const char *field_name_par)
+ :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {}
+ Item_ref(Item **item, const char *table_name_par, const char *field_name_par)
+ :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item) {}
+ /* Constructor need to process subselect with temporary tables (see Item) */
+ Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
{ return ref && (*ref)->eq(item, binary_cmp); }
- double val()
+ double val_real()
{
double tmp=(*ref)->val_result();
null_value=(*ref)->null_value;
@@ -1020,8 +1074,8 @@
public:
Item_ref_null_helper(Item_in_subselect* master, Item **item,
const char *table_name_par, const char *field_name_par):
- Item_ref(item, NULL, table_name_par, field_name_par), owner(master) {}
- double val();
+ Item_ref(item, table_name_par, field_name_par), owner(master) {}
+ double val_real();
longlong val_int();
String* val_str(String* s);
bool get_date(TIME *ltime, uint fuzzydate);
@@ -1089,7 +1143,7 @@
enum Type type() const { return COPY_STR_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return cached_field_type; }
- double val()
+ double val_real()
{
int err;
return (null_value ? 0.0 :
@@ -1319,7 +1373,7 @@
Item_cache_int(): Item_cache() {}
void store(Item *item);
- double val() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
String* val_str(String *str)
{
@@ -1337,7 +1391,7 @@
Item_cache_real(): Item_cache() {}
void store(Item *item);
- double val() { DBUG_ASSERT(fixed == 1); return value; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return value; }
longlong val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1359,7 +1413,7 @@
Item_cache_str(): Item_cache() { }
void store(Item *item);
- double val();
+ double val_real();
longlong val_int();
String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
enum Item_result result_type() const { return STRING_RESULT; }
@@ -1391,7 +1445,7 @@
{
illegal_method_call((const char*)"make_field");
};
- double val()
+ double val_real()
{
illegal_method_call((const char*)"val");
return 0;
@@ -1442,7 +1496,7 @@
Item_result result_type () const { return item_type; }
enum Type type() const { return TYPE_HOLDER; }
- double val();
+ double val_real();
longlong val_int();
String *val_str(String*);
bool join_types(THD *thd, Item *);
@@ -1460,5 +1514,5 @@
extern Item_buff *new_Item_buff(Item *item);
extern Item_result item_cmp_type(Item_result a,Item_result b);
-extern Item *resolve_const_item(Item *item,Item *cmp_item);
+extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item);
extern bool field_is_equal_to_item(Field *field,Item *item);
--- 1.236/sql/mysql_priv.h Thu Nov 18 14:53:16 2004
+++ 1.237/sql/mysql_priv.h Wed Nov 24 11:36:28 2004
@@ -378,6 +378,15 @@
first= save->first;
elements+= save->elements;
}
+ inline void push_back(struct st_sql_list *save)
+ {
+ if (save->first)
+ {
+ *next= save->first;
+ next= save->next;
+ elements+= save->elements;
+ }
+ }
} SQL_LIST;
--- 1.117/sql/sql_lex.cc Tue Oct 26 18:05:16 2004
+++ 1.118/sql/sql_lex.cc Wed Nov 24 11:44:53 2004
@@ -124,7 +124,38 @@
void lex_start(THD *thd, uchar *buf,uint length)
{
LEX *lex= thd->lex;
- lex->thd= thd;
+ lex->unit.init_query();
+ lex->unit.init_select();
+ lex->thd= lex->unit.thd= thd;
+ lex->select_lex.init_query();
+ lex->value_list.empty();
+ lex->param_list.empty();
+ lex->view_list.empty();
+ lex->unit.next= lex->unit.master=
+ lex->unit.link_next= lex->unit.return_to= 0;
+ lex->unit.prev= lex->unit.link_prev= 0;
+ lex->unit.slave= lex->unit.global_parameters= lex->current_select=
+ lex->all_selects_list= &lex->select_lex;
+ lex->select_lex.master= &lex->unit;
+ lex->select_lex.prev= &lex->unit.slave;
+ lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
+ lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
+ lex->select_lex.options= 0;
+ lex->select_lex.init_order();
+ lex->select_lex.group_list.empty();
+ lex->describe= 0;
+ lex->derived_tables= FALSE;
+ lex->view_prepare_mode= FALSE;
+ lex->lock_option= TL_READ;
+ lex->found_colon= 0;
+ lex->safe_to_cache_query= 1;
+ lex->time_zone_tables_used= 0;
+ lex->proc_table= lex->query_tables= 0;
+ lex->query_tables_last= &lex->query_tables;
+ lex->variables_used= 0;
+ lex->select_lex.parent_lex= lex;
+ lex->empty_field_list_on_rset= 0;
+ lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
lex->buf= lex->ptr= buf;
lex->end_of_query=buf+length;
@@ -144,12 +175,10 @@
lex->duplicates= DUP_ERROR;
lex->sphead= NULL;
lex->spcont= NULL;
+ lex->proc_list.first= 0;
- extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
- hash_free(&lex->spfuns);
- hash_init(&lex->spfuns, system_charset_info, 0, 0, 0,
- sp_lex_spfuns_key, 0, 0);
-
+ if (lex->spfuns.records)
+ hash_reset(&lex->spfuns);
}
void lex_end(LEX *lex)
@@ -170,6 +199,14 @@
lex->yylval->symbol.symbol=symbol;
lex->yylval->symbol.str= (char*) tok;
lex->yylval->symbol.length=len;
+
+ if ((symbol->tok == NOT_SYM) &&
+ (lex->thd->variables.sql_mode & MODE_BROKEN_NOT))
+ return NOT2_SYM;
+ if ((symbol->tok == OR_OR_SYM) &&
+ !(lex->thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
+ return OR2_SYM;
+
return symbol->tok;
}
return 0;
@@ -532,6 +569,7 @@
/* Fall through */
case MY_LEX_IDENT_OR_BIN: // TODO: Add binary string handling
case MY_LEX_IDENT:
+ uchar *start;
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(cs))
{
@@ -568,11 +606,16 @@
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
length= (uint) (lex->ptr - lex->tok_start)-1;
+ start= lex->ptr;
if (lex->ignore_space)
{
- for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
+ /*
+ If we find a space then this can't be an identifier. We notice this
+ below by checking start != lex->ptr.
+ */
+ for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
}
- if (c == '.' && ident_map[yyPeek()])
+ if (start == lex->ptr && c == '.' && ident_map[yyPeek()])
lex->next_state=MY_LEX_IDENT_SEP;
else
{ // '(' must follow directly if function
@@ -1021,6 +1064,7 @@
first_cond_optimization= 1;
parsing_place= NO_MATTER;
no_wrap_view_item= 0;
+ link_next= 0;
}
void st_select_lex::init_select()
@@ -1272,7 +1316,7 @@
if (select_limit != HA_POS_ERROR)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "LIMIT & IN/ALL/ANY/SOME subquery");
+ "LIMIT & IN/ALL/ANY/SOME subquery");
return(1);
}
// We need only 1 row to determinate existence
@@ -1412,6 +1456,7 @@
1 - found
0 - OK (table did not found)
*/
+
bool st_select_lex_unit::check_updateable(char *db, char *table)
{
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
@@ -1422,8 +1467,8 @@
/*
- Find db.table which will be updated in this select and
- underlayed ones (except derived tables)
+ Find db.table which will be updated in this select and
+ underlying ones (except derived tables)
SYNOPSIS
st_select_lex::check_updateable()
@@ -1434,11 +1479,30 @@
1 - found
0 - OK (table did not found)
*/
+
bool st_select_lex::check_updateable(char *db, char *table)
{
if (find_table_in_local_list(get_table_list(), db, table))
return 1;
+ return check_updateable_in_subqueries(db, table);
+}
+
+/*
+ Find db.table which will be updated in underlying subqueries
+
+ SYNOPSIS
+ st_select_lex::check_updateable_in_subqueries()
+ db - data base name
+ table - real table name
+
+ RETURN
+ 1 - found
+ 0 - OK (table did not found)
+*/
+
+bool st_select_lex::check_updateable_in_subqueries(char *db, char *table)
+{
for (SELECT_LEX_UNIT *un= first_inner_unit();
un;
un= un->next_unit())
--- 1.148/sql/sql_lex.h Sat Nov 13 20:38:49 2004
+++ 1.149/sql/sql_lex.h Wed Nov 24 11:36:28 2004
@@ -750,11 +750,13 @@
/* Characterstics of trigger being created */
st_trg_chistics trg_chistics;
/*
- Points to table being opened when we are parsing trigger definition
- while opening table. 0 if we are parsing user provided CREATE TRIGGER
- or any other statement. Used for NEW/OLD row field lookup in trigger.
+ List of all items (Item_trigger_field objects) representing fields in
+ old/new version of row in trigger. We use this list for checking whenever
+ all such fields are valid at trigger creation time and for binding these
+ fields to TABLE object at table open (altough for latter pointer to table
+ being opened is probably enough).
*/
- TABLE *trg_table;
+ SQL_LIST trg_table_fields;
st_lex() :result(0)
{
--- 1.376/sql/sql_parse.cc Tue Nov 23 21:18:08 2004
+++ 1.377/sql/sql_parse.cc Wed Nov 24 11:36:28 2004
@@ -3912,11 +3912,11 @@
}
case SQLCOM_CREATE_TRIGGER:
{
- /* We don't care much about trigger body at that point */
+ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
+
+ /* We don't care about trigger body after this point */
delete lex->sphead;
lex->sphead= 0;
-
- res= mysql_create_or_drop_trigger(thd, all_tables, 1);
break;
}
case SQLCOM_DROP_TRIGGER:
--- 1.321/sql/sql_yacc.yy Wed Nov 17 20:00:05 2004
+++ 1.322/sql/sql_yacc.yy Wed Nov 24 11:44:53 2004
@@ -1238,8 +1238,9 @@
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
YYABORT;
}
-
- sp= new sp_head();
+
+ if (!(sp= new sp_head()))
+ YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
@@ -6622,6 +6623,7 @@
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
{
+ Item_trigger_field *trg_fld;
bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
@@ -6638,23 +6640,18 @@
YYABORT;
}
- Item_trigger_field *trg_fld=
- new Item_trigger_field(new_row ? Item_trigger_field::NEW_ROW :
- Item_trigger_field::OLD_ROW,
- $3.str);
-
- if (lex->trg_table &&
- trg_fld->setup_field(thd, lex->trg_table,
- lex->trg_chistics.event))
- {
- /*
- FIXME. Far from perfect solution. See comment for
- "SET NEW.field_name:=..." for more info.
- */
- my_error(ER_BAD_FIELD_ERROR, MYF(0),
- $3.str, new_row ? "NEW": "OLD");
+ if (!(trg_fld= new Item_trigger_field(new_row ?
+ Item_trigger_field::NEW_ROW:
+ Item_trigger_field::OLD_ROW,
+ $3.str)))
YYABORT;
- }
+
+ /*
+ Let us add this item to list of all Item_trigger_field objects
+ in trigger.
+ */
+ lex->trg_table_fields.link_in_list((byte *)trg_fld,
+ (byte**)&trg_fld->next_trg_field);
$$= (Item *)trg_fld;
}
@@ -7156,28 +7153,19 @@
/* QQ: Shouldn't this be field's default value ? */
it= new Item_null();
}
- i= new sp_instr_set_trigger_field(lex->sphead->instructions(),
- lex->spcont, $1.base_name, it);
- if (lex->trg_table && i->setup_field(YYTHD, lex->trg_table,
- lex->trg_chistics.event))
- {
- /*
- FIXME. Now we are catching this kind of errors only
- during opening tables. But this doesn't save us from most
- common user error - misspelling field name, because we
- will bark too late in this case... Moreover it is easy to
- make table unusable with such kind of error...
-
- So in future we either have to parse trigger definition
- second time during create trigger or gather all trigger
- fields in one list and perform setup_field() for them as
- separate stage.
-
- Error message also should be improved.
- */
- my_error(ER_BAD_FIELD_ERROR, MYF(0), $1.base_name, "NEW");
+
+ if (!(i= new sp_instr_set_trigger_field(
+ lex->sphead->instructions(), lex->spcont,
+ $1.base_name, it)))
YYABORT;
- }
+
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ lex->trg_table_fields.link_in_list((byte *)&i->trigger_field,
+ (byte **)&i->trigger_field.next_trg_field);
+
lex->sphead->add_instr(i);
}
else if ($1.var)
--- 1.3/mysql-test/r/trigger.result Tue Oct 26 18:05:16 2004
+++ 1.4/mysql-test/r/trigger.result Wed Nov 24 11:36:28 2004
@@ -178,3 +178,15 @@
insert into t1 values ('y');
drop trigger t1.tx1;
drop table t1;
+create table t1 (i int) engine=myisam;
+insert into t1 values (1), (2);
+create trigger trg1 before delete on t1 for each row set @del_before:= @del_before + old.i;
+create trigger trg2 after delete on t1 for each row set @del_after:= @del_after + old.i;
+set @del_before:=0, @del_after:= 0;
+delete from t1;
+select @del_before, @del_after;
+@del_before @del_after
+3 3
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop table t1;
--- 1.5/mysql-test/t/trigger.test Tue Oct 26 18:05:16 2004
+++ 1.6/mysql-test/t/trigger.test Wed Nov 24 11:36:28 2004
@@ -209,3 +209,20 @@
insert into t1 values ('y');
drop trigger t1.tx1;
drop table t1;
+
+#
+# Test for bug #5890 "Triggers fail for DELETE without WHERE".
+# If we are going to delete all rows in table but DELETE triggers exist
+# we should perform row-by-row deletion instead of using optimized
+# delete_all_rows() method.
+#
+create table t1 (i int) engine=myisam;
+insert into t1 values (1), (2);
+create trigger trg1 before delete on t1 for each row set @del_before:= @del_before + old.i;
+create trigger trg2 after delete on t1 for each row set @del_after:= @del_after + old.i;
+set @del_before:=0, @del_after:= 0;
+delete from t1;
+select @del_before, @del_after;
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop table t1;
--- 1.8/sql/sql_trigger.cc Sat Nov 13 20:35:44 2004
+++ 1.9/sql/sql_trigger.cc Wed Nov 24 11:44:53 2004
@@ -136,6 +136,7 @@
char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
LEX_STRING dir, file;
LEX_STRING *trg_def, *name;
+ Item_trigger_field *trg_field;
List_iterator_fast<LEX_STRING> it(names_list);
/* We don't allow creation of several triggers of the same type yet */
@@ -157,6 +158,31 @@
}
/*
+ Let us check if all references to fields in old/new versions of row in
+ this trigger are ok.
+
+ NOTE: We do it here more from ease of use standpoint. We still have to
+ do some checks on each execution. E.g. we can catch privilege changes
+ only during execution. Also in near future, when we will allow access
+ to other tables from trigger we won't be able to catch changes in other
+ tables...
+
+ To simplify code a bit we have to create Fields for accessing to old row
+ values if we have ON UPDATE trigger.
+ */
+ if (!old_field && lex->trg_chistics.event == TRG_EVENT_UPDATE &&
+ prepare_old_row_accessors(table))
+ return 1;
+
+ for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first);
+ trg_field; trg_field= trg_field->next_trg_field)
+ {
+ trg_field->setup_field(thd, table, lex->trg_chistics.event);
+ if (trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0))
+ return 1;
+ }
+
+ /*
Here we are creating file with triggers and save all triggers in it.
sql_create_definition_file() files handles renaming and backup of older
versions
@@ -275,6 +301,44 @@
/*
+ Prepare array of Field objects which will represent OLD.* row values in
+ ON UPDATE trigger (by referencing to record[1] instead of record[0]).
+
+ SYNOPSIS
+ prepare_old_row_accessors()
+ table - pointer to TABLE object for which we are creating fields.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::prepare_old_row_accessors(TABLE *table)
+{
+ Field **fld, **old_fld;
+
+ if (!(old_field= (Field **)alloc_root(&table->mem_root,
+ (table->fields + 1) *
+ sizeof(Field*))))
+ return 1;
+
+ for (fld= table->field, old_fld= old_field; *fld; fld++, old_fld++)
+ {
+ /*
+ QQ: it is supposed that it is ok to use this function for field
+ cloning...
+ */
+ if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
+ return 1;
+ (*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
+ table->record[0]));
+ }
+ *old_fld= 0;
+
+ return 0;
+}
+
+
+/*
Check whenever .TRG file for table exist and load all triggers it contains.
SYNOPSIS
@@ -317,7 +381,6 @@
if (!strncmp(triggers_file_type.str, parser->type()->str,
parser->type()->length))
{
- Field **fld, **old_fld;
Table_triggers_list *triggers=
new (&table->mem_root) Table_triggers_list();
@@ -330,31 +393,10 @@
table->triggers= triggers;
- /*
- We have to prepare array of Field objects which will represent OLD.*
- row values by referencing to record[1] instead of record[0]
-
- TODO: This could be avoided if there is no ON UPDATE trigger.
- */
- if (!(triggers->old_field=
- (Field **)alloc_root(&table->mem_root, (table->fields + 1) *
- sizeof(Field*))))
+ /* TODO: This could be avoided if there is no ON UPDATE trigger. */
+ if (triggers->prepare_old_row_accessors(table))
DBUG_RETURN(1);
- for (fld= table->field, old_fld= triggers->old_field; *fld;
- fld++, old_fld++)
- {
- /*
- QQ: it is supposed that it is ok to use this function for field
- cloning...
- */
- if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
- DBUG_RETURN(1);
- (*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
- table->record[0]));
- }
- *old_fld= 0;
-
List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
LEX_STRING *trg_create_str, *trg_name_str;
char *trg_name_buff;
@@ -365,7 +407,7 @@
while ((trg_create_str= it++))
{
lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
- lex.trg_table= table;
+
if (yyparse((void *)thd) || thd->is_fatal_error)
{
/*
@@ -399,6 +441,21 @@
if (triggers->names_list.push_back(trg_name_str, &table->mem_root))
goto err_with_lex_cleanup;
+
+ /*
+ Let us bind Item_trigger_field objects representing access to fields
+ in old/new versions of row in trigger to Field objects in table being
+ opened.
+
+ We ignore errors here, because if even something is wrong we still will
+ be willing to open table to perform some operations (e.g. SELECT)...
+ Anyway some things can be checked only during trigger execution.
+ */
+ for (Item_trigger_field *trg_field=
+ (Item_trigger_field *)(lex.trg_table_fields.first);
+ trg_field;
+ trg_field= trg_field->next_trg_field)
+ trg_field->setup_field(thd, table, lex.trg_chistics.event);
lex_end(&lex);
}
--- 1.2/sql/sql_trigger.h Tue Oct 26 18:05:16 2004
+++ 1.3/sql/sql_trigger.h Wed Nov 24 11:36:29 2004
@@ -58,6 +58,12 @@
static bool check_n_load(THD *thd, const char *db, const char *table_name,
TABLE *table);
+ bool has_delete_triggers()
+ {
+ return (bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] ||
+ bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]);
+ }
+
friend class Item_trigger_field;
private:
--- 1.104/sql/sp_head.cc Sat Nov 13 20:35:43 2004
+++ 1.105/sql/sp_head.cc Wed Nov 24 11:36:28 2004
@@ -275,6 +275,11 @@
DBUG_ENTER("sp_head::init");
lex->spcont= m_pcont= new sp_pcontext(NULL);
+ /*
+ Altough trg_table_fields list is used only in triggers we init for all
+ types of stored procedures to simplify reset_lex()/restore_lex() code.
+ */
+ lex->trg_table_fields.empty();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0;
m_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str=
@@ -771,7 +776,7 @@
sublex->spcont= oldlex->spcont;
/* And trigger related stuff too */
sublex->trg_chistics= oldlex->trg_chistics;
- sublex->trg_table= oldlex->trg_table;
+ sublex->trg_table_fields.empty();
sublex->sp_lex_in_use= FALSE;
DBUG_VOID_RETURN;
}
@@ -790,6 +795,7 @@
// Update some state in the old one first
oldlex->ptr= sublex->ptr;
oldlex->next_state= sublex->next_state;
+ oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
// Collect some data from the sub statement lex.
sp_merge_funs(oldlex, sublex);
--- 1.48/sql/sp_head.h Tue Oct 26 18:05:16 2004
+++ 1.49/sql/sp_head.h Wed Nov 24 11:36:28 2004
@@ -231,7 +231,7 @@
private:
- MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
+ MEM_ROOT *m_thd_root; // Temp. store for thd's mem_root
THD *m_thd; // Set if we have reset mem_root
char *m_thd_db; // Original thd->db pointer
| Thread |
|---|
| • bk commit into 5.0 tree (dlenev:1.1684) | dlenev | 24 Nov |