diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log.cc | 8 | ||||
-rw-r--r-- | sql/log_event.cc | 161 | ||||
-rw-r--r-- | sql/log_event.h | 19 | ||||
-rw-r--r-- | sql/mysql_priv.h | 6 | ||||
-rw-r--r-- | sql/set_var.cc | 10 | ||||
-rw-r--r-- | sql/set_var.h | 4 | ||||
-rw-r--r-- | sql/slave.cc | 50 | ||||
-rw-r--r-- | sql/slave.h | 10 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 20 |
9 files changed, 221 insertions, 67 deletions
diff --git a/sql/log.cc b/sql/log.cc index 6c97581d144..7d6854b6fb4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1346,7 +1346,7 @@ bool MYSQL_LOG::write(Log_event* event_info) if (thd) { - /* NOTE: CHARSET AND TZ REPL WILL BE REWRITTEN SHORTLY */ +#if MYSQL_VERSION_ID < 50003 /* To make replication of charsets working in 4.1 we are writing values of charset related variables before every statement in the binlog, @@ -1375,9 +1375,15 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u", if (e.write(file)) goto err; } +#endif /* We use the same ONE_SHOT trick for making replication of time zones working in 4.1. Again in 5.0 we have better means for doing this. + + TODO: we should do like we now do with charsets (no more ONE_SHOT; + logging in each event in a compact format). Dmitri says we can do: + if (time_zone_used) write the timezone to binlog (in a format to be + defined). */ if (thd->time_zone_used && thd->variables.time_zone != global_system_variables.time_zone) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5ee034d785e..d09b2b3dc03 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -953,7 +953,13 @@ void Query_log_event::pack_info(Protocol *protocol) bool Query_log_event::write(IO_CACHE* file) { - uchar buf[QUERY_HEADER_LEN+1+4+1+8+1+1+FN_REFLEN+5], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN+ + 1+4+ // code of flags2 and flags2 + 1+8+ // code of sql_mode and sql_mode + 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog + 1+4+ // code of autoinc and the 2 autoinc variables + 1+6 // code of charset and charset + ], *start, *start_of_status; ulong event_length; if (!query) @@ -1048,9 +1054,15 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start+2, auto_increment_offset); start+= 4; } + if (charset_inited) + { + *(start++)= Q_CHARSET_CODE; + memcpy(start, charset, 6); + start+= 6; + } /* Here there could be code like - if (command-line-option-which-says-"log_this_variable") + if (command-line-option-which-says-"log_this_variable" && inited) { *(start++)= Q_THIS_VARIABLE_CODE; int4store(start, this_variable); @@ -1095,7 +1107,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, thread_id(thd_arg->thread_id), /* save the original thread id; we already know the server id */ slave_proxy_id(thd_arg->variables.pseudo_thread_id), - flags2_inited(1), sql_mode_inited(1), flags2(0), + flags2_inited(1), sql_mode_inited(1), charset_inited(1), sql_mode(thd_arg->variables.sql_mode), auto_increment_increment(thd_arg->variables.auto_increment_increment), auto_increment_offset(thd_arg->variables.auto_increment_offset) @@ -1104,7 +1116,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, time(&end_time); exec_time = (ulong) (end_time - thd->start_time); catalog_len = (catalog) ? (uint32) strlen(catalog) : 0; - status_vars_len= 1+4+1+8+1+1+catalog_len+1; + /* status_vars_len is set just before writing the event */ db_len = (db) ? (uint32) strlen(db) : 0; /* If we don't use flags2 for anything else than options contained in @@ -1114,7 +1126,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, we will probably want to reclaim the 29 bits. So we need the &. */ flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG; - + DBUG_ASSERT(thd->variables.character_set_client->number < 256*256); + DBUG_ASSERT(thd->variables.collation_connection->number < 256*256); + DBUG_ASSERT(thd->variables.collation_server->number < 256*256); + int2store(charset, thd_arg->variables.character_set_client->number); + int2store(charset+2, thd_arg->variables.collation_connection->number); + int2store(charset+4, thd_arg->variables.collation_server->number); DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode)); } #endif /* MYSQL_CLIENT */ @@ -1129,7 +1146,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, const Format_description_log_event *description_event) :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), db(NullS), catalog_len(0), status_vars_len(0), - flags2_inited(0), sql_mode_inited(0) + flags2_inited(0), sql_mode_inited(0), charset_inited(0), + auto_increment_increment(1), auto_increment_offset(1) { ulong data_len; uint32 tmp; @@ -1156,8 +1174,6 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET); db_len = (uint)buf[Q_DB_LEN_OFFSET]; error_code = uint2korr(buf + Q_ERR_CODE_OFFSET); - /* If auto_increment is not set by query_event, they should not be used */ - auto_increment_increment= auto_increment_offset= 1; /* 5.0 format starts here. @@ -1216,6 +1232,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, auto_increment_offset= uint2korr(pos+2); pos+= 4; break; + case Q_CHARSET_CODE: + { + charset_inited= 1; + memcpy(charset, pos, 6); + pos+= 6; + break; + } default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -1348,6 +1371,27 @@ void Query_log_event::print(FILE* file, bool short_form, last_event_info->auto_increment_offset= auto_increment_offset; } + if (likely(charset_inited)) + { + if (unlikely(!last_event_info->charset_inited)) /* first Query event */ + { + last_event_info->charset_inited= 1; + last_event_info->charset[0]= ~charset[0]; // force a difference to force write + } + if (unlikely(bcmp(last_event_info->charset, charset, 6))) + { + fprintf(file,"SET " + "@@session.character_set_client=%d," + "@@session.collation_connection=%d," + "@@session.collation_server=%d" + ";\n", + uint2korr(charset), + uint2korr(charset+2), + uint2korr(charset+4)); + memcpy(last_event_info->charset, charset, 6); + } + } + my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fputs(";\n", file); } @@ -1400,34 +1444,64 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->variables.pseudo_thread_id= thread_id; // for temp tables mysql_log.write(thd,COM_QUERY,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); - - if (flags2_inited) - /* - all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must - take their value from flags2. - */ - thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG); - /* - else, we are in a 3.23/4.0 binlog; we previously received a - Rotate_log_event which reset thd->options and sql_mode, so nothing to do. - */ - - /* - We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a - slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not - force us to ignore the dir too. Imagine you are a ring of machines, and - one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE - on this machine; you don't want it to propagate elsewhere (you don't want - all slaves to start ignoring the dirs). - */ - if (sql_mode_inited) - thd->variables.sql_mode= - (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) | - (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE)); if (ignored_error_code((expected_error= error_code)) || !check_expected_error(thd,rli,expected_error)) + { + if (flags2_inited) + /* + all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must + take their value from flags2. + */ + thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG); + /* + else, we are in a 3.23/4.0 binlog; we previously received a + Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do. + */ + /* + We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a + slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not + force us to ignore the dir too. Imagine you are a ring of machines, and + one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE + on this machine; you don't want it to propagate elsewhere (you don't want + all slaves to start ignoring the dirs). + */ + if (sql_mode_inited) + thd->variables.sql_mode= + (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) | + (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE)); + if (charset_inited) + { + if (rli->cached_charset_compare(charset)) + { + /* Verify that we support the charsets found in the event. */ + if (!(thd->variables.character_set_client= + get_charset(uint2korr(charset), MYF(MY_WME))) || + !(thd->variables.collation_connection= + get_charset(uint2korr(charset+2), MYF(MY_WME))) || + !(thd->variables.collation_server= + get_charset(uint2korr(charset+4), MYF(MY_WME)))) + { + /* + We updated the thd->variables with nonsensical values (0), and the + thread is not guaranteed to terminate now (as it may be configured + to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next + statement we'll have a new charset info with it, so no problem to + have stored 0 in thd->variables. But we invalidate cached + charset to force a check next time (otherwise if next time + charset is unknown again we won't detect it). + */ + rli->cached_charset_invalidate(); + goto compare_errors; + } + thd->update_charset(); // for the charset change to take effect + } + } + + /* Execute the query (note that we bypass dispatch_command()) */ mysql_parse(thd, thd->query, q_len); + + } else { /* @@ -1452,6 +1526,8 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); } goto end; } + +compare_errors: /* If we expected a non-zero error code, and we don't get the same error @@ -1666,12 +1742,7 @@ bool Start_log_event_v3::write(IO_CACHE* file) int Start_log_event_v3::exec_event(struct st_relay_log_info* rli) { DBUG_ENTER("Start_log_event_v3::exec_event"); - /* - If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT - (that's what the MASTER_INFO constructor does), so the test below is not - perfect at all. - */ - switch (rli->relay_log.description_event_for_exec->binlog_version) + switch (binlog_version) { case 3: case 4: @@ -2789,14 +2860,24 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) rli->group_master_log_name, (ulong) rli->group_master_log_pos)); /* - Reset thd->options and sql_mode, because this could be the signal of a - master's downgrade from 5.0 to 4.0. + Reset thd->options and sql_mode etc, because this could be the signal of + a master's downgrade from 5.0 to 4.0. However, no need to reset description_event_for_exec: indeed, if the next master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next master is 4.0 then the events are in the slave's format (conversion). */ set_slave_thread_options(thd); thd->variables.sql_mode= global_system_variables.sql_mode; + thd->variables.auto_increment_increment= + thd->variables.auto_increment_offset= 1; + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.collation_server= + global_system_variables.collation_server; + thd->update_charset(); + rli->cached_charset_invalidate(); } pthread_mutex_unlock(&rli->data_lock); pthread_cond_broadcast(&rli->data_cond); diff --git a/sql/log_event.h b/sql/log_event.h index 64bb9d502e9..7f04582a32d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -232,6 +232,7 @@ struct sql_ex_info #define Q_SQL_MODE_CODE 1 #define Q_CATALOG_CODE 2 #define Q_AUTO_INCREMENT 3 +#define Q_CHARSET_CODE 4 /* Intvar event post-header */ @@ -401,11 +402,19 @@ typedef struct st_last_event_info bool sql_mode_inited; ulong sql_mode; /* must be same as THD.variables.sql_mode */ ulong auto_increment_increment, auto_increment_offset; + bool charset_inited; + char charset[6]; // 3 variables, each of them storable in 2 bytes st_last_event_info() - :flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0), - auto_increment_increment(1),auto_increment_offset(1) + :flags2_inited(0), sql_mode_inited(0), + auto_increment_increment(1),auto_increment_offset(1), charset_inited(0) { - db[0]= 0; /* initially, the db is unknown */ + /* + Currently we only use static LAST_EVENT_INFO objects, so zeroed at + program's startup, but these explicit bzero() is for the day someone + creates dynamic instances. + */ + bzero(db, sizeof(db)); + bzero(charset, sizeof(charset)); } } LAST_EVENT_INFO; #endif @@ -634,7 +643,7 @@ public: status_vars on disk is a sequence of pairs (code, value) where 'code' means 'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so its first byte is its length. For now the order of status vars is: - flags2 - sql_mode - catalog. + flags2 - sql_mode - catalog - autoinc - charset We should add the same thing to Load_log_event, but in fact LOAD DATA INFILE is going to be logged with a new type of event (logging of the plain text query), so Load_log_event would be frozen, so no need. The @@ -655,11 +664,13 @@ public: */ bool flags2_inited; bool sql_mode_inited; + bool charset_inited; uint32 flags2; /* In connections sql_mode is 32 bits now but will be 64 bits soon */ ulong sql_mode; ulong auto_increment_increment, auto_increment_offset; + char charset[6]; #ifndef MYSQL_CLIENT diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index bf84e0a394e..6311b2d5f52 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -285,6 +285,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2) #define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2) #define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2) +/* + Replication uses 8 bytes to store SQL_MODE in the binary log. The day you + use strictly more than 64 bits by adding one more define above, you should + contact the replication team because the replication code should then be + updated (to store more bytes on disk). +*/ #define RAID_BLOCK_SIZE 1024 diff --git a/sql/set_var.cc b/sql/set_var.cc index f4d07360282..142ef64a41f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2061,9 +2061,15 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) } } -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool sys_var_character_set_server::check(THD *thd, set_var *var) { + /* + To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master, + and user wants to change our global character set variables. Because + replicating a 4.1 assumes those are not changed. But that's not easy to + do. + */ if ((var->type == OPT_GLOBAL) && (mysql_bin_log.is_open() || active_mi->slave_running || active_mi->rli.slave_running)) @@ -2168,7 +2174,7 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type) } } -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool sys_var_collation_server::check(THD *thd, set_var *var) { if ((var->type == OPT_GLOBAL) && diff --git a/sql/set_var.h b/sql/set_var.h index 8514b518660..3104fd38976 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -564,7 +564,7 @@ class sys_var_character_set_server :public sys_var_character_set public: sys_var_character_set_server(const char *name_arg) : sys_var_character_set(name_arg) {} -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool check(THD *thd, set_var *var); #endif void set_default(THD *thd, enum_var_type type); @@ -602,7 +602,7 @@ class sys_var_collation_server :public sys_var_collation { public: sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {} -#if defined(HAVE_REPLICATION) +#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003) bool check(THD *thd, set_var *var); #endif bool update(THD *thd, set_var *var); diff --git a/sql/slave.cc b/sql/slave.cc index 0c5ebe0744a..380aba6f3b6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -660,13 +660,14 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, pthread_cond_t* term_cond, volatile uint *slave_running) { + DBUG_ENTER("terminate_slave_thread"); if (term_lock) { pthread_mutex_lock(term_lock); if (!*slave_running) { pthread_mutex_unlock(term_lock); - return ER_SLAVE_NOT_RUNNING; + DBUG_RETURN(ER_SLAVE_NOT_RUNNING); } } DBUG_ASSERT(thd != 0); @@ -678,6 +679,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, while (*slave_running) // Should always be true { + DBUG_PRINT("loop", ("killing slave thread")); KICK_SLAVE(thd); /* There is a small chance that slave thread might miss the first @@ -689,7 +691,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, } if (term_lock) pthread_mutex_unlock(term_lock); - return 0; + DBUG_RETURN(0); } @@ -1418,13 +1420,20 @@ not always make sense; please check the manual before using it)."; values of these 2 are never used (new connections don't use them). We don't test equality of global collation_database either as it's is going to be deprecated (made read-only) in 4.1 very soon. - We don't do it for <3.23.57 because masters <3.23.50 hang on - SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). + The test is only relevant if master < 5.0.3 (we'll test only if it's older + than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores + charset info in each binlog event. + We don't do it for 3.23 because masters <3.23.50 hang on + SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we + test only if master is 4.x. */ - if (strncmp(mi->rli.relay_log.description_event_for_queue->server_version, - "3.23.57",7) < 0) + + /* redundant with rest of code but safer against later additions */ + if (*mysql->server_version == '3') goto err; - if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && + + if ((*mysql->server_version == '4') && + !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -1447,8 +1456,12 @@ be equal for replication to work"; such check will broke everything for them. (And now everything will work for them because by default both their master and slave will have 'SYSTEM' time zone). + + TODO: when the new replication of timezones is sorted out with Dmitri, + change >= '4' to == '4'. */ - if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && + if ((*mysql->server_version >= '4') && + !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && (master_res= mysql_store_result(mysql))) { if ((master_row= mysql_fetch_row(master_res)) && @@ -2527,6 +2540,7 @@ st_relay_log_info::st_relay_log_info() bzero((char*) &info_file, sizeof(info_file)); bzero((char*) &cache_buf, sizeof(cache_buf)); + cached_charset_invalidate(); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); @@ -3078,6 +3092,24 @@ bool st_relay_log_info::is_until_satisfied() } +void st_relay_log_info::cached_charset_invalidate() +{ + /* Full of zeroes means uninitialized. */ + bzero(cached_charset, sizeof(cached_charset)); +} + + +bool st_relay_log_info::cached_charset_compare(char *charset) +{ + if (bcmp(cached_charset, charset, sizeof(cached_charset))) + { + memcpy(cached_charset, charset, sizeof(cached_charset)); + return 1; + } + return 0; +} + + static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) { /* @@ -3722,6 +3754,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions")); pthread_cond_broadcast(&rli->data_cond); rli->ignore_log_space_limit= 0; /* don't need any lock */ + /* we die so won't remember charset - re-update them on next thread start */ + rli->cached_charset_invalidate(); rli->save_temporary_tables = thd->temporary_tables; /* diff --git a/sql/slave.h b/sql/slave.h index e0816fd45a7..598ff0a7845 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -291,6 +291,8 @@ typedef struct st_relay_log_info UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1, UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1 } until_log_names_cmp_result; + + char cached_charset[6]; st_relay_log_info(); ~st_relay_log_info(); @@ -334,6 +336,14 @@ typedef struct st_relay_log_info return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos : group_relay_log_pos); } + /* + Last charset (6 bytes) seen by slave SQL thread is cached here; it helps + the thread save 3 get_charset() per Query_log_event if the charset is not + changing from event to event (common situation). + When the 6 bytes are equal to 0 is used to mean "cache is invalidated". + */ + void cached_charset_invalidate(); + bool cached_charset_compare(char *charset); } RELAY_LOG_INFO; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ec2abfdbf76..a94fb31580c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4032,14 +4032,15 @@ bool_test: bool_pri: bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); } | bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); } - | predicate BETWEEN_SYM bit_expr AND_SYM bool_pri - { $$= new Item_func_between($1,$3,$5); } - | predicate not BETWEEN_SYM bit_expr AND_SYM bool_pri - { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } + | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); } + | bool_pri comp_op predicate %prec EQ + { $$= (*$2)(0)->create($1,$3); } + | bool_pri comp_op all_or_any in_subselect %prec EQ + { $$= all_any_subquery_creator($1, $2, $3, $4); } | predicate ; predicate: - bit_expr IN_SYM '(' expr_list ')' + bit_expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | bit_expr not IN_SYM '(' expr_list ')' { $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); } @@ -4047,6 +4048,10 @@ predicate: { $$= new Item_in_subselect($1, $3); } | bit_expr not IN_SYM in_subselect { $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); } + | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate + { $$= new Item_func_between($1,$3,$5); } + | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate + { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); } | bit_expr SOUNDS_SYM LIKE bit_expr { $$= new Item_func_eq(new Item_func_soundex($1), new Item_func_soundex($4)); } @@ -4057,11 +4062,6 @@ predicate: | bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); } | bit_expr not REGEXP bit_expr { $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); } - | bit_expr EQUAL_SYM bit_expr { $$= new Item_func_equal($1,$3); } - | bit_expr comp_op bit_expr %prec EQ - { $$= (*$2)(0)->create($1,$3); } - | bit_expr comp_op all_or_any in_subselect %prec EQ - { $$= all_any_subquery_creator($1, $2, $3, $4); } | bit_expr ; bit_expr: |